summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-10-10 08:31:08 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-10-10 08:31:08 +0200
commit440783f886e8f9ad94d0ea4d0e7d0090cff5711b (patch)
treefda294e0a56d6c06c309e79b40b48f27ad5f3759
parent385c95c60b72d76a51748fde1fef983d3fbe0b5d (diff)
parente21ddc6ec059f59153dbc42d1281768d32bc6150 (diff)
downloadbarebox-440783f886e8f9ad94d0ea4d0e7d0090cff5711b.tar.gz
barebox-440783f886e8f9ad94d0ea4d0e7d0090cff5711b.tar.xz
Merge branch 'for-next/usb'
-rw-r--r--arch/arm/configs/imx_defconfig2
-rw-r--r--arch/arm/configs/imx_v7_defconfig2
-rw-r--r--drivers/phy/Kconfig15
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-core.c48
-rw-r--r--drivers/phy/usb-nop-xceiv.c104
-rw-r--r--drivers/usb/core/hub.c8
-rw-r--r--drivers/usb/core/usb.c52
-rw-r--r--drivers/usb/host/ehci-hcd.c1
-rw-r--r--drivers/usb/imx/Kconfig3
-rw-r--r--drivers/usb/imx/chipidea-imx.c21
-rw-r--r--drivers/usb/imx/imx-usb-phy.c78
-rw-r--r--include/linux/phy/phy.h16
-rw-r--r--include/usb/ehci.h1
-rw-r--r--include/usb/usb.h1
15 files changed, 314 insertions, 39 deletions
diff --git a/arch/arm/configs/imx_defconfig b/arch/arm/configs/imx_defconfig
index 69ab021e25..7d061cd8a8 100644
--- a/arch/arm/configs/imx_defconfig
+++ b/arch/arm/configs/imx_defconfig
@@ -107,6 +107,8 @@ CONFIG_EEPROM_AT24=y
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_IMX=y
CONFIG_IMX_WEIM=y
+CONFIG_GENERIC_PHY=y
+CONFIG_USB_NOP_XCEIV=y
CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
CONFIG_FS_NFS=y
diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig
index 51cbf60afd..50106dff7f 100644
--- a/arch/arm/configs/imx_v7_defconfig
+++ b/arch/arm/configs/imx_v7_defconfig
@@ -179,6 +179,8 @@ CONFIG_MXS_APBH_DMA=y
CONFIG_GPIO_STMPE=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED=y
+CONFIG_GENERIC_PHY=y
+CONFIG_USB_NOP_XCEIV=y
CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
CONFIG_FS_NFS=y
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index e9461e1a25..b0c8b9bf0e 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -2,9 +2,7 @@
# PHY
#
-menu "PHY Subsystem"
-
-config GENERIC_PHY
+menuconfig GENERIC_PHY
bool "PHY Core"
help
Generic PHY support.
@@ -15,4 +13,13 @@ config GENERIC_PHY
phy users can obtain reference to the PHY. All the users of this
framework should select this config.
-endmenu
+if GENERIC_PHY
+
+config USB_NOP_XCEIV
+ bool "Generic USB nop phy"
+ help
+ This driver is to be used by all the usb transceiver which are either
+ built-in with usb ip or which are autonomous and doesn't require any
+ phy programming such as ISP1x04 etc.
+
+endif
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 74514aeaed..8fc85953b3 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
+obj-$(CONFIG_USB_NOP_XCEIV) += usb-nop-xceiv.o
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 67af14f680..1b6a9f7b1d 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -15,6 +15,7 @@
#include <common.h>
#include <malloc.h>
#include <linux/phy/phy.h>
+#include <usb/phy.h>
static LIST_HEAD(phy_provider_list);
static int phy_ida;
@@ -201,6 +202,17 @@ int phy_power_off(struct phy *phy)
return 0;
}
+struct usb_phy *phy_to_usbphy(struct phy *phy)
+{
+ if (!phy)
+ return NULL;
+
+ if (!phy->ops->to_usbphy)
+ return ERR_PTR(-EINVAL);
+
+ return phy->ops->to_usbphy(phy);
+}
+
static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
{
struct phy_provider *phy_provider;
@@ -268,6 +280,42 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id)
}
/**
+ * of_phy_get_by_phandle() - lookup and obtain a reference to a phy.
+ * @dev: device that requests this phy
+ * @phandle - name of the property holding the phy phandle value
+ * @index - the index of the phy
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * -ENODEV if there is no such phy. The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *of_phy_get_by_phandle(struct device_d *dev, const char *phandle,
+ u8 index)
+{
+ struct device_node *np;
+ struct phy_provider *phy_provider;
+
+ if (!dev->device_node) {
+ dev_dbg(dev, "device does not have a device node entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ np = of_parse_phandle(dev->device_node, phandle, index);
+ if (!np) {
+ dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
+ dev->device_node->full_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ phy_provider = of_phy_provider_lookup(np);
+ if (IS_ERR(phy_provider)) {
+ return ERR_PTR(-ENODEV);
+ }
+
+ return phy_provider->of_xlate(phy_provider->dev, NULL);
+}
+
+/**
* phy_get() - lookup and obtain a reference to a phy.
* @dev: device that requests this phy
* @string: the phy name as given in the dt data or the name of the controller
diff --git a/drivers/phy/usb-nop-xceiv.c b/drivers/phy/usb-nop-xceiv.c
new file mode 100644
index 0000000000..606e098220
--- /dev/null
+++ b/drivers/phy/usb-nop-xceiv.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <of.h>
+#include <errno.h>
+#include <driver.h>
+#include <malloc.h>
+#include <usb/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+struct nop_usbphy {
+ struct usb_phy usb_phy;
+ struct phy *phy;
+ struct phy_provider *provider;
+};
+
+static struct phy *nop_usbphy_xlate(struct device_d *dev,
+ struct of_phandle_args *args)
+{
+ struct nop_usbphy *nopphy = dev->priv;
+
+ return nopphy->phy;
+}
+
+static struct usb_phy *nop_usbphy_to_usbphy(struct phy *phy)
+{
+ struct nop_usbphy *nopphy = phy_get_drvdata(phy);
+
+ return &nopphy->usb_phy;
+}
+
+static const struct phy_ops nop_phy_ops = {
+ .to_usbphy = nop_usbphy_to_usbphy,
+};
+
+static int nop_usbphy_probe(struct device_d *dev)
+{
+ int ret;
+ struct nop_usbphy *nopphy;
+
+ nopphy = xzalloc(sizeof(*nopphy));
+
+ dev->priv = nopphy;
+
+ /* FIXME: Add clk support */
+ /* FIXME: Add vbus regulator support */
+ /* FIXME: Add vbus-detect-gpio support */
+
+ nopphy->usb_phy.dev = dev;
+ nopphy->phy = phy_create(dev, NULL, &nop_phy_ops, NULL);
+ if (IS_ERR(nopphy->phy)) {
+ ret = PTR_ERR(nopphy->phy);
+ goto err_free;
+ }
+
+ phy_set_drvdata(nopphy->phy, nopphy);
+
+ nopphy->provider = of_phy_provider_register(dev, nop_usbphy_xlate);
+ if (IS_ERR(nopphy->provider)) {
+ ret = PTR_ERR(nopphy->provider);
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ free(nopphy);
+
+ return ret;
+};
+
+static __maybe_unused struct of_device_id nop_usbphy_dt_ids[] = {
+ {
+ .compatible = "usb-nop-xceiv",
+ }, {
+ /* sentinel */
+ },
+};
+
+static struct driver_d nop_usbphy_driver = {
+ .name = "usb-nop-xceiv",
+ .probe = nop_usbphy_probe,
+ .of_compatible = DRV_OF_COMPAT(nop_usbphy_dt_ids),
+};
+
+static int nop_usbphy_init(void)
+{
+ return platform_driver_register(&nop_usbphy_driver);
+}
+fs_initcall(nop_usbphy_init);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index dd3c10e825..f44aea55af 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -22,6 +22,7 @@
#include <malloc.h>
#include <errno.h>
#include <scsi.h>
+#include <usb/phy.h>
#include <usb/usb.h>
#include <usb/usb_defs.h>
@@ -189,6 +190,10 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
if (dev->children[port] && !(portstatus & USB_PORT_STAT_CONNECTION)) {
dev_dbg(&dev->dev, "disconnect detected on port %d\n", port + 1);
usb_remove_device(dev->children[port]);
+
+ if (!dev->parent && dev->host->usbphy)
+ usb_phy_notify_disconnect(dev->host->usbphy, dev->speed);
+
return;
}
@@ -231,6 +236,9 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
return;
}
+ if (!dev->parent && dev->host->usbphy)
+ usb_phy_notify_connect(dev->host->usbphy, usb->speed);
+
device_detect(&usb->dev);
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index ce229f2fcc..aba2da0ad3 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -40,6 +40,9 @@
*
* For each transfer (except "Interrupt") we wait for completion.
*/
+
+#define pr_fmt(fmt) "usb: " fmt
+
#include <common.h>
#include <command.h>
#include <malloc.h>
@@ -56,14 +59,6 @@
#include "usb.h"
#include "hub.h"
-/* #define USB_DEBUG */
-
-#ifdef USB_DEBUG
-#define USB_PRINTF(fmt, args...) printf(fmt , ##args)
-#else
-#define USB_PRINTF(fmt, args...)
-#endif
-
#define USB_BUFSIZ 512
static int dev_count;
@@ -113,7 +108,9 @@ int usb_register_host(struct usb_host *host)
static int usb_set_configuration(struct usb_device *dev, int configuration)
{
int res;
- USB_PRINTF("set configuration %d\n", configuration);
+
+ pr_debug("set configuration %d\n", configuration);
+
/* set setup command */
res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0,
@@ -147,21 +144,21 @@ usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep)
/* Control => bidirectional */
dev->epmaxpacketout[b] = ep->wMaxPacketSize;
dev->epmaxpacketin[b] = ep->wMaxPacketSize;
- USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n",
+ pr_debug("##Control EP epmaxpacketout/in[%d] = %d\n",
b, dev->epmaxpacketin[b]);
} else {
if ((ep->bEndpointAddress & 0x80) == 0) {
/* OUT Endpoint */
if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) {
dev->epmaxpacketout[b] = ep->wMaxPacketSize;
- USB_PRINTF("##EP epmaxpacketout[%d] = %d\n",
+ pr_debug("##EP epmaxpacketout[%d] = %d\n",
b, dev->epmaxpacketout[b]);
}
} else {
/* IN Endpoint */
if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) {
dev->epmaxpacketin[b] = ep->wMaxPacketSize;
- USB_PRINTF("##EP epmaxpacketin[%d] = %d\n",
+ pr_debug("##EP epmaxpacketin[%d] = %d\n",
b, dev->epmaxpacketin[b]);
}
} /* if out */
@@ -250,20 +247,20 @@ static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int c
&buffer[index], buffer[index]);
le16_to_cpus(&(dev->config.interface[ifno].ep_desc[epno].\
wMaxPacketSize));
- USB_PRINTF("if %d, ep %d\n", ifno, epno);
+ pr_debug("if %d, ep %d\n", ifno, epno);
break;
default:
if (head->bLength == 0)
return 1;
- USB_PRINTF("unknown Description Type : %x\n",
+ pr_debug("unknown Description Type : %x\n",
head->bDescriptorType);
{
ch = (unsigned char *)head;
for (i = 0; i < head->bLength; i++)
- USB_PRINTF("%02X ", *ch++);
- USB_PRINTF("\n\n\n");
+ pr_debug("%02X ", *ch++);
+ pr_debug("\n\n\n");
}
break;
}
@@ -281,7 +278,8 @@ static int usb_set_address(struct usb_device *dev)
{
int res;
- USB_PRINTF("set address %d\n", dev->devnum);
+ pr_debug("set address %d\n", dev->devnum);
+
res = usb_control_msg(dev, usb_snddefctrl(dev),
USB_REQ_SET_ADDRESS, 0,
(dev->devnum), 0,
@@ -345,7 +343,7 @@ int usb_new_device(struct usb_device *dev)
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
if (err < 0) {
- USB_PRINTF("%s: usb_get_descriptor() failed with %d\n", __func__, err);
+ pr_debug("%s: usb_get_descriptor() failed with %d\n", __func__, err);
goto err_out;
}
@@ -417,7 +415,7 @@ int usb_new_device(struct usb_device *dev)
"len %d, status %lX\n", dev->act_len, dev->status);
goto err_out;
}
- USB_PRINTF("new device: Mfr=%d, Product=%d, SerialNumber=%d\n",
+ pr_debug("new device: Mfr=%d, Product=%d, SerialNumber=%d\n",
dev->descriptor->iManufacturer, dev->descriptor->iProduct,
dev->descriptor->iSerialNumber);
memset(dev->mf, 0, sizeof(dev->mf));
@@ -624,7 +622,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
setup_packet->value = cpu_to_le16(value);
setup_packet->index = cpu_to_le16(index);
setup_packet->length = cpu_to_le16(size);
- USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \
+ pr_debug("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \
"value 0x%X index 0x%X length 0x%X\n",
request, requesttype, value, index, size);
dev->status = USB_ST_NOT_PROC; /*not yet processed */
@@ -744,13 +742,13 @@ int usb_get_configuration_no(struct usb_device *dev,
tmp = le16_to_cpu(config->wTotalLength);
if (tmp > USB_BUFSIZ) {
- USB_PRINTF("usb_get_configuration_no: failed to get " \
+ pr_debug("usb_get_configuration_no: failed to get " \
"descriptor - too long: %u\n", tmp);
return -1;
}
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp);
- USB_PRINTF("get_conf_no %d Result %d, wLength %u\n",
+ pr_debug("get_conf_no %d Result %d, wLength %u\n",
cfgno, result, tmp);
return result;
}
@@ -931,17 +929,17 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
if (!dev->have_langid) {
err = usb_string_sub(dev, 0, 0, tbuf);
if (err < 0) {
- USB_PRINTF("error getting string descriptor 0 " \
+ pr_debug("error getting string descriptor 0 " \
"(error=%lx)\n", dev->status);
return -1;
} else if (tbuf[0] < 4) {
- USB_PRINTF("string descriptor 0 too short\n");
+ pr_debug("string descriptor 0 too short\n");
return -1;
} else {
dev->have_langid = -1;
dev->string_langid = tbuf[2] | (tbuf[3] << 8);
/* always use the first langid listed */
- USB_PRINTF("USB device number %d default " \
+ pr_debug("USB device number %d default " \
"language ID 0x%x\n",
dev->devnum, dev->string_langid);
}
@@ -1063,12 +1061,12 @@ static int usb_match(struct device_d *dev, struct driver_d *drv)
struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver);
const struct usb_device_id *id;
- debug("matching: 0x%04x 0x%04x\n", usbdev->descriptor->idVendor,
+ pr_debug("matching: 0x%04x 0x%04x\n", usbdev->descriptor->idVendor,
usbdev->descriptor->idProduct);
id = usb_match_id(usbdev, usbdrv->id_table);
if (id) {
- debug("match: 0x%04x 0x%04x\n", id->idVendor, id->idProduct);
+ pr_debug("match: 0x%04x 0x%04x\n", id->idVendor, id->idProduct);
return 0;
}
return 1;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 35cf6aa0ad..f6e9099da8 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1297,6 +1297,7 @@ int ehci_register(struct device_d *dev, struct ehci_data *data)
host->hw_dev = dev;
host->init = ehci_init;
+ host->usbphy = data->usbphy;
host->submit_int_msg = submit_int_msg;
host->submit_control_msg = submit_control_msg;
host->submit_bulk_msg = submit_bulk_msg;
diff --git a/drivers/usb/imx/Kconfig b/drivers/usb/imx/Kconfig
index b1ce682f1d..b0c6a4167e 100644
--- a/drivers/usb/imx/Kconfig
+++ b/drivers/usb/imx/Kconfig
@@ -16,5 +16,4 @@ config USB_IMX_CHIPIDEA
config USB_IMX_PHY
bool
- depends on ARCH_IMX
- default y if ARCH_IMX6
+ default y if ARCH_IMX6 && GENERIC_PHY
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index a6f59261c3..ed00ff4a1d 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -26,6 +26,7 @@
#include <usb/ulpi.h>
#include <usb/fsl_usb2.h>
#include <linux/err.h>
+#include <linux/phy/phy.h>
#define MXC_EHCI_PORTSC_MASK ((0xf << 28) | (1 << 25))
@@ -40,6 +41,8 @@ struct imx_chipidea {
struct param_d *param_mode;
int role_registered;
struct regulator *vbus;
+ struct phy *phy;
+ struct usb_phy *usbphy;
};
static int imx_chipidea_port_init(void *drvdata)
@@ -260,6 +263,23 @@ static int imx_chipidea_probe(struct device_d *dev)
if (IS_ERR(ci->vbus))
ci->vbus = NULL;
+ 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)) {
+ ret = PTR_ERR(ci->phy);
+ dev_err(dev, "Cannot get phy: %s\n", strerror(-ret));
+ return ret;
+ } else {
+ ci->usbphy = phy_to_usbphy(ci->phy);
+ if (IS_ERR(ci->usbphy))
+ return PTR_ERR(ci->usbphy);
+
+ ret = phy_init(ci->phy);
+ if (ret)
+ return ret;
+ }
+ }
+
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
@@ -270,6 +290,7 @@ static int imx_chipidea_probe(struct device_d *dev)
ci->data.init = imx_chipidea_port_init;
ci->data.post_init = imx_chipidea_port_post_init;
ci->data.drvdata = ci;
+ ci->data.usbphy = ci->usbphy;
if ((ci->flags & MXC_EHCI_PORTSC_MASK) == MXC_EHCI_MODE_HSIC)
imx_chipidea_port_init(ci);
diff --git a/drivers/usb/imx/imx-usb-phy.c b/drivers/usb/imx/imx-usb-phy.c
index 1aa12be29d..9f46f8de6d 100644
--- a/drivers/usb/imx/imx-usb-phy.c
+++ b/drivers/usb/imx/imx-usb-phy.c
@@ -19,6 +19,8 @@
#include <errno.h>
#include <driver.h>
#include <malloc.h>
+#include <usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -31,15 +33,19 @@
#define USBPHY_CTRL_CLKGATE (1 << 30)
#define USBPHY_CTRL_ENUTMILEVEL3 (1 << 15)
#define USBPHY_CTRL_ENUTMILEVEL2 (1 << 14)
+#define USBPHY_CTRL_ENHOSTDISCONDETECT (1 << 1)
struct imx_usbphy {
+ struct usb_phy usb_phy;
+ struct phy *phy;
void __iomem *base;
struct clk *clk;
+ struct phy_provider *provider;
};
-static int imx_usbphy_enable(struct imx_usbphy *imxphy)
+static int imx_usbphy_phy_init(struct phy *phy)
{
- u32 val;
+ struct imx_usbphy *imxphy = phy_get_drvdata(phy);
clk_enable(imxphy->clk);
@@ -56,13 +62,56 @@ static int imx_usbphy_enable(struct imx_usbphy *imxphy)
writel(0xffffffff, imxphy->base + CLR);
/* set utmilvl2/3 */
- val = readl(imxphy->base + USBPHY_CTRL);
- val |= USBPHY_CTRL_ENUTMILEVEL3 | USBPHY_CTRL_ENUTMILEVEL2;
- writel(val, imxphy->base + USBPHY_CTRL + SET);
+ writel(USBPHY_CTRL_ENUTMILEVEL3 | USBPHY_CTRL_ENUTMILEVEL2,
+ imxphy->base + USBPHY_CTRL + SET);
return 0;
}
+static int imx_usbphy_notify_connect(struct usb_phy *phy,
+ enum usb_device_speed speed)
+{
+ struct imx_usbphy *imxphy = container_of(phy, struct imx_usbphy, usb_phy);
+
+ if (speed == USB_SPEED_HIGH) {
+ writel(USBPHY_CTRL_ENHOSTDISCONDETECT,
+ imxphy->base + USBPHY_CTRL + SET);
+ }
+
+ return 0;
+}
+
+static int imx_usbphy_notify_disconnect(struct usb_phy *phy,
+ enum usb_device_speed speed)
+{
+ struct imx_usbphy *imxphy = container_of(phy, struct imx_usbphy, usb_phy);
+
+ writel(USBPHY_CTRL_ENHOSTDISCONDETECT,
+ imxphy->base + USBPHY_CTRL + CLR);
+
+ return 0;
+}
+
+static struct phy *imx_usbphy_xlate(struct device_d *dev,
+ struct of_phandle_args *args)
+{
+ struct imx_usbphy *imxphy = dev->priv;
+
+ return imxphy->phy;
+}
+
+static struct usb_phy *imx_usbphy_to_usbphy(struct phy *phy)
+{
+ struct imx_usbphy *imxphy = phy_get_drvdata(phy);
+
+ return &imxphy->usb_phy;
+}
+
+static const struct phy_ops imx_phy_ops = {
+ .init = imx_usbphy_phy_init,
+ .to_usbphy = imx_usbphy_to_usbphy,
+};
+
static int imx_usbphy_probe(struct device_d *dev)
{
struct resource *iores;
@@ -85,7 +134,24 @@ static int imx_usbphy_probe(struct device_d *dev)
goto err_clk;
}
- imx_usbphy_enable(imxphy);
+ dev->priv = imxphy;
+
+ imxphy->usb_phy.dev = dev;
+ imxphy->usb_phy.notify_connect = imx_usbphy_notify_connect;
+ imxphy->usb_phy.notify_disconnect = imx_usbphy_notify_disconnect;
+ imxphy->phy = phy_create(dev, NULL, &imx_phy_ops, NULL);
+ if (IS_ERR(imxphy->phy)) {
+ ret = PTR_ERR(imxphy->phy);
+ goto err_clk;
+ }
+
+ phy_set_drvdata(imxphy->phy, imxphy);
+
+ imxphy->provider = of_phy_provider_register(dev, imx_usbphy_xlate);
+ if (IS_ERR(imxphy->provider)) {
+ ret = PTR_ERR(imxphy->provider);
+ goto err_clk;
+ }
dev_dbg(dev, "phy enabled\n");
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 94f0044036..5d96e02df4 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -33,6 +33,7 @@ struct phy_ops {
int (*exit)(struct phy *phy);
int (*power_on)(struct phy *phy);
int (*power_off)(struct phy *phy);
+ struct usb_phy *(*to_usbphy)(struct phy *phy);
};
/**
@@ -136,6 +137,8 @@ static inline void phy_set_bus_width(struct phy *phy, int bus_width)
}
struct phy *phy_get(struct device_d *dev, const char *string);
struct phy *phy_optional_get(struct device_d *dev, const char *string);
+struct phy *of_phy_get_by_phandle(struct device_d *dev, const char *phandle,
+ u8 index);
void phy_put(struct phy *phy);
struct phy *of_phy_get(struct device_node *np, const char *con_id);
struct phy *of_phy_simple_xlate(struct device_d *dev,
@@ -148,6 +151,7 @@ struct phy_provider *__of_phy_provider_register(struct device_d *dev,
struct phy * (*of_xlate)(struct device_d *dev,
struct of_phandle_args *args));
void of_phy_provider_unregister(struct phy_provider *phy_provider);
+struct usb_phy *phy_to_usbphy(struct phy *phy);
#else
static inline int phy_init(struct phy *phy)
{
@@ -198,6 +202,12 @@ static inline struct phy *phy_optional_get(struct device_d *dev,
return ERR_PTR(-ENOSYS);
}
+static inline struct phy *of_phy_get_by_phandle(struct device_d *dev,
+ const char *phandle, u8 index)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline void phy_put(struct phy *phy)
{
}
@@ -235,6 +245,12 @@ static inline struct phy_provider *__of_phy_provider_register(
static inline void of_phy_provider_unregister(struct phy_provider *phy_provider)
{
}
+
+static inline struct usb_phy *phy_to_usbphy(struct phy *phy)
+{
+ return NULL;
+}
+
#endif
#endif /* __DRIVERS_PHY_H */
diff --git a/include/usb/ehci.h b/include/usb/ehci.h
index 93f980d34f..1008e92f02 100644
--- a/include/usb/ehci.h
+++ b/include/usb/ehci.h
@@ -11,6 +11,7 @@ struct ehci_data {
void __iomem *hccr;
void __iomem *hcor;
unsigned long flags;
+ struct usb_phy *usbphy;
/* platform specific init functions */
int (*init)(void *drvdata);
diff --git a/include/usb/usb.h b/include/usb/usb.h
index aedc527f58..93308cec00 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -153,6 +153,7 @@ struct usb_host {
int busnum;
struct usb_device *root_dev;
int sem;
+ struct usb_phy *usbphy;
};
int usb_register_host(struct usb_host *);