Commit 2d5afd51 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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.
parents 0520d37b ce2b21a4
...@@ -19,6 +19,8 @@ Required properties: ...@@ -19,6 +19,8 @@ Required properties:
configured in FS mode; configured in FS mode;
- "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs - "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs
configured in HS mode; 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) - reg : Should contain 1 register range (address and length)
- interrupts : Should contain 1 interrupt - interrupts : Should contain 1 interrupt
- clocks: clock provider specifier - clocks: clock provider specifier
......
...@@ -14,9 +14,9 @@ Required properties: ...@@ -14,9 +14,9 @@ Required properties:
- vusb33-supply : regulator of USB avdd3.3v - vusb33-supply : regulator of USB avdd3.3v
- clocks : a list of phandle + clock-specifier pairs, one for each - clocks : a list of phandle + clock-specifier pairs, one for each
entry in clock-names entry in clock-names
- clock-names : must contain "sys_ck" and "ref_ck" for clock of controller; - clock-names : must contain "sys_ck" for clock of controller,
"wakeup_deb_p0" and "wakeup_deb_p1" are optional, they are the following clocks are optional:
depends on "mediatek,enable-wakeup" "ref_ck", "mcu_ck" and "dam_ck";
- phys : a list of phandle + phy specifier pairs - phys : a list of phandle + phy specifier pairs
- dr_mode : should be one of "host", "peripheral" or "otg", - dr_mode : should be one of "host", "peripheral" or "otg",
refer to usb/generic.txt refer to usb/generic.txt
...@@ -30,9 +30,10 @@ Optional properties: ...@@ -30,9 +30,10 @@ Optional properties:
when supports dual-role mode. when supports dual-role mode.
- vbus-supply : reference to the VBUS regulator, needed when supports - vbus-supply : reference to the VBUS regulator, needed when supports
dual-role mode. dual-role mode.
- pinctl-names : a pinctrl state named "default" must be defined, - pinctrl-names : a pinctrl state named "default" is optional, and need be
"id_float" and "id_ground" are optinal which depends on defined if auto drd switch is enabled, that means the property dr_mode
"mediatek,enable-manual-drd" is set as "otg", and meanwhile the property "mediatek,enable-manual-drd"
is not set.
- pinctrl-0 : pin control group - pinctrl-0 : pin control group
See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
...@@ -44,6 +45,8 @@ Optional properties: ...@@ -44,6 +45,8 @@ Optional properties:
- mediatek,enable-wakeup : supports ip sleep wakeup used by host mode - mediatek,enable-wakeup : supports ip sleep wakeup used by host mode
- mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup - mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
control register, it depends on "mediatek,enable-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: Sub-nodes:
The xhci should be added as subnode to mtu3 as shown in the following example The xhci should be added as subnode to mtu3 as shown in the following example
...@@ -63,9 +66,7 @@ ssusb: usb@11271000 { ...@@ -63,9 +66,7 @@ ssusb: usb@11271000 {
clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>, clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>,
<&pericfg CLK_PERI_USB0>, <&pericfg CLK_PERI_USB0>,
<&pericfg CLK_PERI_USB1>; <&pericfg CLK_PERI_USB1>;
clock-names = "sys_ck", "ref_ck", clock-names = "sys_ck", "ref_ck";
"wakeup_deb_p0",
"wakeup_deb_p1";
vusb33-supply = <&mt6397_vusb_reg>; vusb33-supply = <&mt6397_vusb_reg>;
vbus-supply = <&usb_p0_vbus>; vbus-supply = <&usb_p0_vbus>;
extcon = <&extcon_usb>; extcon = <&extcon_usb>;
......
...@@ -15,6 +15,10 @@ Required properties: ...@@ -15,6 +15,10 @@ Required properties:
- interrupts: Interrupt specifier for the USB3.0 Peripheral - interrupts: Interrupt specifier for the USB3.0 Peripheral
- clocks: clock phandle and specifier pair - 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: Example of R-Car H3 ES1.x:
usb3_peri0: usb@ee020000 { usb3_peri0: usb@ee020000 {
compatible = "renesas,r8a7795-usb3-peri", compatible = "renesas,r8a7795-usb3-peri",
......
...@@ -3,6 +3,8 @@ Renesas Electronics USBHS driver ...@@ -3,6 +3,8 @@ Renesas Electronics USBHS driver
Required properties: Required properties:
- compatible: Must contain one or more of the following: - 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-r8a7790" for r8a7790 (R-Car H2) compatible device
- "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
- "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
...@@ -10,7 +12,8 @@ Required properties: ...@@ -10,7 +12,8 @@ Required properties:
- "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) 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 - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
When compatible with the generic version, nodes must list the When compatible with the generic version, nodes must list the
......
...@@ -395,6 +395,9 @@ enum dwc2_ep0_state { ...@@ -395,6 +395,9 @@ enum dwc2_ep0_state {
* (default when phy_type is UTMI+ or ULPI) * (default when phy_type is UTMI+ or ULPI)
* 1 - 6 MHz * 1 - 6 MHz
* (default when phy_type is Full Speed) * (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 * @ts_dline: Enable Term Select Dline pulsing
* 0 - No (default) * 0 - No (default)
* 1 - Yes * 1 - Yes
...@@ -492,6 +495,7 @@ struct dwc2_core_params { ...@@ -492,6 +495,7 @@ struct dwc2_core_params {
bool dma_desc_fs_enable; bool dma_desc_fs_enable;
bool host_support_fs_ls_low_power; bool host_support_fs_ls_low_power;
bool host_ls_low_power_phy_clk; bool host_ls_low_power_phy_clk;
bool oc_disable;
u8 host_channels; u8 host_channels;
u16 host_rx_fifo_size; u16 host_rx_fifo_size;
......
...@@ -3202,6 +3202,8 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) ...@@ -3202,6 +3202,8 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
call_gadget(hsotg, disconnect); call_gadget(hsotg, disconnect);
hsotg->lx_state = DWC2_L3; 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) ...@@ -4004,6 +4006,11 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
return -EINVAL; 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); epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
spin_lock_irqsave(&hsotg->lock, flags); spin_lock_irqsave(&hsotg->lock, flags);
......
...@@ -213,6 +213,11 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) ...@@ -213,6 +213,11 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
if (hsotg->params.phy_ulpi_ddr) if (hsotg->params.phy_ulpi_ddr)
usbcfg |= GUSBCFG_DDRSEL; usbcfg |= GUSBCFG_DDRSEL;
/* Set external VBUS indicator as needed. */
if (hsotg->params.oc_disable)
usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND |
GUSBCFG_INDICATORPASSTHROUGH);
break; break;
case DWC2_PHY_TYPE_PARAM_UTMI: case DWC2_PHY_TYPE_PARAM_UTMI:
/* UTMI+ interface */ /* UTMI+ interface */
...@@ -3277,7 +3282,6 @@ static void dwc2_conn_id_status_change(struct work_struct *work) ...@@ -3277,7 +3282,6 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
dwc2_core_init(hsotg, false); dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg); dwc2_enable_global_interrupts(hsotg);
spin_lock_irqsave(&hsotg->lock, flags); spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_disconnect(hsotg);
dwc2_hsotg_core_init_disconnected(hsotg, false); dwc2_hsotg_core_init_disconnected(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hsotg_core_connect(hsotg); dwc2_hsotg_core_connect(hsotg);
...@@ -3296,8 +3300,12 @@ static void dwc2_conn_id_status_change(struct work_struct *work) ...@@ -3296,8 +3300,12 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
if (count > 250) if (count > 250)
dev_err(hsotg->dev, dev_err(hsotg->dev,
"Connection id status change timed out\n"); "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 */ /* Initialize the Core for Host mode */
dwc2_core_init(hsotg, false); dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg); dwc2_enable_global_interrupts(hsotg);
......
...@@ -136,6 +136,15 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg) ...@@ -136,6 +136,15 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
p->activate_stm_fs_transceiver = true; 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[] = { const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
...@@ -154,6 +163,8 @@ const struct of_device_id dwc2_of_match_table[] = { ...@@ -154,6 +163,8 @@ const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "st,stm32f4x9-fsotg", { .compatible = "st,stm32f4x9-fsotg",
.data = dwc2_set_stm32f4x9_fsotg_params }, .data = dwc2_set_stm32f4x9_fsotg_params },
{ .compatible = "st,stm32f4x9-hsotg" }, { .compatible = "st,stm32f4x9-hsotg" },
{ .compatible = "st,stm32f7xx-hsotg",
.data = dwc2_set_stm32f7xx_hsotg_params },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, dwc2_of_match_table); MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
...@@ -335,6 +346,9 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) ...@@ -335,6 +346,9 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
num); 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) static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
......
...@@ -156,9 +156,8 @@ static void __dwc3_set_mode(struct work_struct *work) ...@@ -156,9 +156,8 @@ static void __dwc3_set_mode(struct work_struct *work)
} else { } else {
if (dwc->usb2_phy) if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true); 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; break;
case DWC3_GCTL_PRTCAP_DEVICE: case DWC3_GCTL_PRTCAP_DEVICE:
...@@ -166,8 +165,8 @@ static void __dwc3_set_mode(struct work_struct *work) ...@@ -166,8 +165,8 @@ static void __dwc3_set_mode(struct work_struct *work)
if (dwc->usb2_phy) if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false); 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); ret = dwc3_gadget_init(dwc);
if (ret) if (ret)
...@@ -927,12 +926,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) ...@@ -927,12 +926,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
switch (dwc->dr_mode) { switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_PERIPHERAL:
dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
if (dwc->usb2_phy) if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false); 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); ret = dwc3_gadget_init(dwc);
if (ret) { if (ret) {
...@@ -942,12 +942,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) ...@@ -942,12 +942,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
} }
break; break;
case USB_DR_MODE_HOST: case USB_DR_MODE_HOST:
dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
if (dwc->usb2_phy) if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true); 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); ret = dwc3_host_init(dwc);
if (ret) { if (ret) {
...@@ -1293,21 +1294,19 @@ static int dwc3_suspend_common(struct dwc3 *dwc) ...@@ -1293,21 +1294,19 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
{ {
unsigned long flags; unsigned long flags;
switch (dwc->dr_mode) { switch (dwc->current_dr_role) {
case USB_DR_MODE_PERIPHERAL: case DWC3_GCTL_PRTCAP_DEVICE:
case USB_DR_MODE_OTG:
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc); dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
dwc3_core_exit(dwc);
break; break;
case USB_DR_MODE_HOST: case DWC3_GCTL_PRTCAP_HOST:
default: default:
/* do nothing */ /* do nothing */
break; break;
} }
dwc3_core_exit(dwc);
return 0; return 0;
} }
...@@ -1316,18 +1315,17 @@ static int dwc3_resume_common(struct dwc3 *dwc) ...@@ -1316,18 +1315,17 @@ static int dwc3_resume_common(struct dwc3 *dwc)
unsigned long flags; unsigned long flags;
int ret; int ret;
ret = dwc3_core_init(dwc); switch (dwc->current_dr_role) {
if (ret) case DWC3_GCTL_PRTCAP_DEVICE:
return ret; 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); spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc); dwc3_gadget_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags); spin_unlock_irqrestore(&dwc->lock, flags);
/* FALLTHROUGH */ break;
case USB_DR_MODE_HOST: case DWC3_GCTL_PRTCAP_HOST:
default: default:
/* do nothing */ /* do nothing */
break; break;
...@@ -1338,7 +1336,7 @@ static int dwc3_resume_common(struct dwc3 *dwc) ...@@ -1338,7 +1336,7 @@ static int dwc3_resume_common(struct dwc3 *dwc)
static int dwc3_runtime_checks(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_PERIPHERAL:
case USB_DR_MODE_OTG: case USB_DR_MODE_OTG:
if (dwc->connected) if (dwc->connected)
...@@ -1381,19 +1379,17 @@ static int dwc3_runtime_resume(struct device *dev) ...@@ -1381,19 +1379,17 @@ static int dwc3_runtime_resume(struct device *dev)
if (ret) if (ret)
return ret; return ret;
switch (dwc->dr_mode) { switch (dwc->current_dr_role) {
case USB_DR_MODE_PERIPHERAL: case DWC3_GCTL_PRTCAP_DEVICE:
case USB_DR_MODE_OTG:
dwc3_gadget_process_pending_events(dwc); dwc3_gadget_process_pending_events(dwc);
break; break;
case USB_DR_MODE_HOST: case DWC3_GCTL_PRTCAP_HOST:
default: default:
/* do nothing */ /* do nothing */
break; break;
} }
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
pm_runtime_put(dev);
return 0; return 0;
} }
...@@ -1402,13 +1398,12 @@ static int dwc3_runtime_idle(struct device *dev) ...@@ -1402,13 +1398,12 @@ static int dwc3_runtime_idle(struct device *dev)
{ {
struct dwc3 *dwc = dev_get_drvdata(dev); struct dwc3 *dwc = dev_get_drvdata(dev);
switch (dwc->dr_mode) { switch (dwc->current_dr_role) {
case USB_DR_MODE_PERIPHERAL: case DWC3_GCTL_PRTCAP_DEVICE:
case USB_DR_MODE_OTG:
if (dwc3_runtime_checks(dwc)) if (dwc3_runtime_checks(dwc))
return -EBUSY; return -EBUSY;
break; break;
case USB_DR_MODE_HOST: case DWC3_GCTL_PRTCAP_HOST:
default: default:
/* do nothing */ /* do nothing */
break; break;
......
...@@ -529,6 +529,7 @@ struct dwc3_event_buffer { ...@@ -529,6 +529,7 @@ struct dwc3_event_buffer {
* @number: endpoint number (1 - 15) * @number: endpoint number (1 - 15)
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index * @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 * @interval: the interval on which the ISOC transfer is started
* @allocated_requests: number of requests allocated * @allocated_requests: number of requests allocated
* @queued_requests: number of requests queued for transfer * @queued_requests: number of requests queued for transfer
...@@ -581,6 +582,7 @@ struct dwc3_ep { ...@@ -581,6 +582,7 @@ struct dwc3_ep {
u8 resource_index; u8 resource_index;
u32 allocated_requests; u32 allocated_requests;
u32 queued_requests; u32 queued_requests;
u32 frame_number;
u32 interval; u32 interval;
char name[20]; char name[20];
......
...@@ -28,11 +28,13 @@ ...@@ -28,11 +28,13 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h>
struct dwc3_of_simple { struct dwc3_of_simple {
struct device *dev; struct device *dev;
struct clk **clks; struct clk **clks;
int num_clocks; int num_clocks;
struct reset_control *resets;
}; };
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count) 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) ...@@ -95,10 +97,21 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, simple); platform_set_drvdata(pdev, simple);
simple->dev = dev; 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, ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np,
"clocks", "#clock-cells")); "clocks", "#clock-cells"));
if (ret) if (ret)
return ret; goto err_resetc_assert;
ret = of_platform_populate(np, NULL, NULL, dev); ret = of_platform_populate(np, NULL, NULL, dev);
if (ret) { if (ret) {
...@@ -107,7 +120,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) ...@@ -107,7 +120,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
clk_put(simple->clks[i]); clk_put(simple->clks[i]);
} }
return ret; goto err_resetc_assert;
} }
pm_runtime_set_active(dev); pm_runtime_set_active(dev);
...@@ -115,6 +128,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) ...@@ -115,6 +128,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
return 0; 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) static int dwc3_of_simple_remove(struct platform_device *pdev)
...@@ -123,12 +143,15 @@ 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; struct device *dev = &pdev->dev;
int i; int i;
of_platform_depopulate(dev);
for (i = 0; i < simple->num_clocks; i++) { for (i = 0; i < simple->num_clocks; i++) {
clk_disable_unprepare(simple->clks[i]); clk_disable_unprepare(simple->clks[i]);
clk_put(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_put_sync(dev);
pm_runtime_disable(dev); pm_runtime_disable(dev);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
...@@ -61,6 +62,7 @@ struct dwc3_pci { ...@@ -61,6 +62,7 @@ struct dwc3_pci {
guid_t guid; guid_t guid;
unsigned int has_dsm_for_pm:1; unsigned int has_dsm_for_pm:1;
struct work_struct wakeup_work;
}; };
static const struct acpi_gpio_params reset_gpios = { 0, 0, false }; static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
...@@ -174,6 +176,22 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc) ...@@ -174,6 +176,22 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
return 0; 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, static int dwc3_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
...@@ -232,6 +250,9 @@ static int dwc3_pci_probe(struct pci_dev *pci, ...@@ -232,6 +250,9 @@ static int dwc3_pci_probe(struct pci_dev *pci,
device_init_wakeup(dev, true); device_init_wakeup(dev, true);
pci_set_drvdata(pci, dwc); pci_set_drvdata(pci, dwc);
pm_runtime_put(dev); pm_runtime_put(dev);
#ifdef CONFIG_PM
INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
#endif
return 0; return 0;
err: err:
...@@ -243,6 +264,9 @@ static void dwc3_pci_remove(struct pci_dev *pci) ...@@ -243,6 +264,9 @@ static void dwc3_pci_remove(struct pci_dev *pci)
{ {
struct dwc3_pci *dwc = pci_get_drvdata(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); device_init_wakeup(&pci->dev, false);
pm_runtime_get(&pci->dev); pm_runtime_get(&pci->dev);
platform_device_unregister(dwc->dwc3); platform_device_unregister(dwc->dwc3);
...@@ -318,14 +342,15 @@ static int dwc3_pci_runtime_suspend(struct device *dev) ...@@ -318,14 +342,15 @@ static int dwc3_pci_runtime_suspend(struct device *dev)
static int dwc3_pci_runtime_resume(struct device *dev) static int dwc3_pci_runtime_resume(struct device *dev)
{ {
struct dwc3_pci *dwc = dev_get_drvdata(dev); struct dwc3_pci *dwc = dev_get_drvdata(dev);
struct platform_device *dwc3 = dwc->dwc3;
int ret; int ret;
ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0); ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
if (ret) if (ret)
return ret; return ret;
return pm_runtime_get(&dwc3->dev); queue_work(pm_wq, &dwc->wakeup_work);
return 0;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
......
...@@ -487,14 +487,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, ...@@ -487,14 +487,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
static int dwc3_ep0_handle_intf(struct dwc3 *dwc, static int dwc3_ep0_handle_intf(struct dwc3 *dwc,
struct usb_ctrlrequest *ctrl, int set) struct usb_ctrlrequest *ctrl, int set)
{ {
enum usb_device_state state;
u32 wValue; u32 wValue;
u32 wIndex;
int ret = 0; int ret = 0;
wValue = le16_to_cpu(ctrl->wValue); wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
state = dwc->gadget.state;
switch (wValue) { switch (wValue) {
case USB_INTRF_FUNC_SUSPEND: case USB_INTRF_FUNC_SUSPEND:
...@@ -517,14 +513,10 @@ static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc, ...@@ -517,14 +513,10 @@ static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc,
struct usb_ctrlrequest *ctrl, int set) struct usb_ctrlrequest *ctrl, int set)
{ {
struct dwc3_ep *dep; struct dwc3_ep *dep;
enum usb_device_state state;
u32 wValue; u32 wValue;
u32 wIndex;
int ret; int ret;
wValue = le16_to_cpu(ctrl->wValue); wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
state = dwc->gadget.state;
switch (wValue) { switch (wValue) {
case USB_ENDPOINT_HALT: case USB_ENDPOINT_HALT:
...@@ -551,10 +543,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, ...@@ -551,10 +543,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
{ {
u32 recip; u32 recip;
int ret; int ret;
enum usb_device_state state;
recip = ctrl->bRequestType & USB_RECIP_MASK; recip = ctrl->bRequestType & USB_RECIP_MASK;
state = dwc->gadget.state;
switch (recip) { switch (recip) {
case USB_RECIP_DEVICE: case USB_RECIP_DEVICE:
...@@ -712,12 +702,10 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) ...@@ -712,12 +702,10 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
struct dwc3_ep *dep; struct dwc3_ep *dep;
enum usb_device_state state = dwc->gadget.state; enum usb_device_state state = dwc->gadget.state;
u16 wLength; u16 wLength;
u16 wValue;
if (state == USB_STATE_DEFAULT) if (state == USB_STATE_DEFAULT)
return -EINVAL; return -EINVAL;
wValue = le16_to_cpu(ctrl->wValue);
wLength = le16_to_cpu(ctrl->wLength); wLength = le16_to_cpu(ctrl->wLength);
if (wLength != 6) { if (wLength != 6) {
...@@ -842,9 +830,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ...@@ -842,9 +830,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
struct usb_request *ur; struct usb_request *ur;
struct dwc3_trb *trb; struct dwc3_trb *trb;
struct dwc3_ep *ep0; struct dwc3_ep *ep0;
unsigned maxp;
unsigned remaining_ur_length;
void *buf;
u32 transferred = 0; u32 transferred = 0;
u32 status; u32 status;
u32 length; u32 length;
...@@ -871,11 +856,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ...@@ -871,11 +856,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
} }
ur = &r->request; ur = &r->request;
buf = ur->buf;
remaining_ur_length = ur->length;
length = trb->size & DWC3_TRB_SIZE_MASK; length = trb->size & DWC3_TRB_SIZE_MASK;
maxp = ep0->endpoint.maxpacket;
transferred = ur->length - length; transferred = ur->length - length;
ur->actual += transferred; ur->actual += transferred;
...@@ -1001,7 +983,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ...@@ -1001,7 +983,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
} else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && } else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
req->request.length && req->request.zero) { req->request.length && req->request.zero) {
u32 maxpacket; u32 maxpacket;
u32 rem;
ret = usb_gadget_map_request_by_dev(dwc->sysdev, ret = usb_gadget_map_request_by_dev(dwc->sysdev,
&req->request, dep->number); &req->request, dep->number);
...@@ -1009,7 +990,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ...@@ -1009,7 +990,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
return; return;
maxpacket = dep->endpoint.maxpacket; maxpacket = dep->endpoint.maxpacket;
rem = req->request.length % maxpacket;
/* prepare normal TRB */ /* prepare normal TRB */
dwc3_ep0_prepare_one_trb(dep, req->request.dma, dwc3_ep0_prepare_one_trb(dep, req->request.dma,
......
...@@ -1151,9 +1151,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) ...@@ -1151,9 +1151,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); 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 * 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 * 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) ...@@ -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_gadget_ep_cmd_params params;
struct dwc3_request *req; struct dwc3_request *req;
...@@ -1202,6 +1199,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) ...@@ -1202,6 +1199,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
int ret; int ret;
u32 cmd; u32 cmd;
if (!dwc3_calc_trbs_left(dep))
return 0;
starting = !(dep->flags & DWC3_EP_BUSY); starting = !(dep->flags & DWC3_EP_BUSY);
dwc3_prepare_trbs(dep); dwc3_prepare_trbs(dep);
...@@ -1216,8 +1216,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) ...@@ -1216,8 +1216,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
if (starting) { if (starting) {
params.param0 = upper_32_bits(req->trb_dma); params.param0 = upper_32_bits(req->trb_dma);
params.param1 = lower_32_bits(req->trb_dma); params.param1 = lower_32_bits(req->trb_dma);
cmd = DWC3_DEPCMD_STARTTRANSFER | cmd = DWC3_DEPCMD_STARTTRANSFER;
DWC3_DEPCMD_PARAM(cmd_param);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
cmd |= DWC3_DEPCMD_PARAM(dep->frame_number);
} else { } else {
cmd = DWC3_DEPCMD_UPDATETRANSFER | cmd = DWC3_DEPCMD_UPDATETRANSFER |
DWC3_DEPCMD_PARAM(dep->resource_index); DWC3_DEPCMD_PARAM(dep->resource_index);
...@@ -1258,8 +1260,6 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc) ...@@ -1258,8 +1260,6 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
struct dwc3_ep *dep, u32 cur_uf) struct dwc3_ep *dep, u32 cur_uf)
{ {
u32 uf;
if (list_empty(&dep->pending_list)) { if (list_empty(&dep->pending_list)) {
dev_info(dwc->dev, "%s: ran out of requests\n", dev_info(dwc->dev, "%s: ran out of requests\n",
dep->name); dep->name);
...@@ -1271,9 +1271,8 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, ...@@ -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 * Schedule the first trb for one interval in the future or at
* least 4 microframes. * least 4 microframes.
*/ */
uf = cur_uf + max_t(u32, 4, dep->interval); dep->frame_number = cur_uf + max_t(u32, 4, dep->interval);
__dwc3_gadget_kick_transfer(dep);
__dwc3_gadget_kick_transfer(dep, uf);
} }
static void dwc3_gadget_start_isoc(struct dwc3 *dwc, static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
...@@ -1290,7 +1289,6 @@ 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) static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{ {
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
int ret = 0;
if (!dep->endpoint.desc) { if (!dep->endpoint.desc) {
dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", 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) ...@@ -1337,24 +1335,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
} }
if ((dep->flags & DWC3_EP_BUSY) && if ((dep->flags & DWC3_EP_BUSY) &&
!(dep->flags & DWC3_EP_MISSED_ISOC)) { !(dep->flags & DWC3_EP_MISSED_ISOC))
WARN_ON_ONCE(!dep->resource_index); goto out;
ret = __dwc3_gadget_kick_transfer(dep,
dep->resource_index);
}
goto out;
}
if (!dwc3_calc_trbs_left(dep))
return 0; return 0;
}
ret = __dwc3_gadget_kick_transfer(dep, 0);
out: out:
if (ret == -EBUSY) return __dwc3_gadget_kick_transfer(dep);
ret = 0;
return ret;
} }
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, 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, ...@@ -2347,7 +2335,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
req->request.actual = length - req->remaining; req->request.actual = length - req->remaining;
if ((req->request.actual < length) && req->num_pending_sgs) 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); dwc3_gadget_giveback(dep, req, status);
...@@ -2440,13 +2428,8 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, ...@@ -2440,13 +2428,8 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
if (!dep->endpoint.desc) if (!dep->endpoint.desc)
return; return;
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { if (!usb_endpoint_xfer_isoc(dep->endpoint.desc))
int ret; __dwc3_gadget_kick_transfer(dep);
ret = __dwc3_gadget_kick_transfer(dep, 0);
if (!ret || ret == -EBUSY)
return;
}
} }
static void dwc3_endpoint_interrupt(struct dwc3 *dwc, static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
...@@ -2487,15 +2470,10 @@ 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); dwc3_endpoint_transfer_complete(dwc, dep, event);
break; break;
case DWC3_DEPEVT_XFERNOTREADY: 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); dwc3_gadget_start_isoc(dwc, dep, event);
} else { else
int ret; __dwc3_gadget_kick_transfer(dep);
ret = __dwc3_gadget_kick_transfer(dep, 0);
if (!ret || ret == -EBUSY)
return;
}
break; break;
case DWC3_DEPEVT_STREAMEVT: case DWC3_DEPEVT_STREAMEVT:
......
...@@ -1145,6 +1145,7 @@ static int usbg_submit_command(struct f_uas *fu, ...@@ -1145,6 +1145,7 @@ static int usbg_submit_command(struct f_uas *fu,
default: default:
pr_debug_once("Unsupported prio_attr: %02x.\n", pr_debug_once("Unsupported prio_attr: %02x.\n",
cmd_iu->prio_attr); cmd_iu->prio_attr);
/* fall through */
case UAS_SIMPLE_TAG: case UAS_SIMPLE_TAG:
cmd->prio_attr = TCM_SIMPLE_TAG; cmd->prio_attr = TCM_SIMPLE_TAG;
break; break;
......
...@@ -1078,6 +1078,7 @@ static void gs_complete_out(struct usb_ep *ep, struct usb_request *req) ...@@ -1078,6 +1078,7 @@ static void gs_complete_out(struct usb_ep *ep, struct usb_request *req)
default: default:
pr_warn("%s: unexpected %s status %d\n", pr_warn("%s: unexpected %s status %d\n",
__func__, ep->name, req->status); __func__, ep->name, req->status);
/* fall through */
case 0: case 0:
/* normal completion */ /* normal completion */
spin_lock(&info->con_lock); spin_lock(&info->con_lock);
......
...@@ -354,7 +354,7 @@ static unsigned long uvcg_v4l2_get_unmapped_area(struct file *file, ...@@ -354,7 +354,7 @@ static unsigned long uvcg_v4l2_get_unmapped_area(struct file *file,
} }
#endif #endif
struct v4l2_file_operations uvc_v4l2_fops = { const struct v4l2_file_operations uvc_v4l2_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = uvc_v4l2_open, .open = uvc_v4l2_open,
.release = uvc_v4l2_release, .release = uvc_v4l2_release,
......
...@@ -17,6 +17,6 @@ ...@@ -17,6 +17,6 @@
#define __UVC_V4L2_H__ #define __UVC_V4L2_H__
extern const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops; 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__ */ #endif /* __UVC_V4L2_H__ */
...@@ -912,7 +912,7 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget, ...@@ -912,7 +912,7 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
return 0; return 0;
type = usb_endpoint_type(desc); 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) if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
return 0; return 0;
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
* *
* Having this all in one kernel can help some stages of development, * Having this all in one kernel can help some stages of development,
* bypassing some hardware (and driver) issues. UML could help too. * bypassing some hardware (and driver) issues. UML could help too.
*
* Note: The emulation does not include isochronous transfers!
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -137,6 +139,9 @@ static const struct { ...@@ -137,6 +139,9 @@ static const struct {
.caps = _caps, \ .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 */ /* everyone has ep0 */
EP_INFO(ep0name, EP_INFO(ep0name,
USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
...@@ -145,64 +150,72 @@ static const struct { ...@@ -145,64 +150,72 @@ static const struct {
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep2out-bulk", EP_INFO("ep2out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
/*
EP_INFO("ep3in-iso", EP_INFO("ep3in-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep4out-iso", EP_INFO("ep4out-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
*/
EP_INFO("ep5in-int", EP_INFO("ep5in-int",
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep6in-bulk", EP_INFO("ep6in-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep7out-bulk", EP_INFO("ep7out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
/*
EP_INFO("ep8in-iso", EP_INFO("ep8in-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep9out-iso", EP_INFO("ep9out-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
*/
EP_INFO("ep10in-int", EP_INFO("ep10in-int",
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep11in-bulk", EP_INFO("ep11in-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep12out-bulk", EP_INFO("ep12out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
/*
EP_INFO("ep13in-iso", EP_INFO("ep13in-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep14out-iso", EP_INFO("ep14out-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
*/
EP_INFO("ep15in-int", EP_INFO("ep15in-int",
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
/* or like sa1100: two fixed function endpoints */ /* or like sa1100: two fixed function endpoints */
EP_INFO("ep1out-bulk", EP_INFO("ep1out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep2in-bulk", EP_INFO("ep2in-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), 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 */ /* and now some generic EPs so we have enough in multi config */
EP_INFO("ep3out", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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", 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 #undef EP_INFO
}; };
...@@ -1769,6 +1782,7 @@ static void dummy_timer(unsigned long _dum_hcd) ...@@ -1769,6 +1782,7 @@ static void dummy_timer(unsigned long _dum_hcd)
int i; int i;
/* simplistic model for one frame's bandwidth */ /* simplistic model for one frame's bandwidth */
/* FIXME: account for transaction and packet overhead */
switch (dum->gadget.speed) { switch (dum->gadget.speed) {
case USB_SPEED_LOW: case USB_SPEED_LOW:
total = 8/*bytes*/ * 12/*packets*/; total = 8/*bytes*/ * 12/*packets*/;
...@@ -1813,7 +1827,6 @@ static void dummy_timer(unsigned long _dum_hcd) ...@@ -1813,7 +1827,6 @@ static void dummy_timer(unsigned long _dum_hcd)
struct dummy_request *req; struct dummy_request *req;
u8 address; u8 address;
struct dummy_ep *ep = NULL; struct dummy_ep *ep = NULL;
int type;
int status = -EINPROGRESS; int status = -EINPROGRESS;
/* stop when we reach URBs queued after the timer interrupt */ /* stop when we reach URBs queued after the timer interrupt */
...@@ -1825,14 +1838,10 @@ static void dummy_timer(unsigned long _dum_hcd) ...@@ -1825,14 +1838,10 @@ static void dummy_timer(unsigned long _dum_hcd)
goto return_urb; goto return_urb;
else if (dum_hcd->rh_state != DUMMY_RH_RUNNING) else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
continue; continue;
type = usb_pipetype(urb->pipe);
/* used up this frame's non-periodic bandwidth? /* Used up this frame's bandwidth? */
* FIXME there's infinite bandwidth for control and if (total <= 0)
* periodic transfers ... unrealistic. break;
*/
if (total <= 0 && type == PIPE_BULK)
continue;
/* find the gadget's ep for this request (if configured) */ /* find the gadget's ep for this request (if configured) */
address = usb_pipeendpoint (urb->pipe); address = usb_pipeendpoint (urb->pipe);
...@@ -1930,13 +1939,17 @@ static void dummy_timer(unsigned long _dum_hcd) ...@@ -1930,13 +1939,17 @@ static void dummy_timer(unsigned long _dum_hcd)
limit = total; limit = total;
switch (usb_pipetype(urb->pipe)) { switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS: case PIPE_ISOCHRONOUS:
/* FIXME is it urb->interval since the last xfer? /*
* use urb->iso_frame_desc[i]. * We don't support isochronous. But if we did,
* complete whether or not ep has requests queued. * here are some of the issues we'd have to face:
* report random errors, to debug drivers. *
* 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)); limit = max(limit, periodic_bytes(dum, ep));
status = -ENOSYS; status = -EINVAL; /* fail all xfers */
break; break;
case PIPE_INTERRUPT: case PIPE_INTERRUPT:
......
...@@ -127,11 +127,15 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ...@@ -127,11 +127,15 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
mode = 0; mode = 0;
max = get_unaligned_le16(&desc->wMaxPacketSize); max = get_unaligned_le16(&desc->wMaxPacketSize);
switch (max) { switch (max) {
case 64: mode++; case 64:
case 32: mode++; mode++; /* fall through */
case 16: mode++; case 32:
case 8: mode <<= 3; mode++; /* fall through */
break; case 16:
mode++; /* fall through */
case 8:
mode <<= 3;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -1538,7 +1538,7 @@ static int gr_ep_enable(struct usb_ep *_ep, ...@@ -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 * Bits 10-0 set the max payload. 12-11 set the number of
* additional transactions. * additional transactions.
*/ */
max = 0x7ff & usb_endpoint_maxp(desc); max = usb_endpoint_maxp(desc);
nt = usb_endpoint_maxp_mult(desc) - 1; nt = usb_endpoint_maxp_mult(desc) - 1;
buffer_size = GR_BUFFER_SIZE(epctrl); buffer_size = GR_BUFFER_SIZE(epctrl);
if (nt && (mode == 0 || mode == 2)) { if (nt && (mode == 0 || mode == 2)) {
......
/* /*
* Renesas USB3.0 Peripheral driver (USB gadget) * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/sizes.h> #include <linux/sizes.h>
...@@ -334,6 +335,7 @@ struct renesas_usb3 { ...@@ -334,6 +335,7 @@ struct renesas_usb3 {
struct usb_gadget_driver *driver; struct usb_gadget_driver *driver;
struct extcon_dev *extcon; struct extcon_dev *extcon;
struct work_struct extcon_work; struct work_struct extcon_work;
struct phy *phy;
struct renesas_usb3_ep *usb3_ep; struct renesas_usb3_ep *usb3_ep;
int num_usb3_eps; int num_usb3_eps;
...@@ -2239,7 +2241,9 @@ static int renesas_usb3_start(struct usb_gadget *gadget, ...@@ -2239,7 +2241,9 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
/* hook up the driver */ /* hook up the driver */
usb3->driver = 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)); pm_runtime_get_sync(usb3_to_dev(usb3));
renesas_usb3_init_controller(usb3); renesas_usb3_init_controller(usb3);
...@@ -2256,8 +2260,10 @@ static int renesas_usb3_stop(struct usb_gadget *gadget) ...@@ -2256,8 +2260,10 @@ static int renesas_usb3_stop(struct usb_gadget *gadget)
usb3->driver = NULL; usb3->driver = NULL;
renesas_usb3_stop_controller(usb3); renesas_usb3_stop_controller(usb3);
if (usb3->phy)
phy_exit(usb3->phy);
pm_runtime_put(usb3_to_dev(usb3)); pm_runtime_put(usb3_to_dev(usb3));
pm_runtime_disable(usb3_to_dev(usb3));
return 0; return 0;
} }
...@@ -2405,6 +2411,9 @@ static int renesas_usb3_remove(struct platform_device *pdev) ...@@ -2405,6 +2411,9 @@ static int renesas_usb3_remove(struct platform_device *pdev)
renesas_usb3_dma_free_prd(usb3, &pdev->dev); renesas_usb3_dma_free_prd(usb3, &pdev->dev);
__renesas_usb3_ep_free_request(usb3->ep0_req); __renesas_usb3_ep_free_request(usb3->ep0_req);
if (usb3->phy)
phy_put(usb3->phy);
pm_runtime_disable(usb3_to_dev(usb3));
return 0; return 0;
} }
...@@ -2560,20 +2569,15 @@ static int renesas_usb3_probe(struct platform_device *pdev) ...@@ -2560,20 +2569,15 @@ static int renesas_usb3_probe(struct platform_device *pdev)
{ {
struct renesas_usb3 *usb3; struct renesas_usb3 *usb3;
struct resource *res; struct resource *res;
const struct of_device_id *match;
int irq, ret; int irq, ret;
const struct renesas_usb3_priv *priv; const struct renesas_usb3_priv *priv;
const struct soc_device_attribute *attr; 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); attr = soc_device_match(renesas_usb3_quirks_match);
if (attr) if (attr)
priv = attr->data; priv = attr->data;
else else
priv = match->data; priv = of_device_get_match_data(&pdev->dev);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
...@@ -2635,11 +2639,20 @@ static int renesas_usb3_probe(struct platform_device *pdev) ...@@ -2635,11 +2639,20 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto err_dev_create; 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; usb3->workaround_for_vbus = priv->workaround_for_vbus;
renesas_usb3_debugfs_init(usb3, &pdev->dev); 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; return 0;
...@@ -2655,11 +2668,49 @@ static int renesas_usb3_probe(struct platform_device *pdev) ...@@ -2655,11 +2668,49 @@ static int renesas_usb3_probe(struct platform_device *pdev)
return ret; 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 = { static struct platform_driver renesas_usb3_driver = {
.probe = renesas_usb3_probe, .probe = renesas_usb3_probe,
.remove = renesas_usb3_remove, .remove = renesas_usb3_remove,
.driver = { .driver = {
.name = (char *)udc_name, .name = (char *)udc_name,
.pm = &renesas_usb3_pm_ops,
.of_match_table = of_match_ptr(usb3_of_match), .of_match_table = of_match_ptr(usb3_of_match),
}, },
}; };
......
...@@ -46,6 +46,9 @@ struct mtu3_request; ...@@ -46,6 +46,9 @@ struct mtu3_request;
#define MU3D_EP_RXCR1(epnum) (U3D_RX1CSR1 + (((epnum) - 1) * 0x10)) #define MU3D_EP_RXCR1(epnum) (U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
#define MU3D_EP_RXCR2(epnum) (U3D_RX1CSR2 + (((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_RQCSR(epnum) (U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
#define USB_QMU_RQSAR(epnum) (U3D_RXQSAR1 + (((epnum) - 1) * 0x10)) #define USB_QMU_RQSAR(epnum) (U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
#define USB_QMU_RQCPR(epnum) (U3D_RXQCPR1 + (((epnum) - 1) * 0x10)) #define USB_QMU_RQCPR(epnum) (U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
...@@ -91,6 +94,7 @@ enum mtu3_speed { ...@@ -91,6 +94,7 @@ enum mtu3_speed {
MTU3_SPEED_FULL = 1, MTU3_SPEED_FULL = 1,
MTU3_SPEED_HIGH = 3, MTU3_SPEED_HIGH = 3,
MTU3_SPEED_SUPER = 4, MTU3_SPEED_SUPER = 4,
MTU3_SPEED_SUPER_PLUS = 5,
}; };
/** /**
...@@ -111,6 +115,19 @@ enum mtu3_g_ep0_state { ...@@ -111,6 +115,19 @@ enum mtu3_g_ep0_state {
MU3D_EP0_STATE_STALL, 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 * @base: the base address of fifo
* @limit: the bitmap size in bits * @limit: the bitmap size in bits
...@@ -138,23 +155,33 @@ struct mtu3_fifo_info { ...@@ -138,23 +155,33 @@ struct mtu3_fifo_info {
* Checksum value is calculated over the 16 bytes of the GPD by default; * Checksum value is calculated over the 16 bytes of the GPD by default;
* @data_buf_len (RX ONLY): This value indicates the length of * @data_buf_len (RX ONLY): This value indicates the length of
* the assigned data buffer * 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 * @next_gpd: Physical address of the next GPD
* @buffer: Physical address of the data buffer * @buffer: Physical address of the data buffer
* @buf_len: * @buf_len:
* (TX): This value indicates the length of the assigned data buffer * (TX): This value indicates the length of the assigned data buffer
* (RX): The total length of data received * (RX): The total length of data received
* @ext_len: reserved * @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: * @ext_flag:
* bit5 (TX ONLY): Zero Length Packet (ZLP), * bit5 (TX ONLY): Zero Length Packet (ZLP),
*/ */
struct qmu_gpd { struct qmu_gpd {
__u8 flag; __u8 flag;
__u8 chksum; __u8 chksum;
__le16 data_buf_len; union {
__le16 data_buf_len;
__le16 tx_ext_addr;
};
__le32 next_gpd; __le32 next_gpd;
__le32 buffer; __le32 buffer;
__le16 buf_len; __le16 buf_len;
__u8 ext_len; union {
__u8 ext_len;
__u8 rx_ext_addr;
};
__u8 ext_flag; __u8 ext_flag;
} __packed; } __packed;
...@@ -183,7 +210,6 @@ struct mtu3_gpd_ring { ...@@ -183,7 +210,6 @@ struct mtu3_gpd_ring {
* xHCI driver initialization, it's necessary for system bootup * xHCI driver initialization, it's necessary for system bootup
* as device. * as device.
* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not * @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 * @manual_drd_enabled: it's true when supports dual-role device by debugfs
* to switch host/device modes depending on user input. * to switch host/device modes depending on user input.
*/ */
...@@ -194,10 +220,6 @@ struct otg_switch_mtk { ...@@ -194,10 +220,6 @@ struct otg_switch_mtk {
struct notifier_block id_nb; struct notifier_block id_nb;
struct delayed_work extcon_reg_dwork; struct delayed_work extcon_reg_dwork;
bool is_u3_drd; 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; bool manual_drd_enabled;
}; };
...@@ -206,14 +228,17 @@ struct otg_switch_mtk { ...@@ -206,14 +228,17 @@ struct otg_switch_mtk {
* @ippc_base: register base address of IP Power and Clock interface (IPPC) * @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP * @vusb33: usb3.3V shared by device/host IP
* @sys_clk: system clock of mtu3, 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: * @dr_mode: works in which mode:
* host only, device only or dual-role mode * host only, device only or dual-role mode
* @u2_ports: number of usb2.0 host ports * @u2_ports: number of usb2.0 host ports
* @u3_ports: number of usb3.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 * @dbgfs_root: only used when supports manual dual-role switch via debugfs
* @wakeup_en: it's true when supports remote wakeup in host mode * @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 ssusb_mtk {
struct device *dev; struct device *dev;
...@@ -226,17 +251,18 @@ struct ssusb_mtk { ...@@ -226,17 +251,18 @@ struct ssusb_mtk {
struct regulator *vusb33; struct regulator *vusb33;
struct clk *sys_clk; struct clk *sys_clk;
struct clk *ref_clk; struct clk *ref_clk;
struct clk *mcu_clk;
struct clk *dma_clk;
/* otg */ /* otg */
struct otg_switch_mtk otg_switch; struct otg_switch_mtk otg_switch;
enum usb_dr_mode dr_mode; enum usb_dr_mode dr_mode;
bool is_host; bool is_host;
int u2_ports; int u2_ports;
int u3_ports; int u3_ports;
int u3p_dis_msk;
struct dentry *dbgfs_root; struct dentry *dbgfs_root;
/* usb wakeup for host mode */ /* usb wakeup for host mode */
bool wakeup_en; bool wakeup_en;
struct clk *wk_deb_p0;
struct clk *wk_deb_p1;
struct regmap *pericfg; struct regmap *pericfg;
}; };
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* *
*/ */
#include <linux/dma-mapping.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -114,7 +115,9 @@ static int mtu3_device_enable(struct mtu3 *mtu) ...@@ -114,7 +115,9 @@ static int mtu3_device_enable(struct mtu3 *mtu)
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
(SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN | (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
SSUSB_U2_PORT_HOST_SEL)); 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); return ssusb_check_clocks(mtu->ssusb, check_clk);
} }
...@@ -129,7 +132,10 @@ static void mtu3_device_disable(struct mtu3 *mtu) ...@@ -129,7 +132,10 @@ static void mtu3_device_disable(struct mtu3 *mtu)
mtu3_setbits(ibase, SSUSB_U2_CTRL(0), mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN); 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); 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) ...@@ -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) 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); mtu3_ss_func_set(mtu, is_on);
else else
mtu3_hs_softconn_set(mtu, is_on); mtu3_hs_softconn_set(mtu, is_on);
...@@ -546,6 +552,9 @@ static void mtu3_set_speed(struct mtu3 *mtu) ...@@ -546,6 +552,9 @@ static void mtu3_set_speed(struct mtu3 *mtu)
mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN); mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
/* HS/FS detected by HW */ /* HS/FS detected by HW */
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); 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", dev_info(mtu->dev, "max_speed: %s\n",
...@@ -623,6 +632,10 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu) ...@@ -623,6 +632,10 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
udev_speed = USB_SPEED_SUPER; udev_speed = USB_SPEED_SUPER;
maxpkt = 512; maxpkt = 512;
break; break;
case MTU3_SPEED_SUPER_PLUS:
udev_speed = USB_SPEED_SUPER_PLUS;
maxpkt = 512;
break;
default: default:
udev_speed = USB_SPEED_UNKNOWN; udev_speed = USB_SPEED_UNKNOWN;
break; break;
...@@ -759,7 +772,31 @@ static void mtu3_hw_exit(struct mtu3 *mtu) ...@@ -759,7 +772,31 @@ static void mtu3_hw_exit(struct mtu3 *mtu)
mtu3_mem_free(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) int ssusb_gadget_init(struct ssusb_mtk *ssusb)
{ {
...@@ -774,9 +811,9 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) ...@@ -774,9 +811,9 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
return -ENOMEM; return -ENOMEM;
mtu->irq = platform_get_irq(pdev, 0); mtu->irq = platform_get_irq(pdev, 0);
if (mtu->irq <= 0) { if (mtu->irq < 0) {
dev_err(dev, "fail to get irq number\n"); dev_err(dev, "fail to get irq number\n");
return -ENODEV; return mtu->irq;
} }
dev_info(dev, "irq %d\n", mtu->irq); dev_info(dev, "irq %d\n", mtu->irq);
...@@ -800,14 +837,15 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) ...@@ -800,14 +837,15 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
case USB_SPEED_FULL: case USB_SPEED_FULL:
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
case USB_SPEED_SUPER: case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
break; break;
default: default:
dev_err(dev, "invalid max_speed: %s\n", dev_err(dev, "invalid max_speed: %s\n",
usb_speed_string(mtu->max_speed)); usb_speed_string(mtu->max_speed));
/* fall through */ /* fall through */
case USB_SPEED_UNKNOWN: case USB_SPEED_UNKNOWN:
/* default as SS */ /* default as SSP */
mtu->max_speed = USB_SPEED_SUPER; mtu->max_speed = USB_SPEED_SUPER_PLUS;
break; break;
} }
...@@ -820,6 +858,12 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) ...@@ -820,6 +858,12 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
return ret; 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); ret = devm_request_irq(dev, mtu->irq, mtu3_irq, 0, dev_name(dev), mtu);
if (ret) { if (ret) {
dev_err(dev, "request irq %d failed!\n", mtu->irq); dev_err(dev, "request irq %d failed!\n", mtu->irq);
...@@ -845,6 +889,7 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) ...@@ -845,6 +889,7 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
gadget_err: gadget_err:
device_init_wakeup(dev, false); device_init_wakeup(dev, false);
dma_mask_err:
irq_err: irq_err:
mtu3_hw_exit(mtu); mtu3_hw_exit(mtu);
ssusb->u3d = NULL; ssusb->u3d = NULL;
......
...@@ -261,21 +261,22 @@ static void extcon_register_dwork(struct work_struct *work) ...@@ -261,21 +261,22 @@ static void extcon_register_dwork(struct work_struct *work)
* depending on user input. * depending on user input.
* This is useful in special cases, such as uses TYPE-A receptacle but also * This is useful in special cases, such as uses TYPE-A receptacle but also
* wants to support dual-role mode. * 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) static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
{ {
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
if (to_host) if (to_host) {
pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground); ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
else ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float); 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) static int ssusb_mode_show(struct seq_file *sf, void *unused)
{ {
struct ssusb_mtk *ssusb = sf->private; struct ssusb_mtk *ssusb = sf->private;
...@@ -388,17 +389,45 @@ static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb) ...@@ -388,17 +389,45 @@ static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
debugfs_remove_recursive(ssusb->dbgfs_root); 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) int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{ {
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 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); ssusb_debugfs_init(ssusb);
} else {
/* It is enough to delay 1s for waiting for host initialization */ INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork,
schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ); extcon_register_dwork);
/*
* It is enough to delay 1s for waiting for
* host initialization
*/
schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
}
return 0; return 0;
} }
...@@ -407,8 +436,8 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb) ...@@ -407,8 +436,8 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{ {
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
cancel_delayed_work(&otg_sx->extcon_reg_dwork);
if (otg_sx->manual_drd_enabled) if (otg_sx->manual_drd_enabled)
ssusb_debugfs_exit(ssusb); 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) ...@@ -87,6 +87,8 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb); int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
void ssusb_otg_switch_exit(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); 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 #else
...@@ -103,6 +105,10 @@ static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on) ...@@ -103,6 +105,10 @@ static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
return 0; return 0;
} }
static inline void
ssusb_set_force_mode(struct ssusb_mtk *ssusb, enum mtu3_dr_force_mode mode)
{}
#endif #endif
#endif /* _MTU3_DR_H_ */ #endif /* _MTU3_DR_H_ */
...@@ -89,6 +89,7 @@ static int mtu3_ep_enable(struct mtu3_ep *mep) ...@@ -89,6 +89,7 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
switch (mtu->g.speed) { switch (mtu->g.speed) {
case USB_SPEED_SUPER: case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
if (usb_endpoint_xfer_int(desc) || if (usb_endpoint_xfer_int(desc) ||
usb_endpoint_xfer_isoc(desc)) { usb_endpoint_xfer_isoc(desc)) {
interval = desc->bInterval; interval = desc->bInterval;
...@@ -456,7 +457,7 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget) ...@@ -456,7 +457,7 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
return -EOPNOTSUPP; return -EOPNOTSUPP;
spin_lock_irqsave(&mtu->lock, flags); 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); mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
} else { } else {
mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME); mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
......
...@@ -212,8 +212,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) ...@@ -212,8 +212,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
case USB_RECIP_DEVICE: case USB_RECIP_DEVICE:
result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED; result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; 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->u1_enable << USB_DEV_STAT_U1_ENABLED;
result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED; result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
} }
...@@ -329,8 +329,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu, ...@@ -329,8 +329,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
handled = handle_test_mode(mtu, setup); handled = handle_test_mode(mtu, setup);
break; break;
case USB_DEVICE_U1_ENABLE: case USB_DEVICE_U1_ENABLE:
if (mtu->g.speed != USB_SPEED_SUPER || if (mtu->g.speed < USB_SPEED_SUPER ||
mtu->g.state != USB_STATE_CONFIGURED) mtu->g.state != USB_STATE_CONFIGURED)
break; break;
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
...@@ -344,8 +344,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu, ...@@ -344,8 +344,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
handled = 1; handled = 1;
break; break;
case USB_DEVICE_U2_ENABLE: case USB_DEVICE_U2_ENABLE:
if (mtu->g.speed != USB_SPEED_SUPER || if (mtu->g.speed < USB_SPEED_SUPER ||
mtu->g.state != USB_STATE_CONFIGURED) mtu->g.state != USB_STATE_CONFIGURED)
break; break;
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL); lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
...@@ -384,8 +384,8 @@ static int ep0_handle_feature(struct mtu3 *mtu, ...@@ -384,8 +384,8 @@ static int ep0_handle_feature(struct mtu3 *mtu,
break; break;
case USB_RECIP_INTERFACE: case USB_RECIP_INTERFACE:
/* superspeed only */ /* superspeed only */
if ((value == USB_INTRF_FUNC_SUSPEND) if (value == USB_INTRF_FUNC_SUSPEND &&
&& (mtu->g.speed == USB_SPEED_SUPER)) { mtu->g.speed >= USB_SPEED_SUPER) {
/* /*
* forward the request because function drivers * forward the request because function drivers
* should handle it * should handle it
......
...@@ -79,20 +79,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb, ...@@ -79,20 +79,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
if (!ssusb->wakeup_en) if (!ssusb->wakeup_en)
return 0; 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, ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
"mediatek,syscon-wakeup"); "mediatek,syscon-wakeup");
if (IS_ERR(ssusb->pericfg)) { if (IS_ERR(ssusb->pericfg)) {
...@@ -103,36 +89,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb, ...@@ -103,36 +89,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
return 0; 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) static void host_ports_num_get(struct ssusb_mtk *ssusb)
{ {
u32 xhci_cap; u32 xhci_cap;
...@@ -151,6 +107,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb) ...@@ -151,6 +107,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
void __iomem *ibase = ssusb->ippc_base; void __iomem *ibase = ssusb->ippc_base;
int num_u3p = ssusb->u3_ports; int num_u3p = ssusb->u3_ports;
int num_u2p = ssusb->u2_ports; int num_u2p = ssusb->u2_ports;
int u3_ports_disabed;
u32 check_clk; u32 check_clk;
u32 value; u32 value;
int i; int i;
...@@ -158,8 +115,14 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb) ...@@ -158,8 +115,14 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
/* power on host ip */ /* power on host ip */
mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN); 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++) { 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 = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS); value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
value |= SSUSB_U3_PORT_HOST_SEL; value |= SSUSB_U3_PORT_HOST_SEL;
...@@ -175,7 +138,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb) ...@@ -175,7 +138,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
} }
check_clk = SSUSB_XHCI_RST_B_STS; check_clk = SSUSB_XHCI_RST_B_STS;
if (num_u3p) if (num_u3p > u3_ports_disabed)
check_clk = SSUSB_U3_MAC_RST_B_STS; check_clk = SSUSB_U3_MAC_RST_B_STS;
return ssusb_check_clocks(ssusb, check_clk); return ssusb_check_clocks(ssusb, check_clk);
...@@ -190,8 +153,11 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend) ...@@ -190,8 +153,11 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
int ret; int ret;
int i; 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++) { for (i = 0; i < num_u3p; i++) {
if ((0x1 << i) & ssusb->u3p_dis_msk)
continue;
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i)); value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value |= SSUSB_U3_PORT_PDN; value |= SSUSB_U3_PORT_PDN;
value |= suspend ? 0 : SSUSB_U3_PORT_DIS; value |= suspend ? 0 : SSUSB_U3_PORT_DIS;
...@@ -223,6 +189,8 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend) ...@@ -223,6 +189,8 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
static void ssusb_host_setup(struct ssusb_mtk *ssusb) static void ssusb_host_setup(struct ssusb_mtk *ssusb)
{ {
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
host_ports_num_get(ssusb); host_ports_num_get(ssusb);
/* /*
...@@ -231,6 +199,9 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb) ...@@ -231,6 +199,9 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
*/ */
ssusb_host_enable(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 */ /* if port0 supports dual-role, works as host mode by default */
ssusb_set_vbus(&ssusb->otg_switch, 1); ssusb_set_vbus(&ssusb->otg_switch, 1);
} }
...@@ -276,19 +247,14 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb) ...@@ -276,19 +247,14 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb)
int ssusb_wakeup_enable(struct ssusb_mtk *ssusb) int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
{ {
int ret = 0; if (ssusb->wakeup_en)
if (ssusb->wakeup_en) {
ret = ssusb_wakeup_clks_enable(ssusb);
ssusb_wakeup_ip_sleep_en(ssusb); ssusb_wakeup_ip_sleep_en(ssusb);
}
return ret; return 0;
} }
void ssusb_wakeup_disable(struct ssusb_mtk *ssusb) void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
{ {
if (ssusb->wakeup_en) { if (ssusb->wakeup_en)
ssusb_wakeup_ip_sleep_dis(ssusb); ssusb_wakeup_ip_sleep_dis(ssusb);
ssusb_wakeup_clks_disable(ssusb);
}
} }
...@@ -58,6 +58,8 @@ ...@@ -58,6 +58,8 @@
#define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404) #define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404)
#define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408) #define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408)
#define U3D_QCR3 (SSUSB_DEV_BASE + 0x040C) #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_TXQCSR1 (SSUSB_DEV_BASE + 0x0510)
#define U3D_TXQSAR1 (SSUSB_DEV_BASE + 0x0514) #define U3D_TXQSAR1 (SSUSB_DEV_BASE + 0x0514)
...@@ -189,6 +191,13 @@ ...@@ -189,6 +191,13 @@
#define QMU_RX_COZ(x) (BIT(16) << (x)) #define QMU_RX_COZ(x) (BIT(16) << (x))
#define QMU_RX_ZLP(x) (BIT(0) << (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_TXQCSR1 */
/* U3D_RXQCSR1 */ /* U3D_RXQCSR1 */
#define QMU_Q_ACTIVE BIT(15) #define QMU_Q_ACTIVE BIT(15)
...@@ -225,6 +234,7 @@ ...@@ -225,6 +234,7 @@
#define CAP_TX_EP_NUM(x) ((x) & 0x1f) #define CAP_TX_EP_NUM(x) ((x) & 0x1f)
/* U3D_MISC_CTRL */ /* U3D_MISC_CTRL */
#define DMA_ADDR_36BIT BIT(31)
#define VBUS_ON BIT(1) #define VBUS_ON BIT(1)
#define VBUS_FRC_EN BIT(0) #define VBUS_FRC_EN BIT(0)
...@@ -457,11 +467,14 @@ ...@@ -457,11 +467,14 @@
#define SSUSB_VBUS_CHG_INT_B_EN BIT(6) #define SSUSB_VBUS_CHG_INT_B_EN BIT(6)
/* U3D_SSUSB_U3_CTRL_0P */ /* 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_HOST_SEL BIT(2)
#define SSUSB_U3_PORT_PDN BIT(1) #define SSUSB_U3_PORT_PDN BIT(1)
#define SSUSB_U3_PORT_DIS BIT(0) #define SSUSB_U3_PORT_DIS BIT(0)
/* U3D_SSUSB_U2_CTRL_0P */ /* 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_VBUSVALID BIT(9)
#define SSUSB_U2_PORT_OTG_SEL BIT(7) #define SSUSB_U2_PORT_OTG_SEL BIT(7)
#define SSUSB_U2_PORT_HOST BIT(2) #define SSUSB_U2_PORT_HOST BIT(2)
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include "mtu3.h" #include "mtu3.h"
...@@ -110,15 +109,9 @@ static void ssusb_phy_power_off(struct ssusb_mtk *ssusb) ...@@ -110,15 +109,9 @@ static void ssusb_phy_power_off(struct ssusb_mtk *ssusb)
phy_power_off(ssusb->phys[i]); 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; int ret;
ret = regulator_enable(ssusb->vusb33);
if (ret) {
dev_err(ssusb->dev, "failed to enable vusb33\n");
goto vusb33_err;
}
ret = clk_prepare_enable(ssusb->sys_clk); ret = clk_prepare_enable(ssusb->sys_clk);
if (ret) { if (ret) {
...@@ -132,6 +125,52 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb) ...@@ -132,6 +125,52 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
goto ref_clk_err; 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); ret = ssusb_phy_init(ssusb);
if (ret) { if (ret) {
dev_err(ssusb->dev, "failed to init phy\n"); dev_err(ssusb->dev, "failed to init phy\n");
...@@ -149,20 +188,16 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb) ...@@ -149,20 +188,16 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
phy_err: phy_err:
ssusb_phy_exit(ssusb); ssusb_phy_exit(ssusb);
phy_init_err: phy_init_err:
clk_disable_unprepare(ssusb->ref_clk); ssusb_clks_disable(ssusb);
ref_clk_err: clks_err:
clk_disable_unprepare(ssusb->sys_clk);
sys_clk_err:
regulator_disable(ssusb->vusb33); regulator_disable(ssusb->vusb33);
vusb33_err: vusb33_err:
return ret; return ret;
} }
static void ssusb_rscs_exit(struct ssusb_mtk *ssusb) static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
{ {
clk_disable_unprepare(ssusb->sys_clk); ssusb_clks_disable(ssusb);
clk_disable_unprepare(ssusb->ref_clk);
regulator_disable(ssusb->vusb33); regulator_disable(ssusb->vusb33);
ssusb_phy_power_off(ssusb); ssusb_phy_power_off(ssusb);
ssusb_phy_exit(ssusb); ssusb_phy_exit(ssusb);
...@@ -176,31 +211,17 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *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); 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); opt_clk = devm_clk_get(dev, id);
if (IS_ERR(otg_sx->id_pinctrl)) { /* ignore error number except EPROBE_DEFER */
dev_err(ssusb->dev, "Cannot find id pinctrl!\n"); if (IS_ERR(opt_clk) && (PTR_ERR(opt_clk) != -EPROBE_DEFER))
return PTR_ERR(otg_sx->id_pinctrl); opt_clk = NULL;
}
otg_sx->id_float = return opt_clk;
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;
} }
static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) 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) ...@@ -225,18 +246,17 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
return PTR_ERR(ssusb->sys_clk); return PTR_ERR(ssusb->sys_clk);
} }
/* ssusb->ref_clk = get_optional_clk(dev, "ref_ck");
* reference clock is usually a "fixed-clock", make it optional if (IS_ERR(ssusb->ref_clk))
* for backward compatibility and ignore the error if it does return PTR_ERR(ssusb->ref_clk);
* 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 = 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, ssusb->num_phys = of_count_phandle_with_args(node,
"phys", "#phy-cells"); "phys", "#phy-cells");
...@@ -263,10 +283,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) ...@@ -263,10 +283,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
return PTR_ERR(ssusb->ippc_base); return PTR_ERR(ssusb->ippc_base);
ssusb->dr_mode = usb_get_dr_mode(dev); ssusb->dr_mode = usb_get_dr_mode(dev);
if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) { if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN)
dev_err(dev, "dr_mode is error\n"); ssusb->dr_mode = USB_DR_MODE_OTG;
return -EINVAL;
}
if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL) if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
return 0; return 0;
...@@ -276,10 +294,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) ...@@ -276,10 +294,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
if (ret) if (ret)
return ret; return ret;
if (ssusb->dr_mode != USB_DR_MODE_OTG) /* optional property, ignore the error if it does not exist */
return 0; 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"); vbus = devm_regulator_get(&pdev->dev, "vbus");
if (IS_ERR(vbus)) { if (IS_ERR(vbus)) {
dev_err(dev, "failed to get vbus\n"); 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) ...@@ -287,6 +305,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
} }
otg_sx->vbus = vbus; 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->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
otg_sx->manual_drd_enabled = otg_sx->manual_drd_enabled =
of_property_read_bool(node, "enable-manual-drd"); 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) ...@@ -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"); dev_err(ssusb->dev, "couldn't get extcon device\n");
return -EPROBE_DEFER; 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", 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->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk,
otg_sx->manual_drd_enabled ? "manual" : "auto");
return 0; return 0;
} }
...@@ -447,8 +465,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev) ...@@ -447,8 +465,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
ssusb_host_disable(ssusb, true); ssusb_host_disable(ssusb, true);
ssusb_phy_power_off(ssusb); ssusb_phy_power_off(ssusb);
clk_disable_unprepare(ssusb->sys_clk); ssusb_clks_disable(ssusb);
clk_disable_unprepare(ssusb->ref_clk);
ssusb_wakeup_enable(ssusb); ssusb_wakeup_enable(ssusb);
return 0; return 0;
...@@ -466,27 +483,21 @@ static int __maybe_unused mtu3_resume(struct device *dev) ...@@ -466,27 +483,21 @@ static int __maybe_unused mtu3_resume(struct device *dev)
return 0; return 0;
ssusb_wakeup_disable(ssusb); 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) if (ret)
goto err_ref_clk; goto clks_err;
ret = ssusb_phy_power_on(ssusb); ret = ssusb_phy_power_on(ssusb);
if (ret) if (ret)
goto err_power_on; goto phy_err;
ssusb_host_enable(ssusb); ssusb_host_enable(ssusb);
return 0; return 0;
err_power_on: phy_err:
clk_disable_unprepare(ssusb->ref_clk); ssusb_clks_disable(ssusb);
err_ref_clk: clks_err:
clk_disable_unprepare(ssusb->sys_clk);
err_sys_clk:
return ret; return ret;
} }
......
...@@ -40,7 +40,58 @@ ...@@ -40,7 +40,58 @@
#define GPD_FLAGS_IOC BIT(7) #define GPD_FLAGS_IOC BIT(7)
#define GPD_EXT_FLAG_ZLP BIT(5) #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, static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
dma_addr_t dma_addr) dma_addr_t dma_addr)
...@@ -193,21 +244,27 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq) ...@@ -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 mtu3_gpd_ring *ring = &mep->gpd_ring;
struct qmu_gpd *gpd = ring->enqueue; struct qmu_gpd *gpd = ring->enqueue;
struct usb_request *req = &mreq->request; struct usb_request *req = &mreq->request;
dma_addr_t enq_dma;
u16 ext_addr;
/* set all fields to zero as default value */ /* set all fields to zero as default value */
memset(gpd, 0, sizeof(*gpd)); 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->buf_len = cpu_to_le16(req->length);
gpd->flag |= GPD_FLAGS_IOC; gpd->flag |= GPD_FLAGS_IOC;
/* get the next GPD */ /* get the next GPD */
enq = advance_enq_gpd(ring); enq = advance_enq_gpd(ring);
dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p\n", enq_dma = gpd_virt_to_dma(ring, enq);
mep->epnum, gpd, 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; 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) if (req->zero)
gpd->ext_flag |= GPD_EXT_FLAG_ZLP; 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) ...@@ -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 mtu3_gpd_ring *ring = &mep->gpd_ring;
struct qmu_gpd *gpd = ring->enqueue; struct qmu_gpd *gpd = ring->enqueue;
struct usb_request *req = &mreq->request; struct usb_request *req = &mreq->request;
dma_addr_t enq_dma;
u16 ext_addr;
/* set all fields to zero as default value */ /* set all fields to zero as default value */
memset(gpd, 0, sizeof(*gpd)); 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->data_buf_len = cpu_to_le16(req->length);
gpd->flag |= GPD_FLAGS_IOC; gpd->flag |= GPD_FLAGS_IOC;
/* get the next GPD */ /* get the next GPD */
enq = advance_enq_gpd(ring); enq = advance_enq_gpd(ring);
dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p\n", enq_dma = gpd_virt_to_dma(ring, enq);
mep->epnum, gpd, 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; 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->chksum = qmu_calc_checksum((u8 *)gpd);
gpd->flag |= GPD_FLAGS_HWO; gpd->flag |= GPD_FLAGS_HWO;
...@@ -267,8 +330,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep) ...@@ -267,8 +330,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep)
if (mep->is_in) { if (mep->is_in) {
/* set QMU start address */ /* set QMU start address */
mtu3_writel(mbase, USB_QMU_TQSAR(mep->epnum), ring->dma); write_txq_start_addr(mbase, epnum, ring->dma);
mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN); mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_DMAREQEN);
mtu3_setbits(mbase, U3D_QCR0, QMU_TX_CS_EN(epnum)); mtu3_setbits(mbase, U3D_QCR0, QMU_TX_CS_EN(epnum));
/* send zero length packet according to ZLP flag in GPD */ /* send zero length packet according to ZLP flag in GPD */
mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum)); mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum));
...@@ -282,8 +345,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep) ...@@ -282,8 +345,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep)
mtu3_writel(mbase, USB_QMU_TQCSR(epnum), QMU_Q_START); mtu3_writel(mbase, USB_QMU_TQCSR(epnum), QMU_Q_START);
} else { } else {
mtu3_writel(mbase, USB_QMU_RQSAR(mep->epnum), ring->dma); write_rxq_start_addr(mbase, epnum, ring->dma);
mtu3_setbits(mbase, MU3D_EP_RXCR0(mep->epnum), RX_DMAREQEN); mtu3_setbits(mbase, MU3D_EP_RXCR0(epnum), RX_DMAREQEN);
mtu3_setbits(mbase, U3D_QCR0, QMU_RX_CS_EN(epnum)); mtu3_setbits(mbase, U3D_QCR0, QMU_RX_CS_EN(epnum));
/* don't expect ZLP */ /* don't expect ZLP */
mtu3_clrbits(mbase, U3D_QCR3, QMU_RX_ZLP(epnum)); 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) ...@@ -353,9 +416,9 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
struct mtu3_gpd_ring *ring = &mep->gpd_ring; struct mtu3_gpd_ring *ring = &mep->gpd_ring;
void __iomem *mbase = mtu->mac_base; void __iomem *mbase = mtu->mac_base;
struct qmu_gpd *gpd_current = NULL; struct qmu_gpd *gpd_current = NULL;
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
struct usb_request *req = NULL; struct usb_request *req = NULL;
struct mtu3_request *mreq; struct mtu3_request *mreq;
dma_addr_t cur_gpd_dma;
u32 txcsr = 0; u32 txcsr = 0;
int ret; int ret;
...@@ -365,7 +428,8 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum) ...@@ -365,7 +428,8 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
else else
return; 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) { if (le16_to_cpu(gpd_current->buf_len) != 0) {
dev_err(mtu->dev, "TX EP%d buffer length error(!=0)\n", epnum); 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) ...@@ -408,12 +472,13 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
void __iomem *mbase = mtu->mac_base; void __iomem *mbase = mtu->mac_base;
struct qmu_gpd *gpd = ring->dequeue; struct qmu_gpd *gpd = ring->dequeue;
struct qmu_gpd *gpd_current = NULL; struct qmu_gpd *gpd_current = NULL;
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
struct usb_request *request = NULL; struct usb_request *request = NULL;
struct mtu3_request *mreq; struct mtu3_request *mreq;
dma_addr_t cur_gpd_dma;
/*transfer phy address got from QMU register to virtual address */ /*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", dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue); __func__, epnum, gpd, gpd_current, ring->enqueue);
...@@ -446,11 +511,12 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum) ...@@ -446,11 +511,12 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
void __iomem *mbase = mtu->mac_base; void __iomem *mbase = mtu->mac_base;
struct qmu_gpd *gpd = ring->dequeue; struct qmu_gpd *gpd = ring->dequeue;
struct qmu_gpd *gpd_current = NULL; struct qmu_gpd *gpd_current = NULL;
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
struct usb_request *req = NULL; struct usb_request *req = NULL;
struct mtu3_request *mreq; 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", dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue); __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, ...@@ -224,7 +224,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
int err = 0; int err = 0;
u32 clk_rate = 0; u32 clk_rate = 0;
bool needs_vcc = false; bool needs_vcc = false, needs_clk = false;
if (dev->of_node) { if (dev->of_node) {
struct device_node *node = 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, ...@@ -233,6 +233,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
clk_rate = 0; clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply"); 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", nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_ASIS); GPIOD_ASIS);
err = PTR_ERR_OR_ZERO(nop->gpiod_reset); 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, ...@@ -275,6 +276,8 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
if (IS_ERR(nop->clk)) { if (IS_ERR(nop->clk)) {
dev_dbg(dev, "Can't get phy clock: %ld\n", dev_dbg(dev, "Can't get phy clock: %ld\n",
PTR_ERR(nop->clk)); PTR_ERR(nop->clk));
if (needs_clk)
return PTR_ERR(nop->clk);
} }
if (!IS_ERR(nop->clk) && clk_rate) { if (!IS_ERR(nop->clk) && clk_rate) {
......
...@@ -1261,6 +1261,7 @@ static void msm_chg_detect_work(struct work_struct *w) ...@@ -1261,6 +1261,7 @@ static void msm_chg_detect_work(struct work_struct *w)
/* fall through */ /* fall through */
case USB_CHG_STATE_SECONDARY_DONE: case USB_CHG_STATE_SECONDARY_DONE:
motg->chg_state = USB_CHG_STATE_DETECTED; motg->chg_state = USB_CHG_STATE_DETECTED;
/* fall through */
case USB_CHG_STATE_DETECTED: case USB_CHG_STATE_DETECTED:
msm_chg_block_off(motg); msm_chg_block_off(motg);
dev_dbg(phy->dev, "charger = %d\n", motg->chg_type); dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
......
...@@ -67,11 +67,26 @@ ...@@ -67,11 +67,26 @@
#define ANADIG_ANA_MISC0_SET 0x154 #define ANADIG_ANA_MISC0_SET 0x154
#define ANADIG_ANA_MISC0_CLR 0x158 #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 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_USB2_VBUS_DET_STAT 0x220
#define ANADIG_USB1_LOOPBACK_SET 0x1e4 #define ANADIG_USB1_LOOPBACK_SET 0x1e4
#define ANADIG_USB1_LOOPBACK_CLR 0x1e8 #define ANADIG_USB1_LOOPBACK_CLR 0x1e8
#define ANADIG_USB1_LOOPBACK_UTMI_TESTSTART BIT(0)
#define ANADIG_USB2_LOOPBACK_SET 0x244 #define ANADIG_USB2_LOOPBACK_SET 0x244
#define ANADIG_USB2_LOOPBACK_CLR 0x248 #define ANADIG_USB2_LOOPBACK_CLR 0x248
...@@ -479,6 +494,144 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy, ...@@ -479,6 +494,144 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
return 0; 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) static int mxs_phy_probe(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
...@@ -567,6 +720,7 @@ static int mxs_phy_probe(struct platform_device *pdev) ...@@ -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.notify_disconnect = mxs_phy_on_disconnect;
mxs_phy->phy.type = USB_PHY_TYPE_USB2; mxs_phy->phy.type = USB_PHY_TYPE_USB2;
mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup; mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup;
mxs_phy->phy.charger_detect = mxs_phy_charger_detect;
mxs_phy->clk = clk; mxs_phy->clk = clk;
mxs_phy->data = of_id->data; mxs_phy->data = of_id->data;
......
...@@ -368,7 +368,8 @@ static int tahvo_usb_probe(struct platform_device *pdev) ...@@ -368,7 +368,8 @@ static int tahvo_usb_probe(struct platform_device *pdev)
tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable); tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable);
if (IS_ERR(tu->extcon)) { if (IS_ERR(tu->extcon)) {
dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); 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); ret = devm_extcon_dev_register(&pdev->dev, tu->extcon);
......
...@@ -485,6 +485,10 @@ static const struct of_device_id usbhs_of_match[] = { ...@@ -485,6 +485,10 @@ static const struct of_device_id usbhs_of_match[] = {
.compatible = "renesas,usbhs-r8a7796", .compatible = "renesas,usbhs-r8a7796",
.data = (void *)USBHS_TYPE_RCAR_GEN3, .data = (void *)USBHS_TYPE_RCAR_GEN3,
}, },
{
.compatible = "renesas,usbhs-r8a77995",
.data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
},
{ {
.compatible = "renesas,rcar-gen2-usbhs", .compatible = "renesas,rcar-gen2-usbhs",
.data = (void *)USBHS_TYPE_RCAR_GEN2, .data = (void *)USBHS_TYPE_RCAR_GEN2,
...@@ -501,7 +505,6 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev) ...@@ -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_platform_info *info;
struct renesas_usbhs_driver_param *dparam; struct renesas_usbhs_driver_param *dparam;
const struct of_device_id *of_id = of_match_device(usbhs_of_match, dev);
u32 tmp; u32 tmp;
int gpio; int gpio;
...@@ -510,7 +513,7 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev) ...@@ -510,7 +513,7 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
return NULL; return NULL;
dparam = &info->driver_param; 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)) if (!of_property_read_u32(dev->of_node, "renesas,buswait", &tmp))
dparam->buswait_bwait = tmp; dparam->buswait_bwait = tmp;
gpio = of_get_named_gpio_flags(dev->of_node, "renesas,enable-gpio", 0, 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) ...@@ -519,8 +522,12 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
dparam->enable_gpio = gpio; dparam->enable_gpio = gpio;
if (dparam->type == USBHS_TYPE_RCAR_GEN2 || 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->has_usb_dmac = 1;
dparam->pipe_configs = usbhsc_new_pipe;
dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
return info; return info;
} }
...@@ -577,17 +584,12 @@ static int usbhs_probe(struct platform_device *pdev) ...@@ -577,17 +584,12 @@ static int usbhs_probe(struct platform_device *pdev)
switch (priv->dparam.type) { switch (priv->dparam.type) {
case USBHS_TYPE_RCAR_GEN2: case USBHS_TYPE_RCAR_GEN2:
priv->pfunc = usbhs_rcar2_ops; 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; break;
case USBHS_TYPE_RCAR_GEN3: case USBHS_TYPE_RCAR_GEN3:
priv->pfunc = usbhs_rcar3_ops; priv->pfunc = usbhs_rcar3_ops;
if (!priv->dparam.pipe_configs) { break;
priv->dparam.pipe_configs = usbhsc_new_pipe; case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe); priv->pfunc = usbhs_rcar3_with_pll_ops;
}
break; break;
default: default:
if (!info->platform_callback.get_id) { if (!info->platform_callback.get_id) {
......
...@@ -15,24 +15,39 @@ ...@@ -15,24 +15,39 @@
#include "rcar3.h" #include "rcar3.h"
#define LPSTS 0x102 #define LPSTS 0x102
#define UGCTRL 0x180 /* 32-bit register */
#define UGCTRL2 0x184 /* 32-bit register */ #define UGCTRL2 0x184 /* 32-bit register */
#define UGSTS 0x188 /* 32-bit register */
/* Low Power Status register (LPSTS) */ /* Low Power Status register (LPSTS) */
#define LPSTS_SUSPM 0x4000 #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) * USB General control register 2 (UGCTRL2)
* Remarks: bit[31:11] and bit[9:6] should be 0 * 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_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
#define UGCTRL2_USB0SEL_HSUSB 0x00000020
#define UGCTRL2_USB0SEL_OTG 0x00000030 #define UGCTRL2_USB0SEL_OTG 0x00000030
#define UGCTRL2_VBUSSEL 0x00000400 #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) static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
{ {
iowrite32(data, priv->base + reg); 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, static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable) void __iomem *base, int enable)
{ {
...@@ -52,6 +67,34 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, ...@@ -52,6 +67,34 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
return 0; 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) static int usbhs_rcar3_get_id(struct platform_device *pdev)
{ {
return USBHS_GADGET; return USBHS_GADGET;
...@@ -61,3 +104,8 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = { ...@@ -61,3 +104,8 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
.power_ctrl = usbhs_rcar3_power_ctrl, .power_ctrl = usbhs_rcar3_power_ctrl,
.get_id = usbhs_rcar3_get_id, .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,
};
#include "common.h" #include "common.h"
extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops; 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 { ...@@ -188,6 +188,8 @@ struct usb_ep_caps {
* @ops: Function pointers used to access hardware-specific operations. * @ops: Function pointers used to access hardware-specific operations.
* @ep_list:the gadget's ep_list holds all of its endpoints * @ep_list:the gadget's ep_list holds all of its endpoints
* @caps:The structure describing types and directions supported by endoint. * @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 * @maxpacket:The maximum packet size used on this endpoint. The initial
* value can sometimes be reduced (hardware allowing), according to * value can sometimes be reduced (hardware allowing), according to
* the endpoint descriptor used to configure the endpoint. * the endpoint descriptor used to configure the endpoint.
...@@ -349,6 +351,9 @@ struct usb_gadget_ops { ...@@ -349,6 +351,9 @@ struct usb_gadget_ops {
* or B-Peripheral wants to take host role. * or B-Peripheral wants to take host role.
* @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
* MaxPacketSize. * 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 * @quirk_avoids_skb_reserve: udc/platform wants to avoid skb_reserve() in
* u_ether.c to improve performance. * u_ether.c to improve performance.
* @is_selfpowered: if the gadget is self-powered. * @is_selfpowered: if the gadget is self-powered.
......
...@@ -183,8 +183,9 @@ struct renesas_usbhs_driver_param { ...@@ -183,8 +183,9 @@ struct renesas_usbhs_driver_param {
#define USBHS_USB_DMAC_XFER_SIZE 32 /* hardcode the xfer size */ #define USBHS_USB_DMAC_XFER_SIZE 32 /* hardcode the xfer size */
}; };
#define USBHS_TYPE_RCAR_GEN2 1 #define USBHS_TYPE_RCAR_GEN2 1
#define USBHS_TYPE_RCAR_GEN3 2 #define USBHS_TYPE_RCAR_GEN3 2
#define USBHS_TYPE_RCAR_GEN3_WITH_PLL 3
/* /*
* option: * option:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment