summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/usb/twlxxxx-usb.txt40
-rw-r--r--Documentation/devicetree/bindings/usb/usb-phy.txt17
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c1
-rw-r--r--arch/arm/mach-omap2/omap_phy_internal.c138
-rw-r--r--arch/arm/mach-omap2/twl-common.c5
-rw-r--r--arch/arm/mach-omap2/usb-musb.c3
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/devices.c2
-rw-r--r--arch/arm/mach-tegra/devices.h2
-rw-r--r--drivers/usb/dwc3/core.c15
-rw-r--r--drivers/usb/dwc3/core.h5
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c66
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c66
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c67
-rw-r--r--drivers/usb/host/ehci-tegra.c14
-rw-r--r--drivers/usb/musb/am35x.c1
-rw-r--r--drivers/usb/musb/blackfin.c1
-rw-r--r--drivers/usb/musb/da8xx.c1
-rw-r--r--drivers/usb/musb/davinci.c1
-rw-r--r--drivers/usb/musb/musb_dsps.c1
-rw-r--r--drivers/usb/musb/tusb6010.c1
-rw-r--r--drivers/usb/otg/Kconfig2
-rw-r--r--drivers/usb/otg/fsl_otg.c34
-rw-r--r--drivers/usb/otg/mxs-phy.c38
-rw-r--r--drivers/usb/otg/nop-usb-xceiv.c8
-rw-r--r--drivers/usb/otg/otg.c2
-rw-r--r--drivers/usb/otg/twl4030-usb.c26
-rw-r--r--drivers/usb/otg/twl6030-usb.c157
-rw-r--r--drivers/usb/phy/Kconfig17
-rw-r--r--drivers/usb/phy/Makefile3
-rw-r--r--drivers/usb/phy/isp1301.c6
-rw-r--r--drivers/usb/phy/mv_u3d_phy.c345
-rw-r--r--drivers/usb/phy/mv_u3d_phy.h105
-rw-r--r--drivers/usb/phy/omap-usb2.c271
-rw-r--r--drivers/usb/phy/tegra_usb_phy.c (renamed from arch/arm/mach-tegra/usb_phy.c)152
-rw-r--r--include/linux/usb/nop-usb-xceiv.h24
-rw-r--r--include/linux/usb/omap_usb.h46
-rw-r--r--include/linux/usb/otg.h236
-rw-r--r--include/linux/usb/phy.h233
-rw-r--r--include/linux/usb/phy_companion.h34
-rw-r--r--include/linux/usb/tegra_usb_phy.h (renamed from arch/arm/mach-tegra/include/mach/usb_phy.h)16
41 files changed, 1596 insertions, 607 deletions
diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
new file mode 100644
index 000000000000..36b9aede3f40
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
@@ -0,0 +1,40 @@
+USB COMPARATOR OF TWL CHIPS
+
+TWL6030 USB COMPARATOR
+ - compatible : Should be "ti,twl6030-usb"
+ - interrupts : Two interrupt numbers to the cpu should be specified. First
+ interrupt number is the otg interrupt number that raises ID interrupts when
+ the controller has to act as host and the second interrupt number is the
+ usb interrupt number that raises VBUS interrupts when the controller has to
+ act as device
+ - usb-supply : phandle to the regulator device tree node. It should be vusb
+ if it is twl6030 or ldousb if it is twl6025 subclass.
+
+twl6030-usb {
+ compatible = "ti,twl6030-usb";
+ interrupts = < 4 10 >;
+};
+
+Board specific device node entry
+&twl6030-usb {
+ usb-supply = <&vusb>;
+};
+
+TWL4030 USB PHY AND COMPARATOR
+ - compatible : Should be "ti,twl4030-usb"
+ - interrupts : The interrupt numbers to the cpu should be specified. First
+ interrupt number is the otg interrupt number that raises ID interrupts
+ and VBUS interrupts. The second interrupt number is optional.
+ - <supply-name>-supply : phandle to the regulator device tree node.
+ <supply-name> should be vusb1v5, vusb1v8 and vusb3v1
+ - usb_mode : The mode used by the phy to connect to the controller. "1"
+ specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode.
+
+twl4030-usb {
+ compatible = "ti,twl4030-usb";
+ interrupts = < 10 4 >;
+ usb1v5-supply = <&vusb1v5>;
+ usb1v8-supply = <&vusb1v8>;
+ usb3v1-supply = <&vusb3v1>;
+ usb_mode = <1>;
+};
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
new file mode 100644
index 000000000000..80d4148cb661
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -0,0 +1,17 @@
+USB PHY
+
+OMAP USB2 PHY
+
+Required properties:
+ - compatible: Should be "ti,omap-usb2"
+ - reg : Address and length of the register set for the device. Also
+add the address of control module dev conf register until a driver for
+control module is added
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb2phy@4a0ad080 {
+ compatible = "ti,omap-usb2";
+ reg = <0x4a0ad080 0x58>,
+ <0x4a002300 0x4>;
+};
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 0d362e9f9cb9..3d2a988e3d9a 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -32,6 +32,7 @@
#include <linux/spi/ads7846.h>
#include <linux/i2c/twl.h>
#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include <linux/smsc911x.h>
#include <linux/wl12xx.h>
diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c
index d52651a05daa..874aecc0faca 100644
--- a/arch/arm/mach-omap2/omap_phy_internal.c
+++ b/arch/arm/mach-omap2/omap_phy_internal.c
@@ -31,144 +31,6 @@
#include <plat/usb.h>
#include "control.h"
-/* OMAP control module register for UTMI PHY */
-#define CONTROL_DEV_CONF 0x300
-#define PHY_PD 0x1
-
-#define USBOTGHS_CONTROL 0x33c
-#define AVALID BIT(0)
-#define BVALID BIT(1)
-#define VBUSVALID BIT(2)
-#define SESSEND BIT(3)
-#define IDDIG BIT(4)
-
-static struct clk *phyclk, *clk48m, *clk32k;
-static void __iomem *ctrl_base;
-static int usbotghs_control;
-
-int omap4430_phy_init(struct device *dev)
-{
- ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K);
- if (!ctrl_base) {
- pr_err("control module ioremap failed\n");
- return -ENOMEM;
- }
- /* Power down the phy */
- __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-
- if (!dev) {
- iounmap(ctrl_base);
- return 0;
- }
-
- phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
- if (IS_ERR(phyclk)) {
- dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n");
- iounmap(ctrl_base);
- return PTR_ERR(phyclk);
- }
-
- clk48m = clk_get(dev, "ocp2scp_usb_phy_phy_48m");
- if (IS_ERR(clk48m)) {
- dev_err(dev, "cannot clk_get ocp2scp_usb_phy_phy_48m\n");
- clk_put(phyclk);
- iounmap(ctrl_base);
- return PTR_ERR(clk48m);
- }
-
- clk32k = clk_get(dev, "usb_phy_cm_clk32k");
- if (IS_ERR(clk32k)) {
- dev_err(dev, "cannot clk_get usb_phy_cm_clk32k\n");
- clk_put(phyclk);
- clk_put(clk48m);
- iounmap(ctrl_base);
- return PTR_ERR(clk32k);
- }
- return 0;
-}
-
-int omap4430_phy_set_clk(struct device *dev, int on)
-{
- static int state;
-
- if (on && !state) {
- /* Enable the phy clocks */
- clk_enable(phyclk);
- clk_enable(clk48m);
- clk_enable(clk32k);
- state = 1;
- } else if (state) {
- /* Disable the phy clocks */
- clk_disable(phyclk);
- clk_disable(clk48m);
- clk_disable(clk32k);
- state = 0;
- }
- return 0;
-}
-
-int omap4430_phy_power(struct device *dev, int ID, int on)
-{
- if (on) {
- if (ID)
- /* enable VBUS valid, IDDIG groung */
- __raw_writel(AVALID | VBUSVALID, ctrl_base +
- USBOTGHS_CONTROL);
- else
- /*
- * Enable VBUS Valid, AValid and IDDIG
- * high impedance
- */
- __raw_writel(IDDIG | AVALID | VBUSVALID,
- ctrl_base + USBOTGHS_CONTROL);
- } else {
- /* Enable session END and IDIG to high impedance. */
- __raw_writel(SESSEND | IDDIG, ctrl_base +
- USBOTGHS_CONTROL);
- }
- return 0;
-}
-
-int omap4430_phy_suspend(struct device *dev, int suspend)
-{
- if (suspend) {
- /* Disable the clocks */
- omap4430_phy_set_clk(dev, 0);
- /* Power down the phy */
- __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-
- /* save the context */
- usbotghs_control = __raw_readl(ctrl_base + USBOTGHS_CONTROL);
- } else {
- /* Enable the internel phy clcoks */
- omap4430_phy_set_clk(dev, 1);
- /* power on the phy */
- if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) {
- __raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF);
- mdelay(200);
- }
-
- /* restore the context */
- __raw_writel(usbotghs_control, ctrl_base + USBOTGHS_CONTROL);
- }
-
- return 0;
-}
-
-int omap4430_phy_exit(struct device *dev)
-{
- if (ctrl_base)
- iounmap(ctrl_base);
- if (phyclk)
- clk_put(phyclk);
- if (clk48m)
- clk_put(clk48m);
- if (clk32k)
- clk_put(clk32k);
-
- return 0;
-}
-
void am35x_musb_reset(void)
{
u32 regval;
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index db5ff6642375..329b726012f3 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -251,11 +251,6 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
#if defined(CONFIG_ARCH_OMAP4)
static struct twl4030_usb_data omap4_usb_pdata = {
- .phy_init = omap4430_phy_init,
- .phy_exit = omap4430_phy_exit,
- .phy_power = omap4430_phy_power,
- .phy_set_clock = omap4430_phy_set_clk,
- .phy_suspend = omap4430_phy_suspend,
};
static struct regulator_init_data omap4_vdac_idata = {
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index c4a576856661..e9b4b234dc5f 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -117,7 +117,4 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
dev->dma_mask = &musb_dmamask;
dev->coherent_dma_mask = musb_dmamask;
put_device(dev);
-
- if (cpu_is_omap44xx())
- omap4430_phy_init(dev);
}
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index b129f37515bb..ed41905a3bd1 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -23,7 +23,6 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
obj-$(CONFIG_TEGRA_PCI) += pcie.o
-obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index c70e65ffa36b..d8ab76276397 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -27,7 +27,7 @@
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/dma.h>
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
#include "gpio-names.h"
#include "devices.h"
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index 4f5052726495..906a61f340c8 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -22,7 +22,7 @@
#include <linux/platform_device.h>
#include <linux/platform_data/tegra_usb.h>
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
extern struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c34452a7304f..79a24fab13d1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -50,6 +50,7 @@
#include <linux/dma-mapping.h>
#include <linux/of.h>
+#include <linux/usb/otg.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -136,6 +137,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ usb_phy_init(dwc->usb2_phy);
+ usb_phy_init(dwc->usb3_phy);
mdelay(100);
/* Clear USB3 PHY reset */
@@ -465,6 +468,18 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
+ dev_err(dev, "no usb2 phy configured\n");
+ return -EPROBE_DEFER;
+ }
+
+ dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+ if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
+ dev_err(dev, "no usb3 phy configured\n");
+ return -EPROBE_DEFER;
+ }
+
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 151eca876dfd..dbc5713d84fb 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -624,6 +624,8 @@ struct dwc3_scratchpad_array {
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
* @mode: mode of operation
+ * @usb2_phy: pointer to USB2 PHY
+ * @usb3_phy: pointer to USB3 PHY
* @is_selfpowered: true when we are selfpowered
* @three_stage_setup: set if we perform a three phase setup
* @ep0_bounced: true when we used bounce buffer
@@ -667,6 +669,9 @@ struct dwc3 {
struct usb_gadget gadget;
struct usb_gadget_driver *gadget_driver;
+ struct usb_phy *usb2_phy;
+ struct usb_phy *usb3_phy;
+
void __iomem *regs;
size_t regs_size;
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index b8f00389fa34..ca6597853f90 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -19,16 +19,74 @@
#include <linux/platform_data/dwc3-exynos.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include "core.h"
struct dwc3_exynos {
struct platform_device *dwc3;
+ struct platform_device *usb2_phy;
+ struct platform_device *usb3_phy;
struct device *dev;
struct clk *clk;
};
+static int __devinit dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
+{
+ struct nop_usb_xceiv_platform_data pdata;
+ struct platform_device *pdev;
+ int ret;
+
+ memset(&pdata, 0x00, sizeof(pdata));
+
+ pdev = platform_device_alloc("nop_usb_xceiv", 0);
+ if (!pdev)
+ return -ENOMEM;
+
+ exynos->usb2_phy = pdev;
+ pdata.type = USB_PHY_TYPE_USB2;
+
+ ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
+ if (ret)
+ goto err1;
+
+ pdev = platform_device_alloc("nop_usb_xceiv", 1);
+ if (!pdev) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ exynos->usb3_phy = pdev;
+ pdata.type = USB_PHY_TYPE_USB3;
+
+ ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata));
+ if (ret)
+ goto err2;
+
+ ret = platform_device_add(exynos->usb2_phy);
+ if (ret)
+ goto err2;
+
+ ret = platform_device_add(exynos->usb3_phy);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ platform_device_del(exynos->usb2_phy);
+
+err2:
+ platform_device_put(exynos->usb3_phy);
+
+err1:
+ platform_device_put(exynos->usb2_phy);
+
+ return ret;
+}
+
static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
@@ -51,6 +109,12 @@ static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
if (devid < 0)
goto err1;
+ ret = dwc3_exynos_register_phys(exynos);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't register PHYs\n");
+ goto err1;
+ }
+
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
@@ -120,6 +184,8 @@ static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
platform_device_unregister(exynos->dwc3);
+ platform_device_unregister(exynos->usb2_phy);
+ platform_device_unregister(exynos->usb3_phy);
dwc3_put_device_id(exynos->dwc3->id);
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 479dc047da3a..ee57a10d90d0 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -48,6 +48,9 @@
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
+
#include "core.h"
/*
@@ -131,6 +134,8 @@ struct dwc3_omap {
spinlock_t lock;
struct platform_device *dwc3;
+ struct platform_device *usb2_phy;
+ struct platform_device *usb3_phy;
struct device *dev;
int irq;
@@ -152,6 +157,59 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
writel(value, base + offset);
}
+static int __devinit dwc3_omap_register_phys(struct dwc3_omap *omap)
+{
+ struct nop_usb_xceiv_platform_data pdata;
+ struct platform_device *pdev;
+ int ret;
+
+ memset(&pdata, 0x00, sizeof(pdata));
+
+ pdev = platform_device_alloc("nop_usb_xceiv", 0);
+ if (!pdev)
+ return -ENOMEM;
+
+ omap->usb2_phy = pdev;
+ pdata.type = USB_PHY_TYPE_USB2;
+
+ ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
+ if (ret)
+ goto err1;
+
+ pdev = platform_device_alloc("nop_usb_xceiv", 1);
+ if (!pdev) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ omap->usb3_phy = pdev;
+ pdata.type = USB_PHY_TYPE_USB3;
+
+ ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
+ if (ret)
+ goto err2;
+
+ ret = platform_device_add(omap->usb2_phy);
+ if (ret)
+ goto err2;
+
+ ret = platform_device_add(omap->usb3_phy);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ platform_device_del(omap->usb2_phy);
+
+err2:
+ platform_device_put(omap->usb3_phy);
+
+err1:
+ platform_device_put(omap->usb2_phy);
+
+ return ret;
+}
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
@@ -251,6 +309,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ ret = dwc3_omap_register_phys(omap);
+ if (ret) {
+ dev_err(dev, "couldn't register PHYs\n");
+ return ret;
+ }
+
devid = dwc3_get_device_id();
if (devid < 0)
return -ENODEV;
@@ -371,6 +435,8 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)
struct dwc3_omap *omap = platform_get_drvdata(pdev);
platform_device_unregister(omap->dwc3);
+ platform_device_unregister(omap->usb2_phy);
+ platform_device_unregister(omap->usb3_phy);
dwc3_put_device_id(omap->dwc3->id);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index a9ca9adba391..94f550e37f98 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -42,6 +42,9 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
+
#include "core.h"
/* FIXME define these in <linux/pci_ids.h> */
@@ -51,8 +54,64 @@
struct dwc3_pci {
struct device *dev;
struct platform_device *dwc3;
+ struct platform_device *usb2_phy;
+ struct platform_device *usb3_phy;
};
+static int __devinit dwc3_pci_register_phys(struct dwc3_pci *glue)
+{
+ struct nop_usb_xceiv_platform_data pdata;
+ struct platform_device *pdev;
+ int ret;
+
+ memset(&pdata, 0x00, sizeof(pdata));
+
+ pdev = platform_device_alloc("nop_usb_xceiv", 0);
+ if (!pdev)
+ return -ENOMEM;
+
+ glue->usb2_phy = pdev;
+ pdata.type = USB_PHY_TYPE_USB2;
+
+ ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
+ if (ret)
+ goto err1;
+
+ pdev = platform_device_alloc("nop_usb_xceiv", 1);
+ if (!pdev) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ glue->usb3_phy = pdev;
+ pdata.type = USB_PHY_TYPE_USB3;
+
+ ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
+ if (ret)
+ goto err2;
+
+ ret = platform_device_add(glue->usb2_phy);
+ if (ret)
+ goto err2;
+
+ ret = platform_device_add(glue->usb3_phy);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ platform_device_del(glue->usb2_phy);
+
+err2:
+ platform_device_put(glue->usb3_phy);
+
+err1:
+ platform_device_put(glue->usb2_phy);
+
+ return ret;
+}
+
static int __devinit dwc3_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
@@ -80,6 +139,12 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
pci_set_power_state(pci, PCI_D0);
pci_set_master(pci);
+ ret = dwc3_pci_register_phys(glue);
+ if (ret) {
+ dev_err(dev, "couldn't register PHYs\n");
+ return ret;
+ }
+
devid = dwc3_get_device_id();
if (devid < 0) {
ret = -ENOMEM;
@@ -144,6 +209,8 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *glue = pci_get_drvdata(pci);
+ platform_device_unregister(glue->usb2_phy);
+ platform_device_unregister(glue->usb3_phy);
dwc3_put_device_id(glue->dwc3->id);
platform_device_unregister(glue->dwc3);
pci_set_drvdata(pci, NULL);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 26dedb30ad0b..c0d47323b52a 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -27,7 +27,7 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
#include <mach/iomap.h>
#define TEGRA_USB_DMA_ALIGN 32
@@ -49,7 +49,7 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd)
clk_prepare_enable(tegra->emc_clk);
clk_prepare_enable(tegra->clk);
- tegra_usb_phy_power_on(tegra->phy);
+ usb_phy_set_suspend(&tegra->phy->u_phy, 0);
tegra->host_resumed = 1;
}
@@ -58,7 +58,7 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd)
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
tegra->host_resumed = 0;
- tegra_usb_phy_power_off(tegra->phy);
+ usb_phy_set_suspend(&tegra->phy->u_phy, 1);
clk_disable_unprepare(tegra->clk);
clk_disable_unprepare(tegra->emc_clk);
}
@@ -715,7 +715,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto fail_phy;
}
- err = tegra_usb_phy_power_on(tegra->phy);
+ usb_phy_init(&tegra->phy->u_phy);
+
+ err = usb_phy_set_suspend(&tegra->phy->u_phy, 0);
if (err) {
dev_err(&pdev->dev, "Failed to power on the phy\n");
goto fail;
@@ -762,7 +764,7 @@ fail:
usb_put_phy(tegra->transceiver);
}
#endif
- tegra_usb_phy_close(tegra->phy);
+ usb_phy_shutdown(&tegra->phy->u_phy);
fail_phy:
iounmap(hcd->regs);
fail_io:
@@ -800,7 +802,7 @@ static int tegra_ehci_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
- tegra_usb_phy_close(tegra->phy);
+ usb_phy_shutdown(&tegra->phy->u_phy);
iounmap(hcd->regs);
usb_put_hcd(hcd);
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 7a95ab87ac00..5d64c5b5ef52 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -33,6 +33,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include <plat/usb.h>
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 428e6aa3e78a..b562623a8971 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/prefetch.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include <asm/cacheflush.h>
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 0f9fcec4e1d3..16798c9e6f38 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -33,6 +33,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include <mach/da8xx.h>
#include <mach/usb.h>
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 472c8b42d38b..863a9b6286c3 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -33,6 +33,7 @@
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include <mach/cputype.h>
#include <mach/hardware.h>
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 494772fc9e23..c20b8776aafa 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -36,6 +36,7 @@
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include <linux/of.h>
#include <linux/of_device.h>
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 1a1bd9cf40c5..00f21dfee5d7 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -24,6 +24,7 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include "musb_core.h"
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 13fd1ddf742f..d8c8a42bff3e 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -68,7 +68,7 @@ config TWL4030_USB
config TWL6030_USB
tristate "TWL6030 USB Transceiver Driver"
- depends on TWL4030_CORE
+ depends on TWL4030_CORE && OMAP_USB2
select USB_OTG_UTILS
help
Enable this to support the USB OTG transceiver on TWL6030
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index 23c798cb2d7f..c19d1d7173a9 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -544,9 +544,13 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
*/
static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ struct fsl_otg *otg_dev;
+
+ if (!otg)
+ return -ENODEV;
- if (!otg || otg_dev != fsl_otg_dev)
+ otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ if (otg_dev != fsl_otg_dev)
return -ENODEV;
otg->host = host;
@@ -590,12 +594,15 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
static int fsl_otg_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
- struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ struct fsl_otg *otg_dev;
+ if (!otg)
+ return -ENODEV;
+
+ otg_dev = container_of(otg->phy, struct fsl_otg, phy);
VDBG("otg_dev 0x%x\n", (int)otg_dev);
VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev);
-
- if (!otg || otg_dev != fsl_otg_dev)
+ if (otg_dev != fsl_otg_dev)
return -ENODEV;
if (!gadget) {
@@ -660,10 +667,13 @@ static void fsl_otg_event(struct work_struct *work)
/* B-device start SRP */
static int fsl_otg_start_srp(struct usb_otg *otg)
{
- struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ struct fsl_otg *otg_dev;
+
+ if (!otg || otg->phy->state != OTG_STATE_B_IDLE)
+ return -ENODEV;
- if (!otg || otg_dev != fsl_otg_dev
- || otg->phy->state != OTG_STATE_B_IDLE)
+ otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ if (otg_dev != fsl_otg_dev)
return -ENODEV;
otg_dev->fsm.b_bus_req = 1;
@@ -675,9 +685,13 @@ static int fsl_otg_start_srp(struct usb_otg *otg)
/* A_host suspend will call this function to start hnp */
static int fsl_otg_start_hnp(struct usb_otg *otg)
{
- struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ struct fsl_otg *otg_dev;
+
+ if (!otg)
+ return -ENODEV;
- if (!otg || otg_dev != fsl_otg_dev)
+ otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ if (otg_dev != fsl_otg_dev)
return -ENODEV;
DBG("start_hnp...n");
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c
index c1a67cb8e244..88db976647cf 100644
--- a/drivers/usb/otg/mxs-phy.c
+++ b/drivers/usb/otg/mxs-phy.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/workqueue.h>
#define DRIVER_NAME "mxs_phy"
@@ -34,9 +35,16 @@
#define BM_USBPHY_CTRL_ENUTMILEVEL2 BIT(14)
#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT BIT(1)
+/*
+ * Amount of delay in miliseconds to safely enable ENHOSTDISCONDETECT bit
+ * so that connection and reset processing can be completed for the root hub.
+ */
+#define MXY_PHY_ENHOSTDISCONDETECT_DELAY 250
+
struct mxs_phy {
struct usb_phy phy;
struct clk *clk;
+ struct delayed_work enhostdiscondetect_work;
};
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
@@ -62,6 +70,7 @@ static int mxs_phy_init(struct usb_phy *phy)
clk_prepare_enable(mxs_phy->clk);
mxs_phy_hw_init(mxs_phy);
+ INIT_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work, NULL);
return 0;
}
@@ -76,13 +85,34 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
clk_disable_unprepare(mxs_phy->clk);
}
+static void mxs_phy_enhostdiscondetect_delay(struct work_struct *ws)
+{
+ struct mxs_phy *mxs_phy = container_of(ws, struct mxs_phy,
+ enhostdiscondetect_work.work);
+
+ /* Enable HOSTDISCONDETECT after delay. */
+ dev_dbg(mxs_phy->phy.dev, "Setting ENHOSTDISCONDETECT\n");
+ writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ mxs_phy->phy.io_priv + HW_USBPHY_CTRL_SET);
+}
+
static int mxs_phy_on_connect(struct usb_phy *phy, int port)
{
+ struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+
dev_dbg(phy->dev, "Connect on port %d\n", port);
- mxs_phy_hw_init(to_mxs_phy(phy));
- writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
- phy->io_priv + HW_USBPHY_CTRL_SET);
+ mxs_phy_hw_init(mxs_phy);
+
+ /*
+ * Delay enabling ENHOSTDISCONDETECT so that connection and
+ * reset processing can be completed for the root hub.
+ */
+ dev_dbg(phy->dev, "Delaying setting ENHOSTDISCONDETECT\n");
+ PREPARE_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work,
+ mxs_phy_enhostdiscondetect_delay);
+ schedule_delayed_work(&mxs_phy->enhostdiscondetect_work,
+ msecs_to_jiffies(MXY_PHY_ENHOSTDISCONDETECT_DELAY));
return 0;
}
@@ -91,6 +121,8 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy, int port)
{
dev_dbg(phy->dev, "Disconnect on port %d\n", port);
+ /* No need to delay before clearing ENHOSTDISCONDETECT. */
+ dev_dbg(phy->dev, "Clearing ENHOSTDISCONDETECT\n");
writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
phy->io_priv + HW_USBPHY_CTRL_CLR);
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
index 803f958f4133..e52e35e7adaf 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/otg/nop-usb-xceiv.c
@@ -30,6 +30,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
#include <linux/slab.h>
struct nop_usb_xceiv {
@@ -94,7 +95,9 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
{
+ struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
struct nop_usb_xceiv *nop;
+ enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err;
nop = kzalloc(sizeof *nop, GFP_KERNEL);
@@ -107,6 +110,9 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ if (pdata)
+ type = pdata->type;
+
nop->dev = &pdev->dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
@@ -117,7 +123,7 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
nop->phy.otg->set_host = nop_set_host;
nop->phy.otg->set_peripheral = nop_set_peripheral;
- err = usb_add_phy(&nop->phy, USB_PHY_TYPE_USB2);
+ err = usb_add_phy(&nop->phy, type);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index 1bf60a22595c..a30c04115115 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -159,7 +159,7 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
unsigned long flags;
struct usb_phy *phy;
- if (x && x->type != USB_PHY_TYPE_UNDEFINED) {
+ if (x->type != USB_PHY_TYPE_UNDEFINED) {
dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
return -EINVAL;
}
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 523cad5bfea9..f0d2e7530cfe 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -585,23 +585,28 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
struct twl4030_usb *twl;
int status, err;
struct usb_otg *otg;
-
- if (!pdata) {
- dev_dbg(&pdev->dev, "platform_data not available\n");
- return -EINVAL;
- }
+ struct device_node *np = pdev->dev.of_node;
twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL);
if (!twl)
return -ENOMEM;
+ if (np)
+ of_property_read_u32(np, "usb_mode",
+ (enum twl4030_usb_mode *)&twl->usb_mode);
+ else if (pdata)
+ twl->usb_mode = pdata->usb_mode;
+ else {
+ dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
+ return -EINVAL;
+ }
+
otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL);
if (!otg)
return -ENOMEM;
twl->dev = &pdev->dev;
twl->irq = platform_get_irq(pdev, 0);
- twl->usb_mode = pdata->usb_mode;
twl->vbus_supplied = false;
twl->asleep = 1;
twl->linkstat = OMAP_MUSB_UNKNOWN;
@@ -690,12 +695,21 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id twl4030_usb_id_table[] = {
+ { .compatible = "ti,twl4030-usb" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, twl4030_usb_id_table);
+#endif
+
static struct platform_driver twl4030_usb_driver = {
.probe = twl4030_usb_probe,
.remove = __exit_p(twl4030_usb_remove),
.driver = {
.name = "twl4030_usb",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(twl4030_usb_id_table),
},
};
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index 6907d8df7a27..fcadef7864f1 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -25,8 +25,9 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/usb/otg.h>
#include <linux/usb/musb-omap.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/usb/omap_usb.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
@@ -87,7 +88,7 @@
#define VBUS_DET BIT(2)
struct twl6030_usb {
- struct usb_phy phy;
+ struct phy_companion comparator;
struct device *dev;
/* for vbus reporting with irqs disabled */
@@ -104,10 +105,10 @@ struct twl6030_usb {
u8 asleep;
bool irq_enabled;
bool vbus_enable;
- unsigned long features;
+ const char *regulator;
};
-#define phy_to_twl(x) container_of((x), struct twl6030_usb, phy)
+#define comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
/*-------------------------------------------------------------------------*/
@@ -137,50 +138,9 @@ static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
return ret;
}
-static int twl6030_phy_init(struct usb_phy *x)
+static int twl6030_start_srp(struct phy_companion *comparator)
{
- struct twl6030_usb *twl;
- struct device *dev;
- struct twl4030_usb_data *pdata;
-
- twl = phy_to_twl(x);
- dev = twl->dev;
- pdata = dev->platform_data;
-
- if (twl->linkstat == OMAP_MUSB_ID_GROUND)
- pdata->phy_power(twl->dev, 1, 1);
- else
- pdata->phy_power(twl->dev, 0, 1);
-
- return 0;
-}
-
-static void twl6030_phy_shutdown(struct usb_phy *x)
-{
- struct twl6030_usb *twl;
- struct device *dev;
- struct twl4030_usb_data *pdata;
-
- twl = phy_to_twl(x);
- dev = twl->dev;
- pdata = dev->platform_data;
- pdata->phy_power(twl->dev, 0, 0);
-}
-
-static int twl6030_phy_suspend(struct usb_phy *x, int suspend)
-{
- struct twl6030_usb *twl = phy_to_twl(x);
- struct device *dev = twl->dev;
- struct twl4030_usb_data *pdata = dev->platform_data;
-
- pdata->phy_suspend(dev, suspend);
-
- return 0;
-}
-
-static int twl6030_start_srp(struct usb_otg *otg)
-{
- struct twl6030_usb *twl = phy_to_twl(otg->phy);
+ struct twl6030_usb *twl = comparator_to_twl(comparator);
twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
@@ -193,13 +153,6 @@ static int twl6030_start_srp(struct usb_otg *otg)
static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
{
- char *regulator_name;
-
- if (twl->features & TWL6025_SUBCLASS)
- regulator_name = "ldousb";
- else
- regulator_name = "vusb";
-
/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
@@ -209,7 +162,7 @@ static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
/* Program MISC2 register and set bit VUSB_IN_VBAT */
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
- twl->usb3v3 = regulator_get(twl->dev, regulator_name);
+ twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
if (IS_ERR(twl->usb3v3))
return -ENODEV;
@@ -313,23 +266,8 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
return IRQ_HANDLED;
}
-static int twl6030_set_peripheral(struct usb_otg *otg,
- struct usb_gadget *gadget)
-{
- if (!otg)
- return -ENODEV;
-
- otg->gadget = gadget;
- if (!gadget)
- otg->phy->state = OTG_STATE_UNDEFINED;
-
- return 0;
-}
-
-static int twl6030_enable_irq(struct usb_phy *x)
+static int twl6030_enable_irq(struct twl6030_usb *twl)
{
- struct twl6030_usb *twl = phy_to_twl(x);
-
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
@@ -362,9 +300,9 @@ static void otg_set_vbus_work(struct work_struct *data)
CHARGERUSB_CTRL1);
}
-static int twl6030_set_vbus(struct usb_otg *otg, bool enabled)
+static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
{
- struct twl6030_usb *twl = phy_to_twl(otg->phy);
+ struct twl6030_usb *twl = comparator_to_twl(comparator);
twl->vbus_enable = enabled;
schedule_work(&twl->set_vbus_work);
@@ -372,52 +310,44 @@ static int twl6030_set_vbus(struct usb_otg *otg, bool enabled)
return 0;
}
-static int twl6030_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
- if (!otg)
- return -ENODEV;
-
- otg->host = host;
- if (!host)
- otg->phy->state = OTG_STATE_UNDEFINED;
- return 0;
-}
-
static int __devinit twl6030_usb_probe(struct platform_device *pdev)
{
+ u32 ret;
struct twl6030_usb *twl;
int status, err;
- struct twl4030_usb_data *pdata;
- struct usb_otg *otg;
- struct device *dev = &pdev->dev;
- pdata = dev->platform_data;
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct twl4030_usb_data *pdata = dev->platform_data;
twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL);
if (!twl)
return -ENOMEM;
- otg = devm_kzalloc(dev, sizeof *otg, GFP_KERNEL);
- if (!otg)
- return -ENOMEM;
-
twl->dev = &pdev->dev;
twl->irq1 = platform_get_irq(pdev, 0);
twl->irq2 = platform_get_irq(pdev, 1);
- twl->features = pdata->features;
twl->linkstat = OMAP_MUSB_UNKNOWN;
- twl->phy.dev = twl->dev;
- twl->phy.label = "twl6030";
- twl->phy.otg = otg;
- twl->phy.init = twl6030_phy_init;
- twl->phy.shutdown = twl6030_phy_shutdown;
- twl->phy.set_suspend = twl6030_phy_suspend;
+ twl->comparator.set_vbus = twl6030_set_vbus;
+ twl->comparator.start_srp = twl6030_start_srp;
+
+ ret = omap_usb2_set_comparator(&twl->comparator);
+ if (ret == -ENODEV) {
+ dev_info(&pdev->dev, "phy not ready, deferring probe");
+ return -EPROBE_DEFER;
+ }
- otg->phy = &twl->phy;
- otg->set_host = twl6030_set_host;
- otg->set_peripheral = twl6030_set_peripheral;
- otg->set_vbus = twl6030_set_vbus;
- otg->start_srp = twl6030_start_srp;
+ if (np) {
+ twl->regulator = "usb";
+ } else if (pdata) {
+ if (pdata->features & TWL6025_SUBCLASS)
+ twl->regulator = "ldousb";
+ else
+ twl->regulator = "vusb";
+ } else {
+ dev_err(&pdev->dev, "twl6030 initialized without pdata\n");
+ return -EINVAL;
+ }
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
@@ -427,7 +357,6 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "ldo init failed\n");
return err;
}
- usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2);
platform_set_drvdata(pdev, twl);
if (device_create_file(&pdev->dev, &dev_attr_vbus))
@@ -458,9 +387,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
}
twl->asleep = 0;
- pdata->phy_init(dev);
- twl6030_phy_suspend(&twl->phy, 0);
- twl6030_enable_irq(&twl->phy);
+ twl6030_enable_irq(twl);
dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
return 0;
@@ -470,10 +397,6 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev)
{
struct twl6030_usb *twl = platform_get_drvdata(pdev);
- struct twl4030_usb_data *pdata;
- struct device *dev = &pdev->dev;
- pdata = dev->platform_data;
-
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
REG_INT_MSK_LINE_C);
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
@@ -481,19 +404,27 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev)
free_irq(twl->irq1, twl);
free_irq(twl->irq2, twl);
regulator_put(twl->usb3v3);
- pdata->phy_exit(twl->dev);
device_remove_file(twl->dev, &dev_attr_vbus);
cancel_work_sync(&twl->set_vbus_work);
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id twl6030_usb_id_table[] = {
+ { .compatible = "ti,twl6030-usb" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
+#endif
+
static struct platform_driver twl6030_usb_driver = {
.probe = twl6030_usb_probe,
.remove = __exit_p(twl6030_usb_remove),
.driver = {
.name = "twl6030_usb",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(twl6030_usb_id_table),
},
};
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index e7cf84f0751a..63c339b3e676 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -4,6 +4,15 @@
comment "USB Physical Layer drivers"
depends on USB || USB_GADGET
+config OMAP_USB2
+ tristate "OMAP USB2 PHY Driver"
+ select USB_OTG_UTILS
+ help
+ Enable this to support the transceiver that is part of SOC. This
+ driver takes care of all the PHY functionality apart from comparator.
+ The USB OTG controller communicates with the comparator using this
+ driver.
+
config USB_ISP1301
tristate "NXP ISP1301 USB transceiver support"
depends on USB || USB_GADGET
@@ -15,3 +24,11 @@ config USB_ISP1301
To compile this driver as a module, choose M here: the
module will be called isp1301.
+
+config MV_U3D_PHY
+ bool "Marvell USB 3.0 PHY controller Driver"
+ depends on USB_MV_U3D
+ select USB_OTG_UTILS
+ help
+ Enable this to support Marvell USB 3.0 phy controller for Marvell
+ SoC.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index eca095b1a890..b069f29f1225 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -4,4 +4,7 @@
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
+obj-$(CONFIG_OMAP_USB2) += omap-usb2.o
obj-$(CONFIG_USB_ISP1301) += isp1301.o
+obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o
+obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
index b19f4932a037..18dbf7e37607 100644
--- a/drivers/usb/phy/isp1301.c
+++ b/drivers/usb/phy/isp1301.c
@@ -15,12 +15,6 @@
#define DRV_NAME "isp1301"
-#define ISP1301_I2C_ADDR 0x2C
-
-static const unsigned short normal_i2c[] = {
- ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END
-};
-
static const struct i2c_device_id isp1301_id[] = {
{ "isp1301", 0 },
{ }
diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/mv_u3d_phy.c
new file mode 100644
index 000000000000..9f1c5d3c60ec
--- /dev/null
+++ b/drivers/usb/phy/mv_u3d_phy.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/mv_usb.h>
+
+#include "mv_u3d_phy.h"
+
+/*
+ * struct mv_u3d_phy - transceiver driver state
+ * @phy: transceiver structure
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @base: usb phy register memory base
+ */
+struct mv_u3d_phy {
+ struct usb_phy phy;
+ struct mv_usb_platform_data *plat;
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *base;
+};
+
+static u32 mv_u3d_phy_read(void __iomem *base, u32 reg)
+{
+ void __iomem *addr, *data;
+
+ addr = base;
+ data = base + 0x4;
+
+ writel_relaxed(reg, addr);
+ return readl_relaxed(data);
+}
+
+static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value)
+{
+ void __iomem *addr, *data;
+ u32 tmp;
+
+ addr = base;
+ data = base + 0x4;
+
+ writel_relaxed(reg, addr);
+ tmp = readl_relaxed(data);
+ tmp |= value;
+ writel_relaxed(tmp, data);
+}
+
+static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value)
+{
+ void __iomem *addr, *data;
+ u32 tmp;
+
+ addr = base;
+ data = base + 0x4;
+
+ writel_relaxed(reg, addr);
+ tmp = readl_relaxed(data);
+ tmp &= ~value;
+ writel_relaxed(tmp, data);
+}
+
+static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value)
+{
+ void __iomem *addr, *data;
+
+ addr = base;
+ data = base + 0x4;
+
+ writel_relaxed(reg, addr);
+ writel_relaxed(value, data);
+}
+
+void mv_u3d_phy_shutdown(struct usb_phy *phy)
+{
+ struct mv_u3d_phy *mv_u3d_phy;
+ void __iomem *base;
+ u32 val;
+
+ mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
+ base = mv_u3d_phy->base;
+
+ /* Power down Reference Analog current, bit 15
+ * Power down PLL, bit 14
+ * Power down Receiver, bit 13
+ * Power down Transmitter, bit 12
+ * of USB3_POWER_PLL_CONTROL register
+ */
+ val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+ val &= ~(USB3_POWER_PLL_CONTROL_PU);
+ mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+
+ if (mv_u3d_phy->clk)
+ clk_disable(mv_u3d_phy->clk);
+}
+
+static int mv_u3d_phy_init(struct usb_phy *phy)
+{
+ struct mv_u3d_phy *mv_u3d_phy;
+ void __iomem *base;
+ u32 val, count;
+
+ /* enable usb3 phy */
+ mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
+
+ if (mv_u3d_phy->clk)
+ clk_enable(mv_u3d_phy->clk);
+
+ base = mv_u3d_phy->base;
+
+ val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+ val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK);
+ val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT;
+ mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+ udelay(100);
+
+ mv_u3d_phy_write(base, USB3_RESET_CONTROL,
+ USB3_RESET_CONTROL_RESET_PIPE);
+ udelay(100);
+
+ mv_u3d_phy_write(base, USB3_RESET_CONTROL,
+ USB3_RESET_CONTROL_RESET_PIPE
+ | USB3_RESET_CONTROL_RESET_PHY);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+ val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK
+ | USB3_POWER_PLL_CONTROL_PHY_MODE_MASK);
+ val |= (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT)
+ | (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT);
+ mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+ udelay(100);
+
+ mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL,
+ USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE);
+ val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK
+ | USB3_SQUELCH_FFE_FFE_RES_SEL_MASK
+ | USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK);
+ val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT)
+ | (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT)
+ | (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT));
+ mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_GEN1_SET0);
+ val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK;
+ val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT;
+ mv_u3d_phy_write(base, USB3_GEN1_SET0, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_GEN2_SET0);
+ val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK
+ | USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK
+ | USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK);
+ val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT)
+ | (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT)
+ | (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT)
+ | (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT));
+ mv_u3d_phy_write(base, USB3_GEN2_SET0, val);
+ udelay(100);
+
+ mv_u3d_phy_read(base, USB3_TX_EMPPH);
+ val &= ~(USB3_TX_EMPPH_AMP_MASK
+ | USB3_TX_EMPPH_EN_MASK
+ | USB3_TX_EMPPH_AMP_FORCE_MASK
+ | USB3_TX_EMPPH_PAR1_MASK
+ | USB3_TX_EMPPH_PAR2_MASK);
+ val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT)
+ | (1 << USB3_TX_EMPPH_EN_SHIFT)
+ | (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT)
+ | (0x1C << USB3_TX_EMPPH_PAR1_SHIFT)
+ | (1 << USB3_TX_EMPPH_PAR2_SHIFT));
+
+ mv_u3d_phy_write(base, USB3_TX_EMPPH, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_GEN2_SET1);
+ val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK
+ | USB3_GEN2_SET1_G2_RX_SELMUPF_MASK
+ | USB3_GEN2_SET1_G2_RX_SELMUFI_MASK
+ | USB3_GEN2_SET1_G2_RX_SELMUFF_MASK);
+ val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT)
+ | (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT)
+ | (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT)
+ | (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT));
+ mv_u3d_phy_write(base, USB3_GEN2_SET1, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN);
+ val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK;
+ val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT;
+ mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC);
+ val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK;
+ val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT;
+ mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL);
+ val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK;
+ val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT;
+ mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE);
+ val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK
+ | USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK
+ | USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK);
+ val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT)
+ | (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT));
+ mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val);
+ udelay(100);
+
+ val = mv_u3d_phy_read(base, USB3_TXDETRX);
+ val &= ~(USB3_TXDETRX_VTHSEL_MASK);
+ val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT;
+ mv_u3d_phy_write(base, USB3_TXDETRX, val);
+ udelay(100);
+
+ dev_dbg(mv_u3d_phy->dev, "start calibration\n");
+
+calstart:
+ /* Perform Manual Calibration */
+ mv_u3d_phy_set(base, USB3_KVCO_CALI_CONTROL,
+ 1 << USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT);
+
+ mdelay(1);
+
+ count = 0;
+ while (1) {
+ val = mv_u3d_phy_read(base, USB3_KVCO_CALI_CONTROL);
+ if (val & (1 << USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT))
+ break;
+ else if (count > 50) {
+ dev_dbg(mv_u3d_phy->dev, "calibration failure, retry...\n");
+ goto calstart;
+ }
+ count++;
+ mdelay(1);
+ }
+
+ /* active PIPE interface */
+ mv_u3d_phy_write(base, USB3_PIPE_SM_CTRL,
+ 1 << USB3_PIPE_SM_CTRL_PHY_INIT_DONE);
+
+ return 0;
+}
+
+static int __devinit mv_u3d_phy_probe(struct platform_device *pdev)
+{
+ struct mv_u3d_phy *mv_u3d_phy;
+ struct mv_usb_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ void __iomem *phy_base;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing mem resource\n");
+ return -ENODEV;
+ }
+
+ phy_base = devm_request_and_ioremap(dev, res);
+ if (!phy_base) {
+ dev_err(dev, "%s: register mapping failed\n", __func__);
+ return -ENXIO;
+ }
+
+ mv_u3d_phy = devm_kzalloc(dev, sizeof(*mv_u3d_phy), GFP_KERNEL);
+ if (!mv_u3d_phy)
+ return -ENOMEM;
+
+ mv_u3d_phy->dev = &pdev->dev;
+ mv_u3d_phy->plat = pdata;
+ mv_u3d_phy->base = phy_base;
+ mv_u3d_phy->phy.dev = mv_u3d_phy->dev;
+ mv_u3d_phy->phy.label = "mv-u3d-phy";
+ mv_u3d_phy->phy.init = mv_u3d_phy_init;
+ mv_u3d_phy->phy.shutdown = mv_u3d_phy_shutdown;
+
+ ret = usb_add_phy(&mv_u3d_phy->phy, USB_PHY_TYPE_USB3);
+ if (ret)
+ goto err;
+
+ if (!mv_u3d_phy->clk)
+ mv_u3d_phy->clk = clk_get(mv_u3d_phy->dev, "u3dphy");
+
+ platform_set_drvdata(pdev, mv_u3d_phy);
+
+ dev_info(&pdev->dev, "Initialized Marvell USB 3.0 PHY\n");
+err:
+ return ret;
+}
+
+static int __exit mv_u3d_phy_remove(struct platform_device *pdev)
+{
+ struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&mv_u3d_phy->phy);
+
+ if (mv_u3d_phy->clk) {
+ clk_put(mv_u3d_phy->clk);
+ mv_u3d_phy->clk = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver mv_u3d_phy_driver = {
+ .probe = mv_u3d_phy_probe,
+ .remove = __devexit_p(mv_u3d_phy_remove),
+ .driver = {
+ .name = "mv-u3d-phy",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(mv_u3d_phy_driver);
+MODULE_DESCRIPTION("Marvell USB 3.0 PHY controller");
+MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mv-u3d-phy");
diff --git a/drivers/usb/phy/mv_u3d_phy.h b/drivers/usb/phy/mv_u3d_phy.h
new file mode 100644
index 000000000000..2a658cb9a527
--- /dev/null
+++ b/drivers/usb/phy/mv_u3d_phy.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __MV_U3D_PHY_H
+#define __MV_U3D_PHY_H
+
+#define USB3_POWER_PLL_CONTROL 0x1
+#define USB3_KVCO_CALI_CONTROL 0x2
+#define USB3_IMPEDANCE_CALI_CTRL 0x3
+#define USB3_IMPEDANCE_TX_SSC 0x4
+#define USB3_SQUELCH_FFE 0x6
+#define USB3_GEN1_SET0 0xD
+#define USB3_GEN2_SET0 0xF
+#define USB3_GEN2_SET1 0x10
+#define USB3_DIGITAL_LOOPBACK_EN 0x23
+#define USB3_PHY_ISOLATION_MODE 0x26
+#define USB3_TXDETRX 0x48
+#define USB3_TX_EMPPH 0x5E
+#define USB3_RESET_CONTROL 0x90
+#define USB3_PIPE_SM_CTRL 0x91
+
+#define USB3_RESET_CONTROL_RESET_PIPE 0x1
+#define USB3_RESET_CONTROL_RESET_PHY 0x2
+
+#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK (0x1F << 0)
+#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT 0
+#define USB3_PLL_25MHZ 0x2
+#define USB3_PLL_26MHZ 0x5
+#define USB3_POWER_PLL_CONTROL_PHY_MODE_MASK (0x7 << 5)
+#define USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT 5
+#define USB3_POWER_PLL_CONTROL_PU_MASK (0xF << 12)
+#define USB3_POWER_PLL_CONTROL_PU_SHIFT 12
+#define USB3_POWER_PLL_CONTROL_PU (0xF << 12)
+
+#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK (0x1 << 12)
+#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_SHIFT 12
+#define USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT 14
+#define USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT 15
+
+#define USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK 0xF
+#define USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT 0
+#define USB3_SQUELCH_FFE_FFE_RES_SEL_MASK (0x7 << 4)
+#define USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT 4
+#define USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK (0x1F << 8)
+#define USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT 8
+
+#define USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK (0x1 << 15)
+#define USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT 11
+
+#define USB3_GEN2_SET0_G2_TX_AMP_MASK (0x1F << 1)
+#define USB3_GEN2_SET0_G2_TX_AMP_SHIFT 1
+#define USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT 6
+#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK (0xF << 7)
+#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT 7
+#define USB3_GEN2_SET0_G2_TX_EMPH_EN_MASK (0x1 << 11)
+#define USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT 11
+#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK (0x1 << 15)
+#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_SHIFT 15
+
+#define USB3_GEN2_SET1_G2_RX_SELMUPI_MASK (0x7 << 0)
+#define USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT 0
+#define USB3_GEN2_SET1_G2_RX_SELMUPF_MASK (0x7 << 3)
+#define USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT 3
+#define USB3_GEN2_SET1_G2_RX_SELMUFI_MASK (0x3 << 6)
+#define USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT 6
+#define USB3_GEN2_SET1_G2_RX_SELMUFF_MASK (0x3 << 8)
+#define USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT 8
+
+#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK (0x3 << 10)
+#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT 10
+
+#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK (0x7 << 12)
+#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT 12
+
+#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK (0x3F << 0)
+#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT 0
+
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK 0xF
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT 0
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK (0xF << 4)
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT 4
+#define USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK (0x1 << 8)
+
+#define USB3_TXDETRX_VTHSEL_MASK (0x3 << 4)
+#define USB3_TXDETRX_VTHSEL_SHIFT 4
+
+#define USB3_TX_EMPPH_AMP_MASK (0xF << 0)
+#define USB3_TX_EMPPH_AMP_SHIFT 0
+#define USB3_TX_EMPPH_EN_MASK (0x1 << 6)
+#define USB3_TX_EMPPH_EN_SHIFT 6
+#define USB3_TX_EMPPH_AMP_FORCE_MASK (0x1 << 7)
+#define USB3_TX_EMPPH_AMP_FORCE_SHIFT 7
+#define USB3_TX_EMPPH_PAR1_MASK (0x1F << 8)
+#define USB3_TX_EMPPH_PAR1_SHIFT 8
+#define USB3_TX_EMPPH_PAR2_MASK (0x1 << 13)
+#define USB3_TX_EMPPH_PAR2_SHIFT 13
+
+#define USB3_PIPE_SM_CTRL_PHY_INIT_DONE 15
+
+#endif /* __MV_U3D_PHY_H */
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c
new file mode 100644
index 000000000000..15ab3d6f2e8c
--- /dev/null
+++ b/drivers/usb/phy/omap-usb2.c
@@ -0,0 +1,271 @@
+/*
+ * omap-usb2.c - USB PHY, talking to musb controller in OMAP.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * 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.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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 <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/usb/omap_usb.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+
+/**
+ * omap_usb2_set_comparator - links the comparator present in the sytem with
+ * this phy
+ * @comparator - the companion phy(comparator) for this phy
+ *
+ * The phy companion driver should call this API passing the phy_companion
+ * filled with set_vbus and start_srp to be used by usb phy.
+ *
+ * For use by phy companion driver
+ */
+int omap_usb2_set_comparator(struct phy_companion *comparator)
+{
+ struct omap_usb *phy;
+ struct usb_phy *x = usb_get_phy(USB_PHY_TYPE_USB2);
+
+ if (IS_ERR(x))
+ return -ENODEV;
+
+ phy = phy_to_omapusb(x);
+ phy->comparator = comparator;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
+
+/**
+ * omap_usb_phy_power - power on/off the phy using control module reg
+ * @phy: struct omap_usb *
+ * @on: 0 or 1, based on powering on or off the PHY
+ *
+ * XXX: Remove this function once control module driver gets merged
+ */
+static void omap_usb_phy_power(struct omap_usb *phy, int on)
+{
+ u32 val;
+
+ if (on) {
+ val = readl(phy->control_dev);
+ if (val & PHY_PD) {
+ writel(~PHY_PD, phy->control_dev);
+ /* XXX: add proper documentation for this delay */
+ mdelay(200);
+ }
+ } else {
+ writel(PHY_PD, phy->control_dev);
+ }
+}
+
+static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
+{
+ struct omap_usb *phy = phy_to_omapusb(otg->phy);
+
+ if (!phy->comparator)
+ return -ENODEV;
+
+ return phy->comparator->set_vbus(phy->comparator, enabled);
+}
+
+static int omap_usb_start_srp(struct usb_otg *otg)
+{
+ struct omap_usb *phy = phy_to_omapusb(otg->phy);
+
+ if (!phy->comparator)
+ return -ENODEV;
+
+ return phy->comparator->start_srp(phy->comparator);
+}
+
+static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ struct usb_phy *phy = otg->phy;
+
+ otg->host = host;
+ if (!host)
+ phy->state = OTG_STATE_UNDEFINED;
+
+ return 0;
+}
+
+static int omap_usb_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
+{
+ struct usb_phy *phy = otg->phy;
+
+ otg->gadget = gadget;
+ if (!gadget)
+ phy->state = OTG_STATE_UNDEFINED;
+
+ return 0;
+}
+
+static int omap_usb2_suspend(struct usb_phy *x, int suspend)
+{
+ u32 ret;
+ struct omap_usb *phy = phy_to_omapusb(x);
+
+ if (suspend && !phy->is_suspended) {
+ omap_usb_phy_power(phy, 0);
+ pm_runtime_put_sync(phy->dev);
+ phy->is_suspended = 1;
+ } else if (!suspend && phy->is_suspended) {
+ ret = pm_runtime_get_sync(phy->dev);
+ if (ret < 0) {
+ dev_err(phy->dev, "get_sync failed with err %d\n",
+ ret);
+ return ret;
+ }
+ omap_usb_phy_power(phy, 1);
+ phy->is_suspended = 0;
+ }
+
+ return 0;
+}
+
+static int __devinit omap_usb2_probe(struct platform_device *pdev)
+{
+ struct omap_usb *phy;
+ struct usb_otg *otg;
+ struct resource *res;
+
+ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
+ return -ENOMEM;
+ }
+
+ otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+ if (!otg) {
+ dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n");
+ return -ENOMEM;
+ }
+
+ phy->dev = &pdev->dev;
+
+ phy->phy.dev = phy->dev;
+ phy->phy.label = "omap-usb2";
+ phy->phy.set_suspend = omap_usb2_suspend;
+ phy->phy.otg = otg;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ phy->control_dev = devm_request_and_ioremap(&pdev->dev, res);
+ if (phy->control_dev == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENXIO;
+ }
+
+ phy->is_suspended = 1;
+ omap_usb_phy_power(phy, 0);
+
+ otg->set_host = omap_usb_set_host;
+ otg->set_peripheral = omap_usb_set_peripheral;
+ otg->set_vbus = omap_usb_set_vbus;
+ otg->start_srp = omap_usb_start_srp;
+ otg->phy = &phy->phy;
+
+ phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
+ if (IS_ERR(phy->wkupclk)) {
+ dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
+ return PTR_ERR(phy->wkupclk);
+ }
+ clk_prepare(phy->wkupclk);
+
+ usb_add_phy(&phy->phy, USB_PHY_TYPE_USB2);
+
+ platform_set_drvdata(pdev, phy);
+
+ pm_runtime_enable(phy->dev);
+
+ return 0;
+}
+
+static int __devexit omap_usb2_remove(struct platform_device *pdev)
+{
+ struct omap_usb *phy = platform_get_drvdata(pdev);
+
+ clk_unprepare(phy->wkupclk);
+ usb_remove_phy(&phy->phy);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int omap_usb2_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_usb *phy = platform_get_drvdata(pdev);
+
+ clk_disable(phy->wkupclk);
+
+ return 0;
+}
+
+static int omap_usb2_runtime_resume(struct device *dev)
+{
+ u32 ret = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_usb *phy = platform_get_drvdata(pdev);
+
+ ret = clk_enable(phy->wkupclk);
+ if (ret < 0)
+ dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
+
+ return ret;
+}
+
+static const struct dev_pm_ops omap_usb2_pm_ops = {
+ SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume,
+ NULL)
+};
+
+#define DEV_PM_OPS (&omap_usb2_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id omap_usb2_id_table[] = {
+ { .compatible = "ti,omap-usb2" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
+#endif
+
+static struct platform_driver omap_usb2_driver = {
+ .probe = omap_usb2_probe,
+ .remove = __devexit_p(omap_usb2_remove),
+ .driver = {
+ .name = "omap-usb2",
+ .owner = THIS_MODULE,
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(omap_usb2_id_table),
+ },
+};
+
+module_platform_driver(omap_usb2_driver);
+
+MODULE_ALIAS("platform: omap_usb2");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("OMAP USB2 phy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-tegra/usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c
index 022b33a05c3a..4739903245e8 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/drivers/usb/phy/tegra_usb_phy.c
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-tegra/usb_phy.c
- *
* Copyright (C) 2010 Google, Inc.
*
* Author:
@@ -31,7 +29,7 @@
#include <linux/usb/ulpi.h>
#include <asm/mach-types.h>
#include <mach/gpio-tegra.h>
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
#include <mach/iomap.h>
#define ULPI_VIEWPORT 0x170
@@ -482,7 +480,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
return 0;
}
-static void utmi_phy_power_off(struct tegra_usb_phy *phy)
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
@@ -514,7 +512,7 @@ static void utmi_phy_power_off(struct tegra_usb_phy *phy)
UTMIP_FORCE_PDDR_POWERDOWN;
writel(val, base + UTMIP_XCVR_CFG1);
- utmip_pad_power_off(phy);
+ return utmip_pad_power_off(phy);
}
static void utmi_phy_preresume(struct tegra_usb_phy *phy)
@@ -638,7 +636,7 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
return 0;
}
-static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
+static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
@@ -651,15 +649,92 @@ static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
writel(val, base + USB_PORTSC1);
- gpio_direction_output(config->reset_gpio, 0);
clk_disable(phy->clk);
+ return gpio_direction_output(config->reset_gpio, 0);
+}
+
+static int tegra_phy_init(struct usb_phy *x)
+{
+ struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+ struct tegra_ulpi_config *ulpi_config;
+ int err;
+
+ if (phy_is_ulpi(phy)) {
+ ulpi_config = phy->config;
+ phy->clk = clk_get_sys(NULL, ulpi_config->clk);
+ if (IS_ERR(phy->clk)) {
+ pr_err("%s: can't get ulpi clock\n", __func__);
+ err = -ENXIO;
+ goto err1;
+ }
+ if (!gpio_is_valid(ulpi_config->reset_gpio))
+ ulpi_config->reset_gpio =
+ of_get_named_gpio(phy->dev->of_node,
+ "nvidia,phy-reset-gpio", 0);
+ if (!gpio_is_valid(ulpi_config->reset_gpio)) {
+ pr_err("%s: invalid reset gpio: %d\n", __func__,
+ ulpi_config->reset_gpio);
+ err = -EINVAL;
+ goto err1;
+ }
+ gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
+ gpio_direction_output(ulpi_config->reset_gpio, 0);
+ phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
+ } else {
+ err = utmip_pad_open(phy);
+ if (err < 0)
+ goto err1;
+ }
+ return 0;
+err1:
+ clk_disable_unprepare(phy->pll_u);
+ clk_put(phy->pll_u);
+ return err;
+}
+
+static void tegra_usb_phy_close(struct usb_phy *x)
+{
+ struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+
+ if (phy_is_ulpi(phy))
+ clk_put(phy->clk);
+ else
+ utmip_pad_close(phy);
+ clk_disable_unprepare(phy->pll_u);
+ clk_put(phy->pll_u);
+ kfree(phy);
+}
+
+static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
+{
+ if (phy_is_ulpi(phy))
+ return ulpi_phy_power_on(phy);
+ else
+ return utmi_phy_power_on(phy);
+}
+
+static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
+{
+ if (phy_is_ulpi(phy))
+ return ulpi_phy_power_off(phy);
+ else
+ return utmi_phy_power_off(phy);
+}
+
+static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
+{
+ struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+ if (suspend)
+ return tegra_usb_phy_power_off(phy);
+ else
+ return tegra_usb_phy_power_on(phy);
}
struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode)
{
struct tegra_usb_phy *phy;
- struct tegra_ulpi_config *ulpi_config;
unsigned long parent_rate;
int i;
int err;
@@ -672,6 +747,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
phy->regs = regs;
phy->config = config;
phy->mode = phy_mode;
+ phy->dev = dev;
if (!phy->config) {
if (phy_is_ulpi(phy)) {
@@ -704,33 +780,9 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
goto err1;
}
- if (phy_is_ulpi(phy)) {
- ulpi_config = config;
- phy->clk = clk_get_sys(NULL, ulpi_config->clk);
- if (IS_ERR(phy->clk)) {
- pr_err("%s: can't get ulpi clock\n", __func__);
- err = -ENXIO;
- goto err1;
- }
- if (!gpio_is_valid(ulpi_config->reset_gpio))
- ulpi_config->reset_gpio =
- of_get_named_gpio(dev->of_node,
- "nvidia,phy-reset-gpio", 0);
- if (!gpio_is_valid(ulpi_config->reset_gpio)) {
- pr_err("%s: invalid reset gpio: %d\n", __func__,
- ulpi_config->reset_gpio);
- err = -EINVAL;
- goto err1;
- }
- gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
- gpio_direction_output(ulpi_config->reset_gpio, 0);
- phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
- phy->ulpi->io_priv = regs + ULPI_VIEWPORT;
- } else {
- err = utmip_pad_open(phy);
- if (err < 0)
- goto err1;
- }
+ phy->u_phy.init = tegra_phy_init;
+ phy->u_phy.shutdown = tegra_usb_phy_close;
+ phy->u_phy.set_suspend = tegra_usb_phy_suspend;
return phy;
@@ -743,24 +795,6 @@ err0:
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
-{
- if (phy_is_ulpi(phy))
- return ulpi_phy_power_on(phy);
- else
- return utmi_phy_power_on(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on);
-
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
-{
- if (phy_is_ulpi(phy))
- ulpi_phy_power_off(phy);
- else
- utmi_phy_power_off(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off);
-
void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
@@ -803,15 +837,3 @@ void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
utmi_phy_clk_enable(phy);
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
-
-void tegra_usb_phy_close(struct tegra_usb_phy *phy)
-{
- if (phy_is_ulpi(phy))
- clk_put(phy->clk);
- else
- utmip_pad_close(phy);
- clk_disable_unprepare(phy->pll_u);
- clk_put(phy->pll_u);
- kfree(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h
new file mode 100644
index 000000000000..28884c717411
--- /dev/null
+++ b/include/linux/usb/nop-usb-xceiv.h
@@ -0,0 +1,24 @@
+#ifndef __LINUX_USB_NOP_XCEIV_H
+#define __LINUX_USB_NOP_XCEIV_H
+
+#include <linux/usb/otg.h>
+
+struct nop_usb_xceiv_platform_data {
+ enum usb_phy_type type;
+};
+
+#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
+/* sometimes transceivers are accessed only through e.g. ULPI */
+extern void usb_nop_xceiv_register(void);
+extern void usb_nop_xceiv_unregister(void);
+#else
+static inline void usb_nop_xceiv_register(void)
+{
+}
+
+static inline void usb_nop_xceiv_unregister(void)
+{
+}
+#endif
+
+#endif /* __LINUX_USB_NOP_XCEIV_H */
diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h
new file mode 100644
index 000000000000..0ea17f8ae820
--- /dev/null
+++ b/include/linux/usb/omap_usb.h
@@ -0,0 +1,46 @@
+/*
+ * omap_usb.h -- omap usb2 phy header file
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * 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.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __DRIVERS_OMAP_USB2_H
+#define __DRIVERS_OMAP_USB2_H
+
+#include <linux/usb/otg.h>
+
+struct omap_usb {
+ struct usb_phy phy;
+ struct phy_companion *comparator;
+ struct device *dev;
+ u32 __iomem *control_dev;
+ struct clk *wkupclk;
+ u8 is_suspended:1;
+};
+
+#define PHY_PD 0x1
+
+#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
+
+#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
+extern int omap_usb2_set_comparator(struct phy_companion *comparator);
+#else
+static inline int omap_usb2_set_comparator(struct phy_companion *comparator)
+{
+ return -ENODEV;
+}
+#endif
+
+#endif /* __DRIVERS_OMAP_USB_H */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 45824be0a2f9..e8a5fe87c6bd 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -9,56 +9,7 @@
#ifndef __LINUX_USB_OTG_H
#define __LINUX_USB_OTG_H
-#include <linux/notifier.h>
-
-/* OTG defines lots of enumeration states before device reset */
-enum usb_otg_state {
- OTG_STATE_UNDEFINED = 0,
-
- /* single-role peripheral, and dual-role default-b */
- OTG_STATE_B_IDLE,
- OTG_STATE_B_SRP_INIT,
- OTG_STATE_B_PERIPHERAL,
-
- /* extra dual-role default-b states */
- OTG_STATE_B_WAIT_ACON,
- OTG_STATE_B_HOST,
-
- /* dual-role default-a */
- OTG_STATE_A_IDLE,
- OTG_STATE_A_WAIT_VRISE,
- OTG_STATE_A_WAIT_BCON,
- OTG_STATE_A_HOST,
- OTG_STATE_A_SUSPEND,
- OTG_STATE_A_PERIPHERAL,
- OTG_STATE_A_WAIT_VFALL,
- OTG_STATE_A_VBUS_ERR,
-};
-
-enum usb_phy_events {
- USB_EVENT_NONE, /* no events or cable disconnected */
- USB_EVENT_VBUS, /* vbus valid event */
- USB_EVENT_ID, /* id was grounded */
- USB_EVENT_CHARGER, /* usb dedicated charger */
- USB_EVENT_ENUMERATED, /* gadget driver enumerated */
-};
-
-/* associate a type with PHY */
-enum usb_phy_type {
- USB_PHY_TYPE_UNDEFINED,
- USB_PHY_TYPE_USB2,
- USB_PHY_TYPE_USB3,
-};
-
-struct usb_phy;
-
-/* for transceivers connected thru an ULPI interface, the user must
- * provide access ops
- */
-struct usb_phy_io_ops {
- int (*read)(struct usb_phy *x, u32 reg);
- int (*write)(struct usb_phy *x, u32 val, u32 reg);
-};
+#include <linux/usb/phy.h>
struct usb_otg {
u8 default_a;
@@ -85,134 +36,9 @@ struct usb_otg {
};
-/*
- * the otg driver needs to interact with both device side and host side
- * usb controllers. it decides which controller is active at a given
- * moment, using the transceiver, ID signal, HNP and sometimes static
- * configuration information (including "board isn't wired for otg").
- */
-struct usb_phy {
- struct device *dev;
- const char *label;
- unsigned int flags;
-
- enum usb_phy_type type;
- enum usb_otg_state state;
- enum usb_phy_events last_event;
-
- struct usb_otg *otg;
-
- struct device *io_dev;
- struct usb_phy_io_ops *io_ops;
- void __iomem *io_priv;
-
- /* for notification of usb_phy_events */
- struct atomic_notifier_head notifier;
-
- /* to pass extra port status to the root hub */
- u16 port_status;
- u16 port_change;
-
- /* to support controllers that have multiple transceivers */
- struct list_head head;
-
- /* initialize/shutdown the OTG controller */
- int (*init)(struct usb_phy *x);
- void (*shutdown)(struct usb_phy *x);
-
- /* effective for B devices, ignored for A-peripheral */
- int (*set_power)(struct usb_phy *x,
- unsigned mA);
-
- /* for non-OTG B devices: set transceiver into suspend mode */
- int (*set_suspend)(struct usb_phy *x,
- int suspend);
-
- /* notify phy connect status change */
- int (*notify_connect)(struct usb_phy *x, int port);
- int (*notify_disconnect)(struct usb_phy *x, int port);
-};
-
-
-/* for board-specific init logic */
-extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
-extern void usb_remove_phy(struct usb_phy *);
-
-#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
-/* sometimes transceivers are accessed only through e.g. ULPI */
-extern void usb_nop_xceiv_register(void);
-extern void usb_nop_xceiv_unregister(void);
-#else
-static inline void usb_nop_xceiv_register(void)
-{
-}
-
-static inline void usb_nop_xceiv_unregister(void)
-{
-}
-#endif
-
-/* helpers for direct access thru low-level io interface */
-static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
-{
- if (x->io_ops && x->io_ops->read)
- return x->io_ops->read(x, reg);
-
- return -EINVAL;
-}
-
-static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
-{
- if (x->io_ops && x->io_ops->write)
- return x->io_ops->write(x, val, reg);
-
- return -EINVAL;
-}
-
-static inline int
-usb_phy_init(struct usb_phy *x)
-{
- if (x->init)
- return x->init(x);
-
- return 0;
-}
-
-static inline void
-usb_phy_shutdown(struct usb_phy *x)
-{
- if (x->shutdown)
- x->shutdown(x);
-}
-
-/* for usb host and peripheral controller drivers */
#ifdef CONFIG_USB_OTG_UTILS
-extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
-extern struct usb_phy *devm_usb_get_phy(struct device *dev,
- enum usb_phy_type type);
-extern void usb_put_phy(struct usb_phy *);
-extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
extern const char *otg_state_string(enum usb_otg_state state);
#else
-static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
-{
- return NULL;
-}
-
-static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
- enum usb_phy_type type)
-{
- return NULL;
-}
-
-static inline void usb_put_phy(struct usb_phy *x)
-{
-}
-
-static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
-{
-}
-
static inline const char *otg_state_string(enum usb_otg_state state)
{
return NULL;
@@ -262,42 +88,6 @@ otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *periph)
}
static inline int
-usb_phy_set_power(struct usb_phy *x, unsigned mA)
-{
- if (x && x->set_power)
- return x->set_power(x, mA);
- return 0;
-}
-
-/* Context: can sleep */
-static inline int
-usb_phy_set_suspend(struct usb_phy *x, int suspend)
-{
- if (x->set_suspend != NULL)
- return x->set_suspend(x, suspend);
- else
- return 0;
-}
-
-static inline int
-usb_phy_notify_connect(struct usb_phy *x, int port)
-{
- if (x->notify_connect)
- return x->notify_connect(x, port);
- else
- return 0;
-}
-
-static inline int
-usb_phy_notify_disconnect(struct usb_phy *x, int port)
-{
- if (x->notify_disconnect)
- return x->notify_disconnect(x, port);
- else
- return 0;
-}
-
-static inline int
otg_start_srp(struct usb_otg *otg)
{
if (otg && otg->start_srp)
@@ -306,31 +96,7 @@ otg_start_srp(struct usb_otg *otg)
return -ENOTSUPP;
}
-/* notifiers */
-static inline int
-usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&x->notifier, nb);
-}
-
-static inline void
-usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
-{
- atomic_notifier_chain_unregister(&x->notifier, nb);
-}
-
/* for OTG controller drivers (and maybe other stuff) */
extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
-static inline const char *usb_phy_type_string(enum usb_phy_type type)
-{
- switch (type) {
- case USB_PHY_TYPE_USB2:
- return "USB2 PHY";
- case USB_PHY_TYPE_USB3:
- return "USB3 PHY";
- default:
- return "UNKNOWN PHY TYPE";
- }
-}
#endif /* __LINUX_USB_OTG_H */
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
new file mode 100644
index 000000000000..06b5bae35b29
--- /dev/null
+++ b/include/linux/usb/phy.h
@@ -0,0 +1,233 @@
+/* USB OTG (On The Go) defines */
+/*
+ *
+ * These APIs may be used between USB controllers. USB device drivers
+ * (for either host or peripheral roles) don't use these calls; they
+ * continue to use just usb_device and usb_gadget.
+ */
+
+#ifndef __LINUX_USB_PHY_H
+#define __LINUX_USB_PHY_H
+
+#include <linux/notifier.h>
+
+enum usb_phy_events {
+ USB_EVENT_NONE, /* no events or cable disconnected */
+ USB_EVENT_VBUS, /* vbus valid event */
+ USB_EVENT_ID, /* id was grounded */
+ USB_EVENT_CHARGER, /* usb dedicated charger */
+ USB_EVENT_ENUMERATED, /* gadget driver enumerated */
+};
+
+/* associate a type with PHY */
+enum usb_phy_type {
+ USB_PHY_TYPE_UNDEFINED,
+ USB_PHY_TYPE_USB2,
+ USB_PHY_TYPE_USB3,
+};
+
+/* OTG defines lots of enumeration states before device reset */
+enum usb_otg_state {
+ OTG_STATE_UNDEFINED = 0,
+
+ /* single-role peripheral, and dual-role default-b */
+ OTG_STATE_B_IDLE,
+ OTG_STATE_B_SRP_INIT,
+ OTG_STATE_B_PERIPHERAL,
+
+ /* extra dual-role default-b states */
+ OTG_STATE_B_WAIT_ACON,
+ OTG_STATE_B_HOST,
+
+ /* dual-role default-a */
+ OTG_STATE_A_IDLE,
+ OTG_STATE_A_WAIT_VRISE,
+ OTG_STATE_A_WAIT_BCON,
+ OTG_STATE_A_HOST,
+ OTG_STATE_A_SUSPEND,
+ OTG_STATE_A_PERIPHERAL,
+ OTG_STATE_A_WAIT_VFALL,
+ OTG_STATE_A_VBUS_ERR,
+};
+
+struct usb_phy;
+struct usb_otg;
+
+/* for transceivers connected thru an ULPI interface, the user must
+ * provide access ops
+ */
+struct usb_phy_io_ops {
+ int (*read)(struct usb_phy *x, u32 reg);
+ int (*write)(struct usb_phy *x, u32 val, u32 reg);
+};
+
+struct usb_phy {
+ struct device *dev;
+ const char *label;
+ unsigned int flags;
+
+ enum usb_phy_type type;
+ enum usb_otg_state state;
+ enum usb_phy_events last_event;
+
+ struct usb_otg *otg;
+
+ struct device *io_dev;
+ struct usb_phy_io_ops *io_ops;
+ void __iomem *io_priv;
+
+ /* for notification of usb_phy_events */
+ struct atomic_notifier_head notifier;
+
+ /* to pass extra port status to the root hub */
+ u16 port_status;
+ u16 port_change;
+
+ /* to support controllers that have multiple transceivers */
+ struct list_head head;
+
+ /* initialize/shutdown the OTG controller */
+ int (*init)(struct usb_phy *x);
+ void (*shutdown)(struct usb_phy *x);
+
+ /* effective for B devices, ignored for A-peripheral */
+ int (*set_power)(struct usb_phy *x,
+ unsigned mA);
+
+ /* for non-OTG B devices: set transceiver into suspend mode */
+ int (*set_suspend)(struct usb_phy *x,
+ int suspend);
+
+ /* notify phy connect status change */
+ int (*notify_connect)(struct usb_phy *x, int port);
+ int (*notify_disconnect)(struct usb_phy *x, int port);
+};
+
+
+/* for board-specific init logic */
+extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
+extern void usb_remove_phy(struct usb_phy *);
+
+/* helpers for direct access thru low-level io interface */
+static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
+{
+ if (x->io_ops && x->io_ops->read)
+ return x->io_ops->read(x, reg);
+
+ return -EINVAL;
+}
+
+static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
+{
+ if (x->io_ops && x->io_ops->write)
+ return x->io_ops->write(x, val, reg);
+
+ return -EINVAL;
+}
+
+static inline int
+usb_phy_init(struct usb_phy *x)
+{
+ if (x->init)
+ return x->init(x);
+
+ return 0;
+}
+
+static inline void
+usb_phy_shutdown(struct usb_phy *x)
+{
+ if (x->shutdown)
+ x->shutdown(x);
+}
+
+/* for usb host and peripheral controller drivers */
+#ifdef CONFIG_USB_OTG_UTILS
+extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
+extern struct usb_phy *devm_usb_get_phy(struct device *dev,
+ enum usb_phy_type type);
+extern void usb_put_phy(struct usb_phy *);
+extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
+#else
+static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
+{
+ return NULL;
+}
+
+static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
+ enum usb_phy_type type)
+{
+ return NULL;
+}
+
+static inline void usb_put_phy(struct usb_phy *x)
+{
+}
+
+static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
+{
+}
+
+#endif
+
+static inline int
+usb_phy_set_power(struct usb_phy *x, unsigned mA)
+{
+ if (x && x->set_power)
+ return x->set_power(x, mA);
+ return 0;
+}
+
+/* Context: can sleep */
+static inline int
+usb_phy_set_suspend(struct usb_phy *x, int suspend)
+{
+ if (x->set_suspend != NULL)
+ return x->set_suspend(x, suspend);
+ else
+ return 0;
+}
+
+static inline int
+usb_phy_notify_connect(struct usb_phy *x, int port)
+{
+ if (x->notify_connect)
+ return x->notify_connect(x, port);
+ else
+ return 0;
+}
+
+static inline int
+usb_phy_notify_disconnect(struct usb_phy *x, int port)
+{
+ if (x->notify_disconnect)
+ return x->notify_disconnect(x, port);
+ else
+ return 0;
+}
+
+/* notifiers */
+static inline int
+usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&x->notifier, nb);
+}
+
+static inline void
+usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&x->notifier, nb);
+}
+
+static inline const char *usb_phy_type_string(enum usb_phy_type type)
+{
+ switch (type) {
+ case USB_PHY_TYPE_USB2:
+ return "USB2 PHY";
+ case USB_PHY_TYPE_USB3:
+ return "USB3 PHY";
+ default:
+ return "UNKNOWN PHY TYPE";
+ }
+}
+#endif /* __LINUX_USB_PHY_H */
diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h
new file mode 100644
index 000000000000..edd2ec23d282
--- /dev/null
+++ b/include/linux/usb/phy_companion.h
@@ -0,0 +1,34 @@
+/*
+ * phy-companion.h -- phy companion to indicate the comparator part of PHY
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * 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.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __DRIVERS_PHY_COMPANION_H
+#define __DRIVERS_PHY_COMPANION_H
+
+#include <linux/usb/otg.h>
+
+/* phy_companion to take care of VBUS, ID and srp capabilities */
+struct phy_companion {
+
+ /* effective for A-peripheral, ignored for B devices */
+ int (*set_vbus)(struct phy_companion *x, bool enabled);
+
+ /* for B devices only: start session with A-Host */
+ int (*start_srp)(struct phy_companion *x);
+};
+
+#endif /* __DRIVERS_PHY_COMPANION_H */
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/include/linux/usb/tegra_usb_phy.h
index 935ce9f65590..176b1ca06ae4 100644
--- a/arch/arm/mach-tegra/include/mach/usb_phy.h
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-tegra/include/mach/usb_phy.h
- *
* Copyright (C) 2010 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
@@ -14,8 +12,8 @@
*
*/
-#ifndef __MACH_USB_PHY_H
-#define __MACH_USB_PHY_H
+#ifndef __TEGRA_USB_PHY_H
+#define __TEGRA_USB_PHY_H
#include <linux/clk.h>
#include <linux/usb/otg.h>
@@ -59,19 +57,17 @@ struct tegra_usb_phy {
enum tegra_usb_phy_mode mode;
void *config;
struct usb_phy *ulpi;
+ struct usb_phy u_phy;
+ struct device *dev;
};
struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode);
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy);
-
void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy);
-
void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
@@ -81,6 +77,4 @@ void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
-void tegra_usb_phy_close(struct tegra_usb_phy *phy);
-
-#endif /* __MACH_USB_PHY_H */
+#endif /* __TEGRA_USB_PHY_H */