usb: chipidea: introduce CI_HDRC_CONTROLLER_VBUS_EVENT glue layer use
Peter Chen
maintainerPATCH 1/4 usb: chipidea: introduce CI_HDRC_CONTROLLER_VBUS_EVENT glue layer use
From: Peter Chen <[email protected]>
Some vendors glue layer need to handle some events for vbus, eg, some i.mx platforms (imx7d, imx8mm, imx8mn, etc) needs vbus event to handle charger detection, its charger detection is finished at glue layer code, but not at USB PHY driver.
--- drivers/usb/chipidea/udc.c | 7 ++++++- include/linux/usb/chipidea.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-)
drivers/usb/chipidea/udc.c +6 -1
@@ -1561,6 +1561,7 @@ 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 ret =0 ;spin_lock_irqsave (&ci->lock, flags); ci->vbus_active = is_active;
@@ -1570,10 +1571,14 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)usb_phy_set_charger_state (ci->usb_phy, is_active ?USB_CHARGER_PRESENT :USB_CHARGER_ABSENT ); +if (ci->platdata->notify_event) + ret = ci->platdata->notify_event (ci, +CI_HDRC_CONTROLLER_VBUS_EVENT ); +if (ci->driver)ci_hdrc_gadget_connect (_gadget, is_active); -return 0 ; +return ret; }static int ci_udc_wakeup (struct usb_gadget *_gadget)
include/linux/usb/chipidea.h +1 -0
@@ -67,6 +67,7 @@ struct ci_hdrc_platform_data {#define CI_HDRC_CONTROLLER_STOPPED_EVENT 1#define CI_HDRC_IMX_HSIC_ACTIVE_EVENT 2#define CI_HDRC_IMX_HSIC_SUSPEND_EVENT 3 +#define CI_HDRC_CONTROLLER_VBUS_EVENT 4int (*notify_event) (struct ci_hdrc *ci,unsigned event);struct regulator *reg_vbus;struct usb_otg_caps ci_otg_caps;
Signature · 1 line
2.17.1
Peter Chen
maintainerPATCH 2/4 usb: chipidea: introduce imx7d USB charger detection
From: Jun Li <[email protected]>
imx7d (and imx8mm, imx8mn) uses Samsung PHY and USB generic PHY driver. The USB generic PHY driver is impossible to have a charger detection for every user, so we implement USB charger detection routine at glue layer. After the detection has finished, it will notify USB PHY charger framework, and the uevents will be triggered.
--- drivers/usb/chipidea/ci_hdrc_imx.c | 13 +- drivers/usb/chipidea/ci_hdrc_imx.h | 2 + drivers/usb/chipidea/usbmisc_imx.c | 245 +++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+), 1 deletion(-)
drivers/usb/chipidea/ci_hdrc_imx.c +12 -1
@@ -271,6 +271,7 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)struct device *dev = ci->dev->parent;struct ci_hdrc_imx_data *data =dev_get_drvdata (dev);int ret =0 ; +struct imx_usbmisc_data *mdata = data->usbmisc_data;switch (event) {case CI_HDRC_IMX_HSIC_ACTIVE_EVENT :
@@ -284,11 +285,19 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) }break ;case CI_HDRC_IMX_HSIC_SUSPEND_EVENT : - ret =imx_usbmisc_hsic_set_connect (data->usbmisc_data); + ret =imx_usbmisc_hsic_set_connect (mdata);if (ret)dev_err (dev,"hsic_set_connect failed, err=%d\n" , ret);break ; +case CI_HDRC_CONTROLLER_VBUS_EVENT : +if (ci->vbus_active) + ret =imx_usbmisc_charger_detection (mdata, true); +else + ret =imx_usbmisc_charger_detection (mdata, false); +if (ci->usb_phy) +schedule_work (&ci->usb_phy->chg_work); +break ;default :break ; }
@@ -415,6 +424,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) } pdata.usb_phy = data->phy; +if (data->usbmisc_data) + data->usbmisc_data->usb_phy = data->phy; if ((of_device_is_compatible(np, "fsl,imx53-usb") || of_device_is_compatible(np, "fsl,imx51-usb")) && pdata.usb_phy &&
drivers/usb/chipidea/ci_hdrc_imx.h +2 -0
@@ -24,6 +24,7 @@ struct imx_usbmisc_data { unsigned int hsic:1; /* HSIC controlller */ unsigned int ext_id:1; /* ID from exteranl event */ unsigned int ext_vbus:1; /* Vbus from exteranl event */ +struct usb_phy *usb_phy; };int imx_usbmisc_init (struct imx_usbmisc_data *data);
@@ -31,5 +32,6 @@ int imx_usbmisc_init_post(struct imx_usbmisc_data *data);int imx_usbmisc_set_wakeup (struct imx_usbmisc_data *data,bool enabled);int imx_usbmisc_hsic_set_connect (struct imx_usbmisc_data *data);int imx_usbmisc_hsic_set_clk (struct imx_usbmisc_data *data,bool on); +int imx_usbmisc_charger_detection (struct imx_usbmisc_data *data,bool connect);#endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */
drivers/usb/chipidea/usbmisc_imx.c +245 -0
281 lines not on this page · raw message
Signature · 1 line
2.17.1
Peter Chen
maintainerPATCH 3/4 usb: chipidea: pull down dp for possible charger detection operation
In reply to Peter ChenFrom: Peter Chen <[email protected]>
The bootloader may use device mode, and keep dp up. We need dp to be pulled down before possbile charger detection operation.
--- drivers/usb/chipidea/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/usb/chipidea/core.c +4 -1
@@ -1123,8 +1123,11 @@ static int ci_hdrc_probe(struct platform_device *pdev)if (!ci_otg_is_fsm_mode (ci)) {/* only update vbus status for peripheral */ -if (ci->role ==CI_ROLE_GADGET ) +if (ci->role ==CI_ROLE_GADGET ) { +/* Pull down DP for possible charger detection */ +hw_write (ci,OP_USBCMD ,USBCMD_RS ,0 );ci_handle_vbus_change (ci); + } ret =ci_role_start (ci, ci->role);if (ret) {
Signature · 1 line
2.17.1
Peter Chen
maintainerPATCH 4/4 usb: chipidea: usbmisc_imx: using different ops for imx7d and imx7ulp
In reply to Peter ChenFrom: Peter Chen <[email protected]>
imx7ulp uses different USB PHY with imx7d (MXS PHY vs PICO PHY), so the features are supported by non-core register are a little different. For example, autoresume feature is supported by all controllers for imx7ulp, but for imx7d, it is only supported by non-HSIC controller.
Besides, these two platforms use different HSIC controller, imx7ulp needs software operation, but imx7d doesn't.
--- drivers/usb/chipidea/usbmisc_imx.c | 89 ++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 5 deletions(-)
drivers/usb/chipidea/usbmisc_imx.c +84 -5
@@ -100,6 +100,7 @@#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)#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 MX7D_USBNC_AUTO_RESUME BIT(2)/* The default DM/DP value is pull-down */ #define MX7D_USBNC_USB_CTRL2_OPMODE (v) (v << 6)#define MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING MX7D_USBNC_USB_CTRL2_OPMODE(1)
@@ -638,10 +639,17 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data) reg |=MX6_BM_PWR_POLARITY ;writel (reg, usbmisc->base); - reg =readl (usbmisc->base +MX7D_USBNC_USB_CTRL2 ); - reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK ; -writel (reg |MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID , - usbmisc->base +MX7D_USBNC_USB_CTRL2 ); +/* SoC non-burst setting */ + reg =readl (usbmisc->base); +writel (reg |MX6_BM_NON_BURST_SETTING , usbmisc->base); + +if (!data->hsic) { + reg =readl (usbmisc->base +MX7D_USBNC_USB_CTRL2 ); + reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK ; +writel (reg |MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID + |MX7D_USBNC_AUTO_RESUME , + usbmisc->base +MX7D_USBNC_USB_CTRL2 ); + }spin_unlock_irqrestore (&usbmisc->lock, flags);
@@ -832,6 +840,70 @@ static int imx7d_charger_detection(struct imx_usbmisc_data *data)return ret; } +static int usbmisc_imx7ulp_init (struct imx_usbmisc_data *data) +{ +struct imx_usbmisc *usbmisc =dev_get_drvdata (data->dev); +unsigned long flags; +u32 reg; + +if (data->index >=1 ) +return -EINVAL ; + +spin_lock_irqsave (&usbmisc->lock, flags); + reg =readl (usbmisc->base); +if (data->disable_oc) { + reg |=MX6_BM_OVER_CUR_DIS ; + }else { + reg &= ~MX6_BM_OVER_CUR_DIS ; + +/* +* If the polarity is not configured keep it as setup by the +* bootloader. +*/ +if (data->oc_pol_configured && data->oc_pol_active_low) + reg |=MX6_BM_OVER_CUR_POLARITY ; +else if (data->oc_pol_configured) + reg &= ~MX6_BM_OVER_CUR_POLARITY ; + } +/* If the polarity is not set keep it as setup by the bootlader */ +if (data->pwr_pol ==1 ) + reg |=MX6_BM_PWR_POLARITY ; + +writel (reg, usbmisc->base); + +/* SoC non-burst setting */ + reg =readl (usbmisc->base); +writel (reg |MX6_BM_NON_BURST_SETTING , usbmisc->base); + +if (data->hsic) { + reg =readl (usbmisc->base); +writel (reg |MX6_BM_UTMI_ON_CLOCK , usbmisc->base); + + reg =readl (usbmisc->base +MX6_USB_HSIC_CTRL_OFFSET ); + reg |=MX6_BM_HSIC_EN |MX6_BM_HSIC_CLK_ON ; +writel (reg, usbmisc->base +MX6_USB_HSIC_CTRL_OFFSET ); + +/* +* For non-HSIC controller, the autoresume is enabled +* at MXS PHY driver (usbphy_ctrl bit18). +*/ + reg =readl (usbmisc->base +MX7D_USBNC_USB_CTRL2 ); +writel (reg |MX7D_USBNC_AUTO_RESUME , + usbmisc->base +MX7D_USBNC_USB_CTRL2 ); + }else { + reg =readl (usbmisc->base +MX7D_USBNC_USB_CTRL2 ); + reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK ; +writel (reg |MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID , + usbmisc->base +MX7D_USBNC_USB_CTRL2 ); + } + +spin_unlock_irqrestore (&usbmisc->lock, flags); + +usbmisc_imx7d_set_wakeup (data, false); + +return 0 ; +} +static const struct usbmisc_ops imx25_usbmisc_ops = { .init = usbmisc_imx25_init, .post = usbmisc_imx25_post,
@@ -873,6 +945,13 @@ static const struct usbmisc_ops imx7d_usbmisc_ops = { .charger_detection = imx7d_charger_detection, }; +static const struct usbmisc_ops imx7ulp_usbmisc_ops = { + .init = usbmisc_imx7ulp_init, + .set_wakeup = usbmisc_imx7d_set_wakeup, + .hsic_set_connect = usbmisc_imx6_hsic_set_connect, + .hsic_set_clk = usbmisc_imx6_hsic_set_clk, +}; +static inline bool is_imx53_usbmisc (struct imx_usbmisc_data *data) {struct imx_usbmisc *usbmisc =dev_get_drvdata (data->dev);
@@ -1025,7 +1104,7 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { }, { .compatible = "fsl,imx7ulp-usbmisc", - .data = &imx7d_usbmisc_ops, + .data = &imx7ulp_usbmisc_ops, }, {/* sentinel */ } };
Signature · 1 line
2.17.1