From 9f644a64884f97f0d92f0689afc7fcf177b6ee92 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Sun, 2 Sep 2018 19:37:04 +0200 Subject: [PATCH 1/7] usb: chipidea: imx: do not use preprocessor conditionals for PM Use preprocessor conditionals for CONFIG_PM and CONFIG_PM_SLEEP is not necessary since SET_SYSTEM_SLEEP_PM_OPS and SET_RUNTIME_PM_OPS does that internally. It is also the preferred way according to our coding style guidelines. Signed-off-by: Marcus Folkesson Signed-off-by: Peter Chen --- drivers/usb/chipidea/ci_hdrc_imx.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 19f5f5f2a48a..ab79d23ca6ec 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -364,8 +364,7 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev) ci_hdrc_imx_remove(pdev); } -#ifdef CONFIG_PM -static int imx_controller_suspend(struct device *dev) +static int __maybe_unused imx_controller_suspend(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); @@ -377,7 +376,7 @@ static int imx_controller_suspend(struct device *dev) return 0; } -static int imx_controller_resume(struct device *dev) +static int __maybe_unused imx_controller_resume(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret = 0; @@ -408,8 +407,7 @@ static int imx_controller_resume(struct device *dev) return ret; } -#ifdef CONFIG_PM_SLEEP -static int ci_hdrc_imx_suspend(struct device *dev) +static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev) { int ret; @@ -431,7 +429,7 @@ static int ci_hdrc_imx_suspend(struct device *dev) return imx_controller_suspend(dev); } -static int ci_hdrc_imx_resume(struct device *dev) +static int __maybe_unused ci_hdrc_imx_resume(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret; @@ -445,9 +443,8 @@ static int ci_hdrc_imx_resume(struct device *dev) return ret; } -#endif /* CONFIG_PM_SLEEP */ -static int ci_hdrc_imx_runtime_suspend(struct device *dev) +static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret; @@ -466,13 +463,11 @@ static int ci_hdrc_imx_runtime_suspend(struct device *dev) return imx_controller_suspend(dev); } -static int ci_hdrc_imx_runtime_resume(struct device *dev) +static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev) { return imx_controller_resume(dev); } -#endif /* CONFIG_PM */ - static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume) SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, From 1dedbdf2bbb1ede8d96f35f9845ecae179dc1988 Mon Sep 17 00:00:00 2001 From: Nicolas Adell Date: Mon, 27 Aug 2018 15:59:56 +0200 Subject: [PATCH 2/7] usb: chipidea: imx: enable OTG overcurrent in case USB subsystem is already started When initializing the USB subsystem before starting the kernel, OTG overcurrent detection is disabled. In case the OTG polarity of overcurrent is low active, the overcurrent detection is never enabled again and events cannot be reported as expected. Because imx usb overcurrent polarity is low active by default, only detection needs to be enable in usbmisc init function. Signed-off-by: Nicolas Adell Signed-off-by: Peter Chen --- drivers/usb/chipidea/usbmisc_imx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 34ad5bf8acd8..424ecb1f003f 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -343,6 +343,8 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) } else if (data->oc_polarity == 1) { /* High active */ reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); + } else { + reg &= ~(MX6_BM_OVER_CUR_DIS); } writel(reg, usbmisc->base + data->index * 4); From 1f06072cd22fbbd2e961b49c8e4fa9f7a0c120d6 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Sun, 2 Sep 2018 19:36:50 +0200 Subject: [PATCH 3/7] usb: chipidea: imx: make MODULE_LICENCE and SPDX-identifier match The SPDX-License-Identifier is set to GPL-2.0+, which correspond to MODULE_LICENSE "GPL". Signed-off-by: Marcus Folkesson Signed-off-by: Peter Chen --- drivers/usb/chipidea/ci_hdrc_imx.c | 2 +- drivers/usb/chipidea/usbmisc_imx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index ab79d23ca6ec..09b37c0d075d 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -487,7 +487,7 @@ static struct platform_driver ci_hdrc_imx_driver = { module_platform_driver(ci_hdrc_imx_driver); MODULE_ALIAS("platform:imx-usb"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CI HDRC i.MX USB binding"); MODULE_AUTHOR("Marek Vasut "); MODULE_AUTHOR("Richard Zhao "); diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 424ecb1f003f..def80ff547e4 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -635,6 +635,6 @@ static struct platform_driver usbmisc_imx_driver = { module_platform_driver(usbmisc_imx_driver); MODULE_ALIAS("platform:usbmisc-imx"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("driver for imx usb non-core registers"); MODULE_AUTHOR("Richard Zhao "); From 16caf1fa37db4722d8d8c7bc26177279949d75a6 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:55 +0200 Subject: [PATCH 4/7] usb: chipidea: Add dynamic pinctrl selection Some hardware implementations require to configure pins differently according to the USB role (host/device), this can be an update of the pins routing or a simple GPIO value change. This patch introduces new optional "host" and "device" pinctrls. If these pinctrls are defined by the device, they are respectively selected on host/device role start. If a default pinctrl exist, it is restored on host/device role stop. Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- drivers/usb/chipidea/core.c | 19 +++++++++++++++++++ drivers/usb/chipidea/host.c | 9 +++++++++ drivers/usb/chipidea/udc.c | 9 +++++++++ include/linux/usb/chipidea.h | 6 ++++++ 4 files changed, 43 insertions(+) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 85fc6db48e44..7bfcbb23c2a4 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -723,6 +724,24 @@ static int ci_get_platdata(struct device *dev, else cable->connected = false; } + + platdata->pctl = devm_pinctrl_get(dev); + if (!IS_ERR(platdata->pctl)) { + struct pinctrl_state *p; + + p = pinctrl_lookup_state(platdata->pctl, "default"); + if (!IS_ERR(p)) + platdata->pins_default = p; + + p = pinctrl_lookup_state(platdata->pctl, "host"); + if (!IS_ERR(p)) + platdata->pins_host = p; + + p = pinctrl_lookup_state(platdata->pctl, "device"); + if (!IS_ERR(p)) + platdata->pins_device = p; + } + return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 4638d9b066be..d858a82c4f44 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "../host/ehci.h" @@ -153,6 +154,10 @@ static int host_start(struct ci_hdrc *ci) } } + if (ci->platdata->pins_host) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_host); + ret = usb_add_hcd(hcd, 0, 0); if (ret) { goto disable_reg; @@ -197,6 +202,10 @@ static void host_stop(struct ci_hdrc *ci) } ci->hcd = NULL; ci->otg.host = NULL; + + if (ci->platdata->pins_host && ci->platdata->pins_default) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_default); } diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 9852ec5e6e01..829e947cabf5 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1965,6 +1966,10 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) static int udc_id_switch_for_device(struct ci_hdrc *ci) { + if (ci->platdata->pins_device) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_device); + if (ci->is_otg) /* Clear and enable BSV irq */ hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, @@ -1983,6 +1988,10 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci) hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS); ci->vbus_active = 0; + + if (ci->platdata->pins_device && ci->platdata->pins_default) + pinctrl_select_state(ci->platdata->pctl, + ci->platdata->pins_default); } /** diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 07f99362bc90..63758c399e4e 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -77,6 +77,12 @@ struct ci_hdrc_platform_data { struct ci_hdrc_cable vbus_extcon; struct ci_hdrc_cable id_extcon; u32 phy_clkgate_delay_us; + + /* pins */ + struct pinctrl *pctl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_host; + struct pinctrl_state *pins_device; }; /* Default offset of capability registers */ From 1fa9697c85382ef6aebc49384f6143a7c0af3745 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:56 +0200 Subject: [PATCH 5/7] doc: usb: ci-hdrc-usb2: Add pinctrl properties definition Some hardware implementations require to configure pins differently according to the USB role (host/device), this can be an update of the pins routing or a simple GPIO value change. This patch introduces new optional "host" and "device" pinctrls. If these pinctrls are defined by the device, they are respectively selected on host/device role start. Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 2e9318151df7..529e51879fb2 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -80,6 +80,8 @@ Optional properties: controller. It's expected that a mux state of 0 indicates device mode and a mux state of 1 indicates host mode. - mux-control-names: Shall be "usb_switch" if mux-controls is specified. +- pinctrl-names: Names for optional pin modes in "default", "host", "device" +- pinctrl-n: alternate pin modes i.mx specific properties - fsl,usbmisc: phandler of non-core register device, with one From 8b97d73c4d72a2abf58f8e49062a7ee1e5f1334e Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:57 +0200 Subject: [PATCH 6/7] usb: chipidea: Prevent unbalanced IRQ disable The ChipIdea IRQ is disabled before scheduling the otg work and re-enabled on otg work completion. However if the job is already scheduled we have to undo the effect of disable_irq int order to balance the IRQ disable-depth value. Fixes: be6b0c1bd0be ("usb: chipidea: using one inline function to cover queue work operations") Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- drivers/usb/chipidea/otg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 7e7428e48bfa..4f8b8179ec96 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -17,7 +17,8 @@ void ci_handle_vbus_change(struct ci_hdrc *ci); static inline void ci_otg_queue_work(struct ci_hdrc *ci) { disable_irq_nosync(ci->irq); - queue_work(ci->wq, &ci->work); + if (queue_work(ci->wq, &ci->work) == false) + enable_irq(ci->irq); } #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ From 59739131e0ca06db7560f9073fff2fb83f6bc2a5 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 4 Sep 2018 17:18:58 +0200 Subject: [PATCH 7/7] usb: chipidea: Fix otg event handler At OTG work running time, it's possible that several events need to be addressed (e.g. ID and VBUS events). The current implementation handles only one event at a time which leads to ignoring the other one. Fix it. Signed-off-by: Loic Poulain Signed-off-by: Peter Chen --- drivers/usb/chipidea/otg.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index db4ceffcf2a6..f25d4827fd49 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -203,14 +203,17 @@ static void ci_otg_work(struct work_struct *work) } pm_runtime_get_sync(ci->dev); + if (ci->id_event) { ci->id_event = false; ci_handle_id_switch(ci); - } else if (ci->b_sess_valid_event) { + } + + if (ci->b_sess_valid_event) { ci->b_sess_valid_event = false; ci_handle_vbus_change(ci); - } else - dev_err(ci->dev, "unexpected event occurs at %s\n", __func__); + } + pm_runtime_put_sync(ci->dev); enable_irq(ci->irq);