forked from luck/tmp_suning_uos_patched
Merge commit 'xceiv-for-v3.7' into for-3.7/cleanup2
This commit is contained in:
commit
fef40b2369
40
Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
Normal file
40
Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
Normal file
|
@ -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>;
|
||||
};
|
17
Documentation/devicetree/bindings/usb/usb-phy.txt
Normal file
17
Documentation/devicetree/bindings/usb/usb-phy.txt
Normal file
|
@ -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>;
|
||||
};
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ static int tegra_ehci_probe(struct platform_device *pdev)
|
|||
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);
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 || otg_dev != fsl_otg_dev)
|
||||
if (!otg)
|
||||
return -ENODEV;
|
||||
|
||||
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_dev != fsl_otg_dev
|
||||
|| otg->phy->state != OTG_STATE_B_IDLE)
|
||||
if (!otg || otg->phy->state != OTG_STATE_B_IDLE)
|
||||
return -ENODEV;
|
||||
|
||||
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 || otg_dev != fsl_otg_dev)
|
||||
if (!otg)
|
||||
return -ENODEV;
|
||||
|
||||
otg_dev = container_of(otg->phy, struct fsl_otg, phy);
|
||||
if (otg_dev != fsl_otg_dev)
|
||||
return -ENODEV;
|
||||
|
||||
DBG("start_hnp...n");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
static int twl6030_enable_irq(struct twl6030_usb *twl)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
ret = omap_usb2_set_comparator(&twl->comparator);
|
||||
if (ret == -ENODEV) {
|
||||
dev_info(&pdev->dev, "phy not ready, deferring probe");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
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),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
{ }
|
||||
|
|
345
drivers/usb/phy/mv_u3d_phy.c
Normal file
345
drivers/usb/phy/mv_u3d_phy.c
Normal file
|
@ -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");
|
105
drivers/usb/phy/mv_u3d_phy.h
Normal file
105
drivers/usb/phy/mv_u3d_phy.h
Normal file
|
@ -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 */
|
271
drivers/usb/phy/omap-usb2.c
Normal file
271
drivers/usb/phy/omap-usb2.c
Normal file
|
@ -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");
|
|
@ -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 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
|
|||
}
|
||||
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);
|
24
include/linux/usb/nop-usb-xceiv.h
Normal file
24
include/linux/usb/nop-usb-xceiv.h
Normal file
|
@ -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 */
|
46
include/linux/usb/omap_usb.h
Normal file
46
include/linux/usb/omap_usb.h
Normal file
|
@ -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 */
|
|
@ -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;
|
||||
|
@ -261,42 +87,6 @@ otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *periph)
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
|
233
include/linux/usb/phy.h
Normal file
233
include/linux/usb/phy.h
Normal file
|
@ -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 */
|
34
include/linux/usb/phy_companion.h
Normal file
34
include/linux/usb/phy_companion.h
Normal file
|
@ -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 */
|
|
@ -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 */
|
Loading…
Reference in New Issue
Block a user