diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-11-18 12:29:13 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-11-18 12:29:13 +0100 |
commit | b38bcc8e12062452ae86158a3bbc4235fd395d91 (patch) | |
tree | e4b9ff061d2a093a5f358d9df7626feb636324e7 /drivers/usb | |
parent | 347bc8cb26388791c5881a3775cb14a3f765a674 (diff) | |
parent | 4d6141288c33b73027260e73df262464cbe1fd0d (diff) | |
download | linux-b38bcc8e12062452ae86158a3bbc4235fd395d91.tar.gz linux-b38bcc8e12062452ae86158a3bbc4235fd395d91.tar.bz2 linux-b38bcc8e12062452ae86158a3bbc4235fd395d91.zip |
Merge tag 'usb-ci-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb into usb-next
Peter writes:
- Improve the Vbus handler
- Improve the HSIC handler for i.mx serial SoC
- Some other tiny changes
* tag 'usb-ci-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb:
usb: chipidea: imx: pinctrl for HSIC is optional
usb: chipidea: imx: refine the error handling for hsic
usb: chipidea: imx: change hsic power regulator as optional
usb: chipidea: imx: check data->usbmisc_data against NULL before access
usb: chipidea: core: change vbus-regulator as optional
usb: chipidea: imx: enable vbus and id wakeup only for OTG events
usb: chipidea: udc: protect usb interrupt enable
usb: chipidea: udc: add new API ci_hdrc_gadget_connect
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/chipidea/ci_hdrc_imx.c | 79 | ||||
-rw-r--r-- | drivers/usb/chipidea/ci_hdrc_imx.h | 2 | ||||
-rw-r--r-- | drivers/usb/chipidea/core.c | 2 | ||||
-rw-r--r-- | drivers/usb/chipidea/udc.c | 73 | ||||
-rw-r--r-- | drivers/usb/chipidea/usbmisc_imx.c | 31 |
5 files changed, 114 insertions, 73 deletions
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index df8812c30640..d8e7eb2f97b9 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -274,11 +274,14 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) switch (event) { case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: - ret = pinctrl_select_state(data->pinctrl, - data->pinctrl_hsic_active); - if (ret) - dev_err(dev, "hsic_active select failed, err=%d\n", - ret); + if (data->pinctrl) { + ret = pinctrl_select_state(data->pinctrl, + data->pinctrl_hsic_active); + if (ret) + dev_err(dev, + "hsic_active select failed, err=%d\n", + ret); + } break; case CI_HDRC_IMX_HSIC_SUSPEND_EVENT: ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data); @@ -306,7 +309,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) const struct ci_hdrc_imx_platform_flag *imx_platform_flag; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - struct pinctrl_state *pinctrl_hsic_idle; of_id = of_match_device(ci_hdrc_imx_dt_ids, dev); if (!of_id) @@ -330,12 +332,42 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) pdata.flags |= CI_HDRC_IMX_IS_HSIC; data->usbmisc_data->hsic = 1; data->pinctrl = devm_pinctrl_get(dev); - if (IS_ERR(data->pinctrl)) { - dev_err(dev, "pinctrl get failed, err=%ld\n", + if (PTR_ERR(data->pinctrl) == -ENODEV) + data->pinctrl = NULL; + else if (IS_ERR(data->pinctrl)) { + if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER) + dev_err(dev, "pinctrl get failed, err=%ld\n", PTR_ERR(data->pinctrl)); return PTR_ERR(data->pinctrl); } + data->hsic_pad_regulator = + devm_regulator_get_optional(dev, "hsic"); + if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { + /* no pad regualator is needed */ + data->hsic_pad_regulator = NULL; + } else if (IS_ERR(data->hsic_pad_regulator)) { + if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER) + dev_err(dev, + "Get HSIC pad regulator error: %ld\n", + PTR_ERR(data->hsic_pad_regulator)); + return PTR_ERR(data->hsic_pad_regulator); + } + + if (data->hsic_pad_regulator) { + ret = regulator_enable(data->hsic_pad_regulator); + if (ret) { + dev_err(dev, + "Failed to enable HSIC pad regulator\n"); + return ret; + } + } + } + + /* HSIC pinctrl handling */ + if (data->pinctrl) { + struct pinctrl_state *pinctrl_hsic_idle; + pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); if (IS_ERR(pinctrl_hsic_idle)) { dev_err(dev, @@ -358,27 +390,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) PTR_ERR(data->pinctrl_hsic_active)); return PTR_ERR(data->pinctrl_hsic_active); } - - data->hsic_pad_regulator = devm_regulator_get(dev, "hsic"); - if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { - /* no pad regualator is needed */ - data->hsic_pad_regulator = NULL; - } else if (IS_ERR(data->hsic_pad_regulator)) { - dev_err(dev, "Get HSIC pad regulator error: %ld\n", - PTR_ERR(data->hsic_pad_regulator)); - return PTR_ERR(data->hsic_pad_regulator); - } - - if (data->hsic_pad_regulator) { - ret = regulator_enable(data->hsic_pad_regulator); - if (ret) { - dev_err(dev, - "Failed to enable HSIC pad regulator\n"); - return ret; - } - } } if (pdata.flags & CI_HDRC_PMQOS) @@ -433,6 +444,16 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } + if (data->usbmisc_data) { + if (!IS_ERR(pdata.id_extcon.edev) || + of_property_read_bool(np, "usb-role-switch")) + data->usbmisc_data->ext_id = 1; + + if (!IS_ERR(pdata.vbus_extcon.edev) || + of_property_read_bool(np, "usb-role-switch")) + data->usbmisc_data->ext_vbus = 1; + } + ret = imx_usbmisc_init_post(data->usbmisc_data); if (ret) { dev_err(dev, "usbmisc post failed, ret=%d\n", ret); diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index c842e03f8767..de2aac9a2868 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -22,6 +22,8 @@ struct imx_usbmisc_data { unsigned int evdo:1; /* set external vbus divider option */ unsigned int ulpi:1; /* connected to an ULPI phy */ unsigned int hsic:1; /* HSIC controlller */ + unsigned int ext_id:1; /* ID from exteranl event */ + unsigned int ext_vbus:1; /* Vbus from exteranl event */ }; int imx_usbmisc_init(struct imx_usbmisc_data *data); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 98ee575ee500..dce5db41501c 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -683,7 +683,7 @@ static int ci_get_platdata(struct device *dev, if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { /* Get the vbus regulator */ - platdata->reg_vbus = devm_regulator_get(dev, "vbus"); + platdata->reg_vbus = devm_regulator_get_optional(dev, "vbus"); if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { return -EPROBE_DEFER; } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 0b6166a64d72..ffaf46f5d062 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1524,42 +1524,53 @@ static const struct usb_ep_ops usb_ep_ops = { /****************************************************************************** * GADGET block *****************************************************************************/ +/** + * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded + */ +static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active) +{ + struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); + unsigned long flags; + + if (is_active) { + pm_runtime_get_sync(&_gadget->dev); + hw_device_reset(ci); + spin_lock_irqsave(&ci->lock, flags); + if (ci->driver) { + hw_device_state(ci, ci->ep0out->qh.dma); + usb_gadget_set_state(_gadget, USB_STATE_POWERED); + usb_udc_vbus_handler(_gadget, true); + } + spin_unlock_irqrestore(&ci->lock, flags); + } else { + usb_udc_vbus_handler(_gadget, false); + if (ci->driver) + ci->driver->disconnect(&ci->gadget); + hw_device_state(ci, 0); + if (ci->platdata->notify_event) + ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_STOPPED_EVENT); + _gadget_stop_activity(&ci->gadget); + pm_runtime_put_sync(&_gadget->dev); + usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); + } +} + static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) { struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); unsigned long flags; - int gadget_ready = 0; spin_lock_irqsave(&ci->lock, flags); ci->vbus_active = is_active; - if (ci->driver) - gadget_ready = 1; spin_unlock_irqrestore(&ci->lock, flags); if (ci->usb_phy) usb_phy_set_charger_state(ci->usb_phy, is_active ? USB_CHARGER_PRESENT : USB_CHARGER_ABSENT); - if (gadget_ready) { - if (is_active) { - pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(ci); - hw_device_state(ci, ci->ep0out->qh.dma); - usb_gadget_set_state(_gadget, USB_STATE_POWERED); - usb_udc_vbus_handler(_gadget, true); - } else { - usb_udc_vbus_handler(_gadget, false); - if (ci->driver) - ci->driver->disconnect(&ci->gadget); - hw_device_state(ci, 0); - if (ci->platdata->notify_event) - ci->platdata->notify_event(ci, - CI_HDRC_CONTROLLER_STOPPED_EVENT); - _gadget_stop_activity(&ci->gadget); - pm_runtime_put_sync(&_gadget->dev); - usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); - } - } + if (ci->driver) + ci_hdrc_gadget_connect(_gadget, is_active); return 0; } @@ -1785,18 +1796,10 @@ static int ci_udc_start(struct usb_gadget *gadget, return retval; } - pm_runtime_get_sync(&ci->gadget.dev); - if (ci->vbus_active) { - hw_device_reset(ci); - } else { + if (ci->vbus_active) + ci_hdrc_gadget_connect(gadget, 1); + else usb_udc_vbus_handler(&ci->gadget, false); - pm_runtime_put_sync(&ci->gadget.dev); - return retval; - } - - retval = hw_device_state(ci, ci->ep0out->qh.dma); - if (retval) - pm_runtime_put_sync(&ci->gadget.dev); return retval; } @@ -1826,6 +1829,7 @@ static int ci_udc_stop(struct usb_gadget *gadget) unsigned long flags; spin_lock_irqsave(&ci->lock, flags); + ci->driver = NULL; if (ci->vbus_active) { hw_device_state(ci, 0); @@ -1838,7 +1842,6 @@ static int ci_udc_stop(struct usb_gadget *gadget) pm_runtime_put(&ci->gadget.dev); } - ci->driver = NULL; spin_unlock_irqrestore(&ci->lock, flags); ci_udc_stop_for_otg_fsm(ci); diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 078c1fdce493..e81e33c26e6c 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -100,6 +100,9 @@ #define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2) #define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3) +#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \ + MX6_BM_ID_WAKEUP) + struct usbmisc_ops { /* It's called once when probe a usb device */ int (*init)(struct imx_usbmisc_data *data); @@ -330,14 +333,25 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data) return 0; } +static u32 usbmisc_wakeup_setting(struct imx_usbmisc_data *data) +{ + u32 wakeup_setting = MX6_USB_OTG_WAKEUP_BITS; + + if (data->ext_id) + wakeup_setting &= ~MX6_BM_ID_WAKEUP; + + if (data->ext_vbus) + wakeup_setting &= ~MX6_BM_VBUS_WAKEUP; + + return wakeup_setting; +} + static int usbmisc_imx6q_set_wakeup (struct imx_usbmisc_data *data, bool enabled) { struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); unsigned long flags; u32 val; - u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE | - MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP); int ret = 0; if (data->index > 3) @@ -346,11 +360,12 @@ static int usbmisc_imx6q_set_wakeup spin_lock_irqsave(&usbmisc->lock, flags); val = readl(usbmisc->base + data->index * 4); if (enabled) { - val |= wakeup_setting; + val &= ~MX6_USB_OTG_WAKEUP_BITS; + val |= usbmisc_wakeup_setting(data); } else { if (val & MX6_BM_WAKEUP_INTR) pr_debug("wakeup int at ci_hdrc.%d\n", data->index); - val &= ~wakeup_setting; + val &= ~MX6_USB_OTG_WAKEUP_BITS; } writel(val, usbmisc->base + data->index * 4); spin_unlock_irqrestore(&usbmisc->lock, flags); @@ -547,17 +562,17 @@ static int usbmisc_imx7d_set_wakeup struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); unsigned long flags; u32 val; - u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE | - MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP); spin_lock_irqsave(&usbmisc->lock, flags); val = readl(usbmisc->base); if (enabled) { - writel(val | wakeup_setting, usbmisc->base); + val &= ~MX6_USB_OTG_WAKEUP_BITS; + val |= usbmisc_wakeup_setting(data); + writel(val, usbmisc->base); } else { if (val & MX6_BM_WAKEUP_INTR) dev_dbg(data->dev, "wakeup int\n"); - writel(val & ~wakeup_setting, usbmisc->base); + writel(val & ~MX6_USB_OTG_WAKEUP_BITS, usbmisc->base); } spin_unlock_irqrestore(&usbmisc->lock, flags); |