From d78ac48cd554852eee93fb4a672f3bdfd3ecf1af Mon Sep 17 00:00:00 2001 From: Li Jun Date: Tue, 20 Jan 2015 16:03:37 +0800 Subject: [PATCH] MLK-10086-4 usb: chipidea: imx: add HSIC support Add imx6 HSIC support Signed-off-by: Peter Chen (cherry picked from commit 0cebf3e28ec0b7e47a45d16aa2237b819746b494) --- drivers/usb/chipidea/ci_hdrc_imx.c | 158 ++++++++++++++++++++++++++++- drivers/usb/chipidea/ci_hdrc_imx.h | 7 ++ drivers/usb/chipidea/host.c | 44 ++++++++ drivers/usb/chipidea/usbmisc_imx.c | 116 +++++++++++++++++++++ include/linux/usb/chipidea.h | 3 + 5 files changed, 324 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 1e77fba754cc..02e7b7c7fbd4 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -97,6 +97,10 @@ struct ci_hdrc_imx_data { bool imx_usb_charger_detection; struct usb_charger charger; struct regmap *anatop; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_hsic_active; + struct regulator *hsic_pad_regulator; + const struct ci_hdrc_imx_platform_flag *data; /* SoC before i.mx6 (except imx23/imx28) needs three clks */ bool need_three_clks; struct clk *clk_ipg; @@ -115,6 +119,27 @@ static enum power_supply_property imx_usb_charger_power_props[] = { POWER_SUPPLY_PROP_CURRENT_MAX, /* Maximum current in mA */ }; +static inline bool is_imx6q_con(struct ci_hdrc_imx_data *imx_data) +{ + return imx_data->data == &imx6q_usb_data; +} + +static inline bool is_imx6sl_con(struct ci_hdrc_imx_data *imx_data) +{ + return imx_data->data == &imx6sl_usb_data; +} + +static inline bool is_imx6sx_con(struct ci_hdrc_imx_data *imx_data) +{ + return imx_data->data == &imx6sx_usb_data; +} + +static inline bool imx_has_hsic_con(struct ci_hdrc_imx_data *imx_data) +{ + return is_imx6q_con(imx_data) || is_imx6sl_con(imx_data) + || is_imx6sx_con(imx_data); +} + /* Common functions shared by usbmisc drivers */ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) @@ -163,6 +188,26 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) if (of_find_property(np, "external-vbus-divider", NULL)) data->evdo = 1; + if (of_find_property(np, "osc-clkgate-delay", NULL)) { + ret = of_property_read_u32(np, "osc-clkgate-delay", + &data->osc_clkgate_delay); + if (ret) { + dev_err(dev, + "failed to get osc-clkgate-delay value\n"); + return ERR_PTR(ret); + } + /* + * 0 <= osc_clkgate_delay <=7 + * - 0x0 (default) is 0.5ms, + * - 0x1-0x7: 1-7ms + */ + if (data->osc_clkgate_delay > 7) { + dev_err(dev, + "value of osc-clkgate-delay is incorrect\n"); + return ERR_PTR(-EINVAL); + } + } + return data; } @@ -291,6 +336,28 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned event) return ret; imx_usbmisc_charger_secondary_detection(data->usbmisc_data); break; + case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: + if (!IS_ERR(data->pinctrl) && + !IS_ERR(data->pinctrl_hsic_active)) { + ret = pinctrl_select_state(data->pinctrl, + data->pinctrl_hsic_active); + if (ret) + dev_err(dev, + "hsic_active select failed, err=%d\n", + ret); + return ret; + } + break; + case CI_HDRC_IMX_HSIC_SUSPEND_EVENT: + if (data->usbmisc_data) { + ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data); + if (ret) + dev_err(dev, + "hsic_set_connect failed, err=%d\n", + ret); + return ret; + } + break; default: dev_dbg(dev, "unknown event\n"); } @@ -374,6 +441,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) const struct of_device_id *of_id; const struct ci_hdrc_imx_platform_flag *imx_platform_flag; struct device_node *np = pdev->dev.of_node; + struct pinctrl_state *pinctrl_hsic_idle; of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); if (!of_id) @@ -386,10 +454,41 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, data); + + data->data = imx_platform_flag; data->usbmisc_data = usbmisc_get_init_data(&pdev->dev); if (IS_ERR(data->usbmisc_data)) return PTR_ERR(data->usbmisc_data); + data->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(data->pinctrl)) { + dev_dbg(&pdev->dev, "pinctrl get failed, err=%ld\n", + PTR_ERR(data->pinctrl)); + } else { + pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); + if (IS_ERR(pinctrl_hsic_idle)) { + dev_dbg(&pdev->dev, + "pinctrl_hsic_idle lookup failed, err=%ld\n", + PTR_ERR(pinctrl_hsic_idle)); + } else { + ret = pinctrl_select_state(data->pinctrl, + pinctrl_hsic_idle); + if (ret) { + dev_err(&pdev->dev, + "hsic_idle select failed, err=%d\n", + ret); + return ret; + } + } + + data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl, + "active"); + if (IS_ERR(data->pinctrl_hsic_active)) + dev_dbg(&pdev->dev, + "pinctrl_hsic_active lookup failed, err=%ld\n", + PTR_ERR(data->pinctrl_hsic_active)); + } + ret = imx_get_clks(&pdev->dev); if (ret) return ret; @@ -412,6 +511,34 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) data->supports_runtime_pm = true; + if (data->usbmisc_data->index > 1 && (imx_has_hsic_con(data))) { + pdata.flags |= CI_HDRC_IMX_IS_HSIC; + data->hsic_pad_regulator = devm_regulator_get(&pdev->dev, + "pad"); + if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_clk; + } 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(&pdev->dev, + "Get hsic pad regulator error: %ld\n", + PTR_ERR(data->hsic_pad_regulator)); + ret = PTR_ERR(data->hsic_pad_regulator); + goto err_clk; + } + + if (data->hsic_pad_regulator) { + ret = regulator_enable(data->hsic_pad_regulator); + if (ret) { + dev_err(&pdev->dev, + "Fail to enable hsic pad regulator\n"); + goto err_clk; + } + } + } + if (of_find_property(np, "fsl,anatop", NULL)) { data->anatop = syscon_regmap_lookup_by_phandle(np, "fsl,anatop"); @@ -419,7 +546,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "failed to find regmap for anatop\n"); ret = PTR_ERR(data->anatop); - goto err_clk; + goto disable_hsic_regulator; } if (data->usbmisc_data) data->usbmisc_data->anatop = data->anatop; @@ -432,7 +559,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) ret = imx_usb_register_charger(&data->charger, "imx_usb_charger"); if (ret && ret != -ENODEV) - goto err_clk; + goto disable_hsic_regulator; if (!ret) dev_dbg(&pdev->dev, "USB Charger is created\n"); @@ -441,7 +568,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) ret = imx_usbmisc_init(data->usbmisc_data); if (ret) { dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); - goto err_clk; + goto disable_hsic_regulator; } data->ci_pdev = ci_hdrc_add_device(&pdev->dev, @@ -452,7 +579,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "ci_hdrc_add_device failed, err=%d\n", ret); - goto err_clk; + goto disable_hsic_regulator; } ret = imx_usbmisc_init_post(data->usbmisc_data); @@ -472,6 +599,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data->ci_pdev); +disable_hsic_regulator: + if (data->hsic_pad_regulator) + ret = regulator_disable(data->hsic_pad_regulator); err_clk: imx_disable_unprepare_clks(&pdev->dev); return ret; @@ -488,6 +618,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) } ci_hdrc_remove_device(data->ci_pdev); imx_disable_unprepare_clks(&pdev->dev); + if (data->hsic_pad_regulator) + regulator_disable(data->hsic_pad_regulator); return 0; } @@ -501,9 +633,19 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev) static int imx_controller_suspend(struct device *dev) { struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); + int ret; dev_dbg(dev, "at %s\n", __func__); + if (data->usbmisc_data) { + ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false); + if (ret) { + dev_err(dev, + "usbmisc hsic_set_clk failed, ret=%d\n", ret); + return ret; + } + } + imx_disable_unprepare_clks(dev); data->in_lpm = true; @@ -544,8 +686,16 @@ static int imx_controller_resume(struct device *dev) goto clk_disable; } + ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true); + if (ret) { + dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret); + goto hsic_set_clk_fail; + } + return 0; +hsic_set_clk_fail: + imx_usbmisc_set_wakeup(data->usbmisc_data, true); clk_disable: imx_disable_unprepare_clks(dev); return ret; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index d0d18cf07703..5d96152b5f3b 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -47,6 +47,11 @@ struct imx_usbmisc_data { unsigned int disable_oc:1; /* over current detect disabled */ unsigned int oc_polarity:1; /* over current polarity if oc enabled */ unsigned int evdo:1; /* set external vbus divider option */ + /* + * Specifies the delay between powering up the xtal 24MHz clock + * and release the clock to the digital logic inside the analog block + */ + unsigned int osc_clkgate_delay; }; int imx_usbmisc_init(struct imx_usbmisc_data *); @@ -55,5 +60,7 @@ int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *, bool); int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect); int imx_usbmisc_charger_secondary_detection(struct imx_usbmisc_data *data); int imx_usbmisc_power_lost_check(struct imx_usbmisc_data *); +int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *); +int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *, bool); #endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */ diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index b775af451534..fa54af842e97 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -43,6 +43,20 @@ struct ehci_ci_priv { struct regulator *reg_vbus; }; +/* This function is used to override WKCN, WKDN, and WKOC */ +static void ci_ehci_override_wakeup_flag(struct ehci_hcd *ehci, + u32 __iomem *reg, u32 flags, bool set) +{ + u32 val = ehci_readl(ehci, reg); + + if (set) + val |= flags; + else + val &= ~flags; + + ehci_writel(ehci, val, reg); +} + static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -150,6 +164,8 @@ static int ci_imx_ehci_hub_control( u32 temp; unsigned long flags; int retval = 0; + struct device *dev = hcd->self.controller; + struct ci_hdrc *ci = dev_get_drvdata(dev); status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; @@ -174,6 +190,14 @@ static int ci_imx_ehci_hub_control( PORT_SUSPEND, 5000)) ehci_err(ehci, "timeout waiting for SUSPEND\n"); + if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) { + if (ci->platdata->notify_event) + ci->platdata->notify_event + (ci, CI_HDRC_IMX_HSIC_SUSPEND_EVENT); + ci_ehci_override_wakeup_flag(ehci, status_reg, + PORT_WKDISC_E | PORT_WKCONN_E, false); + } + spin_unlock_irqrestore(&ehci->lock, flags); if (ehci_port_speed(ehci, temp) == USB_PORT_STAT_HIGH_SPEED && hcd->usb_phy) { @@ -284,6 +308,11 @@ static int host_start(struct ci_hdrc *ci) } } + if (ci->platdata->notify_event && + (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC)) + ci->platdata->notify_event + (ci, CI_HDRC_IMX_HSIC_ACTIVE_EVENT); + return ret; disable_reg: @@ -407,6 +436,8 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci(hcd); int port; u32 tmp; + struct device *dev = hcd->self.controller; + struct ci_hdrc *ci = dev_get_drvdata(dev); int ret = orig_bus_suspend(hcd); @@ -437,6 +468,19 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd) */ usleep_range(150, 200); + /* + * If a transaction is in progress, there may be + * a delay in suspending the port. Poll until the + * port is suspended. + */ + if (ehci_handshake(ehci, reg, PORT_SUSPEND, + PORT_SUSPEND, 5000)) + ehci_err(ehci, "timeout waiting for SUSPEND\n"); + + if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) + ci_ehci_override_wakeup_flag(ehci, reg, + PORT_WKDISC_E | PORT_WKCONN_E, false); + if (hcd->usb_phy && test_bit(port, &ehci->bus_suspended) && (ehci_port_speed(ehci, portsc) == USB_PORT_STAT_HIGH_SPEED)) diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index c2c3d088e96d..09b31a019088 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -59,10 +59,22 @@ #define MX6_BM_OVER_CUR_DIS BIT(7) #define MX6_BM_OVER_CUR_POLARITY BIT(8) #define MX6_BM_WAKEUP_ENABLE BIT(10) +#define MX6_BM_UTMI_ON_CLOCK BIT(13) #define MX6_BM_ID_WAKEUP BIT(16) #define MX6_BM_VBUS_WAKEUP BIT(17) #define MX6SX_BM_DPDM_WAKEUP_EN BIT(29) #define MX6_BM_WAKEUP_INTR BIT(31) + +#define MX6_USB_HSIC_CTRL_OFFSET 0x10 +/* Send resume signal without 480Mhz PHY clock */ +#define MX6SX_BM_HSIC_AUTO_RESUME BIT(23) +/* set before portsc.suspendM = 1 */ +#define MX6_BM_HSIC_DEV_CONN BIT(21) +/* HSIC enable */ +#define MX6_BM_HSIC_EN BIT(12) +/* Force HSIC module 480M clock on, even when in Host is in suspend mode */ +#define MX6_BM_HSIC_CLK_ON BIT(11) + #define MX6_USB_OTG1_PHY_CTRL 0x18 /* For imx6dql, it is host-only controller, for later imx6, it is otg's */ #define MX6_USB_OTG2_PHY_CTRL 0x1c @@ -113,6 +125,10 @@ struct usbmisc_ops { int (*charger_secondary_detection)(struct imx_usbmisc_data *data); /* It's called when system resume from usb power lost */ int (*power_lost_check)(struct imx_usbmisc_data *data); + /* It's called before setting portsc.suspendM */ + int (*hsic_set_connect)(struct imx_usbmisc_data *data); + /* It's called during suspend/resume */ + int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled); }; struct imx_usbmisc { @@ -252,6 +268,49 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data) return 0; } +static int usbmisc_imx6_hsic_set_connect(struct imx_usbmisc_data *data) +{ + unsigned long flags; + u32 val; + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + + spin_lock_irqsave(&usbmisc->lock, flags); + if (data->index == 2 || data->index == 3) { + val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + if (!(val & MX6_BM_HSIC_DEV_CONN)) + writel(val | MX6_BM_HSIC_DEV_CONN, + usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + } + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + +static int usbmisc_imx6_hsic_set_clk(struct imx_usbmisc_data *data, bool on) +{ + unsigned long flags; + u32 val; + struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev); + + spin_lock_irqsave(&usbmisc->lock, flags); + if (data->index == 2 || data->index == 3) { + val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON; + if (on) + val |= MX6_BM_HSIC_CLK_ON; + else + val &= ~MX6_BM_HSIC_CLK_ON; + writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + } + spin_unlock_irqrestore(&usbmisc->lock, flags); + + return 0; +} + static int usbmisc_imx6q_set_wakeup (struct imx_usbmisc_data *data, bool enabled) { @@ -338,6 +397,31 @@ static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data) spin_unlock_irqrestore(&usbmisc->lock, flags); } + /* For HSIC controller */ + if (data->index == 2) { + spin_lock_irqsave(&usbmisc->lock, flags); + val = readl(usbmisc->base + data->index * 4); + writel(val | MX6_BM_UTMI_ON_CLOCK, + usbmisc->base + data->index * 4); + val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON | + MX6SX_BM_HSIC_AUTO_RESUME; + writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + + (data->index - 2) * 4); + spin_unlock_irqrestore(&usbmisc->lock, flags); + + /* + * Need to add delay to wait 24M OSC to be stable, + * it's board specific. + */ + regmap_read(data->anatop, ANADIG_ANA_MISC0, &val); + /* 0 <= data->osc_clkgate_delay <= 7 */ + if (data->osc_clkgate_delay > ANADIG_ANA_MISC0_CLK_DELAY(val)) + regmap_write(data->anatop, ANADIG_ANA_MISC0_SET, + (data->osc_clkgate_delay) << 26); + } + return 0; } @@ -589,6 +673,8 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = { .init = usbmisc_imx6q_init, .charger_primary_detection = imx6_charger_primary_detection, .charger_secondary_detection = imx6_charger_secondary_detection, + .hsic_set_connect = usbmisc_imx6_hsic_set_connect, + .hsic_set_clk = usbmisc_imx6_hsic_set_clk, }; static const struct usbmisc_ops vf610_usbmisc_ops = { @@ -601,6 +687,8 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = { .charger_primary_detection = imx6_charger_primary_detection, .charger_secondary_detection = imx6_charger_secondary_detection, .power_lost_check = usbmisc_imx6sx_power_lost_check, + .hsic_set_connect = usbmisc_imx6_hsic_set_connect, + .hsic_set_clk = usbmisc_imx6_hsic_set_clk, }; static const struct usbmisc_ops imx7d_usbmisc_ops = { @@ -715,6 +803,34 @@ int imx_usbmisc_power_lost_check(struct imx_usbmisc_data *data) } EXPORT_SYMBOL_GPL(imx_usbmisc_power_lost_check); +int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data) +{ + struct imx_usbmisc *usbmisc; + + if (!data) + return 0; + + usbmisc = dev_get_drvdata(data->dev); + if (!usbmisc->ops->hsic_set_connect) + return 0; + return usbmisc->ops->hsic_set_connect(data); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect); + +int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on) +{ + struct imx_usbmisc *usbmisc; + + if (!data) + return 0; + + usbmisc = dev_get_drvdata(data->dev); + if (!usbmisc->ops->hsic_set_clk) + return 0; + return usbmisc->ops->hsic_set_clk(data, on); +} +EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk); + static const struct of_device_id usbmisc_imx_dt_ids[] = { { .compatible = "fsl,imx25-usbmisc", diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index d4904f40127d..803b5e6fbfdf 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -58,12 +58,15 @@ struct ci_hdrc_platform_data { #define CI_HDRC_OVERRIDE_TX_BURST BIT(10) #define CI_HDRC_OVERRIDE_RX_BURST BIT(11) #define CI_HDRC_IMX_EHCI_QUIRK BIT(12) +#define CI_HDRC_IMX_IS_HSIC BIT(13) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 #define CI_HDRC_CONTROLLER_VBUS_EVENT 2 #define CI_HDRC_NOTIFY_RET_DEFER_EVENT 3 #define CI_HDRC_CONTROLLER_CHARGER_POST_EVENT 4 +#define CI_HDRC_IMX_HSIC_ACTIVE_EVENT 5 +#define CI_HDRC_IMX_HSIC_SUSPEND_EVENT 6 int (*notify_event)(struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; struct usb_otg_caps ci_otg_caps; -- 2.17.1