summaryrefslogtreecommitdiffstats
path: root/drivers/usb/imx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/imx')
-rw-r--r--drivers/usb/imx/Kconfig2
-rw-r--r--drivers/usb/imx/chipidea-imx.c22
-rw-r--r--drivers/usb/imx/imx-usb-misc.c115
-rw-r--r--drivers/usb/imx/imx-usb-phy.c2
4 files changed, 125 insertions, 16 deletions
diff --git a/drivers/usb/imx/Kconfig b/drivers/usb/imx/Kconfig
index b0c6a4167e..8e6f3156a1 100644
--- a/drivers/usb/imx/Kconfig
+++ b/drivers/usb/imx/Kconfig
@@ -16,4 +16,4 @@ config USB_IMX_CHIPIDEA
config USB_IMX_PHY
bool
- default y if ARCH_IMX6 && GENERIC_PHY
+ default y if (ARCH_IMX6 || ARCH_VF610) && GENERIC_PHY
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index ed00ff4a1d..ccd5346133 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -27,6 +27,7 @@
#include <usb/fsl_usb2.h>
#include <linux/err.h>
#include <linux/phy/phy.h>
+#include <linux/clk.h>
#define MXC_EHCI_PORTSC_MASK ((0xf << 28) | (1 << 25))
@@ -37,12 +38,14 @@ struct imx_chipidea {
unsigned long flags;
uint32_t mode;
int portno;
+ struct device_d *usbmisc;
enum usb_phy_interface phymode;
struct param_d *param_mode;
int role_registered;
struct regulator *vbus;
struct phy *phy;
struct usb_phy *usbphy;
+ struct clk *clk;
};
static int imx_chipidea_port_init(void *drvdata)
@@ -67,7 +70,7 @@ static int imx_chipidea_port_init(void *drvdata)
return ret;
}
- ret = imx_usbmisc_port_init(ci->portno, ci->flags);
+ ret = imx_usbmisc_port_init(ci->usbmisc, ci->portno, ci->flags);
if (ret)
dev_err(ci->dev, "misc init failed: %s\n", strerror(-ret));
@@ -79,7 +82,7 @@ static int imx_chipidea_port_post_init(void *drvdata)
struct imx_chipidea *ci = drvdata;
int ret;
- ret = imx_usbmisc_port_post_init(ci->portno, ci->flags);
+ ret = imx_usbmisc_port_post_init(ci->usbmisc, ci->portno, ci->flags);
if (ret)
dev_err(ci->dev, "post misc init failed: %s\n", strerror(-ret));
@@ -95,6 +98,10 @@ static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
"#index-cells", 0, &out_args))
return -ENODEV;
+ ci->usbmisc = of_find_device_by_node(out_args.np);
+ if (!ci->usbmisc)
+ return -ENODEV;
+
ci->portno = out_args.args[0];
ci->flags = MXC_EHCI_MODE_UTMI_8BIT;
@@ -263,6 +270,17 @@ static int imx_chipidea_probe(struct device_d *dev)
if (IS_ERR(ci->vbus))
ci->vbus = NULL;
+ /*
+ * Some devices have more than one clock, in this case they are enabled
+ * by default in the clock driver. At least enable the main clock for
+ * devices which have only one.
+ */
+ ci->clk = clk_get(dev, NULL);
+ if (IS_ERR(ci->clk))
+ return PTR_ERR(ci->clk);
+
+ clk_enable(ci->clk);
+
if (of_property_read_bool(dev->device_node, "fsl,usbphy")) {
ci->phy = of_phy_get_by_phandle(dev, "fsl,usbphy", 0);
if (IS_ERR(ci->phy)) {
diff --git a/drivers/usb/imx/imx-usb-misc.c b/drivers/usb/imx/imx-usb-misc.c
index 7c18ca2a18..dc0de9e9e1 100644
--- a/drivers/usb/imx/imx-usb-misc.c
+++ b/drivers/usb/imx/imx-usb-misc.c
@@ -43,6 +43,11 @@ struct imx_usb_misc_data {
int (*post_init)(void __iomem *base, int port, unsigned int flags);
};
+struct imx_usb_misc_priv {
+ struct imx_usb_misc_data *data;
+ void __iomem *base;
+};
+
static __maybe_unused int mx25_initialize_usb_hw(void __iomem *base, int port, unsigned int flags)
{
unsigned int v;
@@ -348,6 +353,7 @@ static __maybe_unused struct imx_usb_misc_data mx5_data = {
#define MX6_USB_CTRL(n) ((n) * 4)
#define MX6_USB_CTRL_OVER_CUR_DIS (1 << 7)
+#define MX6_USB_CTRL_OVER_CUR_ACT_HIGH (1 << 8)
static void mx6_hsic_pullup(unsigned long reg, int on)
{
@@ -422,6 +428,68 @@ static __maybe_unused struct imx_usb_misc_data mx6_data = {
.post_init = mx6_post_init,
};
+#define MX7D_USBNC_USB_CTRL2 0x4
+#define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK 0x3
+#define MX7D_USB_VBUS_WAKEUP_SOURCE(v) (v << 0)
+#define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS MX7D_USB_VBUS_WAKEUP_SOURCE(0)
+#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)
+
+static int usbmisc_imx7d_init(void __iomem *base, int port,
+ unsigned int flags)
+{
+ u32 reg;
+
+ if (port >= 1)
+ return -EINVAL;
+
+ reg = readl(base);
+ if (flags & MXC_EHCI_DISABLE_OVERCURRENT) {
+ reg |= MX6_USB_CTRL_OVER_CUR_DIS;
+ } else {
+ reg &= ~MX6_USB_CTRL_OVER_CUR_DIS;
+ if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW)
+ reg &= ~MX6_USB_CTRL_OVER_CUR_ACT_HIGH;
+ else
+ reg |= MX6_USB_CTRL_OVER_CUR_ACT_HIGH;
+ }
+ writel(reg, base);
+
+ reg = readl(base + MX7D_USBNC_USB_CTRL2);
+ reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
+ writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
+ base + MX7D_USBNC_USB_CTRL2);
+
+ return 0;
+}
+
+static __maybe_unused struct imx_usb_misc_data mx7_data = {
+ .init = usbmisc_imx7d_init,
+};
+
+#define VF610_OVER_CUR_DIS BIT(7)
+
+static __maybe_unused int vf610_initialize_usb_hw(void __iomem *base, int port,
+ unsigned int flags)
+{
+ u32 reg;
+
+ if (port >= 1)
+ return -EINVAL;
+
+ if (flags & MXC_EHCI_DISABLE_OVERCURRENT) {
+ reg = readl(base);
+ writel(reg | VF610_OVER_CUR_DIS, base);
+ }
+
+ return 0;
+}
+
+static __maybe_unused struct imx_usb_misc_data vf610_data = {
+ .init = vf610_initialize_usb_hw,
+};
+
static struct platform_device_id imx_usbmisc_ids[] = {
#ifdef CONFIG_ARCH_IMX25
{
@@ -471,6 +539,12 @@ static struct platform_device_id imx_usbmisc_ids[] = {
.driver_data = (unsigned long)&mx6_data,
},
#endif
+#ifdef CONFIG_ARCH_IMX7
+ {
+ .name = "imx7d-usb-misc",
+ .driver_data = (unsigned long)&mx7_data,
+ },
+#endif
{
/* sentinel */
},
@@ -519,40 +593,54 @@ static __maybe_unused struct of_device_id imx_usbmisc_dt_ids[] = {
.data = &mx6_data,
},
#endif
+#ifdef CONFIG_ARCH_IMX7
+ {
+ .compatible = "fsl,imx7d-usbmisc",
+ .data = &mx7_data,
+ },
+#endif
+#ifdef CONFIG_ARCH_VF610
+ {
+ .compatible = "fsl,vf610-usbmisc",
+ .data = &vf610_data,
+ },
+#endif
{
/* sentinel */
},
};
-static struct imx_usb_misc_data *imxusbmisc_data;
-static void __iomem *usbmisc_base;
-
-int imx_usbmisc_port_init(int port, unsigned flags)
+int imx_usbmisc_port_init(struct device_d *dev, int port, unsigned flags)
{
- if (!imxusbmisc_data)
+ struct imx_usb_misc_priv *usbmisc = dev->priv;
+
+ if (!usbmisc)
return -ENODEV;
- if (!imxusbmisc_data->init)
+ if (!usbmisc->data->init)
return 0;
- return imxusbmisc_data->init(usbmisc_base, port, flags);
+ return usbmisc->data->init(usbmisc->base, port, flags);
}
-int imx_usbmisc_port_post_init(int port, unsigned flags)
+int imx_usbmisc_port_post_init(struct device_d *dev, int port, unsigned flags)
{
- if (!imxusbmisc_data)
+ struct imx_usb_misc_priv *usbmisc = dev->priv;
+
+ if (!usbmisc)
return -ENODEV;
- if (!imxusbmisc_data->post_init)
+ if (!usbmisc->data->post_init)
return 0;
- return imxusbmisc_data->post_init(usbmisc_base, port, flags);
+ return usbmisc->data->post_init(usbmisc->base, port, flags);
}
static int imx_usbmisc_probe(struct device_d *dev)
{
struct resource *iores;
struct imx_usb_misc_data *devtype;
+ struct imx_usb_misc_priv *usbmisc = dev->priv;
int ret;
ret = dev_get_drvdata(dev, (const void **)&devtype);
@@ -562,9 +650,10 @@ static int imx_usbmisc_probe(struct device_d *dev)
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
- usbmisc_base = IOMEM(iores->start);
- imxusbmisc_data = devtype;
+ usbmisc = xzalloc(sizeof(*usbmisc));
+ usbmisc->base = IOMEM(iores->start);
+ usbmisc->data = devtype;
return 0;
}
diff --git a/drivers/usb/imx/imx-usb-phy.c b/drivers/usb/imx/imx-usb-phy.c
index 9f46f8de6d..274153bd58 100644
--- a/drivers/usb/imx/imx-usb-phy.c
+++ b/drivers/usb/imx/imx-usb-phy.c
@@ -168,6 +168,8 @@ static __maybe_unused struct of_device_id imx_usbphy_dt_ids[] = {
{
.compatible = "fsl,imx23-usbphy",
}, {
+ .compatible = "fsl,vf610-usbphy",
+ }, {
/* sentinel */
},
};