]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
MLK-10086-4 usb: chipidea: imx: add HSIC support
authorLi Jun <b47624@freescale.com>
Tue, 20 Jan 2015 08:03:37 +0000 (16:03 +0800)
committerPeter Chen <peter.chen@freescale.com>
Mon, 26 Jan 2015 05:18:06 +0000 (13:18 +0800)
Add imx6 HSIC support

Signed-off-by: Peter Chen <peter.chen@freescale.com>
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_imx.h
drivers/usb/chipidea/host.c
drivers/usb/chipidea/usbmisc_imx.c
include/linux/usb/chipidea.h

index 52aab74a1b4ed18a74fa057919c2fbfffbc54a71..549184b8acbf8261b24e2e376050ebf42e49e409 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/power/imx6_usb_charger.h>
 #include <linux/busfreq-imx6.h>
+#include <linux/regulator/consumer.h>
 
 #include "ci.h"
 #include "ci_hdrc_imx.h"
@@ -72,8 +73,33 @@ struct ci_hdrc_imx_data {
        bool imx6_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;
 };
 
+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)
@@ -119,6 +145,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;
 }
 
@@ -148,6 +194,28 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned event)
                        return ret;
                imx6_usb_charger_detect_post(&data->charger);
                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");
        }
@@ -169,6 +237,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
                        of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
        const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
        struct device_node *np = pdev->dev.of_node;
+       struct pinctrl_state *pinctrl_hsic_idle;
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
@@ -176,10 +245,40 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
 
        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));
+       }
+
        data->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(data->clk)) {
                dev_err(&pdev->dev,
@@ -214,6 +313,34 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
        if (ret)
                goto err_clk;
 
+       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, "imx6-usb-charger-detection", NULL))
                data->imx6_usb_charger_detection = true;
 
@@ -224,15 +351,17 @@ 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;
                if (data->imx6_usb_charger_detection) {
                        data->charger.anatop = data->anatop;
                        data->charger.dev = &pdev->dev;
                        ret = imx6_usb_create_charger(&data->charger,
                                                "imx6_usb_charger");
                        if (ret && ret != -ENODEV)
-                               goto err_clk;
+                               goto disable_hsic_regulator;
                        if (!ret)
                                dev_dbg(&pdev->dev,
                                        "USB Charger is created\n");
@@ -276,6 +405,9 @@ disable_device:
 remove_charger:
        if (data->imx6_usb_charger_detection)
                imx6_usb_remove_charger(&data->charger);
+disable_hsic_regulator:
+       if (data->hsic_pad_regulator)
+               ret = regulator_disable(data->hsic_pad_regulator);
 err_clk:
        clk_disable_unprepare(data->clk);
        release_bus_freq(BUS_FREQ_HIGH);
@@ -296,6 +428,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
        release_bus_freq(BUS_FREQ_HIGH);
        if (data->imx6_usb_charger_detection)
                imx6_usb_remove_charger(&data->charger);
+       if (data->hsic_pad_regulator)
+               regulator_disable(data->hsic_pad_regulator);
 
        return 0;
 }
@@ -304,9 +438,19 @@ static int ci_hdrc_imx_remove(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;
+               }
+       }
+
        clk_disable_unprepare(data->clk);
        release_bus_freq(BUS_FREQ_HIGH);
        data->in_lpm = true;
@@ -351,8 +495,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:
        clk_disable_unprepare(data->clk);
        release_bus_freq(BUS_FREQ_HIGH);
index 620c538c9a1a7b4c3ef8bb5d1d3d36f9c4955afb..99765ef6a6d0dd72b5bfa0ebe7bbb0cf97bc0156 100644 (file)
@@ -18,11 +18,19 @@ struct imx_usbmisc_data {
 
        unsigned int disable_oc:1; /* over current detect disabled */
        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;
+       struct regmap *anatop;
 };
 
 int imx_usbmisc_init(struct imx_usbmisc_data *);
 int imx_usbmisc_init_post(struct imx_usbmisc_data *);
 int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *, bool);
 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 */
index 20c720199cff688fe2d23b4177edfc6ab8606228..6e5a2b9f00886b1814bfaeca8c528c57f816b097 100644 (file)
@@ -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);
@@ -122,6 +136,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];
 
@@ -146,6 +162,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) {
@@ -248,6 +272,11 @@ static int host_start(struct ci_hdrc *ci)
        if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
                hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
 
+       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;
 
 put_hcd:
@@ -361,6 +390,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);
 
@@ -391,6 +422,18 @@ 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))
index 4139ae11f6d9c476c31991508874e31cbcfef096..3abe742b3684c7198b6a3661ce10fff5f20cdc51 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/regmap.h>
 
 #include "ci_hdrc_imx.h"
 
 
 #define MX6_BM_OVER_CUR_DIS            BIT(7)
 #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
 
 #define VF610_OVER_CUR_DIS             BIT(7)
 
+#define ANADIG_ANA_MISC0               0x150
+#define ANADIG_ANA_MISC0_SET           0x154
+#define ANADIG_ANA_MISC0_CLK_DELAY(x)  ((x >> 26) & 0x7)
+
 struct usbmisc_ops {
        /* It's called once when probe a usb device */
        int (*init)(struct imx_usbmisc_data *data);
@@ -80,6 +97,10 @@ struct usbmisc_ops {
        int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled);
        /* 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 {
@@ -219,6 +240,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)
 {
@@ -296,6 +360,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 ret;
 }
 
@@ -354,6 +443,8 @@ static const struct usbmisc_ops imx53_usbmisc_ops = {
 static const struct usbmisc_ops imx6q_usbmisc_ops = {
        .set_wakeup = usbmisc_imx6q_set_wakeup,
        .init = usbmisc_imx6q_init,
+       .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
+       .hsic_set_clk   = usbmisc_imx6_hsic_set_clk,
 };
 
 static const struct usbmisc_ops vf610_usbmisc_ops = {
@@ -364,6 +455,8 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = {
        .set_wakeup = usbmisc_imx6q_set_wakeup,
        .init = usbmisc_imx6sx_init,
        .power_lost_check = usbmisc_imx6sx_power_lost_check,
+       .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
+       .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
 };
 
 int imx_usbmisc_init(struct imx_usbmisc_data *data)
@@ -422,6 +515,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",
index 7eefb513454dd0946d53f7bcf45a578036dcd7a0..d995f1e7d4ef9a8301bac4605b6ff77bcbf750b9 100644 (file)
@@ -29,12 +29,15 @@ struct ci_hdrc_platform_data {
 #define CI_HDRC_IMX28_WRITE_FIX                BIT(5)
 #define CI_HDRC_FORCE_FULLSPEED                BIT(6)
 #define CI_HDRC_IMX_EHCI_QUIRK         BIT(7)
+#define CI_HDRC_IMX_IS_HSIC            BIT(8)
        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;
        bool                    tpl_support;