usb: changes for v4.15 merge window
Not much going on this time around. With only 51 non-merge commits, this was one of the smallest pull requests from the Gadget tree. Most of the changes are in the mtu3 driver which added support for 36-bit DMA, support for USB 3.1 and support for dual-role (along with some non-critical fixes). The dwc2 driver got a few improvements to how we handle gadget state tracking and also added support for STM32F7xx devices. Other than that, we just some minor non-critical fixes and improvements all over the place. -----BEGIN PGP SIGNATURE----- iQJRBAABCgA7FiEElLzh7wn96CXwjh2IzL64meEamQYFAlnvDUQdHGZlbGlwZS5i YWxiaUBsaW51eC5pbnRlbC5jb20ACgkQzL64meEamQbaFg//WorvPDm7vu/o5G4r pMCLodF0Ye6sFs5Ug2X2Fr3sXpRTlr6LfPi6Zt3rwimF5EBtDuNF0Tu8jKj0vfSI iKYpXIvDOc4DVeqMiQzw3kBt8FQcUjb8cVV2VUbO9ata0ALUF3TH27PUIS0R1vTG HOhSx4EVIkpp2vM9XOFBWi2e46HsDscoymGNXn/b3WmAUysPoNf+7i9NUgI88VHZ KbFmdYlMyvPTOQsJM3EaNIoGmWzoNtuBU+W0aO0h17QweGaDDpINBFocCru/MWT3 d8IaRtkHmq+nUYMM3IrKCL0i40uq86ckm110jEYhBLkZsAlf728118MKnD4PnJoR NMnRn1xLV0/JbGV0Nq1Kz0WefYiWj7nsve7TNnDDteJ8PKZTzQUSb0LQ4KIQTBo3 3LfeQgRmhzSafJ11xr1IWiVti7D6ijkqMw8R+z+YazTCN9Mgwt0aA/BFDihcSNR8 Qan9VHqiCvldfJCY0a+VoD5lE1zWeYqBkDF2XhrjuhEvfo9fjrJnJ1ElQhFDT8w8 zJDerBpxuVlYZta45t7PKS6Y4XiuVZrwXo8ilTQEVg68KoJ4GX7GhKJbfResuaKB OvSvr2aRCAAKhXil7C8sRVjdpRdLhKNY6NQisxEwhrqaGI7RzWIhibFlHGWwLNNv HYjtoNi5JcZmeteEdXeBLRyPUtI= =nkak -----END PGP SIGNATURE----- Merge tag 'usb-for-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next Felipe writes: usb: changes for v4.15 merge window Not much going on this time around. With only 51 non-merge commits, this was one of the smallest pull requests from the Gadget tree. Most of the changes are in the mtu3 driver which added support for 36-bit DMA, support for USB 3.1 and support for dual-role (along with some non-critical fixes). The dwc2 driver got a few improvements to how we handle gadget state tracking and also added support for STM32F7xx devices. Other than that, we just some minor non-critical fixes and improvements all over the place.
This commit is contained in:
Коммит
2d5afd51fe
|
@ -19,6 +19,8 @@ Required properties:
|
|||
configured in FS mode;
|
||||
- "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs
|
||||
configured in HS mode;
|
||||
- "st,stm32f7xx-hsotg": The DWC2 USB HS controller instance in STM32F7xx SoCs
|
||||
configured in HS mode;
|
||||
- reg : Should contain 1 register range (address and length)
|
||||
- interrupts : Should contain 1 interrupt
|
||||
- clocks: clock provider specifier
|
||||
|
|
|
@ -14,9 +14,9 @@ Required properties:
|
|||
- vusb33-supply : regulator of USB avdd3.3v
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : must contain "sys_ck" and "ref_ck" for clock of controller;
|
||||
"wakeup_deb_p0" and "wakeup_deb_p1" are optional, they are
|
||||
depends on "mediatek,enable-wakeup"
|
||||
- clock-names : must contain "sys_ck" for clock of controller,
|
||||
the following clocks are optional:
|
||||
"ref_ck", "mcu_ck" and "dam_ck";
|
||||
- phys : a list of phandle + phy specifier pairs
|
||||
- dr_mode : should be one of "host", "peripheral" or "otg",
|
||||
refer to usb/generic.txt
|
||||
|
@ -30,9 +30,10 @@ Optional properties:
|
|||
when supports dual-role mode.
|
||||
- vbus-supply : reference to the VBUS regulator, needed when supports
|
||||
dual-role mode.
|
||||
- pinctl-names : a pinctrl state named "default" must be defined,
|
||||
"id_float" and "id_ground" are optinal which depends on
|
||||
"mediatek,enable-manual-drd"
|
||||
- pinctrl-names : a pinctrl state named "default" is optional, and need be
|
||||
defined if auto drd switch is enabled, that means the property dr_mode
|
||||
is set as "otg", and meanwhile the property "mediatek,enable-manual-drd"
|
||||
is not set.
|
||||
- pinctrl-0 : pin control group
|
||||
See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
|
||||
|
||||
|
@ -44,6 +45,8 @@ Optional properties:
|
|||
- mediatek,enable-wakeup : supports ip sleep wakeup used by host mode
|
||||
- mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
|
||||
control register, it depends on "mediatek,enable-wakeup".
|
||||
- mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
|
||||
bit1 for u3port1, ... etc;
|
||||
|
||||
Sub-nodes:
|
||||
The xhci should be added as subnode to mtu3 as shown in the following example
|
||||
|
@ -63,9 +66,7 @@ ssusb: usb@11271000 {
|
|||
clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>,
|
||||
<&pericfg CLK_PERI_USB0>,
|
||||
<&pericfg CLK_PERI_USB1>;
|
||||
clock-names = "sys_ck", "ref_ck",
|
||||
"wakeup_deb_p0",
|
||||
"wakeup_deb_p1";
|
||||
clock-names = "sys_ck", "ref_ck";
|
||||
vusb33-supply = <&mt6397_vusb_reg>;
|
||||
vbus-supply = <&usb_p0_vbus>;
|
||||
extcon = <&extcon_usb>;
|
||||
|
|
|
@ -15,6 +15,10 @@ Required properties:
|
|||
- interrupts: Interrupt specifier for the USB3.0 Peripheral
|
||||
- clocks: clock phandle and specifier pair
|
||||
|
||||
Optional properties:
|
||||
- phys: phandle + phy specifier pair
|
||||
- phy-names: must be "usb"
|
||||
|
||||
Example of R-Car H3 ES1.x:
|
||||
usb3_peri0: usb@ee020000 {
|
||||
compatible = "renesas,r8a7795-usb3-peri",
|
||||
|
|
|
@ -3,6 +3,8 @@ Renesas Electronics USBHS driver
|
|||
Required properties:
|
||||
- compatible: Must contain one or more of the following:
|
||||
|
||||
- "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device
|
||||
- "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
|
||||
- "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
|
||||
- "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
|
||||
- "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
|
||||
|
@ -10,7 +12,8 @@ Required properties:
|
|||
- "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
|
||||
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
|
||||
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
|
||||
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 compatible device
|
||||
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
|
||||
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
|
||||
- "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
|
|
|
@ -395,6 +395,9 @@ enum dwc2_ep0_state {
|
|||
* (default when phy_type is UTMI+ or ULPI)
|
||||
* 1 - 6 MHz
|
||||
* (default when phy_type is Full Speed)
|
||||
* @oc_disable: Flag to disable overcurrent condition.
|
||||
* 0 - Allow overcurrent condition to get detected
|
||||
* 1 - Disable overcurrent condtion to get detected
|
||||
* @ts_dline: Enable Term Select Dline pulsing
|
||||
* 0 - No (default)
|
||||
* 1 - Yes
|
||||
|
@ -492,6 +495,7 @@ struct dwc2_core_params {
|
|||
bool dma_desc_fs_enable;
|
||||
bool host_support_fs_ls_low_power;
|
||||
bool host_ls_low_power_phy_clk;
|
||||
bool oc_disable;
|
||||
|
||||
u8 host_channels;
|
||||
u16 host_rx_fifo_size;
|
||||
|
|
|
@ -3202,6 +3202,8 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
|
|||
|
||||
call_gadget(hsotg, disconnect);
|
||||
hsotg->lx_state = DWC2_L3;
|
||||
|
||||
usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4004,6 +4006,11 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) {
|
||||
dev_err(hsotg->dev, "%s: called in host mode?\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
|
|
@ -213,6 +213,11 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
|
|||
usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
|
||||
if (hsotg->params.phy_ulpi_ddr)
|
||||
usbcfg |= GUSBCFG_DDRSEL;
|
||||
|
||||
/* Set external VBUS indicator as needed. */
|
||||
if (hsotg->params.oc_disable)
|
||||
usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND |
|
||||
GUSBCFG_INDICATORPASSTHROUGH);
|
||||
break;
|
||||
case DWC2_PHY_TYPE_PARAM_UTMI:
|
||||
/* UTMI+ interface */
|
||||
|
@ -3277,7 +3282,6 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
|
|||
dwc2_core_init(hsotg, false);
|
||||
dwc2_enable_global_interrupts(hsotg);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
dwc2_hsotg_disconnect(hsotg);
|
||||
dwc2_hsotg_core_init_disconnected(hsotg, false);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
dwc2_hsotg_core_connect(hsotg);
|
||||
|
@ -3296,8 +3300,12 @@ host:
|
|||
if (count > 250)
|
||||
dev_err(hsotg->dev,
|
||||
"Connection id status change timed out\n");
|
||||
hsotg->op_state = OTG_STATE_A_HOST;
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
dwc2_hsotg_disconnect(hsotg);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
hsotg->op_state = OTG_STATE_A_HOST;
|
||||
/* Initialize the Core for Host mode */
|
||||
dwc2_core_init(hsotg, false);
|
||||
dwc2_enable_global_interrupts(hsotg);
|
||||
|
|
|
@ -136,6 +136,15 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
|
|||
p->activate_stm_fs_transceiver = true;
|
||||
}
|
||||
|
||||
static void dwc2_set_stm32f7xx_hsotg_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
p->host_rx_fifo_size = 622;
|
||||
p->host_nperio_tx_fifo_size = 128;
|
||||
p->host_perio_tx_fifo_size = 256;
|
||||
}
|
||||
|
||||
const struct of_device_id dwc2_of_match_table[] = {
|
||||
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
|
||||
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
|
||||
|
@ -154,6 +163,8 @@ const struct of_device_id dwc2_of_match_table[] = {
|
|||
{ .compatible = "st,stm32f4x9-fsotg",
|
||||
.data = dwc2_set_stm32f4x9_fsotg_params },
|
||||
{ .compatible = "st,stm32f4x9-hsotg" },
|
||||
{ .compatible = "st,stm32f7xx-hsotg",
|
||||
.data = dwc2_set_stm32f7xx_hsotg_params },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
||||
|
@ -335,6 +346,9 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
|
|||
num);
|
||||
}
|
||||
}
|
||||
|
||||
if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL))
|
||||
p->oc_disable = true;
|
||||
}
|
||||
|
||||
static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
|
||||
|
|
|
@ -156,9 +156,8 @@ static void __dwc3_set_mode(struct work_struct *work)
|
|||
} else {
|
||||
if (dwc->usb2_phy)
|
||||
otg_set_vbus(dwc->usb2_phy->otg, true);
|
||||
if (dwc->usb2_generic_phy)
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
|
||||
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
|
||||
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
|
||||
}
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
|
@ -166,8 +165,8 @@ static void __dwc3_set_mode(struct work_struct *work)
|
|||
|
||||
if (dwc->usb2_phy)
|
||||
otg_set_vbus(dwc->usb2_phy->otg, false);
|
||||
if (dwc->usb2_generic_phy)
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
|
||||
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
|
||||
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret)
|
||||
|
@ -927,12 +926,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
|
||||
if (dwc->usb2_phy)
|
||||
otg_set_vbus(dwc->usb2_phy->otg, false);
|
||||
if (dwc->usb2_generic_phy)
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
|
||||
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
|
||||
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
|
@ -942,12 +942,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||
}
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||
|
||||
if (dwc->usb2_phy)
|
||||
otg_set_vbus(dwc->usb2_phy->otg, true);
|
||||
if (dwc->usb2_generic_phy)
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
|
||||
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
|
||||
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
|
||||
|
||||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
|
@ -1293,21 +1294,19 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
case USB_DR_MODE_OTG:
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_gadget_suspend(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
dwc3_core_exit(dwc);
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1316,18 +1315,17 @@ static int dwc3_resume_common(struct dwc3 *dwc)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = dwc3_core_init(dwc);
|
||||
if (ret)
|
||||
return ret;
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
ret = dwc3_core_init(dwc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
case USB_DR_MODE_OTG:
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_gadget_resume(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
/* FALLTHROUGH */
|
||||
case USB_DR_MODE_HOST:
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
|
@ -1338,7 +1336,7 @@ static int dwc3_resume_common(struct dwc3 *dwc)
|
|||
|
||||
static int dwc3_runtime_checks(struct dwc3 *dwc)
|
||||
{
|
||||
switch (dwc->dr_mode) {
|
||||
switch (dwc->current_dr_role) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
case USB_DR_MODE_OTG:
|
||||
if (dwc->connected)
|
||||
|
@ -1381,19 +1379,17 @@ static int dwc3_runtime_resume(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
case USB_DR_MODE_OTG:
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
dwc3_gadget_process_pending_events(dwc);
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1402,13 +1398,12 @@ static int dwc3_runtime_idle(struct device *dev)
|
|||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
case USB_DR_MODE_OTG:
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
if (dwc3_runtime_checks(dwc))
|
||||
return -EBUSY;
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
|
|
|
@ -529,6 +529,7 @@ struct dwc3_event_buffer {
|
|||
* @number: endpoint number (1 - 15)
|
||||
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
|
||||
* @resource_index: Resource transfer index
|
||||
* @frame_number: set to the frame number we want this transfer to start (ISOC)
|
||||
* @interval: the interval on which the ISOC transfer is started
|
||||
* @allocated_requests: number of requests allocated
|
||||
* @queued_requests: number of requests queued for transfer
|
||||
|
@ -581,6 +582,7 @@ struct dwc3_ep {
|
|||
u8 resource_index;
|
||||
u32 allocated_requests;
|
||||
u32 queued_requests;
|
||||
u32 frame_number;
|
||||
u32 interval;
|
||||
|
||||
char name[20];
|
||||
|
|
|
@ -28,11 +28,13 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
struct dwc3_of_simple {
|
||||
struct device *dev;
|
||||
struct clk **clks;
|
||||
int num_clocks;
|
||||
struct reset_control *resets;
|
||||
};
|
||||
|
||||
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
|
||||
|
@ -95,10 +97,21 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, simple);
|
||||
simple->dev = dev;
|
||||
|
||||
simple->resets = of_reset_control_array_get_optional_exclusive(np);
|
||||
if (IS_ERR(simple->resets)) {
|
||||
ret = PTR_ERR(simple->resets);
|
||||
dev_err(dev, "failed to get device resets, err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(simple->resets);
|
||||
if (ret)
|
||||
goto err_resetc_put;
|
||||
|
||||
ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np,
|
||||
"clocks", "#clock-cells"));
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_resetc_assert;
|
||||
|
||||
ret = of_platform_populate(np, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
|
@ -107,7 +120,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
|
|||
clk_put(simple->clks[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
goto err_resetc_assert;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
|
@ -115,6 +128,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
|
|||
pm_runtime_get_sync(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_resetc_assert:
|
||||
reset_control_assert(simple->resets);
|
||||
|
||||
err_resetc_put:
|
||||
reset_control_put(simple->resets);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_of_simple_remove(struct platform_device *pdev)
|
||||
|
@ -123,12 +143,15 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
int i;
|
||||
|
||||
of_platform_depopulate(dev);
|
||||
|
||||
for (i = 0; i < simple->num_clocks; i++) {
|
||||
clk_disable_unprepare(simple->clks[i]);
|
||||
clk_put(simple->clks[i]);
|
||||
}
|
||||
|
||||
of_platform_depopulate(dev);
|
||||
reset_control_assert(simple->resets);
|
||||
reset_control_put(simple->resets);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
@ -61,6 +62,7 @@ struct dwc3_pci {
|
|||
guid_t guid;
|
||||
|
||||
unsigned int has_dsm_for_pm:1;
|
||||
struct work_struct wakeup_work;
|
||||
};
|
||||
|
||||
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
|
||||
|
@ -174,6 +176,22 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void dwc3_pci_resume_work(struct work_struct *work)
|
||||
{
|
||||
struct dwc3_pci *dwc = container_of(work, struct dwc3_pci, wakeup_work);
|
||||
struct platform_device *dwc3 = dwc->dwc3;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(&dwc3->dev);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
pm_runtime_mark_last_busy(&dwc3->dev);
|
||||
pm_runtime_put_sync_autosuspend(&dwc3->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dwc3_pci_probe(struct pci_dev *pci,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
|
@ -232,6 +250,9 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
|||
device_init_wakeup(dev, true);
|
||||
pci_set_drvdata(pci, dwc);
|
||||
pm_runtime_put(dev);
|
||||
#ifdef CONFIG_PM
|
||||
INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
err:
|
||||
|
@ -243,6 +264,9 @@ static void dwc3_pci_remove(struct pci_dev *pci)
|
|||
{
|
||||
struct dwc3_pci *dwc = pci_get_drvdata(pci);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
cancel_work_sync(&dwc->wakeup_work);
|
||||
#endif
|
||||
device_init_wakeup(&pci->dev, false);
|
||||
pm_runtime_get(&pci->dev);
|
||||
platform_device_unregister(dwc->dwc3);
|
||||
|
@ -318,14 +342,15 @@ static int dwc3_pci_runtime_suspend(struct device *dev)
|
|||
static int dwc3_pci_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct dwc3_pci *dwc = dev_get_drvdata(dev);
|
||||
struct platform_device *dwc3 = dwc->dwc3;
|
||||
int ret;
|
||||
|
||||
ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return pm_runtime_get(&dwc3->dev);
|
||||
queue_work(pm_wq, &dwc->wakeup_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
|
|
@ -487,14 +487,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
|
|||
static int dwc3_ep0_handle_intf(struct dwc3 *dwc,
|
||||
struct usb_ctrlrequest *ctrl, int set)
|
||||
{
|
||||
enum usb_device_state state;
|
||||
u32 wValue;
|
||||
u32 wIndex;
|
||||
int ret = 0;
|
||||
|
||||
wValue = le16_to_cpu(ctrl->wValue);
|
||||
wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
state = dwc->gadget.state;
|
||||
|
||||
switch (wValue) {
|
||||
case USB_INTRF_FUNC_SUSPEND:
|
||||
|
@ -517,14 +513,10 @@ static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc,
|
|||
struct usb_ctrlrequest *ctrl, int set)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
enum usb_device_state state;
|
||||
u32 wValue;
|
||||
u32 wIndex;
|
||||
int ret;
|
||||
|
||||
wValue = le16_to_cpu(ctrl->wValue);
|
||||
wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
state = dwc->gadget.state;
|
||||
|
||||
switch (wValue) {
|
||||
case USB_ENDPOINT_HALT:
|
||||
|
@ -551,10 +543,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||
{
|
||||
u32 recip;
|
||||
int ret;
|
||||
enum usb_device_state state;
|
||||
|
||||
recip = ctrl->bRequestType & USB_RECIP_MASK;
|
||||
state = dwc->gadget.state;
|
||||
|
||||
switch (recip) {
|
||||
case USB_RECIP_DEVICE:
|
||||
|
@ -712,12 +702,10 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
struct dwc3_ep *dep;
|
||||
enum usb_device_state state = dwc->gadget.state;
|
||||
u16 wLength;
|
||||
u16 wValue;
|
||||
|
||||
if (state == USB_STATE_DEFAULT)
|
||||
return -EINVAL;
|
||||
|
||||
wValue = le16_to_cpu(ctrl->wValue);
|
||||
wLength = le16_to_cpu(ctrl->wLength);
|
||||
|
||||
if (wLength != 6) {
|
||||
|
@ -842,9 +830,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
struct usb_request *ur;
|
||||
struct dwc3_trb *trb;
|
||||
struct dwc3_ep *ep0;
|
||||
unsigned maxp;
|
||||
unsigned remaining_ur_length;
|
||||
void *buf;
|
||||
u32 transferred = 0;
|
||||
u32 status;
|
||||
u32 length;
|
||||
|
@ -871,11 +856,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
}
|
||||
|
||||
ur = &r->request;
|
||||
buf = ur->buf;
|
||||
remaining_ur_length = ur->length;
|
||||
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
maxp = ep0->endpoint.maxpacket;
|
||||
transferred = ur->length - length;
|
||||
ur->actual += transferred;
|
||||
|
||||
|
@ -1001,7 +983,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
} else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
|
||||
req->request.length && req->request.zero) {
|
||||
u32 maxpacket;
|
||||
u32 rem;
|
||||
|
||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||
&req->request, dep->number);
|
||||
|
@ -1009,7 +990,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
return;
|
||||
|
||||
maxpacket = dep->endpoint.maxpacket;
|
||||
rem = req->request.length % maxpacket;
|
||||
|
||||
/* prepare normal TRB */
|
||||
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||
|
|
|
@ -1151,9 +1151,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
|
|||
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
|
||||
|
||||
if (!dwc3_calc_trbs_left(dep))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We can get in a situation where there's a request in the started list
|
||||
* but there weren't enough TRBs to fully kick it in the first time
|
||||
|
@ -1194,7 +1191,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
|
|||
}
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
|
||||
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3_request *req;
|
||||
|
@ -1202,6 +1199,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
|
|||
int ret;
|
||||
u32 cmd;
|
||||
|
||||
if (!dwc3_calc_trbs_left(dep))
|
||||
return 0;
|
||||
|
||||
starting = !(dep->flags & DWC3_EP_BUSY);
|
||||
|
||||
dwc3_prepare_trbs(dep);
|
||||
|
@ -1216,8 +1216,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
|
|||
if (starting) {
|
||||
params.param0 = upper_32_bits(req->trb_dma);
|
||||
params.param1 = lower_32_bits(req->trb_dma);
|
||||
cmd = DWC3_DEPCMD_STARTTRANSFER |
|
||||
DWC3_DEPCMD_PARAM(cmd_param);
|
||||
cmd = DWC3_DEPCMD_STARTTRANSFER;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->frame_number);
|
||||
} else {
|
||||
cmd = DWC3_DEPCMD_UPDATETRANSFER |
|
||||
DWC3_DEPCMD_PARAM(dep->resource_index);
|
||||
|
@ -1258,8 +1260,6 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
|
|||
static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, u32 cur_uf)
|
||||
{
|
||||
u32 uf;
|
||||
|
||||
if (list_empty(&dep->pending_list)) {
|
||||
dev_info(dwc->dev, "%s: ran out of requests\n",
|
||||
dep->name);
|
||||
|
@ -1271,9 +1271,8 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
|||
* Schedule the first trb for one interval in the future or at
|
||||
* least 4 microframes.
|
||||
*/
|
||||
uf = cur_uf + max_t(u32, 4, dep->interval);
|
||||
|
||||
__dwc3_gadget_kick_transfer(dep, uf);
|
||||
dep->frame_number = cur_uf + max_t(u32, 4, dep->interval);
|
||||
__dwc3_gadget_kick_transfer(dep);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
||||
|
@ -1290,7 +1289,6 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
|||
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
int ret = 0;
|
||||
|
||||
if (!dep->endpoint.desc) {
|
||||
dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
|
||||
|
@ -1337,24 +1335,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
}
|
||||
|
||||
if ((dep->flags & DWC3_EP_BUSY) &&
|
||||
!(dep->flags & DWC3_EP_MISSED_ISOC)) {
|
||||
WARN_ON_ONCE(!dep->resource_index);
|
||||
ret = __dwc3_gadget_kick_transfer(dep,
|
||||
dep->resource_index);
|
||||
}
|
||||
!(dep->flags & DWC3_EP_MISSED_ISOC))
|
||||
goto out;
|
||||
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dwc3_calc_trbs_left(dep))
|
||||
return 0;
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0);
|
||||
out:
|
||||
if (ret == -EBUSY)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
return __dwc3_gadget_kick_transfer(dep);
|
||||
}
|
||||
|
||||
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
|
@ -2347,7 +2335,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
req->request.actual = length - req->remaining;
|
||||
|
||||
if ((req->request.actual < length) && req->num_pending_sgs)
|
||||
return __dwc3_gadget_kick_transfer(dep, 0);
|
||||
return __dwc3_gadget_kick_transfer(dep);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, status);
|
||||
|
||||
|
@ -2440,13 +2428,8 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
|
|||
if (!dep->endpoint.desc)
|
||||
return;
|
||||
|
||||
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
int ret;
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0);
|
||||
if (!ret || ret == -EBUSY)
|
||||
return;
|
||||
}
|
||||
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
__dwc3_gadget_kick_transfer(dep);
|
||||
}
|
||||
|
||||
static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
|
@ -2487,15 +2470,10 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|||
dwc3_endpoint_transfer_complete(dwc, dep, event);
|
||||
break;
|
||||
case DWC3_DEPEVT_XFERNOTREADY:
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
dwc3_gadget_start_isoc(dwc, dep, event);
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0);
|
||||
if (!ret || ret == -EBUSY)
|
||||
return;
|
||||
}
|
||||
else
|
||||
__dwc3_gadget_kick_transfer(dep);
|
||||
|
||||
break;
|
||||
case DWC3_DEPEVT_STREAMEVT:
|
||||
|
|
|
@ -1145,6 +1145,7 @@ static int usbg_submit_command(struct f_uas *fu,
|
|||
default:
|
||||
pr_debug_once("Unsupported prio_attr: %02x.\n",
|
||||
cmd_iu->prio_attr);
|
||||
/* fall through */
|
||||
case UAS_SIMPLE_TAG:
|
||||
cmd->prio_attr = TCM_SIMPLE_TAG;
|
||||
break;
|
||||
|
|
|
@ -1078,6 +1078,7 @@ static void gs_complete_out(struct usb_ep *ep, struct usb_request *req)
|
|||
default:
|
||||
pr_warn("%s: unexpected %s status %d\n",
|
||||
__func__, ep->name, req->status);
|
||||
/* fall through */
|
||||
case 0:
|
||||
/* normal completion */
|
||||
spin_lock(&info->con_lock);
|
||||
|
|
|
@ -354,7 +354,7 @@ static unsigned long uvcg_v4l2_get_unmapped_area(struct file *file,
|
|||
}
|
||||
#endif
|
||||
|
||||
struct v4l2_file_operations uvc_v4l2_fops = {
|
||||
const struct v4l2_file_operations uvc_v4l2_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = uvc_v4l2_open,
|
||||
.release = uvc_v4l2_release,
|
||||
|
|
|
@ -17,6 +17,6 @@
|
|||
#define __UVC_V4L2_H__
|
||||
|
||||
extern const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops;
|
||||
extern struct v4l2_file_operations uvc_v4l2_fops;
|
||||
extern const struct v4l2_file_operations uvc_v4l2_fops;
|
||||
|
||||
#endif /* __UVC_V4L2_H__ */
|
||||
|
|
|
@ -912,7 +912,7 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
|
|||
return 0;
|
||||
|
||||
type = usb_endpoint_type(desc);
|
||||
max = 0x7ff & usb_endpoint_maxp(desc);
|
||||
max = usb_endpoint_maxp(desc);
|
||||
|
||||
if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
|
||||
return 0;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
*
|
||||
* Having this all in one kernel can help some stages of development,
|
||||
* bypassing some hardware (and driver) issues. UML could help too.
|
||||
*
|
||||
* Note: The emulation does not include isochronous transfers!
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -137,6 +139,9 @@ static const struct {
|
|||
.caps = _caps, \
|
||||
}
|
||||
|
||||
/* we don't provide isochronous endpoints since we don't support them */
|
||||
#define TYPE_BULK_OR_INT (USB_EP_CAPS_TYPE_BULK | USB_EP_CAPS_TYPE_INT)
|
||||
|
||||
/* everyone has ep0 */
|
||||
EP_INFO(ep0name,
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
|
||||
|
@ -145,64 +150,72 @@ static const struct {
|
|||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep2out-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
|
||||
/*
|
||||
EP_INFO("ep3in-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep4out-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
|
||||
*/
|
||||
EP_INFO("ep5in-int",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep6in-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep7out-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
|
||||
/*
|
||||
EP_INFO("ep8in-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep9out-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
|
||||
*/
|
||||
EP_INFO("ep10in-int",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep11in-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep12out-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
|
||||
/*
|
||||
EP_INFO("ep13in-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep14out-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
|
||||
*/
|
||||
EP_INFO("ep15in-int",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
|
||||
|
||||
/* or like sa1100: two fixed function endpoints */
|
||||
EP_INFO("ep1out-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep2in-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
|
||||
|
||||
/* and now some generic EPs so we have enough in multi config */
|
||||
EP_INFO("ep3out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep4in",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep5out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep6out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep7in",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep8out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep9in",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep10out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep11out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep12in",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep13out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
EP_INFO("ep14in",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep15out",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
|
||||
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
|
||||
|
||||
#undef EP_INFO
|
||||
};
|
||||
|
@ -1769,6 +1782,7 @@ static void dummy_timer(unsigned long _dum_hcd)
|
|||
int i;
|
||||
|
||||
/* simplistic model for one frame's bandwidth */
|
||||
/* FIXME: account for transaction and packet overhead */
|
||||
switch (dum->gadget.speed) {
|
||||
case USB_SPEED_LOW:
|
||||
total = 8/*bytes*/ * 12/*packets*/;
|
||||
|
@ -1813,7 +1827,6 @@ restart:
|
|||
struct dummy_request *req;
|
||||
u8 address;
|
||||
struct dummy_ep *ep = NULL;
|
||||
int type;
|
||||
int status = -EINPROGRESS;
|
||||
|
||||
/* stop when we reach URBs queued after the timer interrupt */
|
||||
|
@ -1825,14 +1838,10 @@ restart:
|
|||
goto return_urb;
|
||||
else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
|
||||
continue;
|
||||
type = usb_pipetype(urb->pipe);
|
||||
|
||||
/* used up this frame's non-periodic bandwidth?
|
||||
* FIXME there's infinite bandwidth for control and
|
||||
* periodic transfers ... unrealistic.
|
||||
*/
|
||||
if (total <= 0 && type == PIPE_BULK)
|
||||
continue;
|
||||
/* Used up this frame's bandwidth? */
|
||||
if (total <= 0)
|
||||
break;
|
||||
|
||||
/* find the gadget's ep for this request (if configured) */
|
||||
address = usb_pipeendpoint (urb->pipe);
|
||||
|
@ -1930,13 +1939,17 @@ restart:
|
|||
limit = total;
|
||||
switch (usb_pipetype(urb->pipe)) {
|
||||
case PIPE_ISOCHRONOUS:
|
||||
/* FIXME is it urb->interval since the last xfer?
|
||||
* use urb->iso_frame_desc[i].
|
||||
* complete whether or not ep has requests queued.
|
||||
* report random errors, to debug drivers.
|
||||
/*
|
||||
* We don't support isochronous. But if we did,
|
||||
* here are some of the issues we'd have to face:
|
||||
*
|
||||
* Is it urb->interval since the last xfer?
|
||||
* Use urb->iso_frame_desc[i].
|
||||
* Complete whether or not ep has requests queued.
|
||||
* Report random errors, to debug drivers.
|
||||
*/
|
||||
limit = max(limit, periodic_bytes(dum, ep));
|
||||
status = -ENOSYS;
|
||||
status = -EINVAL; /* fail all xfers */
|
||||
break;
|
||||
|
||||
case PIPE_INTERRUPT:
|
||||
|
|
|
@ -127,11 +127,15 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
mode = 0;
|
||||
max = get_unaligned_le16(&desc->wMaxPacketSize);
|
||||
switch (max) {
|
||||
case 64: mode++;
|
||||
case 32: mode++;
|
||||
case 16: mode++;
|
||||
case 8: mode <<= 3;
|
||||
break;
|
||||
case 64:
|
||||
mode++; /* fall through */
|
||||
case 32:
|
||||
mode++; /* fall through */
|
||||
case 16:
|
||||
mode++; /* fall through */
|
||||
case 8:
|
||||
mode <<= 3;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1538,7 +1538,7 @@ static int gr_ep_enable(struct usb_ep *_ep,
|
|||
* Bits 10-0 set the max payload. 12-11 set the number of
|
||||
* additional transactions.
|
||||
*/
|
||||
max = 0x7ff & usb_endpoint_maxp(desc);
|
||||
max = usb_endpoint_maxp(desc);
|
||||
nt = usb_endpoint_maxp_mult(desc) - 1;
|
||||
buffer_size = GR_BUFFER_SIZE(epctrl);
|
||||
if (nt && (mode == 0 || mode == 2)) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Renesas USB3.0 Peripheral driver (USB gadget)
|
||||
*
|
||||
* Copyright (C) 2015 Renesas Electronics Corporation
|
||||
* Copyright (C) 2015-2017 Renesas Electronics Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,6 +17,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sizes.h>
|
||||
|
@ -334,6 +335,7 @@ struct renesas_usb3 {
|
|||
struct usb_gadget_driver *driver;
|
||||
struct extcon_dev *extcon;
|
||||
struct work_struct extcon_work;
|
||||
struct phy *phy;
|
||||
|
||||
struct renesas_usb3_ep *usb3_ep;
|
||||
int num_usb3_eps;
|
||||
|
@ -2239,7 +2241,9 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
|
|||
/* hook up the driver */
|
||||
usb3->driver = driver;
|
||||
|
||||
pm_runtime_enable(usb3_to_dev(usb3));
|
||||
if (usb3->phy)
|
||||
phy_init(usb3->phy);
|
||||
|
||||
pm_runtime_get_sync(usb3_to_dev(usb3));
|
||||
|
||||
renesas_usb3_init_controller(usb3);
|
||||
|
@ -2256,8 +2260,10 @@ static int renesas_usb3_stop(struct usb_gadget *gadget)
|
|||
usb3->driver = NULL;
|
||||
renesas_usb3_stop_controller(usb3);
|
||||
|
||||
if (usb3->phy)
|
||||
phy_exit(usb3->phy);
|
||||
|
||||
pm_runtime_put(usb3_to_dev(usb3));
|
||||
pm_runtime_disable(usb3_to_dev(usb3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2405,6 +2411,9 @@ static int renesas_usb3_remove(struct platform_device *pdev)
|
|||
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
|
||||
|
||||
__renesas_usb3_ep_free_request(usb3->ep0_req);
|
||||
if (usb3->phy)
|
||||
phy_put(usb3->phy);
|
||||
pm_runtime_disable(usb3_to_dev(usb3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2560,20 +2569,15 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct renesas_usb3 *usb3;
|
||||
struct resource *res;
|
||||
const struct of_device_id *match;
|
||||
int irq, ret;
|
||||
const struct renesas_usb3_priv *priv;
|
||||
const struct soc_device_attribute *attr;
|
||||
|
||||
match = of_match_node(usb3_of_match, pdev->dev.of_node);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
attr = soc_device_match(renesas_usb3_quirks_match);
|
||||
if (attr)
|
||||
priv = attr->data;
|
||||
else
|
||||
priv = match->data;
|
||||
priv = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
|
@ -2635,11 +2639,20 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto err_dev_create;
|
||||
|
||||
/*
|
||||
* This is an optional. So, if this driver cannot get a phy,
|
||||
* this driver will not handle a phy anymore.
|
||||
*/
|
||||
usb3->phy = devm_phy_get(&pdev->dev, "usb");
|
||||
if (IS_ERR(usb3->phy))
|
||||
usb3->phy = NULL;
|
||||
|
||||
usb3->workaround_for_vbus = priv->workaround_for_vbus;
|
||||
|
||||
renesas_usb3_debugfs_init(usb3, &pdev->dev);
|
||||
|
||||
dev_info(&pdev->dev, "probed\n");
|
||||
dev_info(&pdev->dev, "probed%s\n", usb3->phy ? " with phy" : "");
|
||||
pm_runtime_enable(usb3_to_dev(usb3));
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -2655,11 +2668,49 @@ err_alloc_prd:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int renesas_usb3_suspend(struct device *dev)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||
|
||||
/* Not started */
|
||||
if (!usb3->driver)
|
||||
return 0;
|
||||
|
||||
renesas_usb3_stop_controller(usb3);
|
||||
if (usb3->phy)
|
||||
phy_exit(usb3->phy);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int renesas_usb3_resume(struct device *dev)
|
||||
{
|
||||
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||
|
||||
/* Not started */
|
||||
if (!usb3->driver)
|
||||
return 0;
|
||||
|
||||
if (usb3->phy)
|
||||
phy_init(usb3->phy);
|
||||
pm_runtime_get_sync(dev);
|
||||
renesas_usb3_init_controller(usb3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(renesas_usb3_pm_ops, renesas_usb3_suspend,
|
||||
renesas_usb3_resume);
|
||||
|
||||
static struct platform_driver renesas_usb3_driver = {
|
||||
.probe = renesas_usb3_probe,
|
||||
.remove = renesas_usb3_remove,
|
||||
.driver = {
|
||||
.name = (char *)udc_name,
|
||||
.pm = &renesas_usb3_pm_ops,
|
||||
.of_match_table = of_match_ptr(usb3_of_match),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -46,6 +46,9 @@ struct mtu3_request;
|
|||
#define MU3D_EP_RXCR1(epnum) (U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
|
||||
#define MU3D_EP_RXCR2(epnum) (U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
|
||||
|
||||
#define USB_QMU_TQHIAR(epnum) (U3D_TXQHIAR1 + (((epnum) - 1) * 0x4))
|
||||
#define USB_QMU_RQHIAR(epnum) (U3D_RXQHIAR1 + (((epnum) - 1) * 0x4))
|
||||
|
||||
#define USB_QMU_RQCSR(epnum) (U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
|
||||
#define USB_QMU_RQSAR(epnum) (U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
|
||||
#define USB_QMU_RQCPR(epnum) (U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
|
||||
|
@ -91,6 +94,7 @@ enum mtu3_speed {
|
|||
MTU3_SPEED_FULL = 1,
|
||||
MTU3_SPEED_HIGH = 3,
|
||||
MTU3_SPEED_SUPER = 4,
|
||||
MTU3_SPEED_SUPER_PLUS = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -111,6 +115,19 @@ enum mtu3_g_ep0_state {
|
|||
MU3D_EP0_STATE_STALL,
|
||||
};
|
||||
|
||||
/**
|
||||
* MTU3_DR_FORCE_NONE: automatically switch host and periperal mode
|
||||
* by IDPIN signal.
|
||||
* MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
|
||||
* IDPIN signal.
|
||||
* MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
|
||||
*/
|
||||
enum mtu3_dr_force_mode {
|
||||
MTU3_DR_FORCE_NONE = 0,
|
||||
MTU3_DR_FORCE_HOST,
|
||||
MTU3_DR_FORCE_DEVICE,
|
||||
};
|
||||
|
||||
/**
|
||||
* @base: the base address of fifo
|
||||
* @limit: the bitmap size in bits
|
||||
|
@ -138,23 +155,33 @@ struct mtu3_fifo_info {
|
|||
* Checksum value is calculated over the 16 bytes of the GPD by default;
|
||||
* @data_buf_len (RX ONLY): This value indicates the length of
|
||||
* the assigned data buffer
|
||||
* @tx_ext_addr (TX ONLY): [3:0] are 4 extension bits of @buffer,
|
||||
* [7:4] are 4 extension bits of @next_gpd
|
||||
* @next_gpd: Physical address of the next GPD
|
||||
* @buffer: Physical address of the data buffer
|
||||
* @buf_len:
|
||||
* (TX): This value indicates the length of the assigned data buffer
|
||||
* (RX): The total length of data received
|
||||
* @ext_len: reserved
|
||||
* @rx_ext_addr(RX ONLY): [3:0] are 4 extension bits of @buffer,
|
||||
* [7:4] are 4 extension bits of @next_gpd
|
||||
* @ext_flag:
|
||||
* bit5 (TX ONLY): Zero Length Packet (ZLP),
|
||||
*/
|
||||
struct qmu_gpd {
|
||||
__u8 flag;
|
||||
__u8 chksum;
|
||||
__le16 data_buf_len;
|
||||
union {
|
||||
__le16 data_buf_len;
|
||||
__le16 tx_ext_addr;
|
||||
};
|
||||
__le32 next_gpd;
|
||||
__le32 buffer;
|
||||
__le16 buf_len;
|
||||
__u8 ext_len;
|
||||
union {
|
||||
__u8 ext_len;
|
||||
__u8 rx_ext_addr;
|
||||
};
|
||||
__u8 ext_flag;
|
||||
} __packed;
|
||||
|
||||
|
@ -183,7 +210,6 @@ struct mtu3_gpd_ring {
|
|||
* xHCI driver initialization, it's necessary for system bootup
|
||||
* as device.
|
||||
* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
|
||||
* @id_*: used to maually switch between host and device modes by idpin
|
||||
* @manual_drd_enabled: it's true when supports dual-role device by debugfs
|
||||
* to switch host/device modes depending on user input.
|
||||
*/
|
||||
|
@ -194,10 +220,6 @@ struct otg_switch_mtk {
|
|||
struct notifier_block id_nb;
|
||||
struct delayed_work extcon_reg_dwork;
|
||||
bool is_u3_drd;
|
||||
/* dual-role switch by debugfs */
|
||||
struct pinctrl *id_pinctrl;
|
||||
struct pinctrl_state *id_float;
|
||||
struct pinctrl_state *id_ground;
|
||||
bool manual_drd_enabled;
|
||||
};
|
||||
|
||||
|
@ -206,14 +228,17 @@ struct otg_switch_mtk {
|
|||
* @ippc_base: register base address of IP Power and Clock interface (IPPC)
|
||||
* @vusb33: usb3.3V shared by device/host IP
|
||||
* @sys_clk: system clock of mtu3, shared by device/host IP
|
||||
* @ref_clk: reference clock
|
||||
* @mcu_clk: mcu_bus_ck clock for AHB bus etc
|
||||
* @dma_clk: dma_bus_ck clock for AXI bus etc
|
||||
* @dr_mode: works in which mode:
|
||||
* host only, device only or dual-role mode
|
||||
* @u2_ports: number of usb2.0 host ports
|
||||
* @u3_ports: number of usb3.0 host ports
|
||||
* @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
|
||||
* disable u3port0, bit1==1 to disable u3port1,... etc
|
||||
* @dbgfs_root: only used when supports manual dual-role switch via debugfs
|
||||
* @wakeup_en: it's true when supports remote wakeup in host mode
|
||||
* @wk_deb_p0: port0's wakeup debounce clock
|
||||
* @wk_deb_p1: it's optional, and depends on port1 is supported or not
|
||||
*/
|
||||
struct ssusb_mtk {
|
||||
struct device *dev;
|
||||
|
@ -226,17 +251,18 @@ struct ssusb_mtk {
|
|||
struct regulator *vusb33;
|
||||
struct clk *sys_clk;
|
||||
struct clk *ref_clk;
|
||||
struct clk *mcu_clk;
|
||||
struct clk *dma_clk;
|
||||
/* otg */
|
||||
struct otg_switch_mtk otg_switch;
|
||||
enum usb_dr_mode dr_mode;
|
||||
bool is_host;
|
||||
int u2_ports;
|
||||
int u3_ports;
|
||||
int u3p_dis_msk;
|
||||
struct dentry *dbgfs_root;
|
||||
/* usb wakeup for host mode */
|
||||
bool wakeup_en;
|
||||
struct clk *wk_deb_p0;
|
||||
struct clk *wk_deb_p1;
|
||||
struct regmap *pericfg;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -114,7 +115,9 @@ static int mtu3_device_enable(struct mtu3 *mtu)
|
|||
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
|
||||
(SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
|
||||
SSUSB_U2_PORT_HOST_SEL));
|
||||
mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
|
||||
|
||||
if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
|
||||
mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
|
||||
|
||||
return ssusb_check_clocks(mtu->ssusb, check_clk);
|
||||
}
|
||||
|
@ -129,7 +132,10 @@ static void mtu3_device_disable(struct mtu3 *mtu)
|
|||
|
||||
mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
|
||||
SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN);
|
||||
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
|
||||
|
||||
if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
|
||||
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
|
||||
|
||||
mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
|
||||
}
|
||||
|
||||
|
@ -236,7 +242,7 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
|
|||
|
||||
void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
|
||||
{
|
||||
if (mtu->is_u3_ip && (mtu->max_speed == USB_SPEED_SUPER))
|
||||
if (mtu->is_u3_ip && mtu->max_speed >= USB_SPEED_SUPER)
|
||||
mtu3_ss_func_set(mtu, is_on);
|
||||
else
|
||||
mtu3_hs_softconn_set(mtu, is_on);
|
||||
|
@ -546,6 +552,9 @@ static void mtu3_set_speed(struct mtu3 *mtu)
|
|||
mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
|
||||
/* HS/FS detected by HW */
|
||||
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
|
||||
} else if (mtu->max_speed == USB_SPEED_SUPER) {
|
||||
mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
|
||||
SSUSB_U3_PORT_SSP_SPEED);
|
||||
}
|
||||
|
||||
dev_info(mtu->dev, "max_speed: %s\n",
|
||||
|
@ -623,6 +632,10 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
|
|||
udev_speed = USB_SPEED_SUPER;
|
||||
maxpkt = 512;
|
||||
break;
|
||||
case MTU3_SPEED_SUPER_PLUS:
|
||||
udev_speed = USB_SPEED_SUPER_PLUS;
|
||||
maxpkt = 512;
|
||||
break;
|
||||
default:
|
||||
udev_speed = USB_SPEED_UNKNOWN;
|
||||
break;
|
||||
|
@ -759,7 +772,31 @@ static void mtu3_hw_exit(struct mtu3 *mtu)
|
|||
mtu3_mem_free(mtu);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
* we set 32-bit DMA mask by default, here check whether the controller
|
||||
* supports 36-bit DMA or not, if it does, set 36-bit DMA mask.
|
||||
*/
|
||||
static int mtu3_set_dma_mask(struct mtu3 *mtu)
|
||||
{
|
||||
struct device *dev = mtu->dev;
|
||||
bool is_36bit = false;
|
||||
int ret = 0;
|
||||
u32 value;
|
||||
|
||||
value = mtu3_readl(mtu->mac_base, U3D_MISC_CTRL);
|
||||
if (value & DMA_ADDR_36BIT) {
|
||||
is_36bit = true;
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
|
||||
/* If set 36-bit DMA mask fails, fall back to 32-bit DMA mask */
|
||||
if (ret) {
|
||||
is_36bit = false;
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
||||
}
|
||||
}
|
||||
dev_info(dev, "dma mask: %s bits\n", is_36bit ? "36" : "32");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ssusb_gadget_init(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
|
@ -774,9 +811,9 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
|
|||
return -ENOMEM;
|
||||
|
||||
mtu->irq = platform_get_irq(pdev, 0);
|
||||
if (mtu->irq <= 0) {
|
||||
if (mtu->irq < 0) {
|
||||
dev_err(dev, "fail to get irq number\n");
|
||||
return -ENODEV;
|
||||
return mtu->irq;
|
||||
}
|
||||
dev_info(dev, "irq %d\n", mtu->irq);
|
||||
|
||||
|
@ -800,14 +837,15 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
|
|||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_HIGH:
|
||||
case USB_SPEED_SUPER:
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid max_speed: %s\n",
|
||||
usb_speed_string(mtu->max_speed));
|
||||
/* fall through */
|
||||
case USB_SPEED_UNKNOWN:
|
||||
/* default as SS */
|
||||
mtu->max_speed = USB_SPEED_SUPER;
|
||||
/* default as SSP */
|
||||
mtu->max_speed = USB_SPEED_SUPER_PLUS;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -820,6 +858,12 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = mtu3_set_dma_mask(mtu);
|
||||
if (ret) {
|
||||
dev_err(dev, "mtu3 set dma_mask failed:%d\n", ret);
|
||||
goto dma_mask_err;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, mtu->irq, mtu3_irq, 0, dev_name(dev), mtu);
|
||||
if (ret) {
|
||||
dev_err(dev, "request irq %d failed!\n", mtu->irq);
|
||||
|
@ -845,6 +889,7 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
|
|||
gadget_err:
|
||||
device_init_wakeup(dev, false);
|
||||
|
||||
dma_mask_err:
|
||||
irq_err:
|
||||
mtu3_hw_exit(mtu);
|
||||
ssusb->u3d = NULL;
|
||||
|
|
|
@ -261,21 +261,22 @@ static void extcon_register_dwork(struct work_struct *work)
|
|||
* depending on user input.
|
||||
* This is useful in special cases, such as uses TYPE-A receptacle but also
|
||||
* wants to support dual-role mode.
|
||||
* It generates cable state changes by pulling up/down IDPIN and
|
||||
* notifies driver to switch mode by "extcon-usb-gpio".
|
||||
* NOTE: when use MICRO receptacle, should not enable this interface.
|
||||
*/
|
||||
static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
|
||||
{
|
||||
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
|
||||
|
||||
if (to_host)
|
||||
pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
|
||||
else
|
||||
pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
|
||||
if (to_host) {
|
||||
ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
|
||||
ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
|
||||
ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
|
||||
} else {
|
||||
ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
|
||||
ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
|
||||
ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ssusb_mode_show(struct seq_file *sf, void *unused)
|
||||
{
|
||||
struct ssusb_mtk *ssusb = sf->private;
|
||||
|
@ -388,17 +389,45 @@ static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
|
|||
debugfs_remove_recursive(ssusb->dbgfs_root);
|
||||
}
|
||||
|
||||
void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
|
||||
enum mtu3_dr_force_mode mode)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
|
||||
switch (mode) {
|
||||
case MTU3_DR_FORCE_DEVICE:
|
||||
value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
|
||||
break;
|
||||
case MTU3_DR_FORCE_HOST:
|
||||
value |= SSUSB_U2_PORT_FORCE_IDDIG;
|
||||
value &= ~SSUSB_U2_PORT_RG_IDDIG;
|
||||
break;
|
||||
case MTU3_DR_FORCE_NONE:
|
||||
value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
|
||||
}
|
||||
|
||||
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
|
||||
|
||||
INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
|
||||
|
||||
if (otg_sx->manual_drd_enabled)
|
||||
if (otg_sx->manual_drd_enabled) {
|
||||
ssusb_debugfs_init(ssusb);
|
||||
} else {
|
||||
INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork,
|
||||
extcon_register_dwork);
|
||||
|
||||
/* It is enough to delay 1s for waiting for host initialization */
|
||||
schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
|
||||
/*
|
||||
* It is enough to delay 1s for waiting for
|
||||
* host initialization
|
||||
*/
|
||||
schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -407,8 +436,8 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
|
|||
{
|
||||
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
|
||||
|
||||
cancel_delayed_work(&otg_sx->extcon_reg_dwork);
|
||||
|
||||
if (otg_sx->manual_drd_enabled)
|
||||
ssusb_debugfs_exit(ssusb);
|
||||
else
|
||||
cancel_delayed_work(&otg_sx->extcon_reg_dwork);
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
|
|||
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
|
||||
void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
|
||||
int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
|
||||
void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
|
||||
enum mtu3_dr_force_mode mode);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -103,6 +105,10 @@ static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ssusb_set_force_mode(struct ssusb_mtk *ssusb, enum mtu3_dr_force_mode mode)
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _MTU3_DR_H_ */
|
||||
|
|
|
@ -89,6 +89,7 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
|
|||
|
||||
switch (mtu->g.speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
if (usb_endpoint_xfer_int(desc) ||
|
||||
usb_endpoint_xfer_isoc(desc)) {
|
||||
interval = desc->bInterval;
|
||||
|
@ -456,7 +457,7 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(&mtu->lock, flags);
|
||||
if (mtu->g.speed == USB_SPEED_SUPER) {
|
||||
if (mtu->g.speed >= USB_SPEED_SUPER) {
|
||||
mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
|
||||
} else {
|
||||
mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
|
||||
|
|
|
@ -212,8 +212,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
|
|||
case USB_RECIP_DEVICE:
|
||||
result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
|
||||
result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
|
||||
/* superspeed only */
|
||||
if (mtu->g.speed == USB_SPEED_SUPER) {
|
||||
|
||||
if (mtu->g.speed >= USB_SPEED_SUPER) {
|
||||
result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
|
||||
result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
|
||||
}
|
||||
|
@ -329,8 +329,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
|
|||
handled = handle_test_mode(mtu, setup);
|
||||
break;
|
||||
case USB_DEVICE_U1_ENABLE:
|
||||
if (mtu->g.speed != USB_SPEED_SUPER ||
|
||||
mtu->g.state != USB_STATE_CONFIGURED)
|
||||
if (mtu->g.speed < USB_SPEED_SUPER ||
|
||||
mtu->g.state != USB_STATE_CONFIGURED)
|
||||
break;
|
||||
|
||||
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
|
||||
|
@ -344,8 +344,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
|
|||
handled = 1;
|
||||
break;
|
||||
case USB_DEVICE_U2_ENABLE:
|
||||
if (mtu->g.speed != USB_SPEED_SUPER ||
|
||||
mtu->g.state != USB_STATE_CONFIGURED)
|
||||
if (mtu->g.speed < USB_SPEED_SUPER ||
|
||||
mtu->g.state != USB_STATE_CONFIGURED)
|
||||
break;
|
||||
|
||||
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
|
||||
|
@ -384,8 +384,8 @@ static int ep0_handle_feature(struct mtu3 *mtu,
|
|||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
/* superspeed only */
|
||||
if ((value == USB_INTRF_FUNC_SUSPEND)
|
||||
&& (mtu->g.speed == USB_SPEED_SUPER)) {
|
||||
if (value == USB_INTRF_FUNC_SUSPEND &&
|
||||
mtu->g.speed >= USB_SPEED_SUPER) {
|
||||
/*
|
||||
* forward the request because function drivers
|
||||
* should handle it
|
||||
|
|
|
@ -79,20 +79,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
|
|||
if (!ssusb->wakeup_en)
|
||||
return 0;
|
||||
|
||||
ssusb->wk_deb_p0 = devm_clk_get(dev, "wakeup_deb_p0");
|
||||
if (IS_ERR(ssusb->wk_deb_p0)) {
|
||||
dev_err(dev, "fail to get wakeup_deb_p0\n");
|
||||
return PTR_ERR(ssusb->wk_deb_p0);
|
||||
}
|
||||
|
||||
if (of_property_read_bool(dn, "wakeup_deb_p1")) {
|
||||
ssusb->wk_deb_p1 = devm_clk_get(dev, "wakeup_deb_p1");
|
||||
if (IS_ERR(ssusb->wk_deb_p1)) {
|
||||
dev_err(dev, "fail to get wakeup_deb_p1\n");
|
||||
return PTR_ERR(ssusb->wk_deb_p1);
|
||||
}
|
||||
}
|
||||
|
||||
ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
|
||||
"mediatek,syscon-wakeup");
|
||||
if (IS_ERR(ssusb->pericfg)) {
|
||||
|
@ -103,36 +89,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ssusb_wakeup_clks_enable(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(ssusb->wk_deb_p0);
|
||||
if (ret) {
|
||||
dev_err(ssusb->dev, "failed to enable wk_deb_p0\n");
|
||||
goto usb_p0_err;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ssusb->wk_deb_p1);
|
||||
if (ret) {
|
||||
dev_err(ssusb->dev, "failed to enable wk_deb_p1\n");
|
||||
goto usb_p1_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
usb_p1_err:
|
||||
clk_disable_unprepare(ssusb->wk_deb_p0);
|
||||
usb_p0_err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void ssusb_wakeup_clks_disable(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
clk_disable_unprepare(ssusb->wk_deb_p1);
|
||||
clk_disable_unprepare(ssusb->wk_deb_p0);
|
||||
}
|
||||
|
||||
static void host_ports_num_get(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
u32 xhci_cap;
|
||||
|
@ -151,6 +107,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
|
|||
void __iomem *ibase = ssusb->ippc_base;
|
||||
int num_u3p = ssusb->u3_ports;
|
||||
int num_u2p = ssusb->u2_ports;
|
||||
int u3_ports_disabed;
|
||||
u32 check_clk;
|
||||
u32 value;
|
||||
int i;
|
||||
|
@ -158,8 +115,14 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
|
|||
/* power on host ip */
|
||||
mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
|
||||
|
||||
/* power on and enable all u3 ports */
|
||||
/* power on and enable u3 ports except skipped ones */
|
||||
u3_ports_disabed = 0;
|
||||
for (i = 0; i < num_u3p; i++) {
|
||||
if ((0x1 << i) & ssusb->u3p_dis_msk) {
|
||||
u3_ports_disabed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
|
||||
value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
|
||||
value |= SSUSB_U3_PORT_HOST_SEL;
|
||||
|
@ -175,7 +138,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
|
|||
}
|
||||
|
||||
check_clk = SSUSB_XHCI_RST_B_STS;
|
||||
if (num_u3p)
|
||||
if (num_u3p > u3_ports_disabed)
|
||||
check_clk = SSUSB_U3_MAC_RST_B_STS;
|
||||
|
||||
return ssusb_check_clocks(ssusb, check_clk);
|
||||
|
@ -190,8 +153,11 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
/* power down and disable all u3 ports */
|
||||
/* power down and disable u3 ports except skipped ones */
|
||||
for (i = 0; i < num_u3p; i++) {
|
||||
if ((0x1 << i) & ssusb->u3p_dis_msk)
|
||||
continue;
|
||||
|
||||
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
|
||||
value |= SSUSB_U3_PORT_PDN;
|
||||
value |= suspend ? 0 : SSUSB_U3_PORT_DIS;
|
||||
|
@ -223,6 +189,8 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
|
|||
|
||||
static void ssusb_host_setup(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
|
||||
|
||||
host_ports_num_get(ssusb);
|
||||
|
||||
/*
|
||||
|
@ -231,6 +199,9 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
|
|||
*/
|
||||
ssusb_host_enable(ssusb);
|
||||
|
||||
if (otg_sx->manual_drd_enabled)
|
||||
ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
|
||||
|
||||
/* if port0 supports dual-role, works as host mode by default */
|
||||
ssusb_set_vbus(&ssusb->otg_switch, 1);
|
||||
}
|
||||
|
@ -276,19 +247,14 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb)
|
|||
|
||||
int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ssusb->wakeup_en) {
|
||||
ret = ssusb_wakeup_clks_enable(ssusb);
|
||||
if (ssusb->wakeup_en)
|
||||
ssusb_wakeup_ip_sleep_en(ssusb);
|
||||
}
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
if (ssusb->wakeup_en) {
|
||||
if (ssusb->wakeup_en)
|
||||
ssusb_wakeup_ip_sleep_dis(ssusb);
|
||||
ssusb_wakeup_clks_disable(ssusb);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
#define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404)
|
||||
#define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408)
|
||||
#define U3D_QCR3 (SSUSB_DEV_BASE + 0x040C)
|
||||
#define U3D_TXQHIAR1 (SSUSB_DEV_BASE + 0x0484)
|
||||
#define U3D_RXQHIAR1 (SSUSB_DEV_BASE + 0x04C4)
|
||||
|
||||
#define U3D_TXQCSR1 (SSUSB_DEV_BASE + 0x0510)
|
||||
#define U3D_TXQSAR1 (SSUSB_DEV_BASE + 0x0514)
|
||||
|
@ -189,6 +191,13 @@
|
|||
#define QMU_RX_COZ(x) (BIT(16) << (x))
|
||||
#define QMU_RX_ZLP(x) (BIT(0) << (x))
|
||||
|
||||
/* U3D_TXQHIAR1 */
|
||||
/* U3D_RXQHIAR1 */
|
||||
#define QMU_LAST_DONE_PTR_HI(x) (((x) >> 16) & 0xf)
|
||||
#define QMU_CUR_GPD_ADDR_HI(x) (((x) >> 8) & 0xf)
|
||||
#define QMU_START_ADDR_HI_MSK GENMASK(3, 0)
|
||||
#define QMU_START_ADDR_HI(x) (((x) & 0xf) << 0)
|
||||
|
||||
/* U3D_TXQCSR1 */
|
||||
/* U3D_RXQCSR1 */
|
||||
#define QMU_Q_ACTIVE BIT(15)
|
||||
|
@ -225,6 +234,7 @@
|
|||
#define CAP_TX_EP_NUM(x) ((x) & 0x1f)
|
||||
|
||||
/* U3D_MISC_CTRL */
|
||||
#define DMA_ADDR_36BIT BIT(31)
|
||||
#define VBUS_ON BIT(1)
|
||||
#define VBUS_FRC_EN BIT(0)
|
||||
|
||||
|
@ -457,11 +467,14 @@
|
|||
#define SSUSB_VBUS_CHG_INT_B_EN BIT(6)
|
||||
|
||||
/* U3D_SSUSB_U3_CTRL_0P */
|
||||
#define SSUSB_U3_PORT_SSP_SPEED BIT(9)
|
||||
#define SSUSB_U3_PORT_HOST_SEL BIT(2)
|
||||
#define SSUSB_U3_PORT_PDN BIT(1)
|
||||
#define SSUSB_U3_PORT_DIS BIT(0)
|
||||
|
||||
/* U3D_SSUSB_U2_CTRL_0P */
|
||||
#define SSUSB_U2_PORT_RG_IDDIG BIT(12)
|
||||
#define SSUSB_U2_PORT_FORCE_IDDIG BIT(11)
|
||||
#define SSUSB_U2_PORT_VBUSVALID BIT(9)
|
||||
#define SSUSB_U2_PORT_OTG_SEL BIT(7)
|
||||
#define SSUSB_U2_PORT_HOST BIT(2)
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "mtu3.h"
|
||||
|
@ -110,15 +109,9 @@ static void ssusb_phy_power_off(struct ssusb_mtk *ssusb)
|
|||
phy_power_off(ssusb->phys[i]);
|
||||
}
|
||||
|
||||
static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
|
||||
static int ssusb_clks_enable(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = regulator_enable(ssusb->vusb33);
|
||||
if (ret) {
|
||||
dev_err(ssusb->dev, "failed to enable vusb33\n");
|
||||
goto vusb33_err;
|
||||
}
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(ssusb->sys_clk);
|
||||
if (ret) {
|
||||
|
@ -132,6 +125,52 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
|
|||
goto ref_clk_err;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ssusb->mcu_clk);
|
||||
if (ret) {
|
||||
dev_err(ssusb->dev, "failed to enable mcu_clk\n");
|
||||
goto mcu_clk_err;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ssusb->dma_clk);
|
||||
if (ret) {
|
||||
dev_err(ssusb->dev, "failed to enable dma_clk\n");
|
||||
goto dma_clk_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dma_clk_err:
|
||||
clk_disable_unprepare(ssusb->mcu_clk);
|
||||
mcu_clk_err:
|
||||
clk_disable_unprepare(ssusb->ref_clk);
|
||||
ref_clk_err:
|
||||
clk_disable_unprepare(ssusb->sys_clk);
|
||||
sys_clk_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ssusb_clks_disable(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
clk_disable_unprepare(ssusb->dma_clk);
|
||||
clk_disable_unprepare(ssusb->mcu_clk);
|
||||
clk_disable_unprepare(ssusb->ref_clk);
|
||||
clk_disable_unprepare(ssusb->sys_clk);
|
||||
}
|
||||
|
||||
static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = regulator_enable(ssusb->vusb33);
|
||||
if (ret) {
|
||||
dev_err(ssusb->dev, "failed to enable vusb33\n");
|
||||
goto vusb33_err;
|
||||
}
|
||||
|
||||
ret = ssusb_clks_enable(ssusb);
|
||||
if (ret)
|
||||
goto clks_err;
|
||||
|
||||
ret = ssusb_phy_init(ssusb);
|
||||
if (ret) {
|
||||
dev_err(ssusb->dev, "failed to init phy\n");
|
||||
|
@ -149,20 +188,16 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
|
|||
phy_err:
|
||||
ssusb_phy_exit(ssusb);
|
||||
phy_init_err:
|
||||
clk_disable_unprepare(ssusb->ref_clk);
|
||||
ref_clk_err:
|
||||
clk_disable_unprepare(ssusb->sys_clk);
|
||||
sys_clk_err:
|
||||
ssusb_clks_disable(ssusb);
|
||||
clks_err:
|
||||
regulator_disable(ssusb->vusb33);
|
||||
vusb33_err:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
|
||||
{
|
||||
clk_disable_unprepare(ssusb->sys_clk);
|
||||
clk_disable_unprepare(ssusb->ref_clk);
|
||||
ssusb_clks_disable(ssusb);
|
||||
regulator_disable(ssusb->vusb33);
|
||||
ssusb_phy_power_off(ssusb);
|
||||
ssusb_phy_exit(ssusb);
|
||||
|
@ -176,31 +211,17 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
|
|||
mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
|
||||
}
|
||||
|
||||
static int get_iddig_pinctrl(struct ssusb_mtk *ssusb)
|
||||
/* ignore the error if the clock does not exist */
|
||||
static struct clk *get_optional_clk(struct device *dev, const char *id)
|
||||
{
|
||||
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
|
||||
struct clk *opt_clk;
|
||||
|
||||
otg_sx->id_pinctrl = devm_pinctrl_get(ssusb->dev);
|
||||
if (IS_ERR(otg_sx->id_pinctrl)) {
|
||||
dev_err(ssusb->dev, "Cannot find id pinctrl!\n");
|
||||
return PTR_ERR(otg_sx->id_pinctrl);
|
||||
}
|
||||
opt_clk = devm_clk_get(dev, id);
|
||||
/* ignore error number except EPROBE_DEFER */
|
||||
if (IS_ERR(opt_clk) && (PTR_ERR(opt_clk) != -EPROBE_DEFER))
|
||||
opt_clk = NULL;
|
||||
|
||||
otg_sx->id_float =
|
||||
pinctrl_lookup_state(otg_sx->id_pinctrl, "id_float");
|
||||
if (IS_ERR(otg_sx->id_float)) {
|
||||
dev_err(ssusb->dev, "Cannot find pinctrl id_float!\n");
|
||||
return PTR_ERR(otg_sx->id_float);
|
||||
}
|
||||
|
||||
otg_sx->id_ground =
|
||||
pinctrl_lookup_state(otg_sx->id_pinctrl, "id_ground");
|
||||
if (IS_ERR(otg_sx->id_ground)) {
|
||||
dev_err(ssusb->dev, "Cannot find pinctrl id_ground!\n");
|
||||
return PTR_ERR(otg_sx->id_ground);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return opt_clk;
|
||||
}
|
||||
|
||||
static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
|
||||
|
@ -225,18 +246,17 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
|
|||
return PTR_ERR(ssusb->sys_clk);
|
||||
}
|
||||
|
||||
/*
|
||||
* reference clock is usually a "fixed-clock", make it optional
|
||||
* for backward compatibility and ignore the error if it does
|
||||
* not exist.
|
||||
*/
|
||||
ssusb->ref_clk = devm_clk_get(dev, "ref_ck");
|
||||
if (IS_ERR(ssusb->ref_clk)) {
|
||||
if (PTR_ERR(ssusb->ref_clk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
ssusb->ref_clk = get_optional_clk(dev, "ref_ck");
|
||||
if (IS_ERR(ssusb->ref_clk))
|
||||
return PTR_ERR(ssusb->ref_clk);
|
||||
|
||||
ssusb->ref_clk = NULL;
|
||||
}
|
||||
ssusb->mcu_clk = get_optional_clk(dev, "mcu_ck");
|
||||
if (IS_ERR(ssusb->mcu_clk))
|
||||
return PTR_ERR(ssusb->mcu_clk);
|
||||
|
||||
ssusb->dma_clk = get_optional_clk(dev, "dma_ck");
|
||||
if (IS_ERR(ssusb->dma_clk))
|
||||
return PTR_ERR(ssusb->dma_clk);
|
||||
|
||||
ssusb->num_phys = of_count_phandle_with_args(node,
|
||||
"phys", "#phy-cells");
|
||||
|
@ -263,10 +283,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
|
|||
return PTR_ERR(ssusb->ippc_base);
|
||||
|
||||
ssusb->dr_mode = usb_get_dr_mode(dev);
|
||||
if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) {
|
||||
dev_err(dev, "dr_mode is error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN)
|
||||
ssusb->dr_mode = USB_DR_MODE_OTG;
|
||||
|
||||
if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
|
||||
return 0;
|
||||
|
@ -276,10 +294,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ssusb->dr_mode != USB_DR_MODE_OTG)
|
||||
return 0;
|
||||
/* optional property, ignore the error if it does not exist */
|
||||
of_property_read_u32(node, "mediatek,u3p-dis-msk",
|
||||
&ssusb->u3p_dis_msk);
|
||||
|
||||
/* if dual-role mode is supported */
|
||||
vbus = devm_regulator_get(&pdev->dev, "vbus");
|
||||
if (IS_ERR(vbus)) {
|
||||
dev_err(dev, "failed to get vbus\n");
|
||||
|
@ -287,6 +305,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
|
|||
}
|
||||
otg_sx->vbus = vbus;
|
||||
|
||||
if (ssusb->dr_mode == USB_DR_MODE_HOST)
|
||||
return 0;
|
||||
|
||||
/* if dual-role mode is supported */
|
||||
otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
|
||||
otg_sx->manual_drd_enabled =
|
||||
of_property_read_bool(node, "enable-manual-drd");
|
||||
|
@ -297,15 +319,11 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
|
|||
dev_err(ssusb->dev, "couldn't get extcon device\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
if (otg_sx->manual_drd_enabled) {
|
||||
ret = get_iddig_pinctrl(ssusb);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(dev, "dr_mode: %d, is_u3_dr: %d\n",
|
||||
ssusb->dr_mode, otg_sx->is_u3_drd);
|
||||
dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n",
|
||||
ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk,
|
||||
otg_sx->manual_drd_enabled ? "manual" : "auto");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -447,8 +465,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
|
|||
|
||||
ssusb_host_disable(ssusb, true);
|
||||
ssusb_phy_power_off(ssusb);
|
||||
clk_disable_unprepare(ssusb->sys_clk);
|
||||
clk_disable_unprepare(ssusb->ref_clk);
|
||||
ssusb_clks_disable(ssusb);
|
||||
ssusb_wakeup_enable(ssusb);
|
||||
|
||||
return 0;
|
||||
|
@ -466,27 +483,21 @@ static int __maybe_unused mtu3_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
ssusb_wakeup_disable(ssusb);
|
||||
ret = clk_prepare_enable(ssusb->sys_clk);
|
||||
ret = ssusb_clks_enable(ssusb);
|
||||
if (ret)
|
||||
goto err_sys_clk;
|
||||
|
||||
ret = clk_prepare_enable(ssusb->ref_clk);
|
||||
if (ret)
|
||||
goto err_ref_clk;
|
||||
goto clks_err;
|
||||
|
||||
ret = ssusb_phy_power_on(ssusb);
|
||||
if (ret)
|
||||
goto err_power_on;
|
||||
goto phy_err;
|
||||
|
||||
ssusb_host_enable(ssusb);
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_on:
|
||||
clk_disable_unprepare(ssusb->ref_clk);
|
||||
err_ref_clk:
|
||||
clk_disable_unprepare(ssusb->sys_clk);
|
||||
err_sys_clk:
|
||||
phy_err:
|
||||
ssusb_clks_disable(ssusb);
|
||||
clks_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,58 @@
|
|||
#define GPD_FLAGS_IOC BIT(7)
|
||||
|
||||
#define GPD_EXT_FLAG_ZLP BIT(5)
|
||||
#define GPD_EXT_NGP(x) (((x) & 0xf) << 4)
|
||||
#define GPD_EXT_BUF(x) (((x) & 0xf) << 0)
|
||||
|
||||
#define HILO_GEN64(hi, lo) (((u64)(hi) << 32) + (lo))
|
||||
#define HILO_DMA(hi, lo) \
|
||||
((dma_addr_t)HILO_GEN64((le32_to_cpu(hi)), (le32_to_cpu(lo))))
|
||||
|
||||
static dma_addr_t read_txq_cur_addr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
u32 txcpr;
|
||||
u32 txhiar;
|
||||
|
||||
txcpr = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
|
||||
txhiar = mtu3_readl(mbase, USB_QMU_TQHIAR(epnum));
|
||||
|
||||
return HILO_DMA(QMU_CUR_GPD_ADDR_HI(txhiar), txcpr);
|
||||
}
|
||||
|
||||
static dma_addr_t read_rxq_cur_addr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
u32 rxcpr;
|
||||
u32 rxhiar;
|
||||
|
||||
rxcpr = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
|
||||
rxhiar = mtu3_readl(mbase, USB_QMU_RQHIAR(epnum));
|
||||
|
||||
return HILO_DMA(QMU_CUR_GPD_ADDR_HI(rxhiar), rxcpr);
|
||||
}
|
||||
|
||||
static void write_txq_start_addr(void __iomem *mbase, u8 epnum, dma_addr_t dma)
|
||||
{
|
||||
u32 tqhiar;
|
||||
|
||||
mtu3_writel(mbase, USB_QMU_TQSAR(epnum),
|
||||
cpu_to_le32(lower_32_bits(dma)));
|
||||
tqhiar = mtu3_readl(mbase, USB_QMU_TQHIAR(epnum));
|
||||
tqhiar &= ~QMU_START_ADDR_HI_MSK;
|
||||
tqhiar |= QMU_START_ADDR_HI(upper_32_bits(dma));
|
||||
mtu3_writel(mbase, USB_QMU_TQHIAR(epnum), tqhiar);
|
||||
}
|
||||
|
||||
static void write_rxq_start_addr(void __iomem *mbase, u8 epnum, dma_addr_t dma)
|
||||
{
|
||||
u32 rqhiar;
|
||||
|
||||
mtu3_writel(mbase, USB_QMU_RQSAR(epnum),
|
||||
cpu_to_le32(lower_32_bits(dma)));
|
||||
rqhiar = mtu3_readl(mbase, USB_QMU_RQHIAR(epnum));
|
||||
rqhiar &= ~QMU_START_ADDR_HI_MSK;
|
||||
rqhiar |= QMU_START_ADDR_HI(upper_32_bits(dma));
|
||||
mtu3_writel(mbase, USB_QMU_RQHIAR(epnum), rqhiar);
|
||||
}
|
||||
|
||||
static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
|
||||
dma_addr_t dma_addr)
|
||||
|
@ -193,21 +244,27 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
|
|||
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
|
||||
struct qmu_gpd *gpd = ring->enqueue;
|
||||
struct usb_request *req = &mreq->request;
|
||||
dma_addr_t enq_dma;
|
||||
u16 ext_addr;
|
||||
|
||||
/* set all fields to zero as default value */
|
||||
memset(gpd, 0, sizeof(*gpd));
|
||||
|
||||
gpd->buffer = cpu_to_le32((u32)req->dma);
|
||||
gpd->buffer = cpu_to_le32(lower_32_bits(req->dma));
|
||||
ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma));
|
||||
gpd->buf_len = cpu_to_le16(req->length);
|
||||
gpd->flag |= GPD_FLAGS_IOC;
|
||||
|
||||
/* get the next GPD */
|
||||
enq = advance_enq_gpd(ring);
|
||||
dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p\n",
|
||||
mep->epnum, gpd, enq);
|
||||
enq_dma = gpd_virt_to_dma(ring, enq);
|
||||
dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n",
|
||||
mep->epnum, gpd, enq, enq_dma);
|
||||
|
||||
enq->flag &= ~GPD_FLAGS_HWO;
|
||||
gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
|
||||
gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma));
|
||||
ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma));
|
||||
gpd->tx_ext_addr = cpu_to_le16(ext_addr);
|
||||
|
||||
if (req->zero)
|
||||
gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
|
||||
|
@ -226,21 +283,27 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
|
|||
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
|
||||
struct qmu_gpd *gpd = ring->enqueue;
|
||||
struct usb_request *req = &mreq->request;
|
||||
dma_addr_t enq_dma;
|
||||
u16 ext_addr;
|
||||
|
||||
/* set all fields to zero as default value */
|
||||
memset(gpd, 0, sizeof(*gpd));
|
||||
|
||||
gpd->buffer = cpu_to_le32((u32)req->dma);
|
||||
gpd->buffer = cpu_to_le32(lower_32_bits(req->dma));
|
||||
ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma));
|
||||
gpd->data_buf_len = cpu_to_le16(req->length);
|
||||
gpd->flag |= GPD_FLAGS_IOC;
|
||||
|
||||
/* get the next GPD */
|
||||
enq = advance_enq_gpd(ring);
|
||||
dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p\n",
|
||||
mep->epnum, gpd, enq);
|
||||
enq_dma = gpd_virt_to_dma(ring, enq);
|
||||
dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n",
|
||||
mep->epnum, gpd, enq, enq_dma);
|
||||
|
||||
enq->flag &= ~GPD_FLAGS_HWO;
|
||||
gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
|
||||
gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma));
|
||||
ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma));
|
||||
gpd->rx_ext_addr = cpu_to_le16(ext_addr);
|
||||
gpd->chksum = qmu_calc_checksum((u8 *)gpd);
|
||||
gpd->flag |= GPD_FLAGS_HWO;
|
||||
|
||||
|
@ -267,8 +330,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep)
|
|||
|
||||
if (mep->is_in) {
|
||||
/* set QMU start address */
|
||||
mtu3_writel(mbase, USB_QMU_TQSAR(mep->epnum), ring->dma);
|
||||
mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN);
|
||||
write_txq_start_addr(mbase, epnum, ring->dma);
|
||||
mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_DMAREQEN);
|
||||
mtu3_setbits(mbase, U3D_QCR0, QMU_TX_CS_EN(epnum));
|
||||
/* send zero length packet according to ZLP flag in GPD */
|
||||
mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum));
|
||||
|
@ -282,8 +345,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep)
|
|||
mtu3_writel(mbase, USB_QMU_TQCSR(epnum), QMU_Q_START);
|
||||
|
||||
} else {
|
||||
mtu3_writel(mbase, USB_QMU_RQSAR(mep->epnum), ring->dma);
|
||||
mtu3_setbits(mbase, MU3D_EP_RXCR0(mep->epnum), RX_DMAREQEN);
|
||||
write_rxq_start_addr(mbase, epnum, ring->dma);
|
||||
mtu3_setbits(mbase, MU3D_EP_RXCR0(epnum), RX_DMAREQEN);
|
||||
mtu3_setbits(mbase, U3D_QCR0, QMU_RX_CS_EN(epnum));
|
||||
/* don't expect ZLP */
|
||||
mtu3_clrbits(mbase, U3D_QCR3, QMU_RX_ZLP(epnum));
|
||||
|
@ -353,9 +416,9 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
|
|||
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
|
||||
void __iomem *mbase = mtu->mac_base;
|
||||
struct qmu_gpd *gpd_current = NULL;
|
||||
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
|
||||
struct usb_request *req = NULL;
|
||||
struct mtu3_request *mreq;
|
||||
dma_addr_t cur_gpd_dma;
|
||||
u32 txcsr = 0;
|
||||
int ret;
|
||||
|
||||
|
@ -365,7 +428,8 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
|
|||
else
|
||||
return;
|
||||
|
||||
gpd_current = gpd_dma_to_virt(ring, gpd_dma);
|
||||
cur_gpd_dma = read_txq_cur_addr(mbase, epnum);
|
||||
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
|
||||
|
||||
if (le16_to_cpu(gpd_current->buf_len) != 0) {
|
||||
dev_err(mtu->dev, "TX EP%d buffer length error(!=0)\n", epnum);
|
||||
|
@ -408,12 +472,13 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
|
|||
void __iomem *mbase = mtu->mac_base;
|
||||
struct qmu_gpd *gpd = ring->dequeue;
|
||||
struct qmu_gpd *gpd_current = NULL;
|
||||
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
|
||||
struct usb_request *request = NULL;
|
||||
struct mtu3_request *mreq;
|
||||
dma_addr_t cur_gpd_dma;
|
||||
|
||||
/*transfer phy address got from QMU register to virtual address */
|
||||
gpd_current = gpd_dma_to_virt(ring, gpd_dma);
|
||||
cur_gpd_dma = read_txq_cur_addr(mbase, epnum);
|
||||
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
|
||||
|
||||
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
|
||||
__func__, epnum, gpd, gpd_current, ring->enqueue);
|
||||
|
@ -446,11 +511,12 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
|
|||
void __iomem *mbase = mtu->mac_base;
|
||||
struct qmu_gpd *gpd = ring->dequeue;
|
||||
struct qmu_gpd *gpd_current = NULL;
|
||||
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
|
||||
struct usb_request *req = NULL;
|
||||
struct mtu3_request *mreq;
|
||||
dma_addr_t cur_gpd_dma;
|
||||
|
||||
gpd_current = gpd_dma_to_virt(ring, gpd_dma);
|
||||
cur_gpd_dma = read_rxq_cur_addr(mbase, epnum);
|
||||
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
|
||||
|
||||
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
|
||||
__func__, epnum, gpd, gpd_current, ring->enqueue);
|
||||
|
|
|
@ -224,7 +224,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
|
|||
int err = 0;
|
||||
|
||||
u32 clk_rate = 0;
|
||||
bool needs_vcc = false;
|
||||
bool needs_vcc = false, needs_clk = false;
|
||||
|
||||
if (dev->of_node) {
|
||||
struct device_node *node = dev->of_node;
|
||||
|
@ -233,6 +233,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
|
|||
clk_rate = 0;
|
||||
|
||||
needs_vcc = of_property_read_bool(node, "vcc-supply");
|
||||
needs_clk = of_property_read_bool(node, "clocks");
|
||||
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_ASIS);
|
||||
err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
|
||||
|
@ -275,6 +276,8 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
|
|||
if (IS_ERR(nop->clk)) {
|
||||
dev_dbg(dev, "Can't get phy clock: %ld\n",
|
||||
PTR_ERR(nop->clk));
|
||||
if (needs_clk)
|
||||
return PTR_ERR(nop->clk);
|
||||
}
|
||||
|
||||
if (!IS_ERR(nop->clk) && clk_rate) {
|
||||
|
|
|
@ -1261,6 +1261,7 @@ static void msm_chg_detect_work(struct work_struct *w)
|
|||
/* fall through */
|
||||
case USB_CHG_STATE_SECONDARY_DONE:
|
||||
motg->chg_state = USB_CHG_STATE_DETECTED;
|
||||
/* fall through */
|
||||
case USB_CHG_STATE_DETECTED:
|
||||
msm_chg_block_off(motg);
|
||||
dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
|
||||
|
|
|
@ -67,11 +67,26 @@
|
|||
#define ANADIG_ANA_MISC0_SET 0x154
|
||||
#define ANADIG_ANA_MISC0_CLR 0x158
|
||||
|
||||
#define ANADIG_USB1_CHRG_DETECT_SET 0x1b4
|
||||
#define ANADIG_USB1_CHRG_DETECT_CLR 0x1b8
|
||||
#define ANADIG_USB1_CHRG_DETECT_EN_B BIT(20)
|
||||
#define ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B BIT(19)
|
||||
#define ANADIG_USB1_CHRG_DETECT_CHK_CONTACT BIT(18)
|
||||
|
||||
#define ANADIG_USB1_VBUS_DET_STAT 0x1c0
|
||||
#define ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3)
|
||||
|
||||
#define ANADIG_USB1_CHRG_DET_STAT 0x1d0
|
||||
#define ANADIG_USB1_CHRG_DET_STAT_DM_STATE BIT(2)
|
||||
#define ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED BIT(1)
|
||||
#define ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT BIT(0)
|
||||
|
||||
#define ANADIG_USB2_VBUS_DET_STAT 0x220
|
||||
|
||||
#define ANADIG_USB1_LOOPBACK_SET 0x1e4
|
||||
#define ANADIG_USB1_LOOPBACK_CLR 0x1e8
|
||||
#define ANADIG_USB1_LOOPBACK_UTMI_TESTSTART BIT(0)
|
||||
|
||||
#define ANADIG_USB2_LOOPBACK_SET 0x244
|
||||
#define ANADIG_USB2_LOOPBACK_CLR 0x248
|
||||
|
||||
|
@ -479,6 +494,144 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT 100
|
||||
static int mxs_charger_data_contact_detect(struct mxs_phy *x)
|
||||
{
|
||||
struct regmap *regmap = x->regmap_anatop;
|
||||
int i, stable_contact_count = 0;
|
||||
u32 val;
|
||||
|
||||
/* Check if vbus is valid */
|
||||
regmap_read(regmap, ANADIG_USB1_VBUS_DET_STAT, &val);
|
||||
if (!(val & ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)) {
|
||||
dev_err(x->phy.dev, "vbus is not valid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Enable charger detector */
|
||||
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
|
||||
ANADIG_USB1_CHRG_DETECT_EN_B);
|
||||
/*
|
||||
* - Do not check whether a charger is connected to the USB port
|
||||
* - Check whether the USB plug has been in contact with each other
|
||||
*/
|
||||
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
|
||||
ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
|
||||
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
|
||||
|
||||
/* Check if plug is connected */
|
||||
for (i = 0; i < MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT; i++) {
|
||||
regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
|
||||
if (val & ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT) {
|
||||
stable_contact_count++;
|
||||
if (stable_contact_count > 5)
|
||||
/* Data pin makes contact */
|
||||
break;
|
||||
else
|
||||
usleep_range(5000, 10000);
|
||||
} else {
|
||||
stable_contact_count = 0;
|
||||
usleep_range(5000, 6000);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT) {
|
||||
dev_err(x->phy.dev,
|
||||
"Data pin can't make good contact.\n");
|
||||
/* Disable charger detector */
|
||||
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
|
||||
ANADIG_USB1_CHRG_DETECT_EN_B |
|
||||
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x)
|
||||
{
|
||||
struct regmap *regmap = x->regmap_anatop;
|
||||
enum usb_charger_type chgr_type = UNKNOWN_TYPE;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* - Do check whether a charger is connected to the USB port
|
||||
* - Do not Check whether the USB plug has been in contact with
|
||||
* each other
|
||||
*/
|
||||
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
|
||||
ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
|
||||
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
|
||||
|
||||
msleep(100);
|
||||
|
||||
/* Check if it is a charger */
|
||||
regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
|
||||
if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
|
||||
chgr_type = SDP_TYPE;
|
||||
dev_dbg(x->phy.dev, "It is a stardard downstream port\n");
|
||||
}
|
||||
|
||||
/* Disable charger detector */
|
||||
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
|
||||
ANADIG_USB1_CHRG_DETECT_EN_B |
|
||||
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
|
||||
|
||||
return chgr_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* It must be called after DP is pulled up, which is used to
|
||||
* differentiate DCP and CDP.
|
||||
*/
|
||||
enum usb_charger_type mxs_charger_secondary_detection(struct mxs_phy *x)
|
||||
{
|
||||
struct regmap *regmap = x->regmap_anatop;
|
||||
int val;
|
||||
|
||||
msleep(80);
|
||||
|
||||
regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
|
||||
if (val & ANADIG_USB1_CHRG_DET_STAT_DM_STATE) {
|
||||
dev_dbg(x->phy.dev, "It is a dedicate charging port\n");
|
||||
return DCP_TYPE;
|
||||
} else {
|
||||
dev_dbg(x->phy.dev, "It is a charging downstream port\n");
|
||||
return CDP_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy)
|
||||
{
|
||||
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
|
||||
struct regmap *regmap = mxs_phy->regmap_anatop;
|
||||
void __iomem *base = phy->io_priv;
|
||||
enum usb_charger_type chgr_type = UNKNOWN_TYPE;
|
||||
|
||||
if (mxs_charger_data_contact_detect(mxs_phy))
|
||||
return chgr_type;
|
||||
|
||||
chgr_type = mxs_charger_primary_detection(mxs_phy);
|
||||
|
||||
if (chgr_type != SDP_TYPE) {
|
||||
/* Pull up DP via test */
|
||||
writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
|
||||
base + HW_USBPHY_DEBUG_CLR);
|
||||
regmap_write(regmap, ANADIG_USB1_LOOPBACK_SET,
|
||||
ANADIG_USB1_LOOPBACK_UTMI_TESTSTART);
|
||||
|
||||
chgr_type = mxs_charger_secondary_detection(mxs_phy);
|
||||
|
||||
/* Stop the test */
|
||||
regmap_write(regmap, ANADIG_USB1_LOOPBACK_CLR,
|
||||
ANADIG_USB1_LOOPBACK_UTMI_TESTSTART);
|
||||
writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
|
||||
base + HW_USBPHY_DEBUG_SET);
|
||||
}
|
||||
|
||||
return chgr_type;
|
||||
}
|
||||
|
||||
static int mxs_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
@ -567,6 +720,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
|
|||
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
|
||||
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
|
||||
mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup;
|
||||
mxs_phy->phy.charger_detect = mxs_phy_charger_detect;
|
||||
|
||||
mxs_phy->clk = clk;
|
||||
mxs_phy->data = of_id->data;
|
||||
|
|
|
@ -368,7 +368,8 @@ static int tahvo_usb_probe(struct platform_device *pdev)
|
|||
tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable);
|
||||
if (IS_ERR(tu->extcon)) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
|
||||
return -ENOMEM;
|
||||
ret = PTR_ERR(tu->extcon);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
ret = devm_extcon_dev_register(&pdev->dev, tu->extcon);
|
||||
|
|
|
@ -485,6 +485,10 @@ static const struct of_device_id usbhs_of_match[] = {
|
|||
.compatible = "renesas,usbhs-r8a7796",
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN3,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,usbhs-r8a77995",
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rcar-gen2-usbhs",
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN2,
|
||||
|
@ -501,7 +505,6 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
|
|||
{
|
||||
struct renesas_usbhs_platform_info *info;
|
||||
struct renesas_usbhs_driver_param *dparam;
|
||||
const struct of_device_id *of_id = of_match_device(usbhs_of_match, dev);
|
||||
u32 tmp;
|
||||
int gpio;
|
||||
|
||||
|
@ -510,7 +513,7 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
|
|||
return NULL;
|
||||
|
||||
dparam = &info->driver_param;
|
||||
dparam->type = of_id ? (uintptr_t)of_id->data : 0;
|
||||
dparam->type = (uintptr_t)of_device_get_match_data(dev);
|
||||
if (!of_property_read_u32(dev->of_node, "renesas,buswait", &tmp))
|
||||
dparam->buswait_bwait = tmp;
|
||||
gpio = of_get_named_gpio_flags(dev->of_node, "renesas,enable-gpio", 0,
|
||||
|
@ -519,8 +522,12 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
|
|||
dparam->enable_gpio = gpio;
|
||||
|
||||
if (dparam->type == USBHS_TYPE_RCAR_GEN2 ||
|
||||
dparam->type == USBHS_TYPE_RCAR_GEN3)
|
||||
dparam->type == USBHS_TYPE_RCAR_GEN3 ||
|
||||
dparam->type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) {
|
||||
dparam->has_usb_dmac = 1;
|
||||
dparam->pipe_configs = usbhsc_new_pipe;
|
||||
dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
@ -577,17 +584,12 @@ static int usbhs_probe(struct platform_device *pdev)
|
|||
switch (priv->dparam.type) {
|
||||
case USBHS_TYPE_RCAR_GEN2:
|
||||
priv->pfunc = usbhs_rcar2_ops;
|
||||
if (!priv->dparam.pipe_configs) {
|
||||
priv->dparam.pipe_configs = usbhsc_new_pipe;
|
||||
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
|
||||
}
|
||||
break;
|
||||
case USBHS_TYPE_RCAR_GEN3:
|
||||
priv->pfunc = usbhs_rcar3_ops;
|
||||
if (!priv->dparam.pipe_configs) {
|
||||
priv->dparam.pipe_configs = usbhsc_new_pipe;
|
||||
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
|
||||
}
|
||||
break;
|
||||
case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
|
||||
priv->pfunc = usbhs_rcar3_with_pll_ops;
|
||||
break;
|
||||
default:
|
||||
if (!info->platform_callback.get_id) {
|
||||
|
|
|
@ -15,24 +15,39 @@
|
|||
#include "rcar3.h"
|
||||
|
||||
#define LPSTS 0x102
|
||||
#define UGCTRL 0x180 /* 32-bit register */
|
||||
#define UGCTRL2 0x184 /* 32-bit register */
|
||||
#define UGSTS 0x188 /* 32-bit register */
|
||||
|
||||
/* Low Power Status register (LPSTS) */
|
||||
#define LPSTS_SUSPM 0x4000
|
||||
|
||||
/* R-Car D3 only: USB General control register (UGCTRL) */
|
||||
#define UGCTRL_PLLRESET 0x00000001
|
||||
#define UGCTRL_CONNECT 0x00000004
|
||||
|
||||
/*
|
||||
* USB General control register 2 (UGCTRL2)
|
||||
* Remarks: bit[31:11] and bit[9:6] should be 0
|
||||
*/
|
||||
#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
|
||||
#define UGCTRL2_USB0SEL_HSUSB 0x00000020
|
||||
#define UGCTRL2_USB0SEL_OTG 0x00000030
|
||||
#define UGCTRL2_VBUSSEL 0x00000400
|
||||
|
||||
/* R-Car D3 only: USB General status register (UGSTS) */
|
||||
#define UGSTS_LOCK 0x00000100
|
||||
|
||||
static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
|
||||
{
|
||||
iowrite32(data, priv->base + reg);
|
||||
}
|
||||
|
||||
static u32 usbhs_read32(struct usbhs_priv *priv, u32 reg)
|
||||
{
|
||||
return ioread32(priv->base + reg);
|
||||
}
|
||||
|
||||
static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
|
||||
void __iomem *base, int enable)
|
||||
{
|
||||
|
@ -52,6 +67,34 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* R-Car D3 needs to release UGCTRL.PLLRESET */
|
||||
static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev,
|
||||
void __iomem *base, int enable)
|
||||
{
|
||||
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
|
||||
u32 val;
|
||||
int timeout = 1000;
|
||||
|
||||
if (enable) {
|
||||
usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */
|
||||
usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 |
|
||||
UGCTRL2_USB0SEL_HSUSB);
|
||||
|
||||
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
|
||||
do {
|
||||
val = usbhs_read32(priv, UGSTS);
|
||||
udelay(1);
|
||||
} while (!(val & UGSTS_LOCK) && timeout--);
|
||||
usbhs_write32(priv, UGCTRL, UGCTRL_CONNECT);
|
||||
} else {
|
||||
usbhs_write32(priv, UGCTRL, 0);
|
||||
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
|
||||
usbhs_write32(priv, UGCTRL, UGCTRL_PLLRESET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbhs_rcar3_get_id(struct platform_device *pdev)
|
||||
{
|
||||
return USBHS_GADGET;
|
||||
|
@ -61,3 +104,8 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
|
|||
.power_ctrl = usbhs_rcar3_power_ctrl,
|
||||
.get_id = usbhs_rcar3_get_id,
|
||||
};
|
||||
|
||||
const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = {
|
||||
.power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
|
||||
.get_id = usbhs_rcar3_get_id,
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "common.h"
|
||||
|
||||
extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
|
||||
extern const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops;
|
||||
|
|
|
@ -188,6 +188,8 @@ struct usb_ep_caps {
|
|||
* @ops: Function pointers used to access hardware-specific operations.
|
||||
* @ep_list:the gadget's ep_list holds all of its endpoints
|
||||
* @caps:The structure describing types and directions supported by endoint.
|
||||
* @enabled: The current endpoint enabled/disabled state.
|
||||
* @claimed: True if this endpoint is claimed by a function.
|
||||
* @maxpacket:The maximum packet size used on this endpoint. The initial
|
||||
* value can sometimes be reduced (hardware allowing), according to
|
||||
* the endpoint descriptor used to configure the endpoint.
|
||||
|
@ -349,6 +351,9 @@ struct usb_gadget_ops {
|
|||
* or B-Peripheral wants to take host role.
|
||||
* @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
|
||||
* MaxPacketSize.
|
||||
* @quirk_altset_not_supp: UDC controller doesn't support alt settings.
|
||||
* @quirk_stall_not_supp: UDC controller doesn't support stalling.
|
||||
* @quirk_zlp_not_supp: UDC controller doesn't support ZLP.
|
||||
* @quirk_avoids_skb_reserve: udc/platform wants to avoid skb_reserve() in
|
||||
* u_ether.c to improve performance.
|
||||
* @is_selfpowered: if the gadget is self-powered.
|
||||
|
|
|
@ -183,8 +183,9 @@ struct renesas_usbhs_driver_param {
|
|||
#define USBHS_USB_DMAC_XFER_SIZE 32 /* hardcode the xfer size */
|
||||
};
|
||||
|
||||
#define USBHS_TYPE_RCAR_GEN2 1
|
||||
#define USBHS_TYPE_RCAR_GEN3 2
|
||||
#define USBHS_TYPE_RCAR_GEN2 1
|
||||
#define USBHS_TYPE_RCAR_GEN3 2
|
||||
#define USBHS_TYPE_RCAR_GEN3_WITH_PLL 3
|
||||
|
||||
/*
|
||||
* option:
|
||||
|
|
Загрузка…
Ссылка в новой задаче