Re: [PATCH v12 00/13] Add tested id switch and vbus connect detect support for Chipidea
the USB OTG ID pin. Do the same thing I have done at imx28evk, you probably will work if the ID pin is the same at your board. If it works, please give a tested-by :). -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v12 00/13] Add tested id switch and vbus connect detect support for Chipidea
On Mon, Jul 22, 2013 at 03:40:32AM +0200, Marek Vasut wrote: Dear Peter Chen, On Mon, Jul 22, 2013 at 03:15:28AM +0200, Marek Vasut wrote: Hi Peter, On Fri, Jul 12, 2013 at 03:18:31PM +0200, Marek Vasut wrote: Hi Peter, On Fri, Jul 12, 2013 at 06:04:43AM +0200, Marek Vasut wrote: Hi Peter, On Thu, Jul 11, 2013 at 07:57:19PM +0200, Marek Vasut wrote: Hi Peter, This patchset adds tested otg id switch function and vbus connect and disconnect detection for chipidea driver. And fix kinds of bugs found at chipidea drivers after enabling id and vbus detection. This patch is fully tested at imx6 sabresd platform. My chipidea repo: https://github.com/hzpeterchen/linux-usb.git Changes for v12: - Rebased greg's usb-next tree (3.10.0-rc7+) - Split more small patches for single function and fix. I tested the patchset. Here are the results: - VBUS switching I'm no longer getting any ID interrupts at all when I apply the patch below. The board stays in HOST mode all the time. If I configure it as peripheral, it works as peripheral. Note with [1], I was able to switch from Peripheral-Host , not the other way around. Thanks for your testing. But first, can you have me check if your ID wakeup is enabled? ID wakeup? How do I check? See otgsc at controller register, the ID wakeup enable is bit 24. Yes, ID interrupt (IDIE) is set. I noticed this backtrace in the kernel bootlog, but this only happens if the dr_mode=otg , it comes from the host-mode irq handler : [2.757563] irq 238: nobody cared (try booting with the irqpoll option) [2.764398] CPU: 0 PID: 1 Comm: swapper Not tainted 3.10.0- next-20130711-00013-g011c4b3-dirty #703 [2.773445] [80013878] (unwind_backtrace+0x0/0xe8) from [80011644] (show_stack+0x10/0x14) [2.782027] [80011644] (show_stack+0x10/0x14) from [800659f4] (__report_bad_irq.isra.6+0x20/0xe0) [2.791286] [800659f4] (__report_bad_irq.isra.6+0x20/0xe0) from [80065c98] (note_interrupt+0x16c/0x230) [2.801063] [80065c98] (note_interrupt+0x16c/0x230) from [80064000] (handle_irq_event_percpu+0x10c/0x1a4) [2.811010] [80064000] (handle_irq_event_percpu+0x10c/0x1a4) from [800640e8] (handle_irq_event+0x50/0x78) [2.820958] [800640e8] (handle_irq_event+0x50/0x78) from [8006652c] (handle_level_irq+0x88/0x10c) [2.830210] [8006652c] (handle_level_irq+0x88/0x10c) from [800638d0] (generic_handle_irq+0x28/0x3c) [2.839637] [800638d0] (generic_handle_irq+0x28/0x3c) from [8000f84c] (handle_IRQ+0x30/0x84) [2.848461] [8000f84c] (handle_IRQ+0x30/0x84) from [80012160] (__irq_svc+0x40/0x6c) [2.856510] [80012160] (__irq_svc+0x40/0x6c) from [80022a44] (__do_softirq+0x90/0x1d8) [2.864812] [80022a44] (__do_softirq+0x90/0x1d8) from [80022edc] (irq_exit+0x98/0xd4) [2.873025] [80022edc] (irq_exit+0x98/0xd4) from [8000f850] (handle_IRQ+0x34/0x84) [2.880980] [8000f850] (handle_IRQ+0x34/0x84) from [80012160] (__irq_svc+0x40/0x6c) [2.889020] [80012160] (__irq_svc+0x40/0x6c) from [8001d724] (vprintk_emit+0x1bc/0x524) [2.897411] [8001d724] (vprintk_emit+0x1bc/0x524) from [804da5a4] (printk+0x30/0x40) [2.905551] [804da5a4] (printk+0x30/0x40) from [80630138] (mousedev_init+0x4c/0x60) [2.913617] [80630138] (mousedev_init+0x4c/0x60) from [806178fc] (do_one_initcall+0x94/0x14c) [2.922537] [806178fc] (do_one_initcall+0x94/0x14c) from [80617b20] (kernel_init_freeable+0x16c/0x22c) [2.932230] [80617b20] (kernel_init_freeable+0x16c/0x22c) from [804d8cbc] (kernel_init+0x8/0x150) [2.941486] [804d8cbc] (kernel_init+0x8/0x150) from [8000ea70] (ret_from_fork+0x14/0x24) [2.949932] handlers: [2.952227] [8033fc58] ci_irq [2.955388] Disabling IRQ #238 Marek, I have a test at imx28evk (Freescale imx28evk) for this patchset, it works well for dual-role switch after adding below dts change. There is a kernel dump when works at udc mode(due to enable CONFIG_LOCKUP_DETECTOR), at the first connect, but it does not affect function, it should be a common chipidea problem, I will check later. Sorry for the long delay. I finally got further with this, at least now I can switch Periph-Host again, but if I do so the other way around (unplug host adapter and plug computer cable) and dump the controller registers, I still see the controller in host (according to USBMODE register) mode. The controller stays in HOST mode even if I force
Re: [PATCH v12 00/13] Add tested id switch and vbus connect detect support for Chipidea
On Thu, Jul 25, 2013 at 07:55:23AM +0200, Marek Vasut wrote: Hi Peter, I have not tried the manual switching, but first, you need to close your vbus supply. I think we can close this issue, I will now be also getting MX28EVK. Thanks for all your help! Great. What's the problem? Any changes for this patchset? -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] chipidea: core: Move hw_phymode_configure() into probe
On Thu, Jul 25, 2013 at 06:20:34PM -0300, Fabio Estevam wrote: Currently hw_phymode_configure() is located inside hw_device_reset(), which is only called by chipidea udc driver. When operating in host mode, we also need to call hw_phymode_configure() in order to properly configure the PHY mode, so move this function into probe. After this change, USB Host1 port on mx53qsb board is functional. Signed-off-by: Fabio Estevam fabio.este...@freescale.com --- drivers/usb/chipidea/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a5df24c..a5b3774 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -264,8 +264,6 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) while (hw_read(ci, OP_USBCMD, USBCMD_RST)) udelay(10); /* not RTOS friendly */ - hw_phymode_configure(ci); - if (ci-platdata-notify_event) ci-platdata-notify_event(ci, CI_HDRC_CONTROLLER_RESET_EVENT); @@ -457,6 +455,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ci-platdata-phy_mode) ci-platdata-phy_mode = of_usb_get_phy_mode(dev-of_node); + hw_phymode_configure(ci); + if (!ci-platdata-dr_mode) ci-platdata-dr_mode = of_usb_get_dr_mode(dev-of_node); -- 1.8.1.2 At old version (not upsteamed), Michael did put it at probe, I don't know why move it to hw_device_reset later. Talked with IC guys, usbcmd.rst will not reset PORTSC_PTS at chipidea core IP default, unless some vendors changes this behaviour(very low possibilities). So, it is safe to put it at probe, unless we need consider above uncertain change. Reviewed-by: Peter Chen peter.c...@freescale.com -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] chipidea: ci_hdrc_imx: Remove unused variable 'res'
On Thu, Jul 25, 2013 at 12:55:28AM -0300, Fabio Estevam wrote: From: Fabio Estevam fabio.este...@freescale.com 'res' is not used anywhere, so let's get rid of it. Signed-off-by: Fabio Estevam fabio.este...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c | 7 --- 1 file changed, 7 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 14362c0..06bc775 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -96,7 +96,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) CI_HDRC_PULLUP_ON_VBUS | CI_HDRC_DISABLE_STREAMING, }; - struct resource *res; int ret; if (of_find_property(pdev-dev.of_node, fsl,usbmisc, NULL) @@ -109,12 +108,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) return -ENOMEM; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(pdev-dev, Can't get device resources!\n); - return -ENOENT; - } - data-clk = devm_clk_get(pdev-dev, NULL); if (IS_ERR(data-clk)) { dev_err(pdev-dev, -- 1.8.1.2 Acked-by: Peter Chen peter.c...@freescale.com -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 02/14] usb: chipidea: imx: remove vbus regulator operation
Since we have added vbus reguatlor operation at common host file (chipidea/host.c), the glue layer vbus operation isn't needed any more. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c | 30 +++--- 1 files changed, 7 insertions(+), 23 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 14362c0..d06355e 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -31,7 +31,6 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; - struct regulator *reg_vbus; }; static const struct usbmisc_ops *usbmisc_ops; @@ -141,22 +140,13 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - /* we only support host now, so enable vbus here */ - data-reg_vbus = devm_regulator_get(pdev-dev, vbus); - if (!IS_ERR(data-reg_vbus)) { - ret = regulator_enable(data-reg_vbus); - if (ret) { - dev_err(pdev-dev, - Failed to enable vbus regulator, err=%d\n, - ret); - goto err_clk; - } - } else { - data-reg_vbus = NULL; - } - pdata.phy = data-phy; + /* Get the vbus regulator */ + pdata.reg_vbus = devm_regulator_get(pdev-dev, vbus); + if (IS_ERR(pdata.reg_vbus)) + pdata.reg_vbus = NULL; + if (!pdev-dev.dma_mask) pdev-dev.dma_mask = pdev-dev.coherent_dma_mask; if (!pdev-dev.coherent_dma_mask) @@ -167,7 +157,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) { dev_err(pdev-dev, usbmisc init failed, ret=%d\n, ret); - goto err; + goto err_clk; } } @@ -179,7 +169,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_err(pdev-dev, Can't register ci_hdrc platform device, err=%d\n, ret); - goto err; + goto err_clk; } if (usbmisc_ops usbmisc_ops-post) { @@ -200,9 +190,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data-ci_pdev); -err: - if (data-reg_vbus) - regulator_disable(data-reg_vbus); err_clk: clk_disable_unprepare(data-clk); return ret; @@ -215,9 +202,6 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) pm_runtime_disable(pdev-dev); ci_hdrc_remove_device(data-ci_pdev); - if (data-reg_vbus) - regulator_disable(data-reg_vbus); - if (data-phy) { usb_phy_shutdown(data-phy); module_put(data-phy-dev-driver-owner); -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 13/14] usb: chipidea: udc: .pullup is valid when vbus is on at CI_HDRC_PULLUP_ON_VBUS
When the flag CI_HDRC_PULLUP_ON_VBUS is set, .pullup should only be called when the vbus is active. When the CI_HDRC_PULLUP_ON_VBUS is set, the controller only begins to run when the vbus is on, So, it is only meaningful software set pullup/pulldown after the controller begins to run. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 45abf4d..b7ead5f 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1514,6 +1514,10 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on) { struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); + if ((ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) +!ci-vbus_active) + return -EOPNOTSUPP; + if (is_on) hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); else -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 12/14] usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS
CI_HDRC_REGS_SHARED stands for the controller registers is shared with other USB drivers, if all USB drivers are at chipidea/, it doesn't needed to set. CI_HDRC_PULLUP_ON_VBUS stands for pullup dp when the vbus is on. This flag doesn't need to set if the vbus is always on for gadget since dp has always pulled up after the gadget has initialized. So, the current code seems to misuse this two flags. - When the gadget initializes, the controller doesn't need to run if it depends on vbus (CI_HDRC_PULLUP_ON_VBUS), it does not relate to shared register. - When the gadget starts (load one gadget module), the controller can run if vbus is on (CI_HDRC_PULLUP_ON_VBUS), it also does not relate to shared register. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index c70ce38..45abf4d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1637,8 +1637,7 @@ static int ci_udc_start(struct usb_gadget *gadget, pm_runtime_get_sync(ci-gadget.dev); if (ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) { if (ci-vbus_active) { - if (ci-platdata-flags CI_HDRC_REGS_SHARED) - hw_device_reset(ci, USBMODE_CM_DC); + hw_device_reset(ci, USBMODE_CM_DC); } else { pm_runtime_put_sync(ci-gadget.dev); goto done; @@ -1801,7 +1800,7 @@ static int udc_start(struct ci_hdrc *ci) } } - if (!(ci-platdata-flags CI_HDRC_REGS_SHARED)) { + if (!(ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS)) { retval = hw_device_reset(ci, USBMODE_CM_DC); if (retval) goto put_transceiver; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 01/14] usb: chipidea: add vbus regulator control
For boards which have board level vbus control (eg, through gpio), we need to vbus operation according to below rules: - For host, we need open vbus before start hcd, and close it after remove hcd. - For otg, the vbus needs to be on/off when usb role switches. When the host roles begins, it opens vbus; when the host role finishes, it closes vbus. We put vbus operation to host as host is the only vbus user, When we are at host mode, the vbus is on, when we are not at host mode, vbus should be off. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/host.c | 23 ++- include/linux/usb/chipidea.h |1 + 2 files changed, 23 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 40d0fda..e94e52b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -24,6 +24,7 @@ #include linux/usb.h #include linux/usb/hcd.h #include linux/usb/chipidea.h +#include linux/regulator/consumer.h #include ../host/ehci.h @@ -64,9 +65,19 @@ static int host_start(struct ci_hdrc *ci) ehci-caps = ci-hw_bank.cap; ehci-has_hostpc = ci-hw_bank.lpm; + if (ci-platdata-reg_vbus) { + ret = regulator_enable(ci-platdata-reg_vbus); + if (ret) { + dev_err(ci-dev, + Failed to enable vbus regulator, ret=%d\n, + ret); + goto put_hcd; + } + } + ret = usb_add_hcd(hcd, 0, 0); if (ret) - usb_put_hcd(hcd); + goto disable_reg; else ci-hcd = hcd; @@ -74,6 +85,14 @@ static int host_start(struct ci_hdrc *ci) hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); return ret; + +disable_reg: + regulator_disable(ci-platdata-reg_vbus); + +put_hcd: + usb_put_hcd(hcd); + + return ret; } static void host_stop(struct ci_hdrc *ci) @@ -82,6 +101,8 @@ static void host_stop(struct ci_hdrc *ci) usb_remove_hcd(hcd); usb_put_hcd(hcd); + if (ci-platdata-reg_vbus) + regulator_disable(ci-platdata-reg_vbus); } int ci_hdrc_host_init(struct ci_hdrc *ci) diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 2562994..118bf66 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -24,6 +24,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 void(*notify_event) (struct ci_hdrc *ci, unsigned event); + struct regulator *reg_vbus; }; /* Default offset of capability registers */ -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 07/14] usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG
Since we need otgsc to know vbus's status at some chipidea controllers even it is peripheral-only mode. Besides, some SoCs (eg, AR9331 SoC) don't have otgsc register even the DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS. We inroduce flag CI_HDRC_DUAL_ROLE_NOT_OTG to indicate if the controller is dual role, but not supports OTG. If this flag is not set, we follow the rule that if DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS, then this controller is otg capable. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 38 +++--- include/linux/usb/chipidea.h |5 + 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 93961ff..28983c3 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -405,6 +405,18 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) ci_hdrc_host_destroy(ci); } +static void ci_get_otg_capable(struct ci_hdrc *ci) +{ + if (ci-platdata-flags CI_HDRC_DUAL_ROLE_NOT_OTG) + ci-is_otg = false; + else + ci-is_otg = (hw_read(ci, CAP_DCCPARAMS, + DCCPARAMS_DC | DCCPARAMS_HC) + == (DCCPARAMS_DC | DCCPARAMS_HC)); + if (ci-is_otg) + dev_dbg(ci-dev, It is OTG capable controller\n); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = pdev-dev; @@ -461,6 +473,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } + /* To know if controller is OTG capable or not */ + ci_get_otg_capable(ci); + if (!ci-platdata-phy_mode) ci-platdata-phy_mode = of_usb_get_phy_mode(dev-of_node); @@ -491,10 +506,22 @@ static int ci_hdrc_probe(struct platform_device *pdev) } if (ci-roles[CI_ROLE_HOST] ci-roles[CI_ROLE_GADGET]) { - ci-is_otg = true; - /* ID pin needs 1ms debouce time, we delay 2ms for safe */ - mdelay(2); - ci-role = ci_otg_role(ci); + if (ci-is_otg) { + /* +* ID pin needs 1ms debouce time, +* we delay 2ms for safe. +*/ + mdelay(2); + ci-role = ci_otg_role(ci); + ci_hdrc_otg_init(ci); + } else { + /* +* If the controller is not OTG capable, but support +* role switch, the defalt role is gadget, and the +* user can switch it through debugfs (proc in future?) +*/ + ci-role = CI_ROLE_GADGET; + } } else { ci-role = ci-roles[CI_ROLE_HOST] ? CI_ROLE_HOST @@ -514,9 +541,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; - if (ci-is_otg) - ci_hdrc_otg_init(ci); - ret = dbg_create_files(ci); if (!ret) return 0; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 118bf66..e94dc2e 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -20,6 +20,11 @@ struct ci_hdrc_platform_data { #define CI_HDRC_REQUIRE_TRANSCEIVERBIT(1) #define CI_HDRC_PULLUP_ON_VBUS BIT(2) #define CI_HDRC_DISABLE_STREAMING BIT(3) + /* +* Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, +* but otg is not supported (no register otgsc). +*/ +#define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) enum usb_dr_modedr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 08/14] usb: chipidea: disable all interrupts and clear all interrupts status
During the initialization, it needs to disable all interrupts enable bit as well as clear all interrupts status bits to avoid exceptional interrupt. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 11 ++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 28983c3..8884af6 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -198,6 +198,12 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) if (ci-hw_ep_max ENDPT_MAX) return -ENODEV; + /* Disable all interrupts bits */ + hw_write(ci, OP_USBINTR, 0x, 0); + + /* Clear all interrupts status bits*/ + hw_write(ci, OP_USBSTS, 0x, 0x); + dev_dbg(ci-dev, ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n, ci-hw_bank.lpm, ci-hw_bank.cap, ci-hw_bank.op); @@ -413,8 +419,11 @@ static void ci_get_otg_capable(struct ci_hdrc *ci) ci-is_otg = (hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC | DCCPARAMS_HC) == (DCCPARAMS_DC | DCCPARAMS_HC)); - if (ci-is_otg) + if (ci-is_otg) { dev_dbg(ci-dev, It is OTG capable controller\n); + ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); + ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); + } } static int ci_hdrc_probe(struct platform_device *pdev) -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 10/14] usb: chipidea: add vbus interrupt handler
We add vbus interrupt handler at ci_otg_work, it uses OTGSC_BSV(at otgsc) to know it is connect or disconnet event. Meanwhile, we introduce two flags id_event and b_sess_valid_event to indicate it is an id interrupt or a vbus interrupt. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci.h |5 + drivers/usb/chipidea/core.c | 28 +++- drivers/usb/chipidea/otg.c | 42 +++--- drivers/usb/chipidea/otg.h |1 + drivers/usb/chipidea/udc.c |7 +++ 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 33cb29f..3160363 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -132,6 +132,9 @@ struct hw_bank { * @transceiver: pointer to USB PHY, if any * @hcd: pointer to usb_hcd for ehci host driver * @debugfs: root dentry for this controller in debugfs + * @id_event: indicates there is an id event, and handled at ci_otg_work + * @b_sess_valid_event: indicates there is a vbus event, and handled + * at ci_otg_work */ struct ci_hdrc { struct device *dev; @@ -168,6 +171,8 @@ struct ci_hdrc { struct usb_phy *transceiver; struct usb_hcd *hcd; struct dentry *debugfs; + boolid_event; + boolb_sess_valid_event; }; static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 78c4721..0fbeb45 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -304,16 +304,34 @@ static irqreturn_t ci_irq(int irq, void *data) if (ci-is_otg) otgsc = hw_read(ci, OP_OTGSC, ~0); - if (ci-role != CI_ROLE_END) - ret = ci_role(ci)-irq(ci); + /* +* Handle id change interrupt, it indicates device/host function +* switch. +*/ + if (ci-is_otg (otgsc OTGSC_IDIE) (otgsc OTGSC_IDIS)) { + ci-id_event = true; + ci_clear_otg_interrupt(ci, OTGSC_IDIS); + disable_irq_nosync(ci-irq); + queue_work(ci-wq, ci-work); + return IRQ_HANDLED; + } - if (ci-is_otg (otgsc OTGSC_IDIS)) { - hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS); + /* +* Handle vbus change interrupt, it indicates device connection +* and disconnection events. +*/ + if (ci-is_otg (otgsc OTGSC_BSVIE) (otgsc OTGSC_BSVIS)) { + ci-b_sess_valid_event = true; + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); disable_irq_nosync(ci-irq); queue_work(ci-wq, ci-work); - ret = IRQ_HANDLED; + return IRQ_HANDLED; } + /* Handle device/host interrupt */ + if (ci-role != CI_ROLE_END) + ret = ci_role(ci)-irq(ci); + return ret; } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 68f2faf..c74194d 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -52,13 +52,23 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) return role; } -/** - * ci_role_work - perform role changing based on ID pin - * @work: work struct - */ -static void ci_role_work(struct work_struct *work) +void ci_handle_vbus_change(struct ci_hdrc *ci) +{ + u32 otgsc; + + if (!ci-is_otg) + return; + + otgsc = hw_read(ci, OP_OTGSC, ~0); + + if (otgsc OTGSC_BSV) + usb_gadget_vbus_connect(ci-gadget); + else + usb_gadget_vbus_disconnect(ci-gadget); +} + +static void ci_handle_id_switch(struct ci_hdrc *ci) { - struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); enum ci_role role = ci_otg_role(ci); if (role != ci-role) { @@ -68,17 +78,35 @@ static void ci_role_work(struct work_struct *work) ci_role_stop(ci); ci_role_start(ci, role); } +} +/** + * ci_otg_work - perform otg (vbus/id) event handle + * @work: work struct + */ +static void ci_otg_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + + if (ci-id_event) { + ci-id_event = false; + ci_handle_id_switch(ci); + } else 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__); enable_irq(ci-irq); } + /** * ci_hdrc_otg_init - initialize otg struct * ci: the controller */ int ci_hdrc_otg_init(struct ci_hdrc *ci) { - INIT_WORK(ci-work, ci_role_work); + INIT_WORK(ci-work
[PATCH v13 00/14] Add tested id switch and vbus connect detect support for Chipidea
This patchset adds tested otg id switch function and vbus connect and disconnect detection for chipidea driver. And fix kinds of bugs found at chipidea drivers after enabling id and vbus detection. This patch are fully tested at imx6 sabresd and imx28evk platform by me. Besides, marek tested it on two STMP3780-based boards (not yet mainline) and two MX28-based boards. My chipidea repo: https://github.com/hzpeterchen/linux-usb.git Chagnes for v13: - Add Tested-by: Marek Vasut ma...@denx.de - [Sascha's comments]: Add return value check for devm_regulator_get. [3/14] - [Marc's comments]: Change timeout usage at hw_wait_reg. [11/14] - [Alex's comments]: Using platdata flag to indicate dual role but not OTG controller. [7/14] Changes for v12: - Rebased greg's usb-next tree (3.10.0-rc7+) - Split more small patches for single function and fix. Changes for v11: - mark ci_handle_vbus_change as static as it is only used at core.c [3/9] - Move the vbus operation for platform code to host code, as vbus operation is common operation, and host is the only user for vbus. When it is host mode, we need to open vbus, when it is out of host mode, we need to close vbus. [6/9] [8/9] - Delete the delayed work at core.c as it is not needed. [7/9] Changes for v10: - Delete [8/9] at v9, ci core's drvdata must be set for further operation. [8/8] Changes for v9: - Some small comments from Alex like: variable comment for otg event additional newline. [3/9] - Import function tell show if the controller has otg capable, if the controller supports both host and device, we think it is otg capable, and can read OTGSC. [3/9] - Merge two otg patches [v8 3/8] and [v8 4/8] to one [v9 3/9]. [3/9] - Add inline to ci_hdrc_gadget_destroy if CONFIG_USB_CHIPIDEA_UDC is not defined, it can fix one build warning defined but not used [3/9] - One comment from Felipe about changing calling gadget disconnect API at chipidea's udc driver. I move calling ci-driver-disconnect from _gadget_stop_activity to which calls _gadget_stop_activity except ci13xxx_stop, as udc core will call disconnect when do rmmod gadget. [7/9] - Add ci core probe's return value to ci's platform_data, we do this for getting core's probe's result at platform layer, and quit it if the core's probe fails. [8/9] [9/9] Changes for v8: - Add ci_supports_gadget helper to know if the controller supports gadget, if the controller supports gadget, it needs to read otgsc to know the vbus value, basically, if the controller supports gadget, it will support host as well [3/8] - At ci_hdrc_probe, it needs to add free memory at error path [3/8] - Cosolidate ci-driver = NULL at ci13xxx_stop [8/8] Changes for v7: For Patch 8/8, we only need to set ci-driver to NULL when usb cable is not connected, for other changes, it will case some runtime pm unmatch and un-align with udc-core composite driver problems. Changes for v6: - Add Alex comments for init/destroy function [3/8] [4/8] - Remove memset(ci-gadget, 0, sizeof(ci-gadget)) at destory function [4/8] - Add Kishon's comment: Change the format of struct usb_otg otg at drivers/usb/chipidea/ci.h [1/8] - Add comments for CI_VBUS_STABLE_TIMEOUT [3/8] - Change the otg_set_peripheral return value check as the fully chipidea driver users don't need it. [4/8] - Fix one bug that the oops when re-plug in usb cable after rmmod gadget [8/8] Peter Chen (14): usb: chipidea: add vbus regulator control usb: chipidea: imx: remove vbus regulator operation usb: chipidea: imx: add return value check for devm_regulator_get usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users usb: chipidea: otg: Add otg file used to access otgsc usb: chipidea: Add role init and destory APIs usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG usb: chipidea: disable all interrupts and clear all interrupts status usb: chipidea: move otg relate things to otg file usb: chipidea: add vbus interrupt handler usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS usb: chipidea: udc: .pullup is valid when vbus is on at CI_HDRC_PULLUP_ON_VBUS usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod gadget drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h| 10 ++ drivers/usb/chipidea/ci.h |8 ++ drivers/usb/chipidea/ci_hdrc_imx.c | 40 - drivers/usb/chipidea/core.c| 161 drivers/usb/chipidea/host.c| 30 +++- drivers/usb/chipidea/host.h|6 ++ drivers/usb/chipidea/otg.c | 135 ++ drivers/usb/chipidea/otg.h | 22 + drivers/usb/chipidea/udc.c | 72 drivers/usb/chipidea/udc.h |6 ++ include/linux/usb/chipidea.h |6 ++ 12 files changed, 402 insertions(+), 96 deletions(-) create mode 100644 drivers
[PATCH v13 04/14] usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users
It is useless at below cases: - If we implement both usb host and device at chipidea driver. - If we don't need phy-otg. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |7 ++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index e475fcd..116c762 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1805,7 +1805,12 @@ static int udc_start(struct ci_hdrc *ci) if (ci-transceiver) { retval = otg_set_peripheral(ci-transceiver-otg, ci-gadget); - if (retval) + /* +* If we implement all USB functions using chipidea drivers, +* it doesn't need to call above API, meanwhile, if we only +* use gadget function, calling above API is useless. +*/ + if (retval retval != -ENOTSUPP) goto put_transceiver; } -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 09/14] usb: chipidea: move otg relate things to otg file
Move otg relate things to otg file. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 63 +-- drivers/usb/chipidea/otg.c | 57 +- drivers/usb/chipidea/otg.h |2 + 3 files changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 8884af6..78c4721 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -295,40 +295,6 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) return 0; } -/** - * ci_otg_role - pick role based on ID pin state - * @ci: the controller - */ -static enum ci_role ci_otg_role(struct ci_hdrc *ci) -{ - u32 sts = hw_read(ci, OP_OTGSC, ~0); - enum ci_role role = sts OTGSC_ID - ? CI_ROLE_GADGET - : CI_ROLE_HOST; - - return role; -} - -/** - * ci_role_work - perform role changing based on ID pin - * @work: work struct - */ -static void ci_role_work(struct work_struct *work) -{ - struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); - enum ci_role role = ci_otg_role(ci); - - if (role != ci-role) { - dev_dbg(ci-dev, switching from %s to %s\n, - ci_role(ci)-name, ci-roles[role]-name); - - ci_role_stop(ci); - ci_role_start(ci, role); - } - - enable_irq(ci-irq); -} - static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; @@ -409,6 +375,8 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) { ci_hdrc_gadget_destroy(ci); ci_hdrc_host_destroy(ci); + if (ci-is_otg) + ci_hdrc_otg_destory(ci); } static void ci_get_otg_capable(struct ci_hdrc *ci) @@ -475,13 +443,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - INIT_WORK(ci-work, ci_role_work); - ci-wq = create_singlethread_workqueue(ci_otg); - if (!ci-wq) { - dev_err(dev, can't create workqueue\n); - return -ENODEV; - } - /* To know if controller is OTG capable or not */ ci_get_otg_capable(ci); @@ -510,8 +471,15 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ci-roles[CI_ROLE_HOST] !ci-roles[CI_ROLE_GADGET]) { dev_err(dev, no supported roles\n); - ret = -ENODEV; - goto rm_wq; + return -ENODEV; + } + + if (ci-is_otg) { + ret = ci_hdrc_otg_init(ci); + if (ret) { + dev_err(dev, init otg fails, ret = %d\n, ret); + goto stop; + } } if (ci-roles[CI_ROLE_HOST] ci-roles[CI_ROLE_GADGET]) { @@ -522,7 +490,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) */ mdelay(2); ci-role = ci_otg_role(ci); - ci_hdrc_otg_init(ci); + ci_enable_otg_interrupt(ci, OTGSC_IDIE); } else { /* * If the controller is not OTG capable, but support @@ -541,7 +509,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) { dev_err(dev, can't start %s role\n, ci_role(ci)-name); ret = -ENODEV; - goto rm_wq; + goto stop; } platform_set_drvdata(pdev, ci); @@ -557,9 +525,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) free_irq(ci-irq, ci); stop: ci_role_destroy(ci); -rm_wq: - flush_workqueue(ci-wq); - destroy_workqueue(ci-wq); return ret; } @@ -569,8 +534,6 @@ static int ci_hdrc_remove(struct platform_device *pdev) struct ci_hdrc *ci = platform_get_drvdata(pdev); dbg_remove_files(ci); - flush_workqueue(ci-wq); - destroy_workqueue(ci-wq); free_irq(ci-irq, ci); ci_role_destroy(ci); diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index abefb4d..68f2faf 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -39,12 +39,65 @@ void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) } /** - * ci_hdrc_otg_init - initialize otgsc bits + * ci_otg_role - pick role based on ID pin state + * @ci: the controller + */ +enum ci_role ci_otg_role(struct ci_hdrc *ci) +{ + u32 sts = hw_read(ci, OP_OTGSC, ~0); + enum ci_role role = sts OTGSC_ID + ? CI_ROLE_GADGET + : CI_ROLE_HOST; + + return role; +} + +/** + * ci_role_work - perform role changing based on ID pin + * @work: work struct + */ +static void ci_role_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + enum ci_role role
[PATCH v13 14/14] usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod gadget
] (dump_backtrace+0x0/0x114) from [804ea684] (dump_stack+0x20/0x24) r7: r6:806c3f2c r5:806cf748 r4:80712d18 [804ea664] (dump_stack+0x0/0x24) from [80014adc] (handle_IPI+0x140/0x18c) [8001499c] (handle_IPI+0x0/0x18c) from [800085b0] (gic_handle_irq+0x68/0x70) r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bff60 r5:806ce974 r4:f400010c [80008548] (gic_handle_irq+0x0/0x70) from [8000eac0] (__irq_svc+0x40/0x54) Exception stack(0xbf8bff60 to 0xbf8bffa8) ff60: 000f 8001aea0 bf8be000 80712a48 804f0040 ff80: 806d29e8 412fc09a bf8bffb4 bf8bffb8 bf8bffa8 8000fbcc 8000fbd0 ffa0: 6013 r7:bf8bff94 r6: r5:6013 r4:8000fbd0 [8000fb90] (default_idle+0x0/0x4c) from [8001015c] (cpu_idle+0xbc/0xf8) [800100a0] (cpu_idle+0x0/0xf8) from [804e7930] (secondary_start_kernel+0x120/0x148) r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:0003 r4:806e2008 [804e7810] (secondary_start_kernel+0x0/0x148) from [104e7148] (0x104e7148) r5:001f r4:4f8a806a CPU1: stopping Backtrace: [800132e8] (dump_backtrace+0x0/0x114) from [804ea684] (dump_stack+0x20/0x24) r7: r6:806c3f2c r5:806cf748 r4:80712d18 [804ea664] (dump_stack+0x0/0x24) from [80014adc] (handle_IPI+0x140/0x18c) [8001499c] (handle_IPI+0x0/0x18c) from [800085b0] (gic_handle_irq+0x68/0x70) r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bbf60 r5:806ce974 r4:f400010c [80008548] (gic_handle_irq+0x0/0x70) from [8000eac0] (__irq_svc+0x40/0x54) Exception stack(0xbf8bbf60 to 0xbf8bbfa8) bf60: 000f 8001aea0 bf8ba000 80712a48 804f0040 bf80: 806d29e8 412fc09a bf8bbfb4 bf8bbfb8 bf8bbfa8 8000fbcc 8000fbd0 bfa0: 6013 r7:bf8bbf94 r6: r5:6013 r4:8000fbd0 [8000fb90] (default_idle+0x0/0x4c) from [8001015c] (cpu_idle+0xbc/0xf8) [800100a0] (cpu_idle+0x0/0xf8) from [804e7930] (secondary_start_kernel+0x120/0x148) r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:0001 r4:806e2008 Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c | 13 + 1 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b7ead5f..aeabdcf 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -686,9 +686,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) usb_ep_fifo_flush(ci-ep0out-ep); usb_ep_fifo_flush(ci-ep0in-ep); - if (ci-driver) - ci-driver-disconnect(gadget); - /* make sure to disable all endpoints */ gadget_for_each_ep(ep, gadget) { usb_ep_disable(ep); @@ -717,6 +714,11 @@ __acquires(ci-lock) { int retval; + if (ci-gadget.speed != USB_SPEED_UNKNOWN) { + if (ci-driver) + ci-driver-disconnect(ci-gadget); + } + spin_unlock(ci-lock); retval = _gadget_stop_activity(ci-gadget); if (retval) @@ -1464,6 +1466,8 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) hw_device_state(ci, ci-ep0out-qh.dma); dev_dbg(ci-dev, Connected to host\n); } else { + if (ci-driver) + ci-driver-disconnect(ci-gadget); hw_device_state(ci, 0); if (ci-platdata-notify_event) ci-platdata-notify_event(ci, @@ -1674,13 +1678,14 @@ static int ci_udc_stop(struct usb_gadget *gadget, if (ci-platdata-notify_event) ci-platdata-notify_event(ci, CI_HDRC_CONTROLLER_STOPPED_EVENT); - ci-driver = NULL; spin_unlock_irqrestore(ci-lock, flags); _gadget_stop_activity(ci-gadget); spin_lock_irqsave(ci-lock, flags); pm_runtime_put(ci-gadget.dev); } + ci-driver = NULL; + spin_unlock_irqrestore(ci-lock, flags); return 0; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v13 05/14] usb: chipidea: otg: Add otg file used to access otgsc
This file is mainly used to access otgsc currently, it may add otg related things in the future. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h | 10 drivers/usb/chipidea/core.c |3 +- drivers/usb/chipidea/otg.c| 50 + drivers/usb/chipidea/otg.h| 19 +++ 5 files changed, 82 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 6cf5f68..a99d980 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o -ci_hdrc-y := core.o +ci_hdrc-y := core.o otg.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)+= host.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index aefa026..dd0cf9e 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -79,11 +79,21 @@ #define OTGSC_ASVIS BIT(18) #define OTGSC_BSVIS BIT(19) #define OTGSC_BSEIS BIT(20) +#define OTGSC_1MSIS BIT(21) +#define OTGSC_DPIS BIT(22) #define OTGSC_IDIE BIT(24) #define OTGSC_AVVIE BIT(25) #define OTGSC_ASVIE BIT(26) #define OTGSC_BSVIE BIT(27) #define OTGSC_BSEIE BIT(28) +#define OTGSC_1MSIE BIT(29) +#define OTGSC_DPIE BIT(30) +#define OTGSC_INT_EN_BITS (OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \ + | OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \ + | OTGSC_DPIE) +#define OTGSC_INT_STATUS_BITS (OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS \ + | OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \ + | OTGSC_DPIS) /* USBMODE */ #define USBMODE_CM(0x03UL 0) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a5df24c..761f7e8 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -71,6 +71,7 @@ #include bits.h #include host.h #include debug.h +#include otg.h /* Controller register map */ static uintptr_t ci_regs_nolpm[] = { @@ -508,7 +509,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) goto stop; if (ci-is_otg) - hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); + ci_hdrc_otg_init(ci); ret = dbg_create_files(ci); if (!ret) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c new file mode 100644 index 000..abefb4d --- /dev/null +++ b/drivers/usb/chipidea/otg.c @@ -0,0 +1,50 @@ +/* + * otg.c - ChipIdea USB IP core OTG driver + * + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Author: Peter Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This file mainly handles otgsc register, it may include OTG operation + * in the future. + */ + +#include linux/usb/otg.h +#include linux/usb/gadget.h +#include linux/usb/chipidea.h + +#include ci.h +#include bits.h + +void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + /* Only clear request bits */ + hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits); +} + +void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, bits); +} + +void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, 0); +} + +/** + * ci_hdrc_otg_init - initialize otgsc bits + * ci: the controller + */ +int ci_hdrc_otg_init(struct ci_hdrc *ci) +{ + ci_enable_otg_interrupt(ci, OTGSC_IDIE); + + return 0; +} diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h new file mode 100644 index 000..f24ec37 --- /dev/null +++ b/drivers/usb/chipidea/otg.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Author: Peter Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_OTG_H +#define __DRIVERS_USB_CHIPIDEA_OTG_H + +int ci_hdrc_otg_init(struct ci_hdrc *ci); +void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits); +void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits); +void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits); + +#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body
[PATCH v13 06/14] usb: chipidea: Add role init and destory APIs
- The role's init will be called at probe procedure. - The role's destory will be called at fail patch at probe and driver's removal. - The role's start/stop will be called when specific role has started. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 10 -- drivers/usb/chipidea/host.c |7 +++ drivers/usb/chipidea/host.h |6 ++ drivers/usb/chipidea/udc.c | 36 +++- drivers/usb/chipidea/udc.h |6 ++ 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 761f7e8..93961ff 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -399,6 +399,12 @@ void ci_hdrc_remove_device(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); +static inline void ci_role_destroy(struct ci_hdrc *ci) +{ + ci_hdrc_gadget_destroy(ci); + ci_hdrc_host_destroy(ci); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = pdev-dev; @@ -517,7 +523,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) free_irq(ci-irq, ci); stop: - ci_role_stop(ci); + ci_role_destroy(ci); rm_wq: flush_workqueue(ci-wq); destroy_workqueue(ci-wq); @@ -533,7 +539,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) flush_workqueue(ci-wq); destroy_workqueue(ci-wq); free_irq(ci-irq, ci); - ci_role_stop(ci); + ci_role_destroy(ci); return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index e94e52b..382be5b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -105,6 +105,13 @@ static void host_stop(struct ci_hdrc *ci) regulator_disable(ci-platdata-reg_vbus); } + +void ci_hdrc_host_destroy(struct ci_hdrc *ci) +{ + if (ci-role == CI_ROLE_HOST) + host_stop(ci); +} + int ci_hdrc_host_init(struct ci_hdrc *ci) { struct ci_role_driver *rdrv; diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h index 058875c..5707bf3 100644 --- a/drivers/usb/chipidea/host.h +++ b/drivers/usb/chipidea/host.h @@ -4,6 +4,7 @@ #ifdef CONFIG_USB_CHIPIDEA_HOST int ci_hdrc_host_init(struct ci_hdrc *ci); +void ci_hdrc_host_destroy(struct ci_hdrc *ci); #else @@ -12,6 +13,11 @@ static inline int ci_hdrc_host_init(struct ci_hdrc *ci) return -ENXIO; } +static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci) +{ + +} + #endif #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 116c762..24a100d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -27,6 +27,7 @@ #include udc.h #include bits.h #include debug.h +#include otg.h /* control endpoint description */ static const struct usb_endpoint_descriptor @@ -1844,13 +1845,13 @@ free_qh_pool: } /** - * udc_remove: parent remove must call this to remove UDC + * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC * * No interrupts active, the IRQ has been released */ -static void udc_stop(struct ci_hdrc *ci) +void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) { - if (ci == NULL) + if (!ci-roles[CI_ROLE_GADGET]) return; usb_del_gadget_udc(ci-gadget); @@ -1865,15 +1866,32 @@ static void udc_stop(struct ci_hdrc *ci) if (ci-global_phy) usb_put_phy(ci-transceiver); } - /* my kobject is dynamic, I swear! */ - memset(ci-gadget, 0, sizeof(ci-gadget)); +} + +static int udc_id_switch_for_device(struct ci_hdrc *ci) +{ + if (ci-is_otg) { + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); + ci_enable_otg_interrupt(ci, OTGSC_BSVIE); + } + + return 0; +} + +static void udc_id_switch_for_host(struct ci_hdrc *ci) +{ + if (ci-is_otg) { + /* host doesn't care B_SESSION_VALID event */ + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); + ci_disable_otg_interrupt(ci, OTGSC_BSVIE); + } } /** * ci_hdrc_gadget_init - initialize device related bits * ci: the controller * - * This function enables the gadget role, if the device is device capable. + * This function initializes the gadget, if the device is device capable. */ int ci_hdrc_gadget_init(struct ci_hdrc *ci) { @@ -1886,11 +1904,11 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci) if (!rdrv) return -ENOMEM; - rdrv-start = udc_start; - rdrv-stop = udc_stop; + rdrv-start = udc_id_switch_for_device; + rdrv-stop = udc_id_switch_for_host; rdrv-irq = udc_irq; rdrv-name = gadget; ci-roles[CI_ROLE_GADGET] = rdrv; - return 0; + return udc_start(ci); } diff
[PATCH v13 11/14] usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts
When the gadget role starts, we need to make sure the vbus is lower than OTGSC_BSV, or there will be an vbus interrupt since we use B_SESSION_VALID as vbus interrupt to indicate connect and disconnect. When the host role starts, it may not be useful to wait vbus to lower than OTGSC_BSV, but it can indicate some hardware problems like the vbus is still higher than OTGSC_BSV after we disconnect to host some time later (5000 milliseconds currently), which is obvious not correct. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci.h |3 +++ drivers/usb/chipidea/core.c | 32 drivers/usb/chipidea/otg.c |4 3 files changed, 39 insertions(+), 0 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 3160363..1c94fc5 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -308,4 +308,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode); u8 hw_port_test_get(struct ci_hdrc *ci); +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, + u32 value, unsigned int timeout_ms); + #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 0fbeb45..6f9e04d 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -295,6 +295,38 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) return 0; } +/** + * hw_wait_reg: wait the register value + * + * Sometimes, it needs to wait register value before going on. + * Eg, when switch to device mode, the vbus value should be lower + * than OTGSC_BSV before connects to host. + * + * @ci: the controller + * @reg: register index + * @mask: mast bit + * @value: the bit value to wait + * @timeout_ms: timeout in millisecond + * + * This function returns an error code if timeout + */ +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, + u32 value, unsigned int timeout_ms) +{ + unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); + + while (hw_read(ci, reg, mask) != value) { + if (time_after(jiffies, elapse)) { + dev_err(ci-dev, timeout waiting for %08x in %d\n, + mask, reg); + return -ETIMEDOUT; + } + msleep(20); + } + + return 0; +} + static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index c74194d..d39cce8 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -67,6 +67,7 @@ void ci_handle_vbus_change(struct ci_hdrc *ci) usb_gadget_vbus_disconnect(ci-gadget); } +#define CI_VBUS_STABLE_TIMEOUT_MS 5000 static void ci_handle_id_switch(struct ci_hdrc *ci) { enum ci_role role = ci_otg_role(ci); @@ -76,6 +77,9 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) ci_role(ci)-name, ci-roles[role]-name); ci_role_stop(ci); + /* wait vbus lower than OTGSC_BSV */ + hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0, + CI_VBUS_STABLE_TIMEOUT_MS); ci_role_start(ci, role); } } -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Chipidea tree is out of date one month
Hi Alex, Your chipidea tree is out of date more than one month, https://github.com/virtuoso/linux-ci/commits/ci-for-greg You have not queued any patches since June 26th, below is the oldest patch you have not queued. http://marc.info/?l=linux-usbm=137227196006173w=2 There are two patches you said you will send to Greg after -rc1, but now, Greg's -rc3 is ready, the patches are still not there. http://marc.info/?l=linux-usbm=137344357113728w=2 Besides, please give more comments about patchset, Eg, I sent patchset about 13 patches in it, but you only gave one comment for one patch. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v13 02/14] usb: chipidea: imx: remove vbus regulator operation
On Tue, Jul 30, 2013 at 12:30:25AM +0200, Michael Grzeschik wrote: Hi Peter, On Fri, Jul 26, 2013 at 05:18:18PM +0800, Peter Chen wrote: Since we have added vbus reguatlor operation at common host file (chipidea/host.c), the glue layer vbus operation isn't needed any more. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c | 30 +++--- 1 files changed, 7 insertions(+), 23 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 14362c0..d06355e 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -31,7 +31,6 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; - struct regulator *reg_vbus; }; static const struct usbmisc_ops *usbmisc_ops; @@ -141,22 +140,13 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - /* we only support host now, so enable vbus here */ - data-reg_vbus = devm_regulator_get(pdev-dev, vbus); - if (!IS_ERR(data-reg_vbus)) { - ret = regulator_enable(data-reg_vbus); - if (ret) { - dev_err(pdev-dev, - Failed to enable vbus regulator, err=%d\n, - ret); - goto err_clk; - } - } else { - data-reg_vbus = NULL; - } - pdata.phy = data-phy; + /* Get the vbus regulator */ + pdata.reg_vbus = devm_regulator_get(pdev-dev, vbus); + if (IS_ERR(pdata.reg_vbus)) + pdata.reg_vbus = NULL; + This hunk needs the reg_vbus variable from the previous patch, therefor it should also be added in that patch. As the user of the variable is the previous patch, it's the reason to swap their order. The [1/14] implements the vbus operation at common code (host.c) This one [2/14] implements how the glue layer get the vbus. I am OK to swap above two, but I still can't see obvious reason. Anyway, can't this be done in core.c instead? I don't see why other users don't need this code. We still not implement DT support at core.c, it is a big job, this is the main reason, besides, Alex prefers platform things at glue layer. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v13 03/14] usb: chipidea: imx: add return value check for devm_regulator_get
On Tue, Jul 30, 2013 at 12:47:17AM +0200, Michael Grzeschik wrote: On Fri, Jul 26, 2013 at 05:18:19PM +0800, Peter Chen wrote: - If devm_regulator_get returns -EPROBE_DEFER, we also return -EPROBE_DEFER to wait regulator being ready later. - If devm_regulator_get returns -ENODEV, we think there is no vbus-supply node at DT, it means this board doesn't need vbus control. - If devm_regulator_get returns other error values, it means there are something wrong for getting this regulator. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c | 14 -- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index d06355e..0ced8c1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -144,8 +144,18 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) /* Get the vbus regulator */ pdata.reg_vbus = devm_regulator_get(pdev-dev, vbus); - if (IS_ERR(pdata.reg_vbus)) - pdata.reg_vbus = NULL; + if (PTR_ERR(pdata.reg_vbus) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_clk; + } else if (PTR_ERR(pdata.reg_vbus) == -ENODEV) { + pdata.reg_vbus = NULL; /* no vbus regualator is needed */ + } else if (IS_ERR(pdata.reg_vbus)) { + dev_err(pdev-dev, + Getting regulator error: %ld\n, + PTR_ERR(pdata.reg_vbus)); + ret = PTR_ERR(pdata.reg_vbus); + goto err_clk; + } if (!pdev-dev.dma_mask) pdev-dev.dma_mask = pdev-dev.coherent_dma_mask; -- This is wrong, you should squash that into the previous patch. And as already mentioned, this can probably go into core.c as well. Pick up the habit *not* to change code in one series which another patch of the same series introduced. This only adds *dusty* unused history in the patchstack that nobody needs. A *clean* and *coherent* series with discrete patches is much easier to review and will get accepted much faster. My rule is do ONE thing at ONE patch, is it not correct? Previous one[2/14]: Remove the vbus operation at imx glue layer. This one [3/14]: Fix a bug that vbus may be gotten delay (EPROBE_DEFER), and vbus is valid at this case. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] usb: chipidea: move vbus regulator operation to core
On Tue, Jul 30, 2013 at 02:41:23PM +0200, Michael Grzeschik wrote: From: Michael Grzeschik m...@pengutronix.de This patch moves the regulator code from ci_hdrc_imx gluecode to the core layer. It also checks the errorpathes in case the platformglue didn't prepare an regulator for this driver. Signed-off-by: Michael Grzeschik m.grzesc...@pengutronix.de --- drivers/usb/chipidea/ci_hdrc_imx.c | 26 ++ drivers/usb/chipidea/core.c| 16 include/linux/usb/chipidea.h | 1 + 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 06bc775..d2937e1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -19,7 +19,6 @@ #include linux/dma-mapping.h #include linux/usb/chipidea.h #include linux/clk.h -#include linux/regulator/consumer.h #include ci.h #include ci_hdrc_imx.h @@ -31,7 +30,6 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; - struct regulator *reg_vbus; }; static const struct usbmisc_ops *usbmisc_ops; @@ -134,20 +132,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - /* we only support host now, so enable vbus here */ - data-reg_vbus = devm_regulator_get(pdev-dev, vbus); - if (!IS_ERR(data-reg_vbus)) { - ret = regulator_enable(data-reg_vbus); - if (ret) { - dev_err(pdev-dev, - Failed to enable vbus regulator, err=%d\n, - ret); - goto err_clk; - } - } else { - data-reg_vbus = NULL; - } - pdata.phy = data-phy; if (!pdev-dev.dma_mask) @@ -160,7 +144,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) { dev_err(pdev-dev, usbmisc init failed, ret=%d\n, ret); - goto err; + goto err_clk; } } @@ -172,7 +156,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_err(pdev-dev, Can't register ci_hdrc platform device, err=%d\n, ret); - goto err; + goto err_clk; } if (usbmisc_ops usbmisc_ops-post) { @@ -193,9 +177,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data-ci_pdev); -err: - if (data-reg_vbus) - regulator_disable(data-reg_vbus); err_clk: clk_disable_unprepare(data-clk); return ret; @@ -208,9 +189,6 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) pm_runtime_disable(pdev-dev); ci_hdrc_remove_device(data-ci_pdev); - if (data-reg_vbus) - regulator_disable(data-reg_vbus); - if (data-phy) { usb_phy_shutdown(data-phy); module_put(data-phy-dev-driver-owner); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a5df24c..178b61d 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -57,6 +57,7 @@ #include linux/interrupt.h #include linux/io.h #include linux/kernel.h +#include linux/regulator/consumer.h #include linux/slab.h #include linux/pm_runtime.h #include linux/usb/ch9.h @@ -363,6 +364,21 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, goto put_id; } + /* Get the vbus regulator */ + platdata-reg_vbus = devm_regulator_get(dev, vbus); + if (PTR_ERR(platdata-reg_vbus) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err; + } else if (PTR_ERR(platdata-reg_vbus) == -ENODEV) { + platdata-reg_vbus = NULL; /* no vbus regualator is needed */ + } else if (IS_ERR(platdata-reg_vbus)) { + dev_err(pdev-dev, + Getting regulator error: %ld\n, + PTR_ERR(platdata-reg_vbus)); + ret = PTR_ERR(platdata-reg_vbus); + goto err; + } + pdev-dev.parent = dev; Michael, thanks to do this for me. One small suggestion is: it is better add one function like: ci_get_platdata, and move the vbus stuff to that function. This function is used to get common thing from glue layer. And it is better at the beginning of ci_hdrc_add_device, since the other code at ci_hdrc_add_device are all related to core device. I can help to do refine this patch (with some typo which Felipe mentioned) if you consider it is necessary. I know you may be busy with other things. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb
Re: [PATCH 1/2] chipidea: Remove previous MODULE_ALIAS
On Tue, Jul 30, 2013 at 10:04:28PM -0300, Fabio Estevam wrote: From: Fabio Estevam fabio.este...@freescale.com After the rename to ci_hdrc we ended up with two MODULE_ALIAS entries, so remove the old one. Signed-off-by: Fabio Estevam fabio.este...@freescale.com --- drivers/usb/chipidea/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a5df24c..5cc1b02 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -548,7 +548,6 @@ static struct platform_driver ci_hdrc_driver = { module_platform_driver(ci_hdrc_driver); MODULE_ALIAS(platform:ci_hdrc); -MODULE_ALIAS(platform:ci13xxx); MODULE_LICENSE(GPL v2); MODULE_AUTHOR(David Lopo dl...@chipidea.mips.com); MODULE_DESCRIPTION(ChipIdea HDRC Driver); -- 1.8.1.2 Fabio, good eyes. Reviewed-by: Peter Chen peter.c...@freescale.com -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] chipidea: Use devm_request_irq()
On Tue, Jul 30, 2013 at 10:04:29PM -0300, Fabio Estevam wrote: From: Fabio Estevam fabio.este...@freescale.com By using devm_request_irq() we don't need to call free_irq(), which simplifies the code a bit. Signed-off-by: Fabio Estevam fabio.este...@freescale.com --- drivers/usb/chipidea/core.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 5cc1b02..d185c41 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -502,8 +502,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, ci); - ret = request_irq(ci-irq, ci_irq, IRQF_SHARED, ci-platdata-name, - ci); + ret = devm_request_irq(dev, ci-irq, ci_irq, IRQF_SHARED, +ci-platdata-name, ci); if (ret) goto stop; @@ -514,7 +514,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ret) return 0; - free_irq(ci-irq, ci); stop: ci_role_stop(ci); rm_wq: @@ -531,7 +530,6 @@ static int ci_hdrc_remove(struct platform_device *pdev) dbg_remove_files(ci); flush_workqueue(ci-wq); destroy_workqueue(ci-wq); - free_irq(ci-irq, ci); ci_role_stop(ci); return 0; -- 1.8.1.2 Reviewed-by: Peter Chen peter.c...@freescale.com -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] usb: chipidea: move vbus regulator operation to core
On Wed, Jul 31, 2013 at 09:23:56AM +0200, Michael Grzeschik wrote: Hi Peter, On Wed, Jul 31, 2013 at 09:39:50AM +0800, Peter Chen wrote: On Tue, Jul 30, 2013 at 02:41:23PM +0200, Michael Grzeschik wrote: From: Michael Grzeschik m...@pengutronix.de This patch moves the regulator code from ci_hdrc_imx gluecode to the core layer. It also checks the errorpathes in case the platformglue didn't prepare an regulator for this driver. Signed-off-by: Michael Grzeschik m.grzesc...@pengutronix.de --- drivers/usb/chipidea/ci_hdrc_imx.c | 26 ++ drivers/usb/chipidea/core.c| 16 include/linux/usb/chipidea.h | 1 + 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 06bc775..d2937e1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -19,7 +19,6 @@ #include linux/dma-mapping.h #include linux/usb/chipidea.h #include linux/clk.h -#include linux/regulator/consumer.h #include ci.h #include ci_hdrc_imx.h @@ -31,7 +30,6 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; - struct regulator *reg_vbus; }; static const struct usbmisc_ops *usbmisc_ops; @@ -134,20 +132,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - /* we only support host now, so enable vbus here */ - data-reg_vbus = devm_regulator_get(pdev-dev, vbus); - if (!IS_ERR(data-reg_vbus)) { - ret = regulator_enable(data-reg_vbus); - if (ret) { - dev_err(pdev-dev, - Failed to enable vbus regulator, err=%d\n, - ret); - goto err_clk; - } - } else { - data-reg_vbus = NULL; - } - pdata.phy = data-phy; if (!pdev-dev.dma_mask) @@ -160,7 +144,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) { dev_err(pdev-dev, usbmisc init failed, ret=%d\n, ret); - goto err; + goto err_clk; } } @@ -172,7 +156,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_err(pdev-dev, Can't register ci_hdrc platform device, err=%d\n, ret); - goto err; + goto err_clk; } if (usbmisc_ops usbmisc_ops-post) { @@ -193,9 +177,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data-ci_pdev); -err: - if (data-reg_vbus) - regulator_disable(data-reg_vbus); err_clk: clk_disable_unprepare(data-clk); return ret; @@ -208,9 +189,6 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) pm_runtime_disable(pdev-dev); ci_hdrc_remove_device(data-ci_pdev); - if (data-reg_vbus) - regulator_disable(data-reg_vbus); - if (data-phy) { usb_phy_shutdown(data-phy); module_put(data-phy-dev-driver-owner); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a5df24c..178b61d 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -57,6 +57,7 @@ #include linux/interrupt.h #include linux/io.h #include linux/kernel.h +#include linux/regulator/consumer.h #include linux/slab.h #include linux/pm_runtime.h #include linux/usb/ch9.h @@ -363,6 +364,21 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, goto put_id; } + /* Get the vbus regulator */ + platdata-reg_vbus = devm_regulator_get(dev, vbus); + if (PTR_ERR(platdata-reg_vbus) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err; + } else if (PTR_ERR(platdata-reg_vbus) == -ENODEV) { + platdata-reg_vbus = NULL; /* no vbus regualator is needed */ + } else if (IS_ERR(platdata-reg_vbus)) { + dev_err(pdev-dev, + Getting regulator error: %ld\n, + PTR_ERR(platdata-reg_vbus)); + ret = PTR_ERR(platdata-reg_vbus); + goto err; + } + pdev-dev.parent = dev; Michael, thanks to do this for me. One small suggestion is: it is better add one function like: ci_get_platdata, and move the vbus stuff to that function. This function is used to get common thing from glue layer. And it is better at the beginning of ci_hdrc_add_device, since the other code at ci_hdrc_add_device are all related to core device. I can help to do refine this patch (with some typo which Felipe mentioned
Re: [PATCH 2/2] chipidea: Use devm_request_irq()
On Wed, Jul 31, 2013 at 09:33:06AM +0200, Uwe Kleine-König wrote: On Tue, Jul 30, 2013 at 10:04:29PM -0300, Fabio Estevam wrote: From: Fabio Estevam fabio.este...@freescale.com By using devm_request_irq() we don't need to call free_irq(), which simplifies the code a bit. Signed-off-by: Fabio Estevam fabio.este...@freescale.com --- drivers/usb/chipidea/core.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 5cc1b02..d185c41 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -502,8 +502,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, ci); - ret = request_irq(ci-irq, ci_irq, IRQF_SHARED, ci-platdata-name, - ci); + ret = devm_request_irq(dev, ci-irq, ci_irq, IRQF_SHARED, + ci-platdata-name, ci); Mark Brown (now on Cc:) replied to one of my patches using devm_request_irq: I'm always deeply suspicous of devm_request_irq() since you need to be *very* sure that the interrupt can't fire during cleanup and cause the handlers to try to use data structures that are already being freed. and: devm_request_threaded_irq() is just generally a bit of a warning sign since it needs careful checking to tell if it's safe. The probably problem I find is the free_irq will be called after driver's removal is called, then the problem Mark described will occur. See __device_release_driver(struct device *dev) at drivers/base/dd.c. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] chipidea: Use devm_request_irq()
On Wed, Jul 31, 2013 at 9:27 PM, Mark Brown broo...@kernel.org wrote: On Wed, Jul 31, 2013 at 07:55:27AM -0400, Tejun Heo wrote: If you have DMA / IRQ / command engine deactivations in devm path which often is the case with full conversions, freeing any resources including DMA areas and host private data in the wrong order is a horrible idea. It's worse as it won't really be noticeable in most cases. It's really only interrupts that affect most devices - if there's DMA or anything going on after the remove() then as you said earlier the driver is probably doing something wrong. I think the main point is we should allocate managed resource which is used at interrupt handler before devm_request_irq, and all resources used at interrupt handler should be managed. If we use non-managed resource at interrupt handler, but using managed interrupt handler, things still will go wrong if there is an odd (unexpected) interrupt after we finish deactivation at removal. -- BR, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] chipidea: Use devm_request_irq()
On Wed, Jul 31, 2013 at 10:15:12AM -0400, Tejun Heo wrote: hello, On Wed, Jul 31, 2013 at 09:55:26PM +0800, Peter Chen wrote: I think the main point is we should allocate managed resource which is used at interrupt handler before devm_request_irq, and all resources used at interrupt handler should be managed. If we use non-managed resource at interrupt handler, but using managed interrupt handler, things still will go wrong if there is an odd (unexpected) interrupt after we finish deactivation at removal. In general, applying devm partially isn't a good idea. It's very easy to get into trouble thanks to release order dependency which isn't immediately noticeable and there have been actual bugs caused by that. The strategies which seem to work are either * Convert everything over to devm by wrapping deactivation in a devres callback too. As long as your init sequence is sane (ie. irq shouldn't be request before things used by irq are ready). * Allocate all resources using devres but shut down the execution engine in the remove_one(). Again, as all releases are controlled by devres, you won't have to worry about messing up the release sequencing. thanks, Tejun. So, Alex and Fabio, this patch may not be suitable currently, since many resources at both EHCI and device side are non-managed. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/4] usb: chipidea: improve kconfig 2.0
On Wed, Jul 31, 2013 at 04:21:13PM +0200, Lothar Waßmann wrote: This patch provides a cleaner solution to the problem described in commit 20a677fd. The goal to be achieved is to force USB_CHIPIDEA=m if either USB_EHCI_HCD=m or USB_GADGET=m. If both are 'y' USB_CHIPIDEA may be selected to be 'm' or 'y'. The old patch had the drawback, that USB_CHIPIDEA could be chosen as 'y' though USB_EHCI_HCD or USB_GADGET (or both) were 'm' leading to a situation where USB_CHIPIDEA_HOST or USB_CHIPIDEA_UDC vanished from the config options producing a compilable but dysfunctional driver. Signed-off-by: Lothar Waßmann l...@karo-electronics.de --- drivers/usb/chipidea/Kconfig |7 +++ 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index d1bd8ef..4a851e1 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -1,6 +1,6 @@ config USB_CHIPIDEA tristate ChipIdea Highspeed Dual Role Controller - depends on USB || USB_GADGET + depends on (USB_EHCI_HCD USB_GADGET) || (USB_EHCI_HCD !USB_GADGET) || (!USB_EHCI_HCD USB_GADGET) help Say Y here if your system has a dual role high speed USB controller based on ChipIdea silicon IP. Currently, only the @@ -12,15 +12,14 @@ if USB_CHIPIDEA config USB_CHIPIDEA_UDC bool ChipIdea device controller - depends on USB_GADGET=y || (USB_CHIPIDEA=m USB_GADGET=m) + depends on USB_GADGET help Say Y here to enable device controller functionality of the ChipIdea driver. config USB_CHIPIDEA_HOST bool ChipIdea host controller - depends on USB=y - depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m USB_EHCI_HCD=m) + depends on USB_EHCI_HCD select USB_EHCI_ROOT_HUB_TT help Say Y here to enable host controller functionality of the -- Reviewed-by: Peter Chen peter.c...@freescale.com Hi Alex, Lothar's solution is better than mine, please forget mine: http://marc.info/?l=linux-usbm=137331577104110w=2 After you apply Lothar's patch, please also apply mine fixup ehci host's config patch http://marc.info/?l=linux-usbm=137331577404223w=2 -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/4] usb: chipidea: ci_hdrc_imx: remove an unsolicited module_put() call from ci_hdrc_imx_remove()
On Wed, Jul 31, 2013 at 04:21:14PM +0200, Lothar Waßmann wrote: This prevents the USB PHY refcount to be decremented below zero upon unloading the ci-hdrc-imx module. Signed-off-by: Lothar Waßmann l...@karo-electronics.de --- drivers/usb/chipidea/ci_hdrc_imx.c |4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 14362c0..802eab1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -218,10 +218,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) if (data-reg_vbus) regulator_disable(data-reg_vbus); - if (data-phy) { + if (data-phy) usb_phy_shutdown(data-phy); - module_put(data-phy-dev-driver-owner); - } clk_disable_unprepare(data-clk); Have you met warning? devm_usb_get_phy_by_phandle at probe calls try_module_get. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/4] usb: chipidea: don't clobber return value of ci_role_start()
On Wed, Jul 31, 2013 at 04:21:15PM +0200, Lothar Waßmann wrote: Signed-off-by: Lothar Waßmann l...@karo-electronics.de --- drivers/usb/chipidea/core.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a5df24c..38b0a7a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -497,7 +497,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) ret = ci_role_start(ci, ci-role); if (ret) { dev_err(dev, can't start %s role\n, ci_role(ci)-name); - ret = -ENODEV; goto rm_wq; } +1, it can help get the error one time, without need to add the code and get the error number from ci_role_start again. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 4/4] usb: chipidea: Prevent endless loop registering platform_devices when ci_hdrc_probe() fails.
On Wed, Jul 31, 2013 at 04:21:16PM +0200, Lothar Waßmann wrote: commit 40dcd0e introduced the following code to the ci_hdrc_probe() function: + if (!dev-of_node dev-parent) + dev-of_node = dev-parent-of_node; This inadvertently associates the ci_hdrc device with the ci_hdrc_imx driver (which created the ci_hdrc device in the first place). This results in ci_hdrc_imx_probe() being run for the ci_hdrc device if ci_hdrc_probe() fails for some reason. ci_hdrc_imx_probe() will happily create a new ci_hdrc platform_device whose probing will likewise fail and trigger a new invocation of ci_hdrc_imx_probe() ... ad nauseam. Sorry, I can't understand how it happenes? -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/4] usb: chipidea: ci_hdrc_imx: remove an unsolicited module_put() call from ci_hdrc_imx_remove()
On Thu, Aug 01, 2013 at 10:38:18AM +0200, Lothar Waßmann wrote: Hi, Peter Chen writes: On Wed, Jul 31, 2013 at 04:21:14PM +0200, Lothar Waßmann wrote: This prevents the USB PHY refcount to be decremented below zero upon unloading the ci-hdrc-imx module. Signed-off-by: Lothar Waßmann l...@karo-electronics.de --- drivers/usb/chipidea/ci_hdrc_imx.c |4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 14362c0..802eab1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -218,10 +218,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) if (data-reg_vbus) regulator_disable(data-reg_vbus); - if (data-phy) { + if (data-phy) usb_phy_shutdown(data-phy); - module_put(data-phy-dev-driver-owner); - } clk_disable_unprepare(data-clk); Have you met warning? devm_usb_get_phy_by_phandle at probe calls try_module_get. Since it is a 'devm_*' function I would vouch that it also takes care of the module_put() automagically. Just try loading and unloading the ci-hdrc-imx module and look at the resulting refcount of the mxs_usb_phy module. refcounting is OK without the module_put() here. Oh, yes, it calls module_put at usb_put_phy when devm_xxx_release is called. Acked-by: Peter Chen peter.c...@freescale.com -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/4] usb: chipidea: don't clobber return value of ci_role_start()
On Thu, Aug 01, 2013 at 10:40:42AM +0200, Lothar Waßmann wrote: Hi, Peter Chen writes: On Wed, Jul 31, 2013 at 04:21:15PM +0200, Lothar Waßmann wrote: Signed-off-by: Lothar Waßmann l...@karo-electronics.de --- drivers/usb/chipidea/core.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a5df24c..38b0a7a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -497,7 +497,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) ret = ci_role_start(ci, ci-role); if (ret) { dev_err(dev, can't start %s role\n, ci_role(ci)-name); - ret = -ENODEV; goto rm_wq; } +1, it can help get the error one time, without need to add the code and get the error number from ci_role_start again. I don't get what you mean. For example, the ci_role_start returns error, the user can't get error message directly, it can only get -ENODEV. If the user wants to get what's error at ci_role_start, he needs to add another debug message and re-compile the kernel. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 4/4] usb: chipidea: Prevent endless loop registering platform_devices when ci_hdrc_probe() fails.
On Thu, Aug 01, 2013 at 10:43:52AM +0200, Lothar Waßmann wrote: Hi, Peter Chen writes: On Wed, Jul 31, 2013 at 04:21:16PM +0200, Lothar Waßmann wrote: commit 40dcd0e introduced the following code to the ci_hdrc_probe() function: + if (!dev-of_node dev-parent) + dev-of_node = dev-parent-of_node; This inadvertently associates the ci_hdrc device with the ci_hdrc_imx driver (which created the ci_hdrc device in the first place). This results in ci_hdrc_imx_probe() being run for the ci_hdrc device if ci_hdrc_probe() fails for some reason. ci_hdrc_imx_probe() will happily create a new ci_hdrc platform_device whose probing will likewise fail and trigger a new invocation of ci_hdrc_imx_probe() ... ad nauseam. Sorry, I can't understand how it happenes? If ci_hdrc_probe() fails, the driver core will look for other drivers that might be able to handle the device. Since the of_node has been copied from the parent device imx_usb the driver responsible for the DT match of of_node (ci_hdrc_imx) will be called. Good fix. Reviewed-and-Tested-by: Peter Chen peter.c...@freescale.com -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: USB Interrupt Transaction Scheduling
On Thu, Aug 01, 2013 at 12:14:18PM -0300, Fabio Estevam wrote: Hi Nate, On Tue, Jul 30, 2013 at 6:33 PM, Stoddard, Nate (GE Healthcare) nate.stodd...@med.ge.com wrote: So you would expect a temporary CPU increase when a device is connected or reset since the scheduler will need to set up when the packets will be transferred. Once this is complete, the CPU should return to a lower amount as The reset function at drivers/usb/chipidea/core.c has the following: int hw_device_reset(struct ci_hdrc *ci, u32 mode) { /* should flush stop before reset */ hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); hw_write(ci, OP_USBCMD, USBCMD_RS, 0); hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); while (hw_read(ci, OP_USBCMD, USBCMD_RST)) udelay(10); /* not RTOS friendly */ Maybe this udelay is impacting your performance? It seems that this should be rewritten to avoid the busy loop. No, it is not related to this problem, this function is only called at device mode. All EHCI related is controlled by EHCI core. Currently, we still not override anything for host. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: USB Interrupt Transaction Scheduling
On Tue, Jul 30, 2013 at 09:33:39PM +, Stoddard, Nate (GE Healthcare) wrote: The driver has to set up the data structures for the transfers, which includes scheduling when the SSPLIT and CSPLIT transactions will occur and figuring out how much bandwidth they will consume. The transactions themselves are handled entirely by the EHCI hardware. So you would expect a temporary CPU increase when a device is connected or reset since the scheduler will need to set up when the packets will be transferred. Once this is complete, the CPU should return to a lower amount as the EHCI hardware would be processing the various packet sending: setup tokens, ACK/NAK handshaking, and split packets? I ask because we are seeing much higher constant CPU usage on our target hardware (iMX535) than we are seeing on the test PC. Do you have any recommendations for a good way to confirm the target EHCI hardware is being utilized? Is there a location to instrument in one of the ehci host files (ehci-hcd.c or ehci-q.c)? When the transfer begins, the things are almost the same for all SoCs. The possible reason is you may use an old kernel (2.6.35), and EHCI core is improved. At your old email, you said the cpu utilities will be less at higher kernel version at PC. I think the best way is using newest kernel and newest libusb. Try to find a mx53 board which is supported by upstream kernel, and re-do the test. I don't see how you could have gotten more than 15 interrupt endpoints running at the same time unless the endpoints' bInterval value was larger than 1. On all 7 devices, the IN and OUT interrupt endpoints have bInterval = 1 wMaxPacketSize = 64. Do you think this is worth pursuing? It sounds like a bug, although it might not be. We will re-run the tests with more rigor to confirm the results. I will post the details. -Nate -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 01/12] usb: chipidea: move vbus regulator operation to core
The vbus regulator is a common element for USB vbus operation, So, move it from glue layer to core. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Michael Grzeschik m.grzesc...@pengutronix.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c | 26 ++ drivers/usb/chipidea/core.c| 23 +++ include/linux/usb/chipidea.h |1 + 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index e04611f..b886998 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -19,7 +19,6 @@ #include linux/dma-mapping.h #include linux/usb/chipidea.h #include linux/clk.h -#include linux/regulator/consumer.h #include ci.h #include ci_hdrc_imx.h @@ -31,7 +30,6 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; - struct regulator *reg_vbus; }; static const struct usbmisc_ops *usbmisc_ops; @@ -134,20 +132,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - /* we only support host now, so enable vbus here */ - data-reg_vbus = devm_regulator_get(pdev-dev, vbus); - if (!IS_ERR(data-reg_vbus)) { - ret = regulator_enable(data-reg_vbus); - if (ret) { - dev_err(pdev-dev, - Failed to enable vbus regulator, err=%d\n, - ret); - goto err_clk; - } - } else { - data-reg_vbus = NULL; - } - pdata.phy = data-phy; if (!pdev-dev.dma_mask) @@ -160,7 +144,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) { dev_err(pdev-dev, usbmisc init failed, ret=%d\n, ret); - goto err; + goto err_clk; } } @@ -172,7 +156,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_err(pdev-dev, Can't register ci_hdrc platform device, err=%d\n, ret); - goto err; + goto err_clk; } if (usbmisc_ops usbmisc_ops-post) { @@ -193,9 +177,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data-ci_pdev); -err: - if (data-reg_vbus) - regulator_disable(data-reg_vbus); err_clk: clk_disable_unprepare(data-clk); return ret; @@ -208,9 +189,6 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) pm_runtime_disable(pdev-dev); ci_hdrc_remove_device(data-ci_pdev); - if (data-reg_vbus) - regulator_disable(data-reg_vbus); - if (data-phy) usb_phy_shutdown(data-phy); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 3126c03..26f6599 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -65,6 +65,7 @@ #include linux/usb/chipidea.h #include linux/usb/of.h #include linux/phy.h +#include linux/regulator/consumer.h #include ci.h #include udc.h @@ -342,6 +343,24 @@ static irqreturn_t ci_irq(int irq, void *data) return ret; } +static int ci_get_platdata(struct device *dev, + struct ci_hdrc_platform_data *platdata) +{ + /* Get the vbus regulator */ + platdata-reg_vbus = devm_regulator_get(dev, vbus); + if (PTR_ERR(platdata-reg_vbus) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (PTR_ERR(platdata-reg_vbus) == -ENODEV) { + platdata-reg_vbus = NULL; /* no vbus regualator is needed */ + } else if (IS_ERR(platdata-reg_vbus)) { + dev_err(dev, Getting regulator error: %ld\n, + PTR_ERR(platdata-reg_vbus)); + return PTR_ERR(platdata-reg_vbus); + } + + return 0; +} + static DEFINE_IDA(ci_ida); struct platform_device *ci_hdrc_add_device(struct device *dev, @@ -351,6 +370,10 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, struct platform_device *pdev; int id, ret; + ret = ci_get_platdata(dev, platdata); + if (ret) + return ERR_PTR(ret); + id = ida_simple_get(ci_ida, 0, 0, GFP_KERNEL); if (id 0) return ERR_PTR(id); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 2562994..ce4e1aa 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -24,6 +24,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 void(*notify_event) (struct ci_hdrc *ci
[PATCH v14 04/12] usb: chipidea: otg: Add otg file used to access otgsc
This file is mainly used to access otgsc currently, it may add otg related things in the future. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h | 10 drivers/usb/chipidea/core.c |3 +- drivers/usb/chipidea/otg.c| 50 + drivers/usb/chipidea/otg.h| 19 +++ 5 files changed, 82 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 6cf5f68..a99d980 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o -ci_hdrc-y := core.o +ci_hdrc-y := core.o otg.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)+= host.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index aefa026..dd0cf9e 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -79,11 +79,21 @@ #define OTGSC_ASVIS BIT(18) #define OTGSC_BSVIS BIT(19) #define OTGSC_BSEIS BIT(20) +#define OTGSC_1MSIS BIT(21) +#define OTGSC_DPIS BIT(22) #define OTGSC_IDIE BIT(24) #define OTGSC_AVVIE BIT(25) #define OTGSC_ASVIE BIT(26) #define OTGSC_BSVIE BIT(27) #define OTGSC_BSEIE BIT(28) +#define OTGSC_1MSIE BIT(29) +#define OTGSC_DPIE BIT(30) +#define OTGSC_INT_EN_BITS (OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \ + | OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \ + | OTGSC_DPIE) +#define OTGSC_INT_STATUS_BITS (OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS \ + | OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \ + | OTGSC_DPIS) /* USBMODE */ #define USBMODE_CM(0x03UL 0) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 26f6599..a4be8a5 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -72,6 +72,7 @@ #include bits.h #include host.h #include debug.h +#include otg.h /* Controller register map */ static uintptr_t ci_regs_nolpm[] = { @@ -530,7 +531,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) goto stop; if (ci-is_otg) - hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); + ci_hdrc_otg_init(ci); ret = dbg_create_files(ci); if (!ret) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c new file mode 100644 index 000..abefb4d --- /dev/null +++ b/drivers/usb/chipidea/otg.c @@ -0,0 +1,50 @@ +/* + * otg.c - ChipIdea USB IP core OTG driver + * + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Author: Peter Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This file mainly handles otgsc register, it may include OTG operation + * in the future. + */ + +#include linux/usb/otg.h +#include linux/usb/gadget.h +#include linux/usb/chipidea.h + +#include ci.h +#include bits.h + +void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + /* Only clear request bits */ + hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits); +} + +void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, bits); +} + +void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, 0); +} + +/** + * ci_hdrc_otg_init - initialize otgsc bits + * ci: the controller + */ +int ci_hdrc_otg_init(struct ci_hdrc *ci) +{ + ci_enable_otg_interrupt(ci, OTGSC_IDIE); + + return 0; +} diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h new file mode 100644 index 000..f24ec37 --- /dev/null +++ b/drivers/usb/chipidea/otg.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Author: Peter Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_OTG_H +#define __DRIVERS_USB_CHIPIDEA_OTG_H + +int ci_hdrc_otg_init(struct ci_hdrc *ci); +void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits); +void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits); +void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits); + +#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body
[PATCH v14 05/12] usb: chipidea: Add role init and destory APIs
- The role's init will be called at probe procedure. - The role's destory will be called at fail patch at probe and driver's removal. - The role's start/stop will be called when specific role has started. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 10 -- drivers/usb/chipidea/host.c |7 +++ drivers/usb/chipidea/host.h |6 ++ drivers/usb/chipidea/udc.c | 36 +++- drivers/usb/chipidea/udc.h |6 ++ 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a4be8a5..bfc9aef 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -420,6 +420,12 @@ void ci_hdrc_remove_device(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); +static inline void ci_role_destroy(struct ci_hdrc *ci) +{ + ci_hdrc_gadget_destroy(ci); + ci_hdrc_host_destroy(ci); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = pdev-dev; @@ -539,7 +545,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) free_irq(ci-irq, ci); stop: - ci_role_stop(ci); + ci_role_destroy(ci); rm_wq: flush_workqueue(ci-wq); destroy_workqueue(ci-wq); @@ -555,7 +561,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) flush_workqueue(ci-wq); destroy_workqueue(ci-wq); free_irq(ci-irq, ci); - ci_role_stop(ci); + ci_role_destroy(ci); return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index e94e52b..382be5b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -105,6 +105,13 @@ static void host_stop(struct ci_hdrc *ci) regulator_disable(ci-platdata-reg_vbus); } + +void ci_hdrc_host_destroy(struct ci_hdrc *ci) +{ + if (ci-role == CI_ROLE_HOST) + host_stop(ci); +} + int ci_hdrc_host_init(struct ci_hdrc *ci) { struct ci_role_driver *rdrv; diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h index 058875c..5707bf3 100644 --- a/drivers/usb/chipidea/host.h +++ b/drivers/usb/chipidea/host.h @@ -4,6 +4,7 @@ #ifdef CONFIG_USB_CHIPIDEA_HOST int ci_hdrc_host_init(struct ci_hdrc *ci); +void ci_hdrc_host_destroy(struct ci_hdrc *ci); #else @@ -12,6 +13,11 @@ static inline int ci_hdrc_host_init(struct ci_hdrc *ci) return -ENXIO; } +static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci) +{ + +} + #endif #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 116c762..24a100d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -27,6 +27,7 @@ #include udc.h #include bits.h #include debug.h +#include otg.h /* control endpoint description */ static const struct usb_endpoint_descriptor @@ -1844,13 +1845,13 @@ free_qh_pool: } /** - * udc_remove: parent remove must call this to remove UDC + * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC * * No interrupts active, the IRQ has been released */ -static void udc_stop(struct ci_hdrc *ci) +void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) { - if (ci == NULL) + if (!ci-roles[CI_ROLE_GADGET]) return; usb_del_gadget_udc(ci-gadget); @@ -1865,15 +1866,32 @@ static void udc_stop(struct ci_hdrc *ci) if (ci-global_phy) usb_put_phy(ci-transceiver); } - /* my kobject is dynamic, I swear! */ - memset(ci-gadget, 0, sizeof(ci-gadget)); +} + +static int udc_id_switch_for_device(struct ci_hdrc *ci) +{ + if (ci-is_otg) { + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); + ci_enable_otg_interrupt(ci, OTGSC_BSVIE); + } + + return 0; +} + +static void udc_id_switch_for_host(struct ci_hdrc *ci) +{ + if (ci-is_otg) { + /* host doesn't care B_SESSION_VALID event */ + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); + ci_disable_otg_interrupt(ci, OTGSC_BSVIE); + } } /** * ci_hdrc_gadget_init - initialize device related bits * ci: the controller * - * This function enables the gadget role, if the device is device capable. + * This function initializes the gadget, if the device is device capable. */ int ci_hdrc_gadget_init(struct ci_hdrc *ci) { @@ -1886,11 +1904,11 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci) if (!rdrv) return -ENOMEM; - rdrv-start = udc_start; - rdrv-stop = udc_stop; + rdrv-start = udc_id_switch_for_device; + rdrv-stop = udc_id_switch_for_host; rdrv-irq = udc_irq; rdrv-name = gadget; ci-roles[CI_ROLE_GADGET] = rdrv; - return 0; + return udc_start(ci); } diff
[PATCH v14 06/12] usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG
Since we need otgsc to know vbus's status at some chipidea controllers even it is peripheral-only mode. Besides, some SoCs (eg, AR9331 SoC) don't have otgsc register even the DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS. We inroduce flag CI_HDRC_DUAL_ROLE_NOT_OTG to indicate if the controller is dual role, but not supports OTG. If this flag is not set, we follow the rule that if DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS, then this controller is otg capable. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 38 +++--- include/linux/usb/chipidea.h |5 + 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index bfc9aef..2ae18fd 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -426,6 +426,18 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) ci_hdrc_host_destroy(ci); } +static void ci_get_otg_capable(struct ci_hdrc *ci) +{ + if (ci-platdata-flags CI_HDRC_DUAL_ROLE_NOT_OTG) + ci-is_otg = false; + else + ci-is_otg = (hw_read(ci, CAP_DCCPARAMS, + DCCPARAMS_DC | DCCPARAMS_HC) + == (DCCPARAMS_DC | DCCPARAMS_HC)); + if (ci-is_otg) + dev_dbg(ci-dev, It is OTG capable controller\n); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = pdev-dev; @@ -482,6 +494,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } + /* To know if controller is OTG capable or not */ + ci_get_otg_capable(ci); + if (!ci-platdata-phy_mode) ci-platdata-phy_mode = of_usb_get_phy_mode(dev-of_node); @@ -514,10 +529,22 @@ static int ci_hdrc_probe(struct platform_device *pdev) } if (ci-roles[CI_ROLE_HOST] ci-roles[CI_ROLE_GADGET]) { - ci-is_otg = true; - /* ID pin needs 1ms debouce time, we delay 2ms for safe */ - mdelay(2); - ci-role = ci_otg_role(ci); + if (ci-is_otg) { + /* +* ID pin needs 1ms debouce time, +* we delay 2ms for safe. +*/ + mdelay(2); + ci-role = ci_otg_role(ci); + ci_hdrc_otg_init(ci); + } else { + /* +* If the controller is not OTG capable, but support +* role switch, the defalt role is gadget, and the +* user can switch it through debugfs (proc in future?) +*/ + ci-role = CI_ROLE_GADGET; + } } else { ci-role = ci-roles[CI_ROLE_HOST] ? CI_ROLE_HOST @@ -536,9 +563,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; - if (ci-is_otg) - ci_hdrc_otg_init(ci); - ret = dbg_create_files(ci); if (!ret) return 0; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ce4e1aa..10a607c 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -20,6 +20,11 @@ struct ci_hdrc_platform_data { #define CI_HDRC_REQUIRE_TRANSCEIVERBIT(1) #define CI_HDRC_PULLUP_ON_VBUS BIT(2) #define CI_HDRC_DISABLE_STREAMING BIT(3) + /* +* Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, +* but otg is not supported (no register otgsc). +*/ +#define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) enum usb_dr_modedr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 07/12] usb: chipidea: disable all interrupts and clear all interrupts status
During the initialization, it needs to disable all interrupts enable bit as well as clear all interrupts status bits to avoid exceptional interrupt. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 11 ++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 2ae18fd..2223954 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -199,6 +199,12 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) if (ci-hw_ep_max ENDPT_MAX) return -ENODEV; + /* Disable all interrupts bits */ + hw_write(ci, OP_USBINTR, 0x, 0); + + /* Clear all interrupts status bits*/ + hw_write(ci, OP_USBSTS, 0x, 0x); + dev_dbg(ci-dev, ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n, ci-hw_bank.lpm, ci-hw_bank.cap, ci-hw_bank.op); @@ -434,8 +440,11 @@ static void ci_get_otg_capable(struct ci_hdrc *ci) ci-is_otg = (hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC | DCCPARAMS_HC) == (DCCPARAMS_DC | DCCPARAMS_HC)); - if (ci-is_otg) + if (ci-is_otg) { dev_dbg(ci-dev, It is OTG capable controller\n); + ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); + ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); + } } static int ci_hdrc_probe(struct platform_device *pdev) -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 03/12] usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users
It is useless at below cases: - If we implement both usb host and device at chipidea driver. - If we don't need phy-otg. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |7 ++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index e475fcd..116c762 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1805,7 +1805,12 @@ static int udc_start(struct ci_hdrc *ci) if (ci-transceiver) { retval = otg_set_peripheral(ci-transceiver-otg, ci-gadget); - if (retval) + /* +* If we implement all USB functions using chipidea drivers, +* it doesn't need to call above API, meanwhile, if we only +* use gadget function, calling above API is useless. +*/ + if (retval retval != -ENOTSUPP) goto put_transceiver; } -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 11/12] usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS
CI_HDRC_REGS_SHARED stands for the controller registers is shared with other USB drivers, if all USB drivers are at chipidea/, it doesn't needed to set. CI_HDRC_PULLUP_ON_VBUS stands for pullup dp when the vbus is on. This flag doesn't need to set if the vbus is always on for gadget since dp has always pulled up after the gadget has initialized. So, the current code seems to misuse this two flags. - When the gadget initializes, the controller doesn't need to run if it depends on vbus (CI_HDRC_PULLUP_ON_VBUS), it does not relate to shared register. - When the gadget starts (load one gadget module), the controller can run if vbus is on (CI_HDRC_PULLUP_ON_VBUS), it also does not relate to shared register. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index c70ce38..45abf4d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1637,8 +1637,7 @@ static int ci_udc_start(struct usb_gadget *gadget, pm_runtime_get_sync(ci-gadget.dev); if (ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) { if (ci-vbus_active) { - if (ci-platdata-flags CI_HDRC_REGS_SHARED) - hw_device_reset(ci, USBMODE_CM_DC); + hw_device_reset(ci, USBMODE_CM_DC); } else { pm_runtime_put_sync(ci-gadget.dev); goto done; @@ -1801,7 +1800,7 @@ static int udc_start(struct ci_hdrc *ci) } } - if (!(ci-platdata-flags CI_HDRC_REGS_SHARED)) { + if (!(ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS)) { retval = hw_device_reset(ci, USBMODE_CM_DC); if (retval) goto put_transceiver; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 02/12] usb: chipidea: host: add vbus regulator control
For boards which have board level vbus control (eg, through gpio), we need to vbus operation according to below rules: - For host, we need open vbus before start hcd, and close it after remove hcd. - For otg, the vbus needs to be on/off when usb role switches. When the host roles begins, it opens vbus; when the host role finishes, it closes vbus. We put vbus operation to host as host is the only vbus user, When we are at host mode, the vbus is on, when we are not at host mode, vbus should be off. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/host.c | 23 ++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 40d0fda..e94e52b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -24,6 +24,7 @@ #include linux/usb.h #include linux/usb/hcd.h #include linux/usb/chipidea.h +#include linux/regulator/consumer.h #include ../host/ehci.h @@ -64,9 +65,19 @@ static int host_start(struct ci_hdrc *ci) ehci-caps = ci-hw_bank.cap; ehci-has_hostpc = ci-hw_bank.lpm; + if (ci-platdata-reg_vbus) { + ret = regulator_enable(ci-platdata-reg_vbus); + if (ret) { + dev_err(ci-dev, + Failed to enable vbus regulator, ret=%d\n, + ret); + goto put_hcd; + } + } + ret = usb_add_hcd(hcd, 0, 0); if (ret) - usb_put_hcd(hcd); + goto disable_reg; else ci-hcd = hcd; @@ -74,6 +85,14 @@ static int host_start(struct ci_hdrc *ci) hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); return ret; + +disable_reg: + regulator_disable(ci-platdata-reg_vbus); + +put_hcd: + usb_put_hcd(hcd); + + return ret; } static void host_stop(struct ci_hdrc *ci) @@ -82,6 +101,8 @@ static void host_stop(struct ci_hdrc *ci) usb_remove_hcd(hcd); usb_put_hcd(hcd); + if (ci-platdata-reg_vbus) + regulator_disable(ci-platdata-reg_vbus); } int ci_hdrc_host_init(struct ci_hdrc *ci) -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 09/12] usb: chipidea: add vbus interrupt handler
We add vbus interrupt handler at ci_otg_work, it uses OTGSC_BSV(at otgsc) to know it is connect or disconnet event. Meanwhile, we introduce two flags id_event and b_sess_valid_event to indicate it is an id interrupt or a vbus interrupt. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci.h |5 + drivers/usb/chipidea/core.c | 28 +++- drivers/usb/chipidea/otg.c | 42 +++--- drivers/usb/chipidea/otg.h |1 + drivers/usb/chipidea/udc.c |7 +++ 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 33cb29f..3160363 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -132,6 +132,9 @@ struct hw_bank { * @transceiver: pointer to USB PHY, if any * @hcd: pointer to usb_hcd for ehci host driver * @debugfs: root dentry for this controller in debugfs + * @id_event: indicates there is an id event, and handled at ci_otg_work + * @b_sess_valid_event: indicates there is a vbus event, and handled + * at ci_otg_work */ struct ci_hdrc { struct device *dev; @@ -168,6 +171,8 @@ struct ci_hdrc { struct usb_phy *transceiver; struct usb_hcd *hcd; struct dentry *debugfs; + boolid_event; + boolb_sess_valid_event; }; static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 30be811..0e69282 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -303,16 +303,34 @@ static irqreturn_t ci_irq(int irq, void *data) if (ci-is_otg) otgsc = hw_read(ci, OP_OTGSC, ~0); - if (ci-role != CI_ROLE_END) - ret = ci_role(ci)-irq(ci); + /* +* Handle id change interrupt, it indicates device/host function +* switch. +*/ + if (ci-is_otg (otgsc OTGSC_IDIE) (otgsc OTGSC_IDIS)) { + ci-id_event = true; + ci_clear_otg_interrupt(ci, OTGSC_IDIS); + disable_irq_nosync(ci-irq); + queue_work(ci-wq, ci-work); + return IRQ_HANDLED; + } - if (ci-is_otg (otgsc OTGSC_IDIS)) { - hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS); + /* +* Handle vbus change interrupt, it indicates device connection +* and disconnection events. +*/ + if (ci-is_otg (otgsc OTGSC_BSVIE) (otgsc OTGSC_BSVIS)) { + ci-b_sess_valid_event = true; + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); disable_irq_nosync(ci-irq); queue_work(ci-wq, ci-work); - ret = IRQ_HANDLED; + return IRQ_HANDLED; } + /* Handle device/host interrupt */ + if (ci-role != CI_ROLE_END) + ret = ci_role(ci)-irq(ci); + return ret; } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 68f2faf..c74194d 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -52,13 +52,23 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) return role; } -/** - * ci_role_work - perform role changing based on ID pin - * @work: work struct - */ -static void ci_role_work(struct work_struct *work) +void ci_handle_vbus_change(struct ci_hdrc *ci) +{ + u32 otgsc; + + if (!ci-is_otg) + return; + + otgsc = hw_read(ci, OP_OTGSC, ~0); + + if (otgsc OTGSC_BSV) + usb_gadget_vbus_connect(ci-gadget); + else + usb_gadget_vbus_disconnect(ci-gadget); +} + +static void ci_handle_id_switch(struct ci_hdrc *ci) { - struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); enum ci_role role = ci_otg_role(ci); if (role != ci-role) { @@ -68,17 +78,35 @@ static void ci_role_work(struct work_struct *work) ci_role_stop(ci); ci_role_start(ci, role); } +} +/** + * ci_otg_work - perform otg (vbus/id) event handle + * @work: work struct + */ +static void ci_otg_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + + if (ci-id_event) { + ci-id_event = false; + ci_handle_id_switch(ci); + } else 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__); enable_irq(ci-irq); } + /** * ci_hdrc_otg_init - initialize otg struct * ci: the controller */ int ci_hdrc_otg_init(struct ci_hdrc *ci) { - INIT_WORK(ci-work, ci_role_work); + INIT_WORK(ci-work
[PATCH v14 10/12] usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts
When the gadget role starts, we need to make sure the vbus is lower than OTGSC_BSV, or there will be an vbus interrupt since we use B_SESSION_VALID as vbus interrupt to indicate connect and disconnect. When the host role starts, it may not be useful to wait vbus to lower than OTGSC_BSV, but it can indicate some hardware problems like the vbus is still higher than OTGSC_BSV after we disconnect to host some time later (5000 milliseconds currently), which is obvious not correct. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci.h |3 +++ drivers/usb/chipidea/core.c | 32 drivers/usb/chipidea/otg.c |4 3 files changed, 39 insertions(+), 0 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 3160363..1c94fc5 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -308,4 +308,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode); u8 hw_port_test_get(struct ci_hdrc *ci); +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, + u32 value, unsigned int timeout_ms); + #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 0e69282..f09b4db 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -294,6 +294,38 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) return 0; } +/** + * hw_wait_reg: wait the register value + * + * Sometimes, it needs to wait register value before going on. + * Eg, when switch to device mode, the vbus value should be lower + * than OTGSC_BSV before connects to host. + * + * @ci: the controller + * @reg: register index + * @mask: mast bit + * @value: the bit value to wait + * @timeout_ms: timeout in millisecond + * + * This function returns an error code if timeout + */ +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, + u32 value, unsigned int timeout_ms) +{ + unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); + + while (hw_read(ci, reg, mask) != value) { + if (time_after(jiffies, elapse)) { + dev_err(ci-dev, timeout waiting for %08x in %d\n, + mask, reg); + return -ETIMEDOUT; + } + msleep(20); + } + + return 0; +} + static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index c74194d..d39cce8 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -67,6 +67,7 @@ void ci_handle_vbus_change(struct ci_hdrc *ci) usb_gadget_vbus_disconnect(ci-gadget); } +#define CI_VBUS_STABLE_TIMEOUT_MS 5000 static void ci_handle_id_switch(struct ci_hdrc *ci) { enum ci_role role = ci_otg_role(ci); @@ -76,6 +77,9 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) ci_role(ci)-name, ci-roles[role]-name); ci_role_stop(ci); + /* wait vbus lower than OTGSC_BSV */ + hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0, + CI_VBUS_STABLE_TIMEOUT_MS); ci_role_start(ci, role); } } -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 08/12] usb: chipidea: move otg relate things to otg file
Move otg relate things to otg file. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 63 +-- drivers/usb/chipidea/otg.c | 57 +- drivers/usb/chipidea/otg.h |2 + 3 files changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 2223954..30be811 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -294,40 +294,6 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) return 0; } -/** - * ci_otg_role - pick role based on ID pin state - * @ci: the controller - */ -static enum ci_role ci_otg_role(struct ci_hdrc *ci) -{ - u32 sts = hw_read(ci, OP_OTGSC, ~0); - enum ci_role role = sts OTGSC_ID - ? CI_ROLE_GADGET - : CI_ROLE_HOST; - - return role; -} - -/** - * ci_role_work - perform role changing based on ID pin - * @work: work struct - */ -static void ci_role_work(struct work_struct *work) -{ - struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); - enum ci_role role = ci_otg_role(ci); - - if (role != ci-role) { - dev_dbg(ci-dev, switching from %s to %s\n, - ci_role(ci)-name, ci-roles[role]-name); - - ci_role_stop(ci); - ci_role_start(ci, role); - } - - enable_irq(ci-irq); -} - static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; @@ -430,6 +396,8 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) { ci_hdrc_gadget_destroy(ci); ci_hdrc_host_destroy(ci); + if (ci-is_otg) + ci_hdrc_otg_destory(ci); } static void ci_get_otg_capable(struct ci_hdrc *ci) @@ -496,13 +464,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - INIT_WORK(ci-work, ci_role_work); - ci-wq = create_singlethread_workqueue(ci_otg); - if (!ci-wq) { - dev_err(dev, can't create workqueue\n); - return -ENODEV; - } - /* To know if controller is OTG capable or not */ ci_get_otg_capable(ci); @@ -533,8 +494,15 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ci-roles[CI_ROLE_HOST] !ci-roles[CI_ROLE_GADGET]) { dev_err(dev, no supported roles\n); - ret = -ENODEV; - goto rm_wq; + return -ENODEV; + } + + if (ci-is_otg) { + ret = ci_hdrc_otg_init(ci); + if (ret) { + dev_err(dev, init otg fails, ret = %d\n, ret); + goto stop; + } } if (ci-roles[CI_ROLE_HOST] ci-roles[CI_ROLE_GADGET]) { @@ -545,7 +513,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) */ mdelay(2); ci-role = ci_otg_role(ci); - ci_hdrc_otg_init(ci); + ci_enable_otg_interrupt(ci, OTGSC_IDIE); } else { /* * If the controller is not OTG capable, but support @@ -563,7 +531,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) ret = ci_role_start(ci, ci-role); if (ret) { dev_err(dev, can't start %s role\n, ci_role(ci)-name); - goto rm_wq; + goto stop; } platform_set_drvdata(pdev, ci); @@ -579,9 +547,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) free_irq(ci-irq, ci); stop: ci_role_destroy(ci); -rm_wq: - flush_workqueue(ci-wq); - destroy_workqueue(ci-wq); return ret; } @@ -591,8 +556,6 @@ static int ci_hdrc_remove(struct platform_device *pdev) struct ci_hdrc *ci = platform_get_drvdata(pdev); dbg_remove_files(ci); - flush_workqueue(ci-wq); - destroy_workqueue(ci-wq); free_irq(ci-irq, ci); ci_role_destroy(ci); diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index abefb4d..68f2faf 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -39,12 +39,65 @@ void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) } /** - * ci_hdrc_otg_init - initialize otgsc bits + * ci_otg_role - pick role based on ID pin state + * @ci: the controller + */ +enum ci_role ci_otg_role(struct ci_hdrc *ci) +{ + u32 sts = hw_read(ci, OP_OTGSC, ~0); + enum ci_role role = sts OTGSC_ID + ? CI_ROLE_GADGET + : CI_ROLE_HOST; + + return role; +} + +/** + * ci_role_work - perform role changing based on ID pin + * @work: work struct + */ +static void ci_role_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + enum ci_role
[PATCH v14 12/12] usb: chipidea: udc: .pullup is valid when vbus is on at CI_HDRC_PULLUP_ON_VBUS
When the flag CI_HDRC_PULLUP_ON_VBUS is set, .pullup should only be called when the vbus is active. When the CI_HDRC_PULLUP_ON_VBUS is set, the controller only begins to run when the vbus is on, So, it is only meaningful software set pullup/pulldown after the controller begins to run. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 45abf4d..b7ead5f 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1514,6 +1514,10 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on) { struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); + if ((ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) +!ci-vbus_active) + return -EOPNOTSUPP; + if (is_on) hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); else -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/3] usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod gadget
] (dump_backtrace+0x0/0x114) from [804ea684] (dump_stack+0x20/0x24) r7: r6:806c3f2c r5:806cf748 r4:80712d18 [804ea664] (dump_stack+0x0/0x24) from [80014adc] (handle_IPI+0x140/0x18c) [8001499c] (handle_IPI+0x0/0x18c) from [800085b0] (gic_handle_irq+0x68/0x70) r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bff60 r5:806ce974 r4:f400010c [80008548] (gic_handle_irq+0x0/0x70) from [8000eac0] (__irq_svc+0x40/0x54) Exception stack(0xbf8bff60 to 0xbf8bffa8) ff60: 000f 8001aea0 bf8be000 80712a48 804f0040 ff80: 806d29e8 412fc09a bf8bffb4 bf8bffb8 bf8bffa8 8000fbcc 8000fbd0 ffa0: 6013 r7:bf8bff94 r6: r5:6013 r4:8000fbd0 [8000fb90] (default_idle+0x0/0x4c) from [8001015c] (cpu_idle+0xbc/0xf8) [800100a0] (cpu_idle+0x0/0xf8) from [804e7930] (secondary_start_kernel+0x120/0x148) r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:0003 r4:806e2008 [804e7810] (secondary_start_kernel+0x0/0x148) from [104e7148] (0x104e7148) r5:001f r4:4f8a806a CPU1: stopping Backtrace: [800132e8] (dump_backtrace+0x0/0x114) from [804ea684] (dump_stack+0x20/0x24) r7: r6:806c3f2c r5:806cf748 r4:80712d18 [804ea664] (dump_stack+0x0/0x24) from [80014adc] (handle_IPI+0x140/0x18c) [8001499c] (handle_IPI+0x0/0x18c) from [800085b0] (gic_handle_irq+0x68/0x70) r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bbf60 r5:806ce974 r4:f400010c [80008548] (gic_handle_irq+0x0/0x70) from [8000eac0] (__irq_svc+0x40/0x54) Exception stack(0xbf8bbf60 to 0xbf8bbfa8) bf60: 000f 8001aea0 bf8ba000 80712a48 804f0040 bf80: 806d29e8 412fc09a bf8bbfb4 bf8bbfb8 bf8bbfa8 8000fbcc 8000fbd0 bfa0: 6013 r7:bf8bbf94 r6: r5:6013 r4:8000fbd0 [8000fb90] (default_idle+0x0/0x4c) from [8001015c] (cpu_idle+0xbc/0xf8) [800100a0] (cpu_idle+0x0/0xf8) from [804e7930] (secondary_start_kernel+0x120/0x148) r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:0001 r4:806e2008 Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c | 13 + 1 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b7ead5f..aeabdcf 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -686,9 +686,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) usb_ep_fifo_flush(ci-ep0out-ep); usb_ep_fifo_flush(ci-ep0in-ep); - if (ci-driver) - ci-driver-disconnect(gadget); - /* make sure to disable all endpoints */ gadget_for_each_ep(ep, gadget) { usb_ep_disable(ep); @@ -717,6 +714,11 @@ __acquires(ci-lock) { int retval; + if (ci-gadget.speed != USB_SPEED_UNKNOWN) { + if (ci-driver) + ci-driver-disconnect(ci-gadget); + } + spin_unlock(ci-lock); retval = _gadget_stop_activity(ci-gadget); if (retval) @@ -1464,6 +1466,8 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) hw_device_state(ci, ci-ep0out-qh.dma); dev_dbg(ci-dev, Connected to host\n); } else { + if (ci-driver) + ci-driver-disconnect(ci-gadget); hw_device_state(ci, 0); if (ci-platdata-notify_event) ci-platdata-notify_event(ci, @@ -1674,13 +1678,14 @@ static int ci_udc_stop(struct usb_gadget *gadget, if (ci-platdata-notify_event) ci-platdata-notify_event(ci, CI_HDRC_CONTROLLER_STOPPED_EVENT); - ci-driver = NULL; spin_unlock_irqrestore(ci-lock, flags); _gadget_stop_activity(ci-gadget); spin_lock_irqsave(ci-lock, flags); pm_runtime_put(ci-gadget.dev); } + ci-driver = NULL; + spin_unlock_irqrestore(ci-lock, flags); return 0; -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/3] Misc Chipidea Patch
This patchset is based on my vbus/id patchset Peter Chen (3): usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod gadget usb: chipidea: move platform related things to ci_get_platdata usb: host: delete chipidea dependency drivers/usb/chipidea/core.c | 21 + drivers/usb/chipidea/udc.c | 13 + drivers/usb/host/Kconfig|4 ++-- 3 files changed, 20 insertions(+), 18 deletions(-) -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/3] usb: host: delete chipidea dependency
Now, chipidea host has already depended on USB_EHCI_HCD Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/host/Kconfig |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index cf521d6..b548554 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -63,7 +63,7 @@ config USB_EHCI_HCD config USB_EHCI_ROOT_HUB_TT bool Root Hub Transaction Translators - depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST + depends on USB_EHCI_HCD ---help--- Some EHCI chips have vendor-specific extensions to integrate transaction translators, so that no OHCI or UHCI companion @@ -75,7 +75,7 @@ config USB_EHCI_ROOT_HUB_TT config USB_EHCI_TT_NEWSCHED bool Improved Transaction Translator scheduling - depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST + depends on USB_EHCI_HCD default y ---help--- This changes the periodic scheduling code to fill more of the low -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/3] usb: chipidea: move platform related things to ci_get_platdata
It will make probe cleaner, meanwhile, it fixes the problem http://marc.info/?l=linux-usbm=137528143523296w=2 described indirectly. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 21 + 1 files changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index f09b4db..61c928c 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -381,6 +381,15 @@ static int ci_get_platdata(struct device *dev, return PTR_ERR(platdata-reg_vbus); } + if (!platdata-phy_mode) + platdata-phy_mode = of_usb_get_phy_mode(dev-of_node); + + if (!platdata-dr_mode) + platdata-dr_mode = of_usb_get_dr_mode(dev-of_node); + + if (platdata-dr_mode == USB_DR_MODE_UNKNOWN) + platdata-dr_mode = USB_DR_MODE_OTG; + return 0; } @@ -479,9 +488,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - if (!dev-of_node dev-parent) - dev-of_node = dev-parent-of_node; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) @@ -517,17 +523,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) /* To know if controller is OTG capable or not */ ci_get_otg_capable(ci); - if (!ci-platdata-phy_mode) - ci-platdata-phy_mode = of_usb_get_phy_mode(dev-of_node); - hw_phymode_configure(ci); - if (!ci-platdata-dr_mode) - ci-platdata-dr_mode = of_usb_get_dr_mode(dev-of_node); - - if (ci-platdata-dr_mode == USB_DR_MODE_UNKNOWN) - ci-platdata-dr_mode = USB_DR_MODE_OTG; - dr_mode = ci-platdata-dr_mode; /* initialize role(s) before the interrupt is requested */ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { -- 1.7.0.4 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v14 00/12] Add tested id switch and vbus connect detect support for Chipidea
This patchset adds tested otg id switch function and vbus connect and disconnect detection for chipidea driver. And fix kinds of bugs found at chipidea drivers after enabling id and vbus detection. This patch are fully tested at imx6 sabresd and imx28evk platform by me. Besides, marek tested it on two STMP3780-based boards (not yet mainline) and two MX28-based boards. My chipidea repo: https://github.com/hzpeterchen/linux-usb.git Changes for v14: - This patchset is based on below recent chipidea patches and newest usb-next, it can decrease rebase effort. Fabio Estevam (3): chipidea: ci_hdrc_imx: Remove unused variable 'res' chipidea: core: Move hw_phymode_configure() into probe chipidea: Remove previous MODULE_ALIAS Lothar Wabmann (3): usb: chipidea: improve kconfig 2.0 usb: chipidea: don't clobber return value of ci_role_start() usb: chipidea: ci_hdrc_imx: remove an unsolicited module_put() call from ci_hdrc_imx_remove() Peter Chen (1): usb: chipidea: fix the build error with randconfig - [Michael comments]: move vbus operation to core, and squash two vbus patches. [1/12], [2/12] - [Michael comments]: move out non vbus and non id related patches. [14/14 at v13] Chagnes for v13: - Add Tested-by: Marek Vasut ma...@denx.de - [Sascha's comments]: Add return value check for devm_regulator_get. [3/14] - [Marc's comments]: Change timeout usage at hw_wait_reg. [11/14] - [Alex's comments]: Using platdata flag to indicate dual role but not OTG controller. [7/14] Changes for v12: - Rebased greg's usb-next tree (3.10.0-rc7+) - Split more small patches for single function and fix. Peter Chen (12): usb: chipidea: move vbus regulator operation to core usb: chipidea: host: add vbus regulator control usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users usb: chipidea: otg: Add otg file used to access otgsc usb: chipidea: Add role init and destory APIs usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG usb: chipidea: disable all interrupts and clear all interrupts status usb: chipidea: move otg relate things to otg file usb: chipidea: add vbus interrupt handler usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS usb: chipidea: udc: .pullup is valid when vbus is on at CI_HDRC_PULLUP_ON_VBUS drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h| 10 ++ drivers/usb/chipidea/ci.h |8 ++ drivers/usb/chipidea/ci_hdrc_imx.c | 26 +- drivers/usb/chipidea/core.c| 184 +--- drivers/usb/chipidea/host.c| 30 ++- drivers/usb/chipidea/host.h|6 + drivers/usb/chipidea/otg.c | 135 ++ drivers/usb/chipidea/otg.h | 22 + drivers/usb/chipidea/udc.c | 59 +--- drivers/usb/chipidea/udc.h |6 + include/linux/usb/chipidea.h |6 + 12 files changed, 401 insertions(+), 93 deletions(-) create mode 100644 drivers/usb/chipidea/otg.c create mode 100644 drivers/usb/chipidea/otg.h -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/1] usb: chipidea: refine the operation of creating register mapping
- The old operation needs to call hw_alloc_regmap two times, and the first operation is only used to know if the controller is lpm supported, besides, there is a kfree before kzalloc, it is also tricky. - Fix the memory leak for ci-hw_bank.regmap when unload module. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci.h |2 +- drivers/usb/chipidea/core.c | 11 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 1c94fc5..e5cb585 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -92,7 +92,7 @@ struct ci_role_driver { * @regmap: register lookup table */ struct hw_bank { - unsignedlpm; + boollpm; resource_size_t phys; void __iomem*abs; void __iomem*cap; diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 135f7f9..8d7a600 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -123,8 +123,6 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) { int i; - kfree(ci-hw_bank.regmap); - ci-hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *), GFP_KERNEL); if (!ci-hw_bank.regmap) @@ -183,11 +181,9 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) ci-hw_bank.cap += ci-platdata-capoffset; ci-hw_bank.op = ci-hw_bank.cap + (ioread32(ci-hw_bank.cap) 0xff); - hw_alloc_regmap(ci, false); - reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) - __ffs(HCCPARAMS_LEN); - ci-hw_bank.lpm = reg; - hw_alloc_regmap(ci, !!reg); + ci-hw_bank.lpm = !!(ioread32(ci-hw_bank.cap + + ci_regs_nolpm[CAP_HCCPARAMS]) HCCPARAMS_LEN); + hw_alloc_regmap(ci, ci-hw_bank.lpm); ci-hw_bank.size = ci-hw_bank.op - ci-hw_bank.abs; ci-hw_bank.size += OP_LAST; ci-hw_bank.size /= sizeof(u32); @@ -602,6 +598,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) { struct ci_hdrc *ci = platform_get_drvdata(pdev); + kfree(ci-hw_bank.regmap); dbg_remove_files(ci); free_irq(ci-irq, ci); ci_role_destroy(ci); -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] usb: chipidea: refine the operation of creating register mapping
On Mon, Aug 05, 2013 at 10:05:56AM +0300, Alexander Shishkin wrote: Peter Chen peter.c...@freescale.com writes: - The old operation needs to call hw_alloc_regmap two times, and the first operation is only used to know if the controller is lpm supported, besides, there is a kfree before kzalloc, it is also tricky. Why tricky? kfree() is called from either NULL or a valid pointer, both of which is perfectly valid. I know it is valid, it is just strange that you call kfree before kmalloc. - Fix the memory leak for ci-hw_bank.regmap when unload module. ci-hw_bank.op = ci-hw_bank.cap + (ioread32(ci-hw_bank.cap) 0xff); - hw_alloc_regmap(ci, false); - reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) - __ffs(HCCPARAMS_LEN); - ci-hw_bank.lpm = reg; - hw_alloc_regmap(ci, !!reg); + ci-hw_bank.lpm = !!(ioread32(ci-hw_bank.cap + + ci_regs_nolpm[CAP_HCCPARAMS]) HCCPARAMS_LEN); + hw_alloc_regmap(ci, ci-hw_bank.lpm); The idea of the original code is to avoid this ioread and have all the register offset maths done by hw_read(), since it's done there anyway. And it kind of looks better to me the way it's done right now. So unless you really want to optimize away one call to hw_alloc_regmap(), I'd prefer to keep it as it is. I do this just because it is strange that calling hw_alloc_regmap two times at the first glance, and the first time is just to know if it is lpm supported, besides, calling kfree before kmalloc is a strange thing, don't you think so? @@ -602,6 +598,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) { struct ci_hdrc *ci = platform_get_drvdata(pdev); + kfree(ci-hw_bank.regmap); This one seems perfectly valid. Regards, -- Alex -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/1] usb: gadget: zero: Add flexible auto remote wakeup test method
In order to increase test coverage, we can change the interval between two remote wakeups every time, and the interval can be any user defined value. This change will no affect current behavior if the user does not use two introduced module paramters. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/gadget/zero.c | 26 +++--- 1 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0deb9d6..076f2be 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -38,7 +38,6 @@ */ /* #define VERBOSE_DEBUG */ - #include linux/kernel.h #include linux/slab.h #include linux/device.h @@ -95,6 +94,18 @@ unsigned autoresume = DEFAULT_AUTORESUME; module_param(autoresume, uint, S_IRUGO); MODULE_PARM_DESC(autoresume, zero, or seconds before remote wakeup); +/* Maximum Autoresume time */ +unsigned max_autoresume; +module_param(max_autoresume, uint, S_IRUGO); +MODULE_PARM_DESC(max_autoresume, maximum seconds before remote wakeup); + +/* Internal between two remote wakeups */ +unsigned autoresume_interal_ms; +module_param(autoresume_interal_ms, uint, S_IRUGO); +MODULE_PARM_DESC(autoresume_interal_ms, + milliseconds internal between sending two wakeups); + +static unsigned autoresume_step_ms; /*-*/ static struct usb_device_descriptor device_desc = { @@ -183,8 +194,16 @@ static void zero_suspend(struct usb_composite_dev *cdev) return; if (autoresume) { - mod_timer(autoresume_timer, jiffies + (HZ * autoresume)); - DBG(cdev, suspend, wakeup in %d seconds\n, autoresume); + if (max_autoresume + (autoresume_step_ms max_autoresume * 1000)) + autoresume_step_ms = autoresume * 1000; + + mod_timer(autoresume_timer, jiffies + + msecs_to_jiffies(autoresume_step_ms)); + DBG(cdev, suspend, wakeup in %d milliseconds\n, + autoresume_step_ms); + + autoresume_step_ms += autoresume_interal_ms; } else DBG(cdev, %s\n, __func__); } @@ -316,6 +335,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev) if (autoresume) { sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + autoresume_step_ms = autoresume * 1000; } /* support OTG systems */ -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 00/12] Add tested id switch and vbus connect detect support for Chipidea
On Fri, Aug 02, 2013 at 04:33:53PM +0800, Peter Chen wrote: This patchset adds tested otg id switch function and vbus connect and disconnect detection for chipidea driver. And fix kinds of bugs found at chipidea drivers after enabling id and vbus detection. This patch are fully tested at imx6 sabresd and imx28evk platform by me. Besides, marek tested it on two STMP3780-based boards (not yet mainline) and two MX28-based boards. My chipidea repo: https://github.com/hzpeterchen/linux-usb.git Changes for v14: - This patchset is based on below recent chipidea patches and newest usb-next, it can decrease rebase effort. Fabio Estevam (3): chipidea: ci_hdrc_imx: Remove unused variable 'res' chipidea: core: Move hw_phymode_configure() into probe chipidea: Remove previous MODULE_ALIAS Lothar Wabmann (3): usb: chipidea: improve kconfig 2.0 usb: chipidea: don't clobber return value of ci_role_start() usb: chipidea: ci_hdrc_imx: remove an unsolicited module_put() call from ci_hdrc_imx_remove() Peter Chen (1): usb: chipidea: fix the build error with randconfig - [Michael comments]: move vbus operation to core, and squash two vbus patches. [1/12], [2/12] - [Michael comments]: move out non vbus and non id related patches. [14/14 at v13] Hi Alex, any comments? Chagnes for v13: - Add Tested-by: Marek Vasut ma...@denx.de - [Sascha's comments]: Add return value check for devm_regulator_get. [3/14] - [Marc's comments]: Change timeout usage at hw_wait_reg. [11/14] - [Alex's comments]: Using platdata flag to indicate dual role but not OTG controller. [7/14] Changes for v12: - Rebased greg's usb-next tree (3.10.0-rc7+) - Split more small patches for single function and fix. Peter Chen (12): usb: chipidea: move vbus regulator operation to core usb: chipidea: host: add vbus regulator control usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users usb: chipidea: otg: Add otg file used to access otgsc usb: chipidea: Add role init and destory APIs usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG usb: chipidea: disable all interrupts and clear all interrupts status usb: chipidea: move otg relate things to otg file usb: chipidea: add vbus interrupt handler usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS usb: chipidea: udc: .pullup is valid when vbus is on at CI_HDRC_PULLUP_ON_VBUS drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h| 10 ++ drivers/usb/chipidea/ci.h |8 ++ drivers/usb/chipidea/ci_hdrc_imx.c | 26 +- drivers/usb/chipidea/core.c| 184 +--- drivers/usb/chipidea/host.c| 30 ++- drivers/usb/chipidea/host.h|6 + drivers/usb/chipidea/otg.c | 135 ++ drivers/usb/chipidea/otg.h | 22 + drivers/usb/chipidea/udc.c | 59 +--- drivers/usb/chipidea/udc.h |6 + include/linux/usb/chipidea.h |6 + 12 files changed, 401 insertions(+), 93 deletions(-) create mode 100644 drivers/usb/chipidea/otg.c create mode 100644 drivers/usb/chipidea/otg.h -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] USB: global suspend and remote wakeup don't mix
On Tue, Aug 06, 2013 at 01:05:40PM -0400, Alan Stern wrote: On Wed, 7 Aug 2013, Huang Rui wrote: Could you explain that how can you make sure the root cause is unable to relay wakup requests from downstream port to upstream port if downstream port's suspend feature is not set? The OS is unable wakeup from S3 at that time. We can't fetch dmesg log and serial port is suspend either at that time. Did you use any other tools to trace this issue? Could you teach me? Actually, I was encoutered this issue either. It was simple. I ran two tests. They were exactly the same, except that the suspend feature was set in the first test and was not set in the second test. Remote wakeup worked in the first test and not in the second. Got it, but I'm still a little confused. For example, one mouse is attached at usb2.0 port of roothub, and it supports remote wakeup. But the wakeup attribute is disabled for mouse defaultly, am I right? So Yes. remote wakeup doesn't work on this mouse, then run system suspend into s3 with global suspend(don't send Set Suspend Feature request). In this case, remote wakeup and global suspend doesn't mix, am I right? No. In this case they do mix okay. But system still can not wake up normally. In this case, the system is not supposed to wake up when you press a mouse button, because the mouse is disabled for remote wakeup. Therefore the system behaves correctly. Instead of a mouse, consider a USB keyboard. Keyboards _are_ enabled for remote wakeup by default. And suppose the keyboard is plugged into an external hub, not the root hub. Then pressing a key on the keyboard _should_ cause the system to wake up from S3. But with some hubs, if you use global suspend then pressing a key does not wake up the system. For end user, the keyboard connects to roothub directly and connects to intermediate hub (then connects to roothub) may not be different, since the hub may solder at the board directly. What the end user sees is the standard A USB port. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/1] usb: gadget: zero: Add flexible auto remote wakeup test method
In order to increase test coverage, we can change the interval between two remote wakeups every time, and the interval can be any user defined value. This change will no affect current behavior if the user does not use two introduced module paramters. Signed-off-by: Peter Chen peter.c...@freescale.com --- Changes for v2: - Change some typo and description drivers/usb/gadget/zero.c | 25 +++-- 1 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0deb9d6..21da094 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -95,6 +95,18 @@ unsigned autoresume = DEFAULT_AUTORESUME; module_param(autoresume, uint, S_IRUGO); MODULE_PARM_DESC(autoresume, zero, or seconds before remote wakeup); +/* Maximum Autoresume time */ +unsigned max_autoresume; +module_param(max_autoresume, uint, S_IRUGO); +MODULE_PARM_DESC(max_autoresume, maximum seconds before remote wakeup); + +/* Interval between two remote wakeups */ +unsigned autoresume_interval_ms; +module_param(autoresume_interval_ms, uint, S_IRUGO); +MODULE_PARM_DESC(autoresume_interval_ms, + milliseconds to increase successive wakup delays); + +static unsigned autoresume_step_ms; /*-*/ static struct usb_device_descriptor device_desc = { @@ -183,8 +195,16 @@ static void zero_suspend(struct usb_composite_dev *cdev) return; if (autoresume) { - mod_timer(autoresume_timer, jiffies + (HZ * autoresume)); - DBG(cdev, suspend, wakeup in %d seconds\n, autoresume); + if (max_autoresume + (autoresume_step_ms max_autoresume * 1000)) + autoresume_step_ms = autoresume * 1000; + + mod_timer(autoresume_timer, jiffies + + msecs_to_jiffies(autoresume_step_ms)); + DBG(cdev, suspend, wakeup in %d milliseconds\n, + autoresume_step_ms); + + autoresume_step_ms += autoresume_interval_ms; } else DBG(cdev, %s\n, __func__); } @@ -316,6 +336,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev) if (autoresume) { sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + autoresume_step_ms = autoresume * 1000; } /* support OTG systems */ -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/1] usb: chipidea: imx: include usbmisc_imx.c in ci_hdrc_imx.c
At former design, both ci_hdrc_imx and usbmisc_imx are individual module, ci_hdrc_imx is glue layer for imx usb driver. usbmisc_imx handles non-core registers which has different register layout for imx SoC serials, it usually supplies interface for wakeup setting, PHY setting, etc. usbmisc_imx uses symbols from ci_hdrc_imx, So, when we combile both of drivers as loadable module, usbmisc is needed to be unload first. However at ci_hdrc_imx, it needs to call usbmisc_imx's interface at its removal function once we enable wakeup/runtime pm function, so keeping two drivers can't work well at loadable module use case. To fix loadable module use case, we need to build usbmisc_imx into ci_hdrc_imx. The usbmisc_imx still handles misc setting for controllers, and will be included at ci_hdrc_imx. There is a short discussion for it: http://marc.info/?l=linux-usbm=136861599423172w=2 Besides, we update dts and binding doc for at this commit Signed-off-by: Peter Chen peter.c...@freescale.com --- .../devicetree/bindings/usb/ci13xxx-imx.txt| 10 +- .../devicetree/bindings/usb/usbmisc-imx.txt| 14 -- arch/arm/boot/dts/imx23.dtsi |1 + arch/arm/boot/dts/imx25.dtsi | 14 +- arch/arm/boot/dts/imx28.dtsi |2 + arch/arm/boot/dts/imx51.dtsi | 13 + arch/arm/boot/dts/imx53.dtsi | 13 + arch/arm/boot/dts/imx6qdl.dtsi | 20 +- drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/ci_hdrc_imx.c | 125 ++- drivers/usb/chipidea/ci_hdrc_imx.h | 32 ++-- drivers/usb/chipidea/usbmisc_imx.c | 237 +--- 12 files changed, 192 insertions(+), 291 deletions(-) delete mode 100644 Documentation/devicetree/bindings/usb/usbmisc-imx.txt diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt index b4b5b79..13720a2 100644 --- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt +++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt @@ -13,8 +13,8 @@ Recommended properies: Optional properties: - fsl,usbphy: phandler of usb phy that connects to the only one port -- fsl,usbmisc: phandler of non-core register device, with one argument - that indicate usb controller index +- ci,noncore: phandler of non-core register device, the user must enable +syscon driver to use it - vbus-supply: regulator for vbus - disable-over-current: disable over current detect - external-vbus-divider: enables off-chip resistor divider for Vbus @@ -25,7 +25,11 @@ usb@02184000 { /* USB OTG */ reg = 0x02184000 0x200; interrupts = 0 43 0x04; fsl,usbphy = usbphy1; - fsl,usbmisc = usbmisc 0; + ci,noncore = noncore; disable-over-current; external-vbus-divider; }; +noncore: usb-non-core@02184800 { +compatible = fsl,imx-usb-non-core, syscon; +reg = 0x02184800 0x200; +}; diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt deleted file mode 100644 index 97ce94e..000 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ /dev/null @@ -1,14 +0,0 @@ -* Freescale i.MX non-core registers - -Required properties: -- #index-cells: Cells used to descibe usb controller index. Should be 1 -- compatible: Should be one of below: - fsl,imx6q-usbmisc for imx6q -- reg: Should contain registers location and length - -Examples: -usbmisc@02184800 { - #index-cells = 1; - compatible = fsl,imx6q-usbmisc; - reg = 0x02184800 0x200; -}; diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index 587ceef..a0d8471 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -20,6 +20,7 @@ gpio2 = gpio2; serial0 = auart0; serial1 = auart1; + usb0 = usb0; }; cpus { diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 1f72862..7bb94ce 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -461,7 +461,7 @@ interrupts = 37; clocks = clks 9, clks 70, clks 8; clock-names = ipg, ahb, per; - fsl,usbmisc = usbmisc 0; + ci,noncore = noncore; status = disabled; }; @@ -471,17 +471,13 @@ interrupts = 35; clocks = clks 9, clks 70, clks 8; clock-names = ipg, ahb, per; - fsl,usbmisc = usbmisc 1; + ci,noncore = noncore; status = disabled
Re: [PATCH 1/1] usb: chipidea: imx: include usbmisc_imx.c in ci_hdrc_imx.c
On Wed, Aug 07, 2013 at 10:15:22AM +0200, Sascha Hauer wrote: On Wed, Aug 07, 2013 at 01:34:37PM +0800, Peter Chen wrote: At former design, both ci_hdrc_imx and usbmisc_imx are individual module, ci_hdrc_imx is glue layer for imx usb driver. usbmisc_imx handles non-core registers which has different register layout for imx SoC serials, it usually supplies interface for wakeup setting, PHY setting, etc. usbmisc_imx uses symbols from ci_hdrc_imx, So, when we combile both of drivers as loadable module, usbmisc is needed to be unload first. However at ci_hdrc_imx, it needs to call usbmisc_imx's interface at its removal function once we enable wakeup/runtime pm function, so keeping two drivers can't work well at loadable module use case. To fix loadable module use case, we need to build usbmisc_imx into ci_hdrc_imx. The usbmisc_imx still handles misc setting for controllers, and will be included at ci_hdrc_imx. There is a short discussion for it: http://marc.info/?l=linux-usbm=136861599423172w=2 Besides, we update dts and binding doc for at this commit This patch does far too many things at once. - Convert imx-usb-misc from a driver into something which is called directly - add aliases - change devicetree bindings (which causes pain and it's not explained why this is necessary at all) Yes, I need to split doc from implementation. - converts the misc stuff to regmap Please split this up so that it can be reviewed. The changes are all related to convert usbmisc_imx from a driver to something which can be called directly. - usbmisc has #index-cells to indicate controller number, now, it is not a driver, we use aliases at controller driver to instead of it. - When usbmisc_imx is a device, the register maps only one time. But ci_hdrc_imx will be several devices, the non-core register will be mapped several times, we have to use syscon to visit one register region among several devices. #include ci.h #include ci_hdrc_imx.h +#include usbmisc_imx.c Don't include C files. Yes, it is not a good practice, but I want to keep ci_hdrc_imx.c as clean as possible. The SoC related implementation will be more and more in the future after we add more USB functions. Do you have any good suggestions how to organize general imx stuff and SoC specifc? Put all the things at controller driver is another solution. - ret); - memset(usbdev, 0, sizeof(*usbdev)); + ret = of_alias_get_id(np, usb); + if (ret 0) { + dev_err(dev, failed to get alias id, errno %d\n, ret); return ret; } - usbdev-index = args.args[0]; - of_node_put(args.np); if (of_find_property(np, disable-over-current, NULL)) - usbdev-disable_oc = 1; + data-disable_oc = 1; if (of_find_property(np, external-vbus-divider, NULL)) - usbdev-evdo = 1; + data-evdo = 1; + + /* mx23 and mx28 doesn't have non core registers */ + if (data-misc_data (!strcmp(data-misc_data-name, imx23-usb) || + !strcmp(data-misc_data-name, imx28-usb))) + return 0; If a USB node does not have a usbmisc (or noncore) property then don't initialize it. No need for string compares. OK, will let the code be simple, I can't add device_id for mxs either. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] usb: chipidea: imx: include usbmisc_imx.c in ci_hdrc_imx.c
On Wed, Aug 07, 2013 at 11:08:45AM +0200, Sascha Hauer wrote: - Convert imx-usb-misc from a driver into something which is called directly - add aliases - change devicetree bindings (which causes pain and it's not explained why this is necessary at all) Yes, I need to split doc from implementation. No, you don't. You just have to explain *why* the bindings need to be chaged. OK, I will - converts the misc stuff to regmap Please split this up so that it can be reviewed. The changes are all related to convert usbmisc_imx from a driver to something which can be called directly. - usbmisc has #index-cells to indicate controller number, now, it is not a driver, we use aliases at controller driver to instead of it. Why? We need to know controller number, like pdev-id in the past. The registers at non core register is messy, the specific bit is for specific controller. - When usbmisc_imx is a device, the register maps only one time. But ci_hdrc_imx will be several devices, the non-core register will be mapped several times, we have to use syscon to visit one register region among several devices. Converting the imx-usb misc driver to regmap is fine, but I see no reason to not make this a separate patch. This would make this much easier to read. You mean delete reg entry at usbmisc dts, and using noncore phandle at usbmisc_imx.c as the first patch, then, convert driver as separate file. Yes, it is not a good practice, but I want to keep ci_hdrc_imx.c as clean as possible. The SoC related implementation will be more and more in the future after we add more USB functions. Just because you want to have the binary code in a single module doesn't mean the source code has to be in a single C file. OK, I will do. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] usb: chipidea: imx: include usbmisc_imx.c in ci_hdrc_imx.c
On Wed, Aug 07, 2013 at 11:11:10AM +0200, Sascha Hauer wrote: On Wed, Aug 07, 2013 at 01:34:37PM +0800, Peter Chen wrote: - - reg = usbmisc-base + MX25_USB_PHY_CTRL_OFFSET; - - if (usbdev-evdo) { - spin_lock_irqsave(usbmisc-lock, flags); - val = readl(reg); - writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); - spin_unlock_irqrestore(usbmisc-lock, flags); + if (data-evdo) { + spin_lock_irqsave(data-lock, flags); + regmap_read(data-non_core_base_addr, + MX25_USB_PHY_CTRL_OFFSET, val); + regmap_write(data-non_core_base_addr, + MX25_USB_PHY_CTRL_OFFSET, + val | MX25_BM_EXTERNAL_VBUS_DIVIDER); + spin_unlock_irqrestore(data-lock, flags); Have a look at regmap_update_bits. You won't need this spinlock anymore. Thanks. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] usb: chipidea: imx: include usbmisc_imx.c in ci_hdrc_imx.c
On Wed, Aug 07, 2013 at 12:05:07PM +0200, Sascha Hauer wrote: We need to know controller number, like pdev-id in the past. The registers at non core register is messy, the specific bit is for specific controller. The controller number is present in the old binding: fsl,usbmisc = usbmisc 1; ^^^ Merging the usbmisc stuff into the imx driver shouldn't be a reason to change this binding. Please get used to the fact that dt bindings cannot be changed easily just because the newer binding looks nicer. They define an ABI and breaking this ABI causes pain. But current situation is the device node of usbmisc will not be needed. The usbmisc will not be a driver. We only need usbmisc to supply kinds of SoC specific implementations, as well as filling the content of the data at struct of_device_id (imx-usb's). - When usbmisc_imx is a device, the register maps only one time. But ci_hdrc_imx will be several devices, the non-core register will be mapped several times, we have to use syscon to visit one register region among several devices. Converting the imx-usb misc driver to regmap is fine, but I see no reason to not make this a separate patch. This would make this much easier to read. You mean delete reg entry at usbmisc dts, and using noncore phandle at usbmisc_imx.c as the first patch, then, convert driver as separate file. I mean: create a patch which converts the usbmisc driver to regmap and base your other stuff on this patch. This is what I mean. We can't request one region twice, so we need to delete devm_ioremap_resource at probe first. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] usb: chipidea: imx: include usbmisc_imx.c in ci_hdrc_imx.c
On Wed, Aug 07, 2013 at 12:06:42PM +0200, Sascha Hauer wrote: On Wed, Aug 07, 2013 at 01:34:37PM +0800, Peter Chen wrote: diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt index b4b5b79..13720a2 100644 --- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt +++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt @@ -13,8 +13,8 @@ Recommended properies: Optional properties: - fsl,usbphy: phandler of usb phy that connects to the only one port -- fsl,usbmisc: phandler of non-core register device, with one argument - that indicate usb controller index +- ci,noncore: phandler of non-core register device, the user must enable +syscon driver to use it Don't add Linux specifics to the binding documentation. The bindings are supposed to be OS agnostic. OK, I will change it. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] usb: chipidea: imx: include usbmisc_imx.c in ci_hdrc_imx.c
On Wed, Aug 07, 2013 at 02:28:20PM +0200, Michael Grzeschik wrote: Hi Peter, On Wed, Aug 07, 2013 at 05:24:45PM +0800, Peter Chen wrote: On Wed, Aug 07, 2013 at 12:05:07PM +0200, Sascha Hauer wrote: We need to know controller number, like pdev-id in the past. The registers at non core register is messy, the specific bit is for specific controller. The controller number is present in the old binding: fsl,usbmisc = usbmisc 1; ^^^ Merging the usbmisc stuff into the imx driver shouldn't be a reason to change this binding. Please get used to the fact that dt bindings cannot be changed easily just because the newer binding looks nicer. They define an ABI and breaking this ABI causes pain. But current situation is the device node of usbmisc will not be needed. The usbmisc will not be a driver. We only need usbmisc to supply kinds of SoC specific implementations, as well as filling the content of the data at struct of_device_id (imx-usb's). - When usbmisc_imx is a device, the register maps only one time. But ci_hdrc_imx will be several devices, the non-core register will be mapped several times, we have to use syscon to visit one register region among several devices. Converting the imx-usb misc driver to regmap is fine, but I see no reason to not make this a separate patch. This would make this much easier to read. You mean delete reg entry at usbmisc dts, and using noncore phandle at usbmisc_imx.c as the first patch, then, convert driver as separate file. I mean: create a patch which converts the usbmisc driver to regmap and base your other stuff on this patch. This is what I mean. We can't request one region twice, so we need to delete devm_ioremap_resource at probe first. Please try to reply with your answers in direct context to the questions. Otherwise this thread will not end and probably produce more confusion than answers. What we need is a clearly seperated series of independent changes; Just like Sascha already mentioned: On Wed, Aug 07, 2013 at 10:15:22AM +0200, Sascha Hauer wrote: This patch does far too many things at once. - Convert imx-usb-misc from a driver into something which is called directly - add aliases - change devicetree bindings (which causes pain and it's not explained why this is necessary at all) - converts the misc stuff to regmap Please split this up so that it can be reviewed. Your work needs the clean seperation before we can discuss the changes more in detail. Please try that first! Thanks, Michael. I will do that. But discussion is needed, it can let us understand the problem deeply. For you, what the real problem, for me, how to do it properly. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/1] usb: chipidea: imx: delete the dead code
Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c |3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index b886998..30fdc2f 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -23,9 +23,6 @@ #include ci.h #include ci_hdrc_imx.h -#define pdev_to_phy(pdev) \ - ((struct usb_phy *)platform_get_drvdata(pdev)) - struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/5] usb: chipidea: imx: rename the DT doc name
To reflect source file name change Signed-off-by: Peter Chen peter.c...@freescale.com --- .../devicetree/bindings/usb/ci13xxx-imx.txt| 31 .../devicetree/bindings/usb/ci_hdrc_imx.txt| 31 Documentation/devicetree/bindings/usb/mxs-phy.txt | 13 .../devicetree/bindings/usb/phy-mxs-usb.txt| 13 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt deleted file mode 100644 index b4b5b79..000 --- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt +++ /dev/null @@ -1,31 +0,0 @@ -* Freescale i.MX ci13xxx usb controllers - -Required properties: -- compatible: Should be fsl,imx27-usb -- reg: Should contain registers location and length -- interrupts: Should contain controller interrupt - -Recommended properies: -- phy_type: the type of the phy connected to the core. Should be one - of utmi, utmi_wide, ulpi, serial or hsic. Without this - property the PORTSC register won't be touched -- dr_mode: One of host, peripheral or otg. Defaults to otg - -Optional properties: -- fsl,usbphy: phandler of usb phy that connects to the only one port -- fsl,usbmisc: phandler of non-core register device, with one argument - that indicate usb controller index -- vbus-supply: regulator for vbus -- disable-over-current: disable over current detect -- external-vbus-divider: enables off-chip resistor divider for Vbus - -Examples: -usb@02184000 { /* USB OTG */ - compatible = fsl,imx6q-usb, fsl,imx27-usb; - reg = 0x02184000 0x200; - interrupts = 0 43 0x04; - fsl,usbphy = usbphy1; - fsl,usbmisc = usbmisc 0; - disable-over-current; - external-vbus-divider; -}; diff --git a/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt b/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt new file mode 100644 index 000..b4b5b79 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt @@ -0,0 +1,31 @@ +* Freescale i.MX ci13xxx usb controllers + +Required properties: +- compatible: Should be fsl,imx27-usb +- reg: Should contain registers location and length +- interrupts: Should contain controller interrupt + +Recommended properies: +- phy_type: the type of the phy connected to the core. Should be one + of utmi, utmi_wide, ulpi, serial or hsic. Without this + property the PORTSC register won't be touched +- dr_mode: One of host, peripheral or otg. Defaults to otg + +Optional properties: +- fsl,usbphy: phandler of usb phy that connects to the only one port +- fsl,usbmisc: phandler of non-core register device, with one argument + that indicate usb controller index +- vbus-supply: regulator for vbus +- disable-over-current: disable over current detect +- external-vbus-divider: enables off-chip resistor divider for Vbus + +Examples: +usb@02184000 { /* USB OTG */ + compatible = fsl,imx6q-usb, fsl,imx27-usb; + reg = 0x02184000 0x200; + interrupts = 0 43 0x04; + fsl,usbphy = usbphy1; + fsl,usbmisc = usbmisc 0; + disable-over-current; + external-vbus-divider; +}; diff --git a/Documentation/devicetree/bindings/usb/mxs-phy.txt b/Documentation/devicetree/bindings/usb/mxs-phy.txt deleted file mode 100644 index 5835b27..000 --- a/Documentation/devicetree/bindings/usb/mxs-phy.txt +++ /dev/null @@ -1,13 +0,0 @@ -* Freescale MXS USB Phy Device - -Required properties: -- compatible: Should be fsl,imx23-usbphy -- reg: Should contain registers location and length -- interrupts: Should contain phy interrupt - -Example: -usbphy1: usbphy@020c9000 { - compatible = fsl,imx6q-usbphy, fsl,imx23-usbphy; - reg = 0x020c9000 0x1000; - interrupts = 0 44 0x04; -}; diff --git a/Documentation/devicetree/bindings/usb/phy-mxs-usb.txt b/Documentation/devicetree/bindings/usb/phy-mxs-usb.txt new file mode 100644 index 000..5835b27 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/phy-mxs-usb.txt @@ -0,0 +1,13 @@ +* Freescale MXS USB Phy Device + +Required properties: +- compatible: Should be fsl,imx23-usbphy +- reg: Should contain registers location and length +- interrupts: Should contain phy interrupt + +Example: +usbphy1: usbphy@020c9000 { + compatible = fsl,imx6q-usbphy, fsl,imx23-usbphy; + reg = 0x020c9000 0x1000; + interrupts = 0 44 0x04; +}; -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/5] usb: chipidea: usbmisc_imx: Using regmap to access register
Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/usbmisc_imx.c | 71 +--- 1 files changed, 34 insertions(+), 37 deletions(-) diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index ac5a461..545efbf 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -15,6 +15,7 @@ #include linux/err.h #include linux/io.h #include linux/delay.h +#include linux/regmap.h #include ci_hdrc_imx.h @@ -34,10 +35,10 @@ struct imx_usbmisc { void __iomem *base; - spinlock_t lock; struct clk *clk; struct usbmisc_usb_device usbdev[USB_DEV_MAX]; const struct usbmisc_ops *ops; + struct regmap *regmap; }; static struct imx_usbmisc *usbmisc; @@ -66,21 +67,16 @@ static struct usbmisc_usb_device *get_usbdev(struct device *dev) static int usbmisc_imx25_post(struct device *dev) { struct usbmisc_usb_device *usbdev; - void __iomem *reg; - unsigned long flags; - u32 val; usbdev = get_usbdev(dev); if (IS_ERR(usbdev)) return PTR_ERR(usbdev); - reg = usbmisc-base + MX25_USB_PHY_CTRL_OFFSET; - if (usbdev-evdo) { - spin_lock_irqsave(usbmisc-lock, flags); - val = readl(reg); - writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); - spin_unlock_irqrestore(usbmisc-lock, flags); + regmap_update_bits(usbmisc-regmap, + MX25_USB_PHY_CTRL_OFFSET, + MX25_BM_EXTERNAL_VBUS_DIVIDER, + MX25_BM_EXTERNAL_VBUS_DIVIDER); usleep_range(5000, 1); /* needed to stabilize voltage */ } @@ -90,37 +86,33 @@ static int usbmisc_imx25_post(struct device *dev) static int usbmisc_imx53_init(struct device *dev) { struct usbmisc_usb_device *usbdev; - void __iomem *reg = NULL; - unsigned long flags; - u32 val = 0; + unsigned int reg = 0, val = 0; usbdev = get_usbdev(dev); if (IS_ERR(usbdev)) return PTR_ERR(usbdev); if (usbdev-disable_oc) { - spin_lock_irqsave(usbmisc-lock, flags); switch (usbdev-index) { case 0: - reg = usbmisc-base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; + reg = MX53_USB_OTG_PHY_CTRL_0_OFFSET; + val = MX53_BM_OVER_CUR_DIS_OTG; break; case 1: - reg = usbmisc-base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; + reg = MX53_USB_OTG_PHY_CTRL_0_OFFSET; + val = MX53_BM_OVER_CUR_DIS_H1; break; case 2: - reg = usbmisc-base + MX53_USB_UH2_CTRL_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + reg = MX53_USB_UH2_CTRL_OFFSET; + val = MX53_BM_OVER_CUR_DIS_UHx; break; case 3: - reg = usbmisc-base + MX53_USB_UH3_CTRL_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + reg = MX53_USB_UH3_CTRL_OFFSET; + val = MX53_BM_OVER_CUR_DIS_UHx; break; } - if (reg val) - writel(val, reg); - spin_unlock_irqrestore(usbmisc-lock, flags); + if (usbdev-index = 0 usbdev-index = 3) + regmap_update_bits(usbmisc-regmap, reg, val, val); } return 0; @@ -128,22 +120,15 @@ static int usbmisc_imx53_init(struct device *dev) static int usbmisc_imx6q_init(struct device *dev) { - struct usbmisc_usb_device *usbdev; - unsigned long flags; - u32 reg; usbdev = get_usbdev(dev); if (IS_ERR(usbdev)) return PTR_ERR(usbdev); - if (usbdev-disable_oc) { - spin_lock_irqsave(usbmisc-lock, flags); - reg = readl(usbmisc-base + usbdev-index * 4); - writel(reg | MX6_BM_OVER_CUR_DIS, - usbmisc-base + usbdev-index * 4); - spin_unlock_irqrestore(usbmisc-lock, flags); - } + if (usbdev-disable_oc) + regmap_update_bits(usbmisc-regmap, usbdev-index * 4, + MX6_BM_OVER_CUR_DIS, MX6_BM_OVER_CUR_DIS); return 0; } @@ -177,6 +162,12 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); +static struct regmap_config usbmisc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4
[PATCH v2 0/5] usb: chipidea: delete usbmisc_imx
At former design, both ci13xxx_imx and usbmisc_imx are individual module, ci13xxx_imx is glue layer for imx usb driver. usbmisc_imx handles non-core registers which have different register layout for imx SoC serials, it usually supplies interface for wakeup setting, PHY setting, etc. usbmisc_imx uses symbols from ci_hdrc_imx, So, when we combile both of drivers as loadable module, usbmisc is needed to be unload first. However at ci_hdrc_imx, it needs to call usbmisc_imx's interface at its removal function once we enable wakeup/runtime pm function, so keeping two drivers together will not work at loadable module use case. To fix loadable module use case, we need to build usbmisc_imx and ci_hdrc_imx together as one module, the usbmisc_imx still handles misc setting for controllers. The first one of this serial has no relateship with this topic, but it is related to rename file, and the other patches will use the new file name, so I hope they can be queued together. Peter Chen (5): usb: chipidea: imx: rename the DT doc name usb: chipidea: usbmisc_imx: Using regmap to access register usb: chipidea: imx: build ci_hdrc_imx.c and usbmisc_imx.c together arm: dts: imx: add aliases for usb arm: dts: imx: Delete usbmisc_imx .../devicetree/bindings/usb/ci13xxx-imx.txt| 31 --- .../devicetree/bindings/usb/ci_hdrc_imx.txt| 35 +++ Documentation/devicetree/bindings/usb/mxs-phy.txt | 13 -- .../devicetree/bindings/usb/phy-mxs-usb.txt| 13 ++ .../devicetree/bindings/usb/usbmisc-imx.txt| 14 -- arch/arm/boot/dts/imx23.dtsi |1 + arch/arm/boot/dts/imx25.dtsi | 14 +- arch/arm/boot/dts/imx28.dtsi |2 + arch/arm/boot/dts/imx51.dtsi | 20 +- arch/arm/boot/dts/imx53.dtsi | 20 +- arch/arm/boot/dts/imx6qdl.dtsi | 20 +- drivers/usb/chipidea/ci_hdrc_imx.c | 113 +-- drivers/usb/chipidea/ci_hdrc_imx.h | 28 ++-- drivers/usb/chipidea/usbmisc_imx.c | 217 +++- drivers/usb/chipidea/usbmisc_imx.h | 14 ++ 15 files changed, 201 insertions(+), 354 deletions(-) delete mode 100644 Documentation/devicetree/bindings/usb/ci13xxx-imx.txt create mode 100644 Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt delete mode 100644 Documentation/devicetree/bindings/usb/mxs-phy.txt create mode 100644 Documentation/devicetree/bindings/usb/phy-mxs-usb.txt delete mode 100644 Documentation/devicetree/bindings/usb/usbmisc-imx.txt create mode 100644 drivers/usb/chipidea/usbmisc_imx.h -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 3/5] usb: chipidea: imx: build ci_hdrc_imx.c and usbmisc_imx.c together
At former design, both ci13xxx_imx and usbmisc_imx are individual module, ci13xxx_imx is glue layer for imx usb driver. usbmisc_imx handles non-core registers which have different register layout for imx SoC serials, it usually supplies interface for wakeup setting, PHY setting, etc. usbmisc_imx uses symbols from ci_hdrc_imx, So, when we combile both of drivers as loadable module, usbmisc is needed to be unload first. However at ci_hdrc_imx, it needs to call usbmisc_imx's interface at its removal function once we enable wakeup/runtime pm function, so keeping two drivers together will not work at loadable module use case. To fix loadable module use case, we need to build usbmisc_imx and ci_hdrc_imx together as one module, the usbmisc_imx still handles misc setting for controllers. There is a short discussion for it: http://marc.info/?l=linux-usbm=136861599423172w=2 Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c | 113 +++--- drivers/usb/chipidea/ci_hdrc_imx.h | 28 +++--- drivers/usb/chipidea/usbmisc_imx.c | 186 +++- drivers/usb/chipidea/usbmisc_imx.h | 14 +++ 4 files changed, 98 insertions(+), 243 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 30fdc2f..be7c86f 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -19,68 +19,68 @@ #include linux/dma-mapping.h #include linux/usb/chipidea.h #include linux/clk.h +#include linux/mfd/syscon.h #include ci.h #include ci_hdrc_imx.h +#include usbmisc_imx.h -struct ci_hdrc_imx_data { - struct usb_phy *phy; - struct platform_device *ci_pdev; - struct clk *clk; +static const struct of_device_id ci_hdrc_imx_dt_ids[] = { + { + .compatible = fsl,imx25-usb, + .data = imx25_usbmisc_data, + }, + { + .compatible = fsl,imx53-usb, + .data = imx53_usbmisc_data, + }, + { + .compatible = fsl,imx6q-usb, + .data = imx6q_usbmisc_data, + }, + { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); -static const struct usbmisc_ops *usbmisc_ops; - -/* Common functions shared by usbmisc drivers */ - -int usbmisc_set_ops(const struct usbmisc_ops *ops) -{ - if (usbmisc_ops) - return -EBUSY; - - usbmisc_ops = ops; - - return 0; -} -EXPORT_SYMBOL_GPL(usbmisc_set_ops); - -void usbmisc_unset_ops(const struct usbmisc_ops *ops) -{ - usbmisc_ops = NULL; -} -EXPORT_SYMBOL_GPL(usbmisc_unset_ops); - -int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) +static int usbmisc_init(struct device *dev) { struct device_node *np = dev-of_node; - struct of_phandle_args args; + struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret; + const struct of_device_id *of_id = + of_match_device(ci_hdrc_imx_dt_ids, dev); - usbdev-dev = dev; + if (of_id-data) + data-misc_data = (struct usbmisc_data *)of_id-data; + else + dev_dbg(dev, no usbmisc data\n); - ret = of_parse_phandle_with_args(np, fsl,usbmisc, #index-cells, - 0, args); - if (ret) { - dev_err(dev, Failed to parse property fsl,usbmisc, errno %d\n, - ret); - memset(usbdev, 0, sizeof(*usbdev)); + ret = of_alias_get_id(np, usb); + if (ret 0) { + dev_err(dev, failed to get alias id, errno %d\n, ret); return ret; } - usbdev-index = args.args[0]; - of_node_put(args.np); if (of_find_property(np, disable-over-current, NULL)) - usbdev-disable_oc = 1; + data-disable_oc = 1; if (of_find_property(np, external-vbus-divider, NULL)) - usbdev-evdo = 1; + data-evdo = 1; + + /* Currently, the usbmisc only handles non core register stuffs */ + if (!data-misc_data) + return 0; + + data-regmap = syscon_regmap_lookup_by_phandle + (np, ci,noncore); + if (IS_ERR(data-regmap)) { + dev_err(dev, can't find non-core regmap: %ld\n, + PTR_ERR(data-regmap)); + return PTR_ERR(data-regmap); + } return 0; } -EXPORT_SYMBOL_GPL(usbmisc_get_init_data); - -/* End of common functions shared by usbmisc drivers*/ - static int ci_hdrc_imx_probe(struct platform_device *pdev) { struct ci_hdrc_imx_data *data; @@ -93,10 +93,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) }; int ret; - if (of_find_property(pdev-dev.of_node, fsl,usbmisc, NULL) -!usbmisc_ops) - return -EPROBE_DEFER; - data = devm_kzalloc(pdev-dev, sizeof
[PATCH v2 4/5] arm: dts: imx: add aliases for usb
At imx usb driver, it needs to know the controller id to access register. Signed-off-by: Peter Chen peter.c...@freescale.com --- arch/arm/boot/dts/imx23.dtsi |1 + arch/arm/boot/dts/imx28.dtsi |2 ++ arch/arm/boot/dts/imx51.dtsi |4 arch/arm/boot/dts/imx53.dtsi |4 arch/arm/boot/dts/imx6qdl.dtsi |4 5 files changed, 15 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi index 587ceef..a0d8471 100644 --- a/arch/arm/boot/dts/imx23.dtsi +++ b/arch/arm/boot/dts/imx23.dtsi @@ -20,6 +20,7 @@ gpio2 = gpio2; serial0 = auart0; serial1 = auart1; + usb0 = usb0; }; cpus { diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 9524a05..931be9c 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -29,6 +29,8 @@ serial4 = auart4; ethernet0 = mac0; ethernet1 = mac1; + usb0 = usb0; + usb1 = usb1; }; cpus { diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 25764b5..67f114c 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -22,6 +22,10 @@ gpio1 = gpio2; gpio2 = gpio3; gpio3 = gpio4; + usb0 = usbotg; + usb1 = usbh1; + usb2 = usbh2; + usb3 = usbh3; }; tzic: tz-interrupt-controller@e000 { diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 569aa9f..429a16f 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -30,6 +30,10 @@ i2c0 = i2c1; i2c1 = i2c2; i2c2 = i2c3; + usb0 = usbotg; + usb1 = usbh1; + usb2 = usbh2; + usb3 = usbh3; }; tzic: tz-interrupt-controller@0fffc000 { diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index f21d259..be1811c 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -26,6 +26,10 @@ gpio4 = gpio5; gpio5 = gpio6; gpio6 = gpio7; + usb0 = usbotg; + usb1 = usbh1; + usb2 = usbh2; + usb3 = usbh3; }; intc: interrupt-controller@00a01000 { -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 5/5] arm: dts: imx: Delete usbmisc_imx
Since ci_hdrc_imx and usbmisc_imx has relationship between each other, they can't be existed as two modules. We change the code, and make the usbmisc_imx has no longer a driver. Due to above reason, we introduce non core register phandle to know the non core register, and delete the binding doc from usbmisc_imx as well. Signed-off-by: Peter Chen peter.c...@freescale.com --- .../devicetree/bindings/usb/ci_hdrc_imx.txt| 12 .../devicetree/bindings/usb/usbmisc-imx.txt| 14 -- arch/arm/boot/dts/imx25.dtsi | 14 +- arch/arm/boot/dts/imx51.dtsi | 16 +++- arch/arm/boot/dts/imx53.dtsi | 16 +++- arch/arm/boot/dts/imx6qdl.dtsi | 16 +++- 6 files changed, 34 insertions(+), 54 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt b/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt index b4b5b79..56d94cb 100644 --- a/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt +++ b/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt @@ -1,4 +1,4 @@ -* Freescale i.MX ci13xxx usb controllers +* Freescale i.MX chipidea usb controllers Required properties: - compatible: Should be fsl,imx27-usb @@ -13,8 +13,7 @@ Recommended properies: Optional properties: - fsl,usbphy: phandler of usb phy that connects to the only one port -- fsl,usbmisc: phandler of non-core register device, with one argument - that indicate usb controller index +- ci,noncore: phandler of non-core register node - vbus-supply: regulator for vbus - disable-over-current: disable over current detect - external-vbus-divider: enables off-chip resistor divider for Vbus @@ -25,7 +24,12 @@ usb@02184000 { /* USB OTG */ reg = 0x02184000 0x200; interrupts = 0 43 0x04; fsl,usbphy = usbphy1; - fsl,usbmisc = usbmisc 0; + ci,noncore = noncore; disable-over-current; external-vbus-divider; }; + +noncore: usb-non-core@02184800 { +compatible = fsl,imx-usb-non-core, syscon; +reg = 0x02184800 0x200; +}; diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt deleted file mode 100644 index 97ce94e..000 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ /dev/null @@ -1,14 +0,0 @@ -* Freescale i.MX non-core registers - -Required properties: -- #index-cells: Cells used to descibe usb controller index. Should be 1 -- compatible: Should be one of below: - fsl,imx6q-usbmisc for imx6q -- reg: Should contain registers location and length - -Examples: -usbmisc@02184800 { - #index-cells = 1; - compatible = fsl,imx6q-usbmisc; - reg = 0x02184800 0x200; -}; diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 7011539..a09251b 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -460,7 +460,7 @@ interrupts = 37; clocks = clks 9, clks 70, clks 8; clock-names = ipg, ahb, per; - fsl,usbmisc = usbmisc 0; + ci,noncore = noncore; status = disabled; }; @@ -470,17 +470,13 @@ interrupts = 35; clocks = clks 9, clks 70, clks 8; clock-names = ipg, ahb, per; - fsl,usbmisc = usbmisc 1; + ci,noncore = noncore; status = disabled; }; - usbmisc: usbmisc@53ff4600 { - #index-cells = 1; - compatible = fsl,imx25-usbmisc; - clocks = clks 9, clks 70, clks 8; - clock-names = ipg, ahb, per; - reg = 0x53ff4600 0x00f; - status = disabled; + noncore: usb-non-core@53ff4600 { +compatible = fsl,imx-usb-non-core, syscon; +reg = 0x53ff4600 0xf; }; dryice@53ffc000 { diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 67f114c..8e55499 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -191,7 +191,7 @@ reg = 0x73f8 0x0200; interrupts = 18; clocks = clks 108; - fsl,usbmisc = usbmisc 0; + ci,noncore = noncore; fsl,usbphy = usbphy0; status = disabled
Re: [PATCH v2 5/5] arm: dts: imx: Delete usbmisc_imx
On Thu, Aug 08, 2013 at 12:38:59PM +0200, Sascha Hauer wrote: On Thu, Aug 08, 2013 at 03:33:01PM +0800, Peter Chen wrote: Since ci_hdrc_imx and usbmisc_imx has relationship between each other, they can't be existed as two modules. We change the code, and make the usbmisc_imx has no longer a driver. Due to above reason, we introduce non core register phandle to know the non core register, and delete the binding doc from usbmisc_imx as well. Signed-off-by: Peter Chen peter.c...@freescale.com --- .../devicetree/bindings/usb/ci_hdrc_imx.txt| 12 .../devicetree/bindings/usb/usbmisc-imx.txt| 14 -- arch/arm/boot/dts/imx25.dtsi | 14 +- arch/arm/boot/dts/imx51.dtsi | 16 +++- arch/arm/boot/dts/imx53.dtsi | 16 +++- arch/arm/boot/dts/imx6qdl.dtsi | 16 +++- 6 files changed, 34 insertions(+), 54 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt b/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt index b4b5b79..56d94cb 100644 --- a/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt +++ b/Documentation/devicetree/bindings/usb/ci_hdrc_imx.txt @@ -1,4 +1,4 @@ -* Freescale i.MX ci13xxx usb controllers +* Freescale i.MX chipidea usb controllers Required properties: - compatible: Should be fsl,imx27-usb @@ -13,8 +13,7 @@ Recommended properies: Optional properties: - fsl,usbphy: phandler of usb phy that connects to the only one port -- fsl,usbmisc: phandler of non-core register device, with one argument - that indicate usb controller index +- ci,noncore: phandler of non-core register node - vbus-supply: regulator for vbus - disable-over-current: disable over current detect - external-vbus-divider: enables off-chip resistor divider for Vbus @@ -25,7 +24,12 @@ usb@02184000 { /* USB OTG */ reg = 0x02184000 0x200; interrupts = 0 43 0x04; fsl,usbphy = usbphy1; - fsl,usbmisc = usbmisc 0; + ci,noncore = noncore; disable-over-current; external-vbus-divider; }; + +noncore: usb-non-core@02184800 { +compatible = fsl,imx-usb-non-core, syscon; +reg = 0x02184800 0x200; +}; diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt deleted file mode 100644 index 97ce94e..000 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ /dev/null @@ -1,14 +0,0 @@ -* Freescale i.MX non-core registers - -Required properties: -- #index-cells: Cells used to descibe usb controller index. Should be 1 -- compatible: Should be one of below: - fsl,imx6q-usbmisc for imx6q -- reg: Should contain registers location and length - -Examples: -usbmisc@02184800 { - #index-cells = 1; - compatible = fsl,imx6q-usbmisc; - reg = 0x02184800 0x200; -}; diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 7011539..a09251b 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -460,7 +460,7 @@ interrupts = 37; clocks = clks 9, clks 70, clks 8; clock-names = ipg, ahb, per; - fsl,usbmisc = usbmisc 0; + ci,noncore = noncore; status = disabled; }; @@ -470,17 +470,13 @@ interrupts = 35; clocks = clks 9, clks 70, clks 8; clock-names = ipg, ahb, per; - fsl,usbmisc = usbmisc 1; + ci,noncore = noncore; status = disabled; }; - usbmisc: usbmisc@53ff4600 { - #index-cells = 1; - compatible = fsl,imx25-usbmisc; - clocks = clks 9, clks 70, clks 8; - clock-names = ipg, ahb, per; - reg = 0x53ff4600 0x00f; - status = disabled; + noncore: usb-non-core@53ff4600 { +compatible = fsl,imx-usb-non-core, syscon; +reg = 0x53ff4600 0xf; }; This is bullshit for multiple reasons. It's the usbmisc unit that changes between different SoCs, not the chipidea core. So pretending the usbmisc unit is generic by removing the SoC specific compatible and instead leaking in the SoC type from the chipidea device nodes is just crazy. Please do not call usbmisc as unit, it should not be a driver, it is a lib, it is usbmisc-lib to implement functions
Re: [PATCH v2 5/5] arm: dts: imx: Delete usbmisc_imx
On Fri, Aug 09, 2013 at 08:20:45AM +0200, Sascha Hauer wrote: On Thu, Aug 08, 2013 at 06:19:43PM +0800, Peter Chen wrote: - compatible = fsl,imx25-usbmisc; - clocks = clks 9, clks 70, clks 8; - clock-names = ipg, ahb, per; - reg = 0x53ff4600 0x00f; - status = disabled; + noncore: usb-non-core@53ff4600 { +compatible = fsl,imx-usb-non-core, syscon; +reg = 0x53ff4600 0xf; }; This is bullshit for multiple reasons. It's the usbmisc unit that changes between different SoCs, not the chipidea core. So pretending the usbmisc unit is generic by removing the SoC specific compatible and instead leaking in the SoC type from the chipidea device nodes is just crazy. Please do not call usbmisc as unit, it should not be a driver, it is a lib, it is usbmisc-lib to implement functions for controller driver. At current design, there are two drivers (ci_hdrc_imx usbmisc_imx) to control one hardware (one imx usb controller). You will need to control the same clocks at two drivers, it is not a good idea. It's more meaningful to talk about devices instead of drivers. The USB core consists of three (on most i.MX) devices, namely three identical chipidea cores. The clocks are shared between all these devices and the clock framework handles this just fine due to reference counting. Three devices? What do you mean? host, device, and otg at former fsl usb driver framework? You know it is better together the resources, something like register mapping, clocks, etc. The less place we put clock we the less error we will meet especially when we introduce runtime power management. Besides, there are dependencies between two drivers, the usbmisc will be unloaded first, how usbmisc can supply the functions after it is unloaded? Remember, it is one hardware, why one driver can forbid another to use controller's function? What you are doing here is to model the DT after how the Linux driver is programmed. This really is a bad idea. Remember that the bindings have to be OS agnostic. They can't be changed just because you want to resolve your module probe dependencies. I am a beginner for DT, how DT binding can't be changed if the driver has re-designed? If I understand correctly, you say bindings have to be OS agnostic, you mean the same DT can be used at all late Linux versions after the binding has finished, is it correct? And not only Linux, but also *BSD and others. Currently I use the same bindings for barebox which means I would have to change the bindings there aswell once you change them in the Kernel. Understand, just like other ABIs, such as sys ctrl, ioctl, etc. So the binding review should be careful and no regression. Again, binding is for driver, if it is not suitable as a driver, what the meaningful for the existent of binding? Maybe I would believe you if you removed the need for a driver, but what you do is to replace a 'usbmisc driver' handling a 'usbmisc device' with a 'syscon driver' handling a 'syscon device'. The real change here is that the implementation of the driver logic is moved from the usbmisc driver to the chipidea driver. Yes, since all chipidea devices need to visit the same register mapping. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] USB: chipidea: i.MX: simplify usbmisc
On Fri, Aug 09, 2013 at 08:56:56AM +0200, Sascha Hauer wrote: The chipidea i.MX driver is split into two drivers. The ci_hdrc_imx driver handles the chipidea cores and the usbmisc_imx driver handles the noncore registers common to all chipidea cores (but SoC specific). Current flow is: - usbmisc sets an ops pointer in the ci_hdrc_imx driver during probe - ci_hdrc_imx checks if the pointer is valid during probe, if yes calls the functions in the ops pointer. - usbmisc_imx calls back into the ci_hdrc_imx driver to get additional data This is overly complicated and has problems if the drivers are compiled as modules. In this case the usbmisc_imx driver can be unloaded even if the ci_hdrc_imx driver still needs usbmisc functionality. This patch changes this by letting the ci_hdrc_imx driver calling functions from the usbmisc_imx driver. This way the symbol resolving during module load makes sure the ci_hdrc_imx driver depends on the usbmisc_imx driver. Also instead of letting the usbmisc_imx driver call back into the ci_hdrc_imx driver, pass the needed data in the first place. Signed-off-by: Sascha Hauer s.ha...@pengutronix.de --- drivers/usb/chipidea/ci_hdrc_imx.c | 74 +++-- drivers/usb/chipidea/ci_hdrc_imx.h | 17 ++- drivers/usb/chipidea/usbmisc_imx.c | 95 +- 3 files changed, 72 insertions(+), 114 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 11ed423..7e722fe 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -29,57 +29,43 @@ struct ci_hdrc_imx_data { struct platform_device *ci_pdev; struct clk *clk; struct regulator *reg_vbus; + struct imx_usbmisc_data *usbmisc_data; }; -static const struct usbmisc_ops *usbmisc_ops; - /* Common functions shared by usbmisc drivers */ -int usbmisc_set_ops(const struct usbmisc_ops *ops) -{ - if (usbmisc_ops) - return -EBUSY; - - usbmisc_ops = ops; - - return 0; -} -EXPORT_SYMBOL_GPL(usbmisc_set_ops); - -void usbmisc_unset_ops(const struct usbmisc_ops *ops) -{ - usbmisc_ops = NULL; -} -EXPORT_SYMBOL_GPL(usbmisc_unset_ops); - -int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) +static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) { struct device_node *np = dev-of_node; struct of_phandle_args args; + struct imx_usbmisc_data *data; int ret; - usbdev-dev = dev; + if (!of_get_property(np, fsl,usbmisc, NULL)) + return NULL; ret = of_parse_phandle_with_args(np, fsl,usbmisc, #index-cells, 0, args); if (ret) { dev_err(dev, Failed to parse property fsl,usbmisc, errno %d\n, ret); - memset(usbdev, 0, sizeof(*usbdev)); - return ret; + return ERR_PTR(ret); } - usbdev-index = args.args[0]; - of_node_put(args.np); Is it a bug fix? + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); + + data-index = args.args[0]; if (of_find_property(np, disable-over-current, NULL)) - usbdev-disable_oc = 1; + data-disable_oc = 1; if (of_find_property(np, external-vbus-divider, NULL)) - usbdev-evdo = 1; + data-evdo = 1; - return 0; + return data; } -EXPORT_SYMBOL_GPL(usbmisc_get_init_data); /* End of common functions shared by usbmisc drivers*/ @@ -96,10 +82,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) struct resource *res; int ret; - if (of_find_property(pdev-dev.of_node, fsl,usbmisc, NULL) - !usbmisc_ops) - return -EPROBE_DEFER; - data = devm_kzalloc(pdev-dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(pdev-dev, Failed to allocate ci_hdrc-imx data!\n); @@ -112,6 +94,10 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) return -ENOENT; } + data-usbmisc_data = usbmisc_get_init_data(pdev-dev); + if (IS_ERR(data-usbmisc_data)) + return PTR_ERR(data-usbmisc_data); + You need to consider mx23/mx28 case which doesn't have usbmisc. Your version can fix current loadable module problem, and it is also easy to add new ops in future. After fixing mx23/mx28 case, we can use your version. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 06/12] usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG
On Fri, Aug 09, 2013 at 03:55:56PM +0300, Alexander Shishkin wrote: Peter Chen peter.c...@freescale.com writes: Since we need otgsc to know vbus's status at some chipidea controllers even it is peripheral-only mode. Besides, some SoCs (eg, AR9331 SoC) don't have otgsc register even the DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS. We inroduce flag CI_HDRC_DUAL_ROLE_NOT_OTG to indicate if the controller is dual role, but not supports OTG. If this flag is not set, we follow the rule that if DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS, then this controller is otg capable. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 38 +++--- include/linux/usb/chipidea.h |5 + 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index bfc9aef..2ae18fd 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -426,6 +426,18 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) ci_hdrc_host_destroy(ci); } +static void ci_get_otg_capable(struct ci_hdrc *ci) +{ + if (ci-platdata-flags CI_HDRC_DUAL_ROLE_NOT_OTG) + ci-is_otg = false; + else + ci-is_otg = (hw_read(ci, CAP_DCCPARAMS, + DCCPARAMS_DC | DCCPARAMS_HC) + == (DCCPARAMS_DC | DCCPARAMS_HC)); + if (ci-is_otg) + dev_dbg(ci-dev, It is OTG capable controller\n); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = pdev-dev; @@ -482,6 +494,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } + /* To know if controller is OTG capable or not */ + ci_get_otg_capable(ci); The comment is redundant. Will delete + } else { + /* +* If the controller is not OTG capable, but support +* role switch, the defalt role is gadget, and the +* user can switch it through debugfs (proc in future?) It's not going to be in procfs ever, so that part of the comment can go. I can delete now, but the role switch does not a debug function, we may not put it at debugfs, do you think so? +*/ + ci-role = CI_ROLE_GADGET; I think we might need a config option for this in the future, at least. Yes, we can add CONFIG_CI_DEFAULT_ROLE in the future. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 04/12] usb: chipidea: otg: Add otg file used to access otgsc
On Fri, Aug 09, 2013 at 04:00:13PM +0300, Alexander Shishkin wrote: Peter Chen peter.c...@freescale.com writes: This file is mainly used to access otgsc currently, it may add otg related things in the future. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h | 10 drivers/usb/chipidea/core.c |3 +- drivers/usb/chipidea/otg.c| 50 + drivers/usb/chipidea/otg.h| 19 +++ 5 files changed, 82 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 6cf5f68..a99d980 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o -ci_hdrc-y := core.o +ci_hdrc-y := core.o otg.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)+= host.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index aefa026..dd0cf9e 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -79,11 +79,21 @@ #define OTGSC_ASVIS BIT(18) #define OTGSC_BSVIS BIT(19) #define OTGSC_BSEIS BIT(20) +#define OTGSC_1MSIS BIT(21) +#define OTGSC_DPIS BIT(22) #define OTGSC_IDIE BIT(24) #define OTGSC_AVVIE BIT(25) #define OTGSC_ASVIE BIT(26) #define OTGSC_BSVIE BIT(27) #define OTGSC_BSEIE BIT(28) +#define OTGSC_1MSIE BIT(29) +#define OTGSC_DPIE BIT(30) +#define OTGSC_INT_EN_BITS (OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \ + | OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \ + | OTGSC_DPIE) +#define OTGSC_INT_STATUS_BITS (OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS \ + | OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \ + | OTGSC_DPIS) /* USBMODE */ #define USBMODE_CM(0x03UL 0) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 26f6599..a4be8a5 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -72,6 +72,7 @@ #include bits.h #include host.h #include debug.h +#include otg.h /* Controller register map */ static uintptr_t ci_regs_nolpm[] = { @@ -530,7 +531,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) goto stop; if (ci-is_otg) - hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); + ci_hdrc_otg_init(ci); ret = dbg_create_files(ci); if (!ret) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c new file mode 100644 index 000..abefb4d --- /dev/null +++ b/drivers/usb/chipidea/otg.c @@ -0,0 +1,50 @@ +/* + * otg.c - ChipIdea USB IP core OTG driver + * + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Author: Peter Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This file mainly handles otgsc register, it may include OTG operation + * in the future. + */ + +#include linux/usb/otg.h +#include linux/usb/gadget.h +#include linux/usb/chipidea.h + +#include ci.h +#include bits.h You don't include otg.h here, which makes sparse think that you wanted these functions to be static. Will add + +void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + /* Only clear request bits */ + hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits); +} + +void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, bits); +} + +void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, 0); +} These functions look like they would be better off as static inlines in otg.h than here. Will do -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 11/12] usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS
On Fri, Aug 09, 2013 at 04:23:11PM +0300, Alexander Shishkin wrote: Peter Chen peter.c...@freescale.com writes: CI_HDRC_REGS_SHARED stands for the controller registers is shared with other USB drivers, if all USB drivers are at chipidea/, it doesn't needed to set. We still have the msm driver that uses REGS_SHARED. Yes, I have considered it. At udc interrupt handler, the REGS_SHARED is still used. The msm set both CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS. CI_HDRC_PULLUP_ON_VBUS stands for pullup dp when the vbus is on. This flag doesn't need to set if the vbus is always on for gadget since dp has always pulled up after the gadget has initialized. Didn't we agree at some point to get rid of this flag altogether once we have proper VBUS detection? Yes, we can delete it now, the reason why I haven't remove it is: I met some use cases that the vbus is always on recently, no connection/disconnection. Eg, the USB audio device connects to Apple Sound machine, the vbus is the power of the device system. I checked the code just now again, we can cover such kind of case. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v14 11/12] usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS
On Fri, Aug 09, 2013 at 07:46:00PM +0800, Peter Chen wrote: On Fri, Aug 09, 2013 at 04:23:11PM +0300, Alexander Shishkin wrote: Peter Chen peter.c...@freescale.com writes: CI_HDRC_REGS_SHARED stands for the controller registers is shared with other USB drivers, if all USB drivers are at chipidea/, it doesn't needed to set. We still have the msm driver that uses REGS_SHARED. Yes, I have considered it. At udc interrupt handler, the REGS_SHARED is still used. The msm set both CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS. CI_HDRC_PULLUP_ON_VBUS stands for pullup dp when the vbus is on. This flag doesn't need to set if the vbus is always on for gadget since dp has always pulled up after the gadget has initialized. Didn't we agree at some point to get rid of this flag altogether once we have proper VBUS detection? Yes, we can delete it now, the reason why I haven't remove it is: I met some use cases that the vbus is always on recently, no connection/disconnection. Eg, the USB audio device connects to Apple Sound machine, the vbus is the power of the device system. I checked the code just now again, we can cover such kind of case. I will have a patch to delete CI_HDRC_PULLUP_ON_VBUS. If we squash two patches, the change like below: diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index bd1fe25..ab3e74a 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -91,7 +91,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) .name = ci_hdrc_imx, .capoffset = DEF_CAPOFFSET, .flags = CI_HDRC_REQUIRE_TRANSCEIVER | - CI_HDRC_PULLUP_ON_VBUS | CI_HDRC_DISABLE_STREAMING, }; int ret; diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index fb657ef..2d51d85 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -49,7 +49,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { .name = ci_hdrc_msm, .flags = CI_HDRC_REGS_SHARED | CI_HDRC_REQUIRE_TRANSCEIVER | - CI_HDRC_PULLUP_ON_VBUS | CI_HDRC_DISABLE_STREAMING, .notify_event = ci_hdrc_msm_notify_event, diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index c70ce38..f77c904 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1635,14 +1635,11 @@ static int ci_udc_start(struct usb_gadget *gadget, ci-driver = driver; pm_runtime_get_sync(ci-gadget.dev); - if (ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) { - if (ci-vbus_active) { - if (ci-platdata-flags CI_HDRC_REGS_SHARED) - hw_device_reset(ci, USBMODE_CM_DC); - } else { - pm_runtime_put_sync(ci-gadget.dev); - goto done; - } + if (ci-vbus_active) { + hw_device_reset(ci, USBMODE_CM_DC); + } else { + pm_runtime_put_sync(ci-gadget.dev); + goto done; } retval = hw_device_state(ci, ci-ep0out-qh.dma); @@ -1665,8 +1662,7 @@ static int ci_udc_stop(struct usb_gadget *gadget, spin_lock_irqsave(ci-lock, flags); - if (!(ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) || - ci-vbus_active) { + if (ci-vbus_active) { hw_device_state(ci, 0); if (ci-platdata-notify_event) ci-platdata-notify_event(ci, @@ -1801,12 +1797,6 @@ static int udc_start(struct ci_hdrc *ci) } } - if (!(ci-platdata-flags CI_HDRC_REGS_SHARED)) { - retval = hw_device_reset(ci, USBMODE_CM_DC); - if (retval) - goto put_transceiver; - } - if (ci-transceiver) { retval = otg_set_peripheral(ci-transceiver-otg, ci-gadget); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 10a607c..7c4ba37 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -18,13 +18,12 @@ struct ci_hdrc_platform_data { unsigned longflags; #define CI_HDRC_REGS_SHAREDBIT(0) #define CI_HDRC_REQUIRE_TRANSCEIVERBIT(1) -#define CI_HDRC_PULLUP_ON_VBUS BIT(2) -#define CI_HDRC_DISABLE_STREAMING BIT(3) +#define CI_HDRC_DISABLE_STREAMING BIT(2) /* * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, * but otg is not supported (no register otgsc). */ -#define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) +#define
Re: [PATCH] usb: chipidea: enable to build host support as module
On Sun, Aug 11, 2013 at 01:00:49PM +0200, Luka Perkov wrote: USB_CHIPIDEA_HOST does not need to depend on USB=y, USB_CHIPIDEA_HOST will work just fine even if USB=m is used. The depends line can be safely removed since USB_CHIPIDEA already depends on USB. Tested on Gateworks imx6q Ventana board (gw-5400-a) and imx6dl Wandboard Dual (imx6dl-wandboard). Signed-off-by: Luka Perkov l...@openwrt.org --- drivers/usb/chipidea/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index d1bd8ef..3eb5a31 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -19,7 +19,6 @@ config USB_CHIPIDEA_UDC config USB_CHIPIDEA_HOST bool ChipIdea host controller - depends on USB=y depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m USB_EHCI_HCD=m) select USB_EHCI_ROOT_HUB_TT help Hi Luka, Lothar has already posted a solution for it. http://marc.info/?l=linux-usbm=137533651927159w=2 -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 02/13] usb: chipidea: host: add vbus regulator control
For boards which have board level vbus control (eg, through gpio), we need to vbus operation according to below rules: - For host, we need open vbus before start hcd, and close it after remove hcd. - For otg, the vbus needs to be on/off when usb role switches. When the host roles begins, it opens vbus; when the host role finishes, it closes vbus. We put vbus operation to host as host is the only vbus user, When we are at host mode, the vbus is on, when we are not at host mode, vbus should be off. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/host.c | 23 ++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 40d0fda..e94e52b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -24,6 +24,7 @@ #include linux/usb.h #include linux/usb/hcd.h #include linux/usb/chipidea.h +#include linux/regulator/consumer.h #include ../host/ehci.h @@ -64,9 +65,19 @@ static int host_start(struct ci_hdrc *ci) ehci-caps = ci-hw_bank.cap; ehci-has_hostpc = ci-hw_bank.lpm; + if (ci-platdata-reg_vbus) { + ret = regulator_enable(ci-platdata-reg_vbus); + if (ret) { + dev_err(ci-dev, + Failed to enable vbus regulator, ret=%d\n, + ret); + goto put_hcd; + } + } + ret = usb_add_hcd(hcd, 0, 0); if (ret) - usb_put_hcd(hcd); + goto disable_reg; else ci-hcd = hcd; @@ -74,6 +85,14 @@ static int host_start(struct ci_hdrc *ci) hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); return ret; + +disable_reg: + regulator_disable(ci-platdata-reg_vbus); + +put_hcd: + usb_put_hcd(hcd); + + return ret; } static void host_stop(struct ci_hdrc *ci) @@ -82,6 +101,8 @@ static void host_stop(struct ci_hdrc *ci) usb_remove_hcd(hcd); usb_put_hcd(hcd); + if (ci-platdata-reg_vbus) + regulator_disable(ci-platdata-reg_vbus); } int ci_hdrc_host_init(struct ci_hdrc *ci) -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 01/13] usb: chipidea: move vbus regulator operation to core
The vbus regulator is a common element for USB vbus operation, So, move it from glue layer to core. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Michael Grzeschik m.grzesc...@pengutronix.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c | 26 ++ drivers/usb/chipidea/core.c| 23 +++ include/linux/usb/chipidea.h |1 + 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 35008e3..bd1fe25 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -19,7 +19,6 @@ #include linux/dma-mapping.h #include linux/usb/chipidea.h #include linux/clk.h -#include linux/regulator/consumer.h #include ci.h #include ci_hdrc_imx.h @@ -31,7 +30,6 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; - struct regulator *reg_vbus; }; static const struct usbmisc_ops *usbmisc_ops; @@ -134,20 +132,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - /* we only support host now, so enable vbus here */ - data-reg_vbus = devm_regulator_get(pdev-dev, vbus); - if (!IS_ERR(data-reg_vbus)) { - ret = regulator_enable(data-reg_vbus); - if (ret) { - dev_err(pdev-dev, - Failed to enable vbus regulator, err=%d\n, - ret); - goto err_clk; - } - } else { - data-reg_vbus = NULL; - } - pdata.phy = data-phy; if (!pdev-dev.dma_mask) @@ -160,7 +144,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) { dev_err(pdev-dev, usbmisc init failed, ret=%d\n, ret); - goto err; + goto err_clk; } } @@ -172,7 +156,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_err(pdev-dev, Can't register ci_hdrc platform device, err=%d\n, ret); - goto err; + goto err_clk; } if (usbmisc_ops usbmisc_ops-post) { @@ -193,9 +177,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data-ci_pdev); -err: - if (data-reg_vbus) - regulator_disable(data-reg_vbus); err_clk: clk_disable_unprepare(data-clk); return ret; @@ -208,9 +189,6 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) pm_runtime_disable(pdev-dev); ci_hdrc_remove_device(data-ci_pdev); - if (data-reg_vbus) - regulator_disable(data-reg_vbus); - if (data-phy) usb_phy_shutdown(data-phy); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 3126c03..26f6599 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -65,6 +65,7 @@ #include linux/usb/chipidea.h #include linux/usb/of.h #include linux/phy.h +#include linux/regulator/consumer.h #include ci.h #include udc.h @@ -342,6 +343,24 @@ static irqreturn_t ci_irq(int irq, void *data) return ret; } +static int ci_get_platdata(struct device *dev, + struct ci_hdrc_platform_data *platdata) +{ + /* Get the vbus regulator */ + platdata-reg_vbus = devm_regulator_get(dev, vbus); + if (PTR_ERR(platdata-reg_vbus) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (PTR_ERR(platdata-reg_vbus) == -ENODEV) { + platdata-reg_vbus = NULL; /* no vbus regualator is needed */ + } else if (IS_ERR(platdata-reg_vbus)) { + dev_err(dev, Getting regulator error: %ld\n, + PTR_ERR(platdata-reg_vbus)); + return PTR_ERR(platdata-reg_vbus); + } + + return 0; +} + static DEFINE_IDA(ci_ida); struct platform_device *ci_hdrc_add_device(struct device *dev, @@ -351,6 +370,10 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, struct platform_device *pdev; int id, ret; + ret = ci_get_platdata(dev, platdata); + if (ret) + return ERR_PTR(ret); + id = ida_simple_get(ci_ida, 0, 0, GFP_KERNEL); if (id 0) return ERR_PTR(id); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 2562994..ce4e1aa 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -24,6 +24,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 void(*notify_event) (struct ci_hdrc *ci
[PATCH v15 00/13] Add tested id switch and vbus connect detect support for Chipidea
This patchset adds tested otg id switch function and vbus connect and disconnect detection for chipidea driver. And fix kinds of bugs found at chipidea drivers after enabling id and vbus detection. This patch are fully tested at imx6 sabresd and imx28evk platform by me. Besides, marek tested it on two STMP3780-based boards (not yet mainline) and two MX28-based boards. My chipidea repo: https://github.com/hzpeterchen/linux-usb.git Changes for v15: - Mark otgsc API as static line, and move them to otg.h [4/13] - Remove some redundant comments [6/13] - Fix some typos [8/13] - Retire flag CI_HDRC_PULLUP_ON_VBUS [12/13] [13/13] Changes for v14: - This patchset is based on below recent chipidea patches and newest usb-next, it can decrease rebase effort. Fabio Estevam (3): chipidea: ci_hdrc_imx: Remove unused variable 'res' chipidea: core: Move hw_phymode_configure() into probe chipidea: Remove previous MODULE_ALIAS Lothar Wabmann (3): usb: chipidea: improve kconfig 2.0 usb: chipidea: don't clobber return value of ci_role_start() usb: chipidea: ci_hdrc_imx: remove an unsolicited module_put() call from ci_hdrc_imx_remove() Peter Chen (1): usb: chipidea: fix the build error with randconfig - [Michael comments]: move vbus operation to core, and squash two vbus patches. [1/12], [2/12] - [Michael comments]: move out non vbus and non id related patches. [14/14 at v13] Chagnes for v13: - Add Tested-by: Marek Vasut ma...@denx.de - [Sascha's comments]: Add return value check for devm_regulator_get. [3/14] - [Marc's comments]: Change timeout usage at hw_wait_reg. [11/14] - [Alex's comments]: Using platdata flag to indicate dual role but not OTG controller. [7/14] Changes for v12: - Rebased greg's usb-next tree (3.10.0-rc7+) - Split more small patches for single function and fix. Peter Chen (12): usb: chipidea: move vbus regulator operation to core usb: chipidea: host: add vbus regulator control usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users usb: chipidea: otg: Add otg file used to access otgsc usb: chipidea: Add role init and destory APIs usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG usb: chipidea: disable all interrupts and clear all interrupts status usb: chipidea: move otg relate things to otg file usb: chipidea: add vbus interrupt handler usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS usb: chipidea: udc: .pullup is valid when vbus is on at CI_HDRC_PULLUP_ON_VBUS Peter Chen (13): usb: chipidea: move vbus regulator operation to core usb: chipidea: host: add vbus regulator control usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users usb: chipidea: otg: Add otg file used to access otgsc usb: chipidea: Add role init and destroy APIs usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG usb: chipidea: disable all interrupts and clear all interrupts status usb: chipidea: move otg related things to otg file usb: chipidea: add vbus interrupt handler usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS usb: chipidea: retire flag CI_HDRC_PULLUP_ON_VBUS usb: chipidea: udc: .pullup is valid only when vbus is there drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h| 10 ++ drivers/usb/chipidea/ci.h |8 ++ drivers/usb/chipidea/ci_hdrc_imx.c | 27 +- drivers/usb/chipidea/ci_hdrc_msm.c |1 - drivers/usb/chipidea/core.c| 183 +--- drivers/usb/chipidea/host.c| 30 ++- drivers/usb/chipidea/host.h|6 + drivers/usb/chipidea/otg.c | 120 +++ drivers/usb/chipidea/otg.h | 35 +++ drivers/usb/chipidea/udc.c | 78 ++-- drivers/usb/chipidea/udc.h |6 + include/linux/usb/chipidea.h |7 +- 13 files changed, 401 insertions(+), 112 deletions(-) create mode 100644 drivers/usb/chipidea/otg.c create mode 100644 drivers/usb/chipidea/otg.h -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 10/13] usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts
When the gadget role starts, we need to make sure the vbus is lower than OTGSC_BSV, or there will be an vbus interrupt since we use B_SESSION_VALID as vbus interrupt to indicate connect and disconnect. When the host role starts, it may not be useful to wait vbus to lower than OTGSC_BSV, but it can indicate some hardware problems like the vbus is still higher than OTGSC_BSV after we disconnect to host some time later (5000 milliseconds currently), which is obvious not correct. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci.h |3 +++ drivers/usb/chipidea/core.c | 32 drivers/usb/chipidea/otg.c |4 3 files changed, 39 insertions(+), 0 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 3160363..1c94fc5 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -308,4 +308,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode); u8 hw_port_test_get(struct ci_hdrc *ci); +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, + u32 value, unsigned int timeout_ms); + #endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index ec0bb11..cfeae3c 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -294,6 +294,38 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) return 0; } +/** + * hw_wait_reg: wait the register value + * + * Sometimes, it needs to wait register value before going on. + * Eg, when switch to device mode, the vbus value should be lower + * than OTGSC_BSV before connects to host. + * + * @ci: the controller + * @reg: register index + * @mask: mast bit + * @value: the bit value to wait + * @timeout_ms: timeout in millisecond + * + * This function returns an error code if timeout + */ +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, + u32 value, unsigned int timeout_ms) +{ + unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); + + while (hw_read(ci, reg, mask) != value) { + if (time_after(jiffies, elapse)) { + dev_err(ci-dev, timeout waiting for %08x in %d\n, + mask, reg); + return -ETIMEDOUT; + } + msleep(20); + } + + return 0; +} + static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 7f37484..39bd7ec 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -52,6 +52,7 @@ void ci_handle_vbus_change(struct ci_hdrc *ci) usb_gadget_vbus_disconnect(ci-gadget); } +#define CI_VBUS_STABLE_TIMEOUT_MS 5000 static void ci_handle_id_switch(struct ci_hdrc *ci) { enum ci_role role = ci_otg_role(ci); @@ -61,6 +62,9 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) ci_role(ci)-name, ci-roles[role]-name); ci_role_stop(ci); + /* wait vbus lower than OTGSC_BSV */ + hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0, + CI_VBUS_STABLE_TIMEOUT_MS); ci_role_start(ci, role); } } -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 11/13] usb: chipidea: udc: misuse flag CI_HDRC_REGS_SHARED and CI_HDRC_PULLUP_ON_VBUS
CI_HDRC_REGS_SHARED stands for the controller registers is shared with other USB drivers, if all USB drivers are at chipidea/, it doesn't needed to set. CI_HDRC_PULLUP_ON_VBUS stands for pullup dp when the vbus is on. This flag doesn't need to set if the vbus is always on for gadget since dp has always pulled up after the gadget has initialized. So, the current code seems to misuse this two flags. - When the gadget initializes, the controller doesn't need to run if it depends on vbus (CI_HDRC_PULLUP_ON_VBUS), it does not relate to shared register. - When the gadget starts (load one gadget module), the controller can run if vbus is on (CI_HDRC_PULLUP_ON_VBUS), it also does not relate to shared register. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index c70ce38..45abf4d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1637,8 +1637,7 @@ static int ci_udc_start(struct usb_gadget *gadget, pm_runtime_get_sync(ci-gadget.dev); if (ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) { if (ci-vbus_active) { - if (ci-platdata-flags CI_HDRC_REGS_SHARED) - hw_device_reset(ci, USBMODE_CM_DC); + hw_device_reset(ci, USBMODE_CM_DC); } else { pm_runtime_put_sync(ci-gadget.dev); goto done; @@ -1801,7 +1800,7 @@ static int udc_start(struct ci_hdrc *ci) } } - if (!(ci-platdata-flags CI_HDRC_REGS_SHARED)) { + if (!(ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS)) { retval = hw_device_reset(ci, USBMODE_CM_DC); if (retval) goto put_transceiver; -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 04/13] usb: chipidea: otg: Add otg file used to access otgsc
This file is mainly used to access otgsc currently, it may add otg related things in the future. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/Makefile |2 +- drivers/usb/chipidea/bits.h | 10 ++ drivers/usb/chipidea/core.c |3 ++- drivers/usb/chipidea/otg.c| 35 +++ drivers/usb/chipidea/otg.h| 32 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 6cf5f68..a99d980 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o -ci_hdrc-y := core.o +ci_hdrc-y := core.o otg.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)+= host.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index aefa026..dd0cf9e 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -79,11 +79,21 @@ #define OTGSC_ASVIS BIT(18) #define OTGSC_BSVIS BIT(19) #define OTGSC_BSEIS BIT(20) +#define OTGSC_1MSIS BIT(21) +#define OTGSC_DPIS BIT(22) #define OTGSC_IDIE BIT(24) #define OTGSC_AVVIE BIT(25) #define OTGSC_ASVIE BIT(26) #define OTGSC_BSVIE BIT(27) #define OTGSC_BSEIE BIT(28) +#define OTGSC_1MSIE BIT(29) +#define OTGSC_DPIE BIT(30) +#define OTGSC_INT_EN_BITS (OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \ + | OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \ + | OTGSC_DPIE) +#define OTGSC_INT_STATUS_BITS (OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS \ + | OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \ + | OTGSC_DPIS) /* USBMODE */ #define USBMODE_CM(0x03UL 0) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 26f6599..a4be8a5 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -72,6 +72,7 @@ #include bits.h #include host.h #include debug.h +#include otg.h /* Controller register map */ static uintptr_t ci_regs_nolpm[] = { @@ -530,7 +531,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) goto stop; if (ci-is_otg) - hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); + ci_hdrc_otg_init(ci); ret = dbg_create_files(ci); if (!ret) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c new file mode 100644 index 000..999a085 --- /dev/null +++ b/drivers/usb/chipidea/otg.c @@ -0,0 +1,35 @@ +/* + * otg.c - ChipIdea USB IP core OTG driver + * + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Author: Peter Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This file mainly handles otgsc register, it may include OTG operation + * in the future. + */ + +#include linux/usb/otg.h +#include linux/usb/gadget.h +#include linux/usb/chipidea.h + +#include ci.h +#include bits.h +#include otg.h + +/** + * ci_hdrc_otg_init - initialize otgsc bits + * ci: the controller + */ +int ci_hdrc_otg_init(struct ci_hdrc *ci) +{ + ci_enable_otg_interrupt(ci, OTGSC_IDIE); + + return 0; +} diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h new file mode 100644 index 000..376eaee --- /dev/null +++ b/drivers/usb/chipidea/otg.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Author: Peter Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_OTG_H +#define __DRIVERS_USB_CHIPIDEA_OTG_H + +static inline void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + /* Only clear request bits */ + hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits); +} + +static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, bits); +} + +static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) +{ + hw_write(ci, OP_OTGSC, bits, 0); +} + +int ci_hdrc_otg_init(struct ci_hdrc *ci); + +#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 05/13] usb: chipidea: Add role init and destroy APIs
- The role's init will be called at probe procedure. - The role's destroy will be called at fail patch at probe and driver's removal. - The role's start/stop will be called when specific role has started. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 10 -- drivers/usb/chipidea/host.c |7 +++ drivers/usb/chipidea/host.h |6 ++ drivers/usb/chipidea/udc.c | 36 +++- drivers/usb/chipidea/udc.h |6 ++ 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index a4be8a5..bfc9aef 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -420,6 +420,12 @@ void ci_hdrc_remove_device(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); +static inline void ci_role_destroy(struct ci_hdrc *ci) +{ + ci_hdrc_gadget_destroy(ci); + ci_hdrc_host_destroy(ci); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = pdev-dev; @@ -539,7 +545,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) free_irq(ci-irq, ci); stop: - ci_role_stop(ci); + ci_role_destroy(ci); rm_wq: flush_workqueue(ci-wq); destroy_workqueue(ci-wq); @@ -555,7 +561,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) flush_workqueue(ci-wq); destroy_workqueue(ci-wq); free_irq(ci-irq, ci); - ci_role_stop(ci); + ci_role_destroy(ci); return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index e94e52b..382be5b 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -105,6 +105,13 @@ static void host_stop(struct ci_hdrc *ci) regulator_disable(ci-platdata-reg_vbus); } + +void ci_hdrc_host_destroy(struct ci_hdrc *ci) +{ + if (ci-role == CI_ROLE_HOST) + host_stop(ci); +} + int ci_hdrc_host_init(struct ci_hdrc *ci) { struct ci_role_driver *rdrv; diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h index 058875c..5707bf3 100644 --- a/drivers/usb/chipidea/host.h +++ b/drivers/usb/chipidea/host.h @@ -4,6 +4,7 @@ #ifdef CONFIG_USB_CHIPIDEA_HOST int ci_hdrc_host_init(struct ci_hdrc *ci); +void ci_hdrc_host_destroy(struct ci_hdrc *ci); #else @@ -12,6 +13,11 @@ static inline int ci_hdrc_host_init(struct ci_hdrc *ci) return -ENXIO; } +static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci) +{ + +} + #endif #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 116c762..24a100d 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -27,6 +27,7 @@ #include udc.h #include bits.h #include debug.h +#include otg.h /* control endpoint description */ static const struct usb_endpoint_descriptor @@ -1844,13 +1845,13 @@ free_qh_pool: } /** - * udc_remove: parent remove must call this to remove UDC + * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC * * No interrupts active, the IRQ has been released */ -static void udc_stop(struct ci_hdrc *ci) +void ci_hdrc_gadget_destroy(struct ci_hdrc *ci) { - if (ci == NULL) + if (!ci-roles[CI_ROLE_GADGET]) return; usb_del_gadget_udc(ci-gadget); @@ -1865,15 +1866,32 @@ static void udc_stop(struct ci_hdrc *ci) if (ci-global_phy) usb_put_phy(ci-transceiver); } - /* my kobject is dynamic, I swear! */ - memset(ci-gadget, 0, sizeof(ci-gadget)); +} + +static int udc_id_switch_for_device(struct ci_hdrc *ci) +{ + if (ci-is_otg) { + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); + ci_enable_otg_interrupt(ci, OTGSC_BSVIE); + } + + return 0; +} + +static void udc_id_switch_for_host(struct ci_hdrc *ci) +{ + if (ci-is_otg) { + /* host doesn't care B_SESSION_VALID event */ + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); + ci_disable_otg_interrupt(ci, OTGSC_BSVIE); + } } /** * ci_hdrc_gadget_init - initialize device related bits * ci: the controller * - * This function enables the gadget role, if the device is device capable. + * This function initializes the gadget, if the device is device capable. */ int ci_hdrc_gadget_init(struct ci_hdrc *ci) { @@ -1886,11 +1904,11 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci) if (!rdrv) return -ENOMEM; - rdrv-start = udc_start; - rdrv-stop = udc_stop; + rdrv-start = udc_id_switch_for_device; + rdrv-stop = udc_id_switch_for_host; rdrv-irq = udc_irq; rdrv-name = gadget; ci-roles[CI_ROLE_GADGET] = rdrv; - return 0; + return udc_start(ci); } diff
[PATCH v15 12/13] usb: chipidea: retire flag CI_HDRC_PULLUP_ON_VBUS
Currently, the controller only runs when the ci-vbus_active is true. So the flag CI_HDRC_PULLUP_ON_VBUS is useless no longer. If the user doesn't have otgsc, he/she needs to change ci_handle_vbus_change to update ci-vbus_active. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci_hdrc_imx.c |1 - drivers/usb/chipidea/ci_hdrc_msm.c |1 - drivers/usb/chipidea/udc.c | 24 ++-- include/linux/usb/chipidea.h |1 - 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index bd1fe25..ab3e74a 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -91,7 +91,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) .name = ci_hdrc_imx, .capoffset = DEF_CAPOFFSET, .flags = CI_HDRC_REQUIRE_TRANSCEIVER | - CI_HDRC_PULLUP_ON_VBUS | CI_HDRC_DISABLE_STREAMING, }; int ret; diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index fb657ef..2d51d85 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -49,7 +49,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { .name = ci_hdrc_msm, .flags = CI_HDRC_REGS_SHARED | CI_HDRC_REQUIRE_TRANSCEIVER | - CI_HDRC_PULLUP_ON_VBUS | CI_HDRC_DISABLE_STREAMING, .notify_event = ci_hdrc_msm_notify_event, diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 45abf4d..90c3572 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1448,9 +1448,6 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) unsigned long flags; int gadget_ready = 0; - if (!(ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS)) - return -EOPNOTSUPP; - spin_lock_irqsave(ci-lock, flags); ci-vbus_active = is_active; if (ci-driver) @@ -1635,13 +1632,11 @@ static int ci_udc_start(struct usb_gadget *gadget, ci-driver = driver; pm_runtime_get_sync(ci-gadget.dev); - if (ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) { - if (ci-vbus_active) { - hw_device_reset(ci, USBMODE_CM_DC); - } else { - pm_runtime_put_sync(ci-gadget.dev); - goto done; - } + if (ci-vbus_active) { + hw_device_reset(ci, USBMODE_CM_DC); + } else { + pm_runtime_put_sync(ci-gadget.dev); + goto done; } retval = hw_device_state(ci, ci-ep0out-qh.dma); @@ -1664,8 +1659,7 @@ static int ci_udc_stop(struct usb_gadget *gadget, spin_lock_irqsave(ci-lock, flags); - if (!(ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS) || - ci-vbus_active) { + if (ci-vbus_active) { hw_device_state(ci, 0); if (ci-platdata-notify_event) ci-platdata-notify_event(ci, @@ -1800,12 +1794,6 @@ static int udc_start(struct ci_hdrc *ci) } } - if (!(ci-platdata-flags CI_HDRC_PULLUP_ON_VBUS)) { - retval = hw_device_reset(ci, USBMODE_CM_DC); - if (retval) - goto put_transceiver; - } - if (ci-transceiver) { retval = otg_set_peripheral(ci-transceiver-otg, ci-gadget); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 10a607c..7d39967 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -18,7 +18,6 @@ struct ci_hdrc_platform_data { unsigned longflags; #define CI_HDRC_REGS_SHAREDBIT(0) #define CI_HDRC_REQUIRE_TRANSCEIVERBIT(1) -#define CI_HDRC_PULLUP_ON_VBUS BIT(2) #define CI_HDRC_DISABLE_STREAMING BIT(3) /* * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 06/13] usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG
Since we need otgsc to know vbus's status at some chipidea controllers even it is peripheral-only mode. Besides, some SoCs (eg, AR9331 SoC) don't have otgsc register even the DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS. We inroduce flag CI_HDRC_DUAL_ROLE_NOT_OTG to indicate if the controller is dual role, but not supports OTG. If this flag is not set, we follow the rule that if DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS, then this controller is otg capable. Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 37 ++--- include/linux/usb/chipidea.h |5 + 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index bfc9aef..56294e0 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -426,6 +426,18 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) ci_hdrc_host_destroy(ci); } +static void ci_get_otg_capable(struct ci_hdrc *ci) +{ + if (ci-platdata-flags CI_HDRC_DUAL_ROLE_NOT_OTG) + ci-is_otg = false; + else + ci-is_otg = (hw_read(ci, CAP_DCCPARAMS, + DCCPARAMS_DC | DCCPARAMS_HC) + == (DCCPARAMS_DC | DCCPARAMS_HC)); + if (ci-is_otg) + dev_dbg(ci-dev, It is OTG capable controller\n); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = pdev-dev; @@ -482,6 +494,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } + ci_get_otg_capable(ci); + if (!ci-platdata-phy_mode) ci-platdata-phy_mode = of_usb_get_phy_mode(dev-of_node); @@ -514,10 +528,22 @@ static int ci_hdrc_probe(struct platform_device *pdev) } if (ci-roles[CI_ROLE_HOST] ci-roles[CI_ROLE_GADGET]) { - ci-is_otg = true; - /* ID pin needs 1ms debouce time, we delay 2ms for safe */ - mdelay(2); - ci-role = ci_otg_role(ci); + if (ci-is_otg) { + /* +* ID pin needs 1ms debouce time, +* we delay 2ms for safe. +*/ + mdelay(2); + ci-role = ci_otg_role(ci); + ci_hdrc_otg_init(ci); + } else { + /* +* If the controller is not OTG capable, but support +* role switch, the defalt role is gadget, and the +* user can switch it through debugfs. +*/ + ci-role = CI_ROLE_GADGET; + } } else { ci-role = ci-roles[CI_ROLE_HOST] ? CI_ROLE_HOST @@ -536,9 +562,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; - if (ci-is_otg) - ci_hdrc_otg_init(ci); - ret = dbg_create_files(ci); if (!ret) return 0; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ce4e1aa..10a607c 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -20,6 +20,11 @@ struct ci_hdrc_platform_data { #define CI_HDRC_REQUIRE_TRANSCEIVERBIT(1) #define CI_HDRC_PULLUP_ON_VBUS BIT(2) #define CI_HDRC_DISABLE_STREAMING BIT(3) + /* +* Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, +* but otg is not supported (no register otgsc). +*/ +#define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) enum usb_dr_modedr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 08/13] usb: chipidea: move otg related things to otg file
Move otg related things to otg file. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 63 +-- drivers/usb/chipidea/otg.c | 57 +- drivers/usb/chipidea/otg.h |2 + 3 files changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 8ce0c45..e869269 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -294,40 +294,6 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode) return 0; } -/** - * ci_otg_role - pick role based on ID pin state - * @ci: the controller - */ -static enum ci_role ci_otg_role(struct ci_hdrc *ci) -{ - u32 sts = hw_read(ci, OP_OTGSC, ~0); - enum ci_role role = sts OTGSC_ID - ? CI_ROLE_GADGET - : CI_ROLE_HOST; - - return role; -} - -/** - * ci_role_work - perform role changing based on ID pin - * @work: work struct - */ -static void ci_role_work(struct work_struct *work) -{ - struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); - enum ci_role role = ci_otg_role(ci); - - if (role != ci-role) { - dev_dbg(ci-dev, switching from %s to %s\n, - ci_role(ci)-name, ci-roles[role]-name); - - ci_role_stop(ci); - ci_role_start(ci, role); - } - - enable_irq(ci-irq); -} - static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; @@ -430,6 +396,8 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) { ci_hdrc_gadget_destroy(ci); ci_hdrc_host_destroy(ci); + if (ci-is_otg) + ci_hdrc_otg_destroy(ci); } static void ci_get_otg_capable(struct ci_hdrc *ci) @@ -496,13 +464,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - INIT_WORK(ci-work, ci_role_work); - ci-wq = create_singlethread_workqueue(ci_otg); - if (!ci-wq) { - dev_err(dev, can't create workqueue\n); - return -ENODEV; - } - ci_get_otg_capable(ci); if (!ci-platdata-phy_mode) @@ -532,8 +493,15 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ci-roles[CI_ROLE_HOST] !ci-roles[CI_ROLE_GADGET]) { dev_err(dev, no supported roles\n); - ret = -ENODEV; - goto rm_wq; + return -ENODEV; + } + + if (ci-is_otg) { + ret = ci_hdrc_otg_init(ci); + if (ret) { + dev_err(dev, init otg fails, ret = %d\n, ret); + goto stop; + } } if (ci-roles[CI_ROLE_HOST] ci-roles[CI_ROLE_GADGET]) { @@ -544,7 +512,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) */ mdelay(2); ci-role = ci_otg_role(ci); - ci_hdrc_otg_init(ci); + ci_enable_otg_interrupt(ci, OTGSC_IDIE); } else { /* * If the controller is not OTG capable, but support @@ -562,7 +530,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) ret = ci_role_start(ci, ci-role); if (ret) { dev_err(dev, can't start %s role\n, ci_role(ci)-name); - goto rm_wq; + goto stop; } platform_set_drvdata(pdev, ci); @@ -578,9 +546,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) free_irq(ci-irq, ci); stop: ci_role_destroy(ci); -rm_wq: - flush_workqueue(ci-wq); - destroy_workqueue(ci-wq); return ret; } @@ -590,8 +555,6 @@ static int ci_hdrc_remove(struct platform_device *pdev) struct ci_hdrc *ci = platform_get_drvdata(pdev); dbg_remove_files(ci); - flush_workqueue(ci-wq); - destroy_workqueue(ci-wq); free_irq(ci-irq, ci); ci_role_destroy(ci); diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 999a085..3b66cbe 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -24,12 +24,65 @@ #include otg.h /** - * ci_hdrc_otg_init - initialize otgsc bits + * ci_otg_role - pick role based on ID pin state + * @ci: the controller + */ +enum ci_role ci_otg_role(struct ci_hdrc *ci) +{ + u32 sts = hw_read(ci, OP_OTGSC, ~0); + enum ci_role role = sts OTGSC_ID + ? CI_ROLE_GADGET + : CI_ROLE_HOST; + + return role; +} + +/** + * ci_role_work - perform role changing based on ID pin + * @work: work struct + */ +static void ci_role_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + enum ci_role role = ci_otg_role(ci); + + if (role != ci-role
[PATCH v15 03/13] usb: chipidea: udc: otg_set_peripheral is useless for some chipidea users
It is useless at below cases: - If we implement both usb host and device at chipidea driver. - If we don't need phy-otg. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/udc.c |7 ++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index e475fcd..116c762 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1805,7 +1805,12 @@ static int udc_start(struct ci_hdrc *ci) if (ci-transceiver) { retval = otg_set_peripheral(ci-transceiver-otg, ci-gadget); - if (retval) + /* +* If we implement all USB functions using chipidea drivers, +* it doesn't need to call above API, meanwhile, if we only +* use gadget function, calling above API is useless. +*/ + if (retval retval != -ENOTSUPP) goto put_transceiver; } -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v15 09/13] usb: chipidea: add vbus interrupt handler
We add vbus interrupt handler at ci_otg_work, it uses OTGSC_BSV(at otgsc) to know it is connect or disconnet event. Meanwhile, we introduce two flags id_event and b_sess_valid_event to indicate it is an id interrupt or a vbus interrupt. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/ci.h |5 + drivers/usb/chipidea/core.c | 28 +++- drivers/usb/chipidea/otg.c | 42 +++--- drivers/usb/chipidea/otg.h |1 + drivers/usb/chipidea/udc.c |7 +++ 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 33cb29f..3160363 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -132,6 +132,9 @@ struct hw_bank { * @transceiver: pointer to USB PHY, if any * @hcd: pointer to usb_hcd for ehci host driver * @debugfs: root dentry for this controller in debugfs + * @id_event: indicates there is an id event, and handled at ci_otg_work + * @b_sess_valid_event: indicates there is a vbus event, and handled + * at ci_otg_work */ struct ci_hdrc { struct device *dev; @@ -168,6 +171,8 @@ struct ci_hdrc { struct usb_phy *transceiver; struct usb_hcd *hcd; struct dentry *debugfs; + boolid_event; + boolb_sess_valid_event; }; static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index e869269..ec0bb11 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -303,16 +303,34 @@ static irqreturn_t ci_irq(int irq, void *data) if (ci-is_otg) otgsc = hw_read(ci, OP_OTGSC, ~0); - if (ci-role != CI_ROLE_END) - ret = ci_role(ci)-irq(ci); + /* +* Handle id change interrupt, it indicates device/host function +* switch. +*/ + if (ci-is_otg (otgsc OTGSC_IDIE) (otgsc OTGSC_IDIS)) { + ci-id_event = true; + ci_clear_otg_interrupt(ci, OTGSC_IDIS); + disable_irq_nosync(ci-irq); + queue_work(ci-wq, ci-work); + return IRQ_HANDLED; + } - if (ci-is_otg (otgsc OTGSC_IDIS)) { - hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS); + /* +* Handle vbus change interrupt, it indicates device connection +* and disconnection events. +*/ + if (ci-is_otg (otgsc OTGSC_BSVIE) (otgsc OTGSC_BSVIS)) { + ci-b_sess_valid_event = true; + ci_clear_otg_interrupt(ci, OTGSC_BSVIS); disable_irq_nosync(ci-irq); queue_work(ci-wq, ci-work); - ret = IRQ_HANDLED; + return IRQ_HANDLED; } + /* Handle device/host interrupt */ + if (ci-role != CI_ROLE_END) + ret = ci_role(ci)-irq(ci); + return ret; } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 3b66cbe..7f37484 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -37,13 +37,23 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) return role; } -/** - * ci_role_work - perform role changing based on ID pin - * @work: work struct - */ -static void ci_role_work(struct work_struct *work) +void ci_handle_vbus_change(struct ci_hdrc *ci) +{ + u32 otgsc; + + if (!ci-is_otg) + return; + + otgsc = hw_read(ci, OP_OTGSC, ~0); + + if (otgsc OTGSC_BSV) + usb_gadget_vbus_connect(ci-gadget); + else + usb_gadget_vbus_disconnect(ci-gadget); +} + +static void ci_handle_id_switch(struct ci_hdrc *ci) { - struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); enum ci_role role = ci_otg_role(ci); if (role != ci-role) { @@ -53,17 +63,35 @@ static void ci_role_work(struct work_struct *work) ci_role_stop(ci); ci_role_start(ci, role); } +} +/** + * ci_otg_work - perform otg (vbus/id) event handle + * @work: work struct + */ +static void ci_otg_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); + + if (ci-id_event) { + ci-id_event = false; + ci_handle_id_switch(ci); + } else 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__); enable_irq(ci-irq); } + /** * ci_hdrc_otg_init - initialize otg struct * ci: the controller */ int ci_hdrc_otg_init(struct ci_hdrc *ci) { - INIT_WORK(ci-work, ci_role_work); + INIT_WORK(ci-work
[PATCH v15 07/13] usb: chipidea: disable all interrupts and clear all interrupts status
During the initialization, it needs to disable all interrupts enable bit as well as clear all interrupts status bits to avoid exceptional interrupt. Tested-by: Marek Vasut ma...@denx.de Signed-off-by: Peter Chen peter.c...@freescale.com --- drivers/usb/chipidea/core.c | 11 ++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 56294e0..8ce0c45 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -199,6 +199,12 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) if (ci-hw_ep_max ENDPT_MAX) return -ENODEV; + /* Disable all interrupts bits */ + hw_write(ci, OP_USBINTR, 0x, 0); + + /* Clear all interrupts status bits*/ + hw_write(ci, OP_USBSTS, 0x, 0x); + dev_dbg(ci-dev, ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n, ci-hw_bank.lpm, ci-hw_bank.cap, ci-hw_bank.op); @@ -434,8 +440,11 @@ static void ci_get_otg_capable(struct ci_hdrc *ci) ci-is_otg = (hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC | DCCPARAMS_HC) == (DCCPARAMS_DC | DCCPARAMS_HC)); - if (ci-is_otg) + if (ci-is_otg) { dev_dbg(ci-dev, It is OTG capable controller\n); + ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); + ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); + } } static int ci_hdrc_probe(struct platform_device *pdev) -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] USB: chipidea: i.MX: remove unused define
On Mon, Aug 12, 2013 at 12:29:41PM +0200, Sascha Hauer wrote: Signed-off-by: Sascha Hauer s.ha...@pengutronix.de --- drivers/usb/chipidea/ci_hdrc_imx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 14362c0..11ed423 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -24,9 +24,6 @@ #include ci.h #include ci_hdrc_imx.h -#define pdev_to_phy(pdev) \ - ((struct usb_phy *)platform_get_drvdata(pdev)) - This one has already submitted by me, and queued by alex. -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] USB: chipidea: i.MX: simplify usbmisc
+ MX53_USB_OTG_PHY_CTRL_0_OFFSET; val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; @@ -126,22 +105,19 @@ static int usbmisc_imx53_init(struct device *dev) return 0; } -static int usbmisc_imx6q_init(struct device *dev) +static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) { - - struct usbmisc_usb_device *usbdev; unsigned long flags; u32 reg; - usbdev = get_usbdev(dev); - if (IS_ERR(usbdev)) - return PTR_ERR(usbdev); + if (data-index 3) + return -EINVAL; - if (usbdev-disable_oc) { + if (data-disable_oc) { spin_lock_irqsave(usbmisc-lock, flags); - reg = readl(usbmisc-base + usbdev-index * 4); + reg = readl(usbmisc-base + data-index * 4); writel(reg | MX6_BM_OVER_CUR_DIS, - usbmisc-base + usbdev-index * 4); + usbmisc-base + data-index * 4); spin_unlock_irqrestore(usbmisc-lock, flags); } @@ -160,6 +136,26 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = { .init = usbmisc_imx6q_init, }; +int imx_usbmisc_init(struct imx_usbmisc_data *data) +{ + if (!usbmisc) + return -EPROBE_DEFER; + if (!usbmisc-ops-init) + return 0; + return usbmisc-ops-init(data); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_init); + +int imx_usbmisc_init_post(struct imx_usbmisc_data *data) +{ + if (!usbmisc) + return -EPROBE_DEFER; + if (!usbmisc-ops-post) + return 0; + return usbmisc-ops-post(data); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); + static const struct of_device_id usbmisc_imx_dt_ids[] = { { .compatible = fsl,imx25-usbmisc, @@ -216,19 +212,12 @@ static int usbmisc_imx_probe(struct platform_device *pdev) of_match_device(usbmisc_imx_dt_ids, pdev-dev); data-ops = (const struct usbmisc_ops *)tmp_dev-data; usbmisc = data; - ret = usbmisc_set_ops(data-ops); - if (ret) { - usbmisc = NULL; - clk_disable_unprepare(data-clk); - return ret; - } return 0; } static int usbmisc_imx_remove(struct platform_device *pdev) { - usbmisc_unset_ops(usbmisc-ops); clk_disable_unprepare(usbmisc-clk); usbmisc = NULL; return 0; -- 1.8.4.rc1 Acked-by: Peter Chen peter.c...@freescale.com -- Best Regards, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] dwc3: dwc3-pci: Use SIMPLE_DEV_PM_OPS
On Wed, Aug 7, 2013 at 7:51 PM, Fabio Estevam feste...@gmail.com wrote: From: Fabio Estevam fabio.este...@freescale.com Using SIMPLE_DEV_PM_OPS can make the code simpler and cleaner. Signed-off-by: Fabio Estevam fabio.este...@freescale.com --- drivers/usb/dwc3/dwc3-pci.c | 15 +-- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 5d746e5..b922315 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -191,7 +191,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dwc3_pci_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); @@ -216,15 +216,10 @@ static int dwc3_pci_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_SLEEP */ -static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) -}; - -#define DEV_PM_OPS (dwc3_pci_dev_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(dwc3_pci_dev_pm_ops, dwc3_pci_suspend, +dwc3_pci_resume); static struct pci_driver dwc3_pci_driver = { .name = dwc3-pci, @@ -232,7 +227,7 @@ static struct pci_driver dwc3_pci_driver = { .probe = dwc3_pci_probe, .remove = dwc3_pci_remove, .driver = { - .pm = DEV_PM_OPS, + .pm = dwc3_pci_dev_pm_ops, }, }; It seems .pm is not NULL if CONFIG_PM_SLEEP is not defined which is not the same with former code. -- BR, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] dwc3: dwc3-pci: Use SIMPLE_DEV_PM_OPS
On Tue, Aug 13, 2013 at 8:59 PM, Fabio Estevam feste...@gmail.com wrote: On Tue, Aug 13, 2013 at 3:59 AM, Peter Chen hzpeterc...@gmail.com wrote: It seems .pm is not NULL if CONFIG_PM_SLEEP is not defined which is not the same with former code. With SIMPLE_DEV_PM_OPS macro we don't need to define the NULL function variants. Take a look at include/linux/pm.h to get a clear picture. But what I see is the dwc3_pci_dev_pm_ops is not NULL if CONFIG_PM_SLEEP is not defined. static foo(void) {} static goo(void) {} struct dev_pm_ops { int a; int b; }; #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) #define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ const struct dev_pm_ops name = { \ SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ } SIMPLE_DEV_PM_OPS(test_name, foo, goo); void main(void) { printf(the pointer of name is %p\n, test_name); return; } -- BR, Peter Chen -- To unsubscribe from this list: send the line unsubscribe linux-usb in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html