usb: phy: move all PHY drivers to drivers/usb/phy/
authorFelipe Balbi <balbi@ti.com>
Thu, 7 Mar 2013 09:01:15 +0000 (11:01 +0200)
committerFelipe Balbi <balbi@ti.com>
Mon, 18 Mar 2013 09:18:04 +0000 (11:18 +0200)
that's a much more reasonable location for
those drivers. It helps us saving drivers/usb/otg/
for when we actually start adding generic OTG
code.

Also completely delete drivers/usb/otg/ as there's
nothing left there.

Signed-off-by: Felipe Balbi <balbi@ti.com>
38 files changed:
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/otg/Kconfig [deleted file]
drivers/usb/otg/Makefile [deleted file]
drivers/usb/otg/ab8500-usb.c [deleted file]
drivers/usb/otg/fsl_otg.c [deleted file]
drivers/usb/otg/fsl_otg.h [deleted file]
drivers/usb/otg/gpio_vbus.c [deleted file]
drivers/usb/otg/isp1301_omap.c [deleted file]
drivers/usb/otg/msm_otg.c [deleted file]
drivers/usb/otg/mv_otg.c [deleted file]
drivers/usb/otg/mv_otg.h [deleted file]
drivers/usb/otg/mxs-phy.c [deleted file]
drivers/usb/otg/nop-usb-xceiv.c [deleted file]
drivers/usb/otg/otg_fsm.c [deleted file]
drivers/usb/otg/otg_fsm.h [deleted file]
drivers/usb/otg/twl4030-usb.c [deleted file]
drivers/usb/otg/twl6030-usb.c [deleted file]
drivers/usb/otg/ulpi.c [deleted file]
drivers/usb/otg/ulpi_viewport.c [deleted file]
drivers/usb/phy/Kconfig
drivers/usb/phy/Makefile
drivers/usb/phy/ab8500-usb.c [new file with mode: 0644]
drivers/usb/phy/fsl_otg.c [new file with mode: 0644]
drivers/usb/phy/fsl_otg.h [new file with mode: 0644]
drivers/usb/phy/gpio_vbus.c [new file with mode: 0644]
drivers/usb/phy/isp1301_omap.c [new file with mode: 0644]
drivers/usb/phy/msm_otg.c [new file with mode: 0644]
drivers/usb/phy/mv_otg.c [new file with mode: 0644]
drivers/usb/phy/mv_otg.h [new file with mode: 0644]
drivers/usb/phy/mxs-phy.c [new file with mode: 0644]
drivers/usb/phy/nop-usb-xceiv.c [new file with mode: 0644]
drivers/usb/phy/otg_fsm.c [new file with mode: 0644]
drivers/usb/phy/otg_fsm.h [new file with mode: 0644]
drivers/usb/phy/twl4030-usb.c [new file with mode: 0644]
drivers/usb/phy/twl6030-usb.c [new file with mode: 0644]
drivers/usb/phy/ulpi.c [new file with mode: 0644]
drivers/usb/phy/ulpi_viewport.c [new file with mode: 0644]

index 640ae6c6d2d2ae67f504cb72582c40a8e85c9216..2c481b808276b5afc65176a792b0c6278fe52037 100644 (file)
@@ -186,6 +186,4 @@ source "drivers/usb/atm/Kconfig"
 
 source "drivers/usb/gadget/Kconfig"
 
-source "drivers/usb/otg/Kconfig"
-
 endif # USB_SUPPORT
index 8f5ebced5df0010e4d881c7978a5e132d92c8306..860306b143922223d611fb621a3dbe61fb09d13b 100644 (file)
@@ -6,8 +6,6 @@
 
 obj-$(CONFIG_USB)              += core/
 
-obj-$(CONFIG_USB_OTG_UTILS)    += otg/
-
 obj-$(CONFIG_USB_DWC3)         += dwc3/
 
 obj-$(CONFIG_USB_MON)          += mon/
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
deleted file mode 100644 (file)
index 37962c9..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#
-# USB OTG infrastructure may be needed for peripheral-only, host-only,
-# or OTG-capable configurations when OTG transceivers or controllers
-# are used.
-#
-
-comment "OTG and related infrastructure"
-
-config USB_OTG_UTILS
-       bool
-       help
-         Select this to make sure the build includes objects from
-         the OTG infrastructure directory.
-
-if USB || USB_GADGET
-
-#
-# USB Transceiver Drivers
-#
-config USB_GPIO_VBUS
-       tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
-       depends on GENERIC_GPIO
-       select USB_OTG_UTILS
-       help
-         Provides simple GPIO VBUS sensing for controllers with an
-         internal transceiver via the usb_phy interface, and
-         optionally control of a D+ pullup GPIO as well as a VBUS
-         current limit regulator.
-
-config ISP1301_OMAP
-       tristate "Philips ISP1301 with OMAP OTG"
-       depends on I2C && ARCH_OMAP_OTG
-       select USB_OTG_UTILS
-       help
-         If you say yes here you get support for the Philips ISP1301
-         USB-On-The-Go transceiver working with the OMAP OTG controller.
-         The ISP1301 is a full speed USB  transceiver which is used in
-         products including H2, H3, and H4 development boards for Texas
-         Instruments OMAP processors.
-
-         This driver can also be built as a module.  If so, the module
-         will be called isp1301_omap.
-
-config USB_ULPI
-       bool "Generic ULPI Transceiver Driver"
-       depends on ARM
-       select USB_OTG_UTILS
-       help
-         Enable this to support ULPI connected USB OTG transceivers which
-         are likely found on embedded boards.
-
-config USB_ULPI_VIEWPORT
-       bool
-       depends on USB_ULPI
-       help
-         Provides read/write operations to the ULPI phy register set for
-         controllers with a viewport register (e.g. Chipidea/ARC controllers).
-
-config TWL4030_USB
-       tristate "TWL4030 USB Transceiver Driver"
-       depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver on TWL4030
-         family chips (including the TWL5030 and TPS659x0 devices).
-         This transceiver supports high and full speed devices plus,
-         in host mode, low speed.
-
-config TWL6030_USB
-       tristate "TWL6030 USB Transceiver Driver"
-       depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver on TWL6030
-         family chips. This TWL6030 transceiver has the VBUS and ID GND
-         and OTG SRP events capabilities. For all other transceiver functionality
-         UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
-         are hooked to this driver through platform_data structure.
-         The definition of internal PHY APIs are in the mach-omap2 layer.
-
-config NOP_USB_XCEIV
-       tristate "NOP USB Transceiver Driver"
-       select USB_OTG_UTILS
-       help
-         This driver is to be used by all the usb transceiver which are either
-         built-in with usb ip or which are autonomous and doesn't require any
-         phy programming such as ISP1x04 etc.
-
-config USB_MSM_OTG
-       tristate "OTG support for Qualcomm on-chip USB controller"
-       depends on (USB || USB_GADGET) && ARCH_MSM
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver on MSM chips. It
-         handles PHY initialization, clock management, and workarounds
-         required after resetting the hardware and power management.
-         This driver is required even for peripheral only or host only
-         mode configurations.
-         This driver is not supported on boards like trout which
-         has an external PHY.
-
-config AB8500_USB
-       tristate "AB8500 USB Transceiver Driver"
-       depends on AB8500_CORE
-       select USB_OTG_UTILS
-       help
-         Enable this to support the USB OTG transceiver in AB8500 chip.
-         This transceiver supports high and full speed devices plus,
-         in host mode, low speed.
-
-config FSL_USB2_OTG
-       bool "Freescale USB OTG Transceiver Driver"
-       depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
-       select USB_OTG
-       select USB_OTG_UTILS
-       help
-         Enable this to support Freescale USB OTG transceiver.
-
-config USB_MXS_PHY
-       tristate "Freescale MXS USB PHY support"
-       depends on ARCH_MXC || ARCH_MXS
-       select STMP_DEVICE
-       select USB_OTG_UTILS
-       help
-         Enable this to support the Freescale MXS USB PHY.
-
-         MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
-
-config USB_MV_OTG
-       tristate "Marvell USB OTG support"
-       depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
-       select USB_OTG
-       select USB_OTG_UTILS
-       help
-         Say Y here if you want to build Marvell USB OTG transciever
-         driver in kernel (including PXA and MMP series). This driver
-         implements role switch between EHCI host driver and gadget driver.
-
-         To compile this driver as a module, choose M here.
-
-endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
deleted file mode 100644 (file)
index 6abc453..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# OTG infrastructure and transceiver drivers
-#
-
-ccflags-$(CONFIG_USB_DEBUG)            := -DDEBUG
-ccflags-$(CONFIG_USB_GADGET_DEBUG)     += -DDEBUG
-
-# transceiver drivers
-obj-$(CONFIG_USB_GPIO_VBUS)    += gpio_vbus.o
-obj-$(CONFIG_ISP1301_OMAP)     += isp1301_omap.o
-obj-$(CONFIG_TWL4030_USB)      += twl4030-usb.o
-obj-$(CONFIG_TWL6030_USB)      += twl6030-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV)    += nop-usb-xceiv.o
-obj-$(CONFIG_USB_ULPI)         += ulpi.o
-obj-$(CONFIG_USB_ULPI_VIEWPORT)        += ulpi_viewport.o
-obj-$(CONFIG_USB_MSM_OTG)      += msm_otg.o
-obj-$(CONFIG_AB8500_USB)       += ab8500-usb.o
-fsl_usb2_otg-objs              := fsl_otg.o otg_fsm.o
-obj-$(CONFIG_FSL_USB2_OTG)     += fsl_usb2_otg.o
-obj-$(CONFIG_USB_MXS_PHY)      += mxs-phy.o
-obj-$(CONFIG_USB_MV_OTG)       += mv_otg.o
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
deleted file mode 100644 (file)
index 2d86f26..0000000
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * drivers/usb/otg/ab8500_usb.c
- *
- * USB transceiver driver for AB8500 chip
- *
- * Copyright (C) 2010 ST-Ericsson AB
- * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/usb/otg.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab8500.h>
-
-#define AB8500_MAIN_WD_CTRL_REG 0x01
-#define AB8500_USB_LINE_STAT_REG 0x80
-#define AB8500_USB_PHY_CTRL_REG 0x8A
-
-#define AB8500_BIT_OTG_STAT_ID (1 << 0)
-#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
-#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
-#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
-#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
-
-#define AB8500_V1x_LINK_STAT_WAIT (HZ/10)
-#define AB8500_WD_KICK_DELAY_US 100 /* usec */
-#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
-#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */
-
-/* Usb line status register */
-enum ab8500_usb_link_status {
-       USB_LINK_NOT_CONFIGURED = 0,
-       USB_LINK_STD_HOST_NC,
-       USB_LINK_STD_HOST_C_NS,
-       USB_LINK_STD_HOST_C_S,
-       USB_LINK_HOST_CHG_NM,
-       USB_LINK_HOST_CHG_HS,
-       USB_LINK_HOST_CHG_HS_CHIRP,
-       USB_LINK_DEDICATED_CHG,
-       USB_LINK_ACA_RID_A,
-       USB_LINK_ACA_RID_B,
-       USB_LINK_ACA_RID_C_NM,
-       USB_LINK_ACA_RID_C_HS,
-       USB_LINK_ACA_RID_C_HS_CHIRP,
-       USB_LINK_HM_IDGND,
-       USB_LINK_RESERVED,
-       USB_LINK_NOT_VALID_LINK
-};
-
-struct ab8500_usb {
-       struct usb_phy phy;
-       struct device *dev;
-       int irq_num_id_rise;
-       int irq_num_id_fall;
-       int irq_num_vbus_rise;
-       int irq_num_vbus_fall;
-       int irq_num_link_status;
-       unsigned vbus_draw;
-       struct delayed_work dwork;
-       struct work_struct phy_dis_work;
-       unsigned long link_status_wait;
-       int rev;
-};
-
-static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
-{
-       return container_of(x, struct ab8500_usb, phy);
-}
-
-static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
-{
-       abx500_set_register_interruptible(ab->dev,
-               AB8500_SYS_CTRL2_BLOCK,
-               AB8500_MAIN_WD_CTRL_REG,
-               AB8500_BIT_WD_CTRL_ENABLE);
-
-       udelay(AB8500_WD_KICK_DELAY_US);
-
-       abx500_set_register_interruptible(ab->dev,
-               AB8500_SYS_CTRL2_BLOCK,
-               AB8500_MAIN_WD_CTRL_REG,
-               (AB8500_BIT_WD_CTRL_ENABLE
-               | AB8500_BIT_WD_CTRL_KICK));
-
-       if (ab->rev > 0x10) /* v1.1 v2.0 */
-               udelay(AB8500_WD_V11_DISABLE_DELAY_US);
-       else /* v1.0 */
-               msleep(AB8500_WD_V10_DISABLE_DELAY_MS);
-
-       abx500_set_register_interruptible(ab->dev,
-               AB8500_SYS_CTRL2_BLOCK,
-               AB8500_MAIN_WD_CTRL_REG,
-               0);
-}
-
-static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
-                                       bool enable)
-{
-       u8 ctrl_reg;
-       abx500_get_register_interruptible(ab->dev,
-                               AB8500_USB,
-                               AB8500_USB_PHY_CTRL_REG,
-                               &ctrl_reg);
-       if (sel_host) {
-               if (enable)
-                       ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN;
-               else
-                       ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN;
-       } else {
-               if (enable)
-                       ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN;
-               else
-                       ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN;
-       }
-
-       abx500_set_register_interruptible(ab->dev,
-                               AB8500_USB,
-                               AB8500_USB_PHY_CTRL_REG,
-                               ctrl_reg);
-
-       /* Needed to enable the phy.*/
-       if (enable)
-               ab8500_usb_wd_workaround(ab);
-}
-
-#define ab8500_usb_host_phy_en(ab)     ab8500_usb_phy_ctrl(ab, true, true)
-#define ab8500_usb_host_phy_dis(ab)    ab8500_usb_phy_ctrl(ab, true, false)
-#define ab8500_usb_peri_phy_en(ab)     ab8500_usb_phy_ctrl(ab, false, true)
-#define ab8500_usb_peri_phy_dis(ab)    ab8500_usb_phy_ctrl(ab, false, false)
-
-static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
-{
-       u8 reg;
-       enum ab8500_usb_link_status lsts;
-       void *v = NULL;
-       enum usb_phy_events event;
-
-       abx500_get_register_interruptible(ab->dev,
-                       AB8500_USB,
-                       AB8500_USB_LINE_STAT_REG,
-                       &reg);
-
-       lsts = (reg >> 3) & 0x0F;
-
-       switch (lsts) {
-       case USB_LINK_NOT_CONFIGURED:
-       case USB_LINK_RESERVED:
-       case USB_LINK_NOT_VALID_LINK:
-               /* TODO: Disable regulators. */
-               ab8500_usb_host_phy_dis(ab);
-               ab8500_usb_peri_phy_dis(ab);
-               ab->phy.state = OTG_STATE_B_IDLE;
-               ab->phy.otg->default_a = false;
-               ab->vbus_draw = 0;
-               event = USB_EVENT_NONE;
-               break;
-
-       case USB_LINK_STD_HOST_NC:
-       case USB_LINK_STD_HOST_C_NS:
-       case USB_LINK_STD_HOST_C_S:
-       case USB_LINK_HOST_CHG_NM:
-       case USB_LINK_HOST_CHG_HS:
-       case USB_LINK_HOST_CHG_HS_CHIRP:
-               if (ab->phy.otg->gadget) {
-                       /* TODO: Enable regulators. */
-                       ab8500_usb_peri_phy_en(ab);
-                       v = ab->phy.otg->gadget;
-               }
-               event = USB_EVENT_VBUS;
-               break;
-
-       case USB_LINK_HM_IDGND:
-               if (ab->phy.otg->host) {
-                       /* TODO: Enable regulators. */
-                       ab8500_usb_host_phy_en(ab);
-                       v = ab->phy.otg->host;
-               }
-               ab->phy.state = OTG_STATE_A_IDLE;
-               ab->phy.otg->default_a = true;
-               event = USB_EVENT_ID;
-               break;
-
-       case USB_LINK_ACA_RID_A:
-       case USB_LINK_ACA_RID_B:
-               /* TODO */
-       case USB_LINK_ACA_RID_C_NM:
-       case USB_LINK_ACA_RID_C_HS:
-       case USB_LINK_ACA_RID_C_HS_CHIRP:
-       case USB_LINK_DEDICATED_CHG:
-               /* TODO: vbus_draw */
-               event = USB_EVENT_CHARGER;
-               break;
-       }
-
-       atomic_notifier_call_chain(&ab->phy.notifier, event, v);
-
-       return 0;
-}
-
-static void ab8500_usb_delayed_work(struct work_struct *work)
-{
-       struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
-                                               dwork.work);
-
-       ab8500_usb_link_status_update(ab);
-}
-
-static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data)
-{
-       struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
-       /* Wait for link status to become stable. */
-       schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data)
-{
-       struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
-       /* Link status will not be updated till phy is disabled. */
-       ab8500_usb_peri_phy_dis(ab);
-
-       /* Wait for link status to become stable. */
-       schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v20_irq(int irq, void *data)
-{
-       struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
-       ab8500_usb_link_status_update(ab);
-
-       return IRQ_HANDLED;
-}
-
-static void ab8500_usb_phy_disable_work(struct work_struct *work)
-{
-       struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
-                                               phy_dis_work);
-
-       if (!ab->phy.otg->host)
-               ab8500_usb_host_phy_dis(ab);
-
-       if (!ab->phy.otg->gadget)
-               ab8500_usb_peri_phy_dis(ab);
-}
-
-static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
-{
-       struct ab8500_usb *ab;
-
-       if (!phy)
-               return -ENODEV;
-
-       ab = phy_to_ab(phy);
-
-       ab->vbus_draw = mA;
-
-       if (mA)
-               atomic_notifier_call_chain(&ab->phy.notifier,
-                               USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
-       return 0;
-}
-
-/* TODO: Implement some way for charging or other drivers to read
- * ab->vbus_draw.
- */
-
-static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
-{
-       /* TODO */
-       return 0;
-}
-
-static int ab8500_usb_set_peripheral(struct usb_otg *otg,
-                                       struct usb_gadget *gadget)
-{
-       struct ab8500_usb *ab;
-
-       if (!otg)
-               return -ENODEV;
-
-       ab = phy_to_ab(otg->phy);
-
-       /* Some drivers call this function in atomic context.
-        * Do not update ab8500 registers directly till this
-        * is fixed.
-        */
-
-       if (!gadget) {
-               /* TODO: Disable regulators. */
-               otg->gadget = NULL;
-               schedule_work(&ab->phy_dis_work);
-       } else {
-               otg->gadget = gadget;
-               otg->phy->state = OTG_STATE_B_IDLE;
-
-               /* Phy will not be enabled if cable is already
-                * plugged-in. Schedule to enable phy.
-                * Use same delay to avoid any race condition.
-                */
-               schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-       }
-
-       return 0;
-}
-
-static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       struct ab8500_usb *ab;
-
-       if (!otg)
-               return -ENODEV;
-
-       ab = phy_to_ab(otg->phy);
-
-       /* Some drivers call this function in atomic context.
-        * Do not update ab8500 registers directly till this
-        * is fixed.
-        */
-
-       if (!host) {
-               /* TODO: Disable regulators. */
-               otg->host = NULL;
-               schedule_work(&ab->phy_dis_work);
-       } else {
-               otg->host = host;
-               /* Phy will not be enabled if cable is already
-                * plugged-in. Schedule to enable phy.
-                * Use same delay to avoid any race condition.
-                */
-               schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-       }
-
-       return 0;
-}
-
-static void ab8500_usb_irq_free(struct ab8500_usb *ab)
-{
-       if (ab->rev < 0x20) {
-               free_irq(ab->irq_num_id_rise, ab);
-               free_irq(ab->irq_num_id_fall, ab);
-               free_irq(ab->irq_num_vbus_rise, ab);
-               free_irq(ab->irq_num_vbus_fall, ab);
-       } else {
-               free_irq(ab->irq_num_link_status, ab);
-       }
-}
-
-static int ab8500_usb_v1x_res_setup(struct platform_device *pdev,
-                               struct ab8500_usb *ab)
-{
-       int err;
-
-       ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R");
-       if (ab->irq_num_id_rise < 0) {
-               dev_err(&pdev->dev, "ID rise irq not found\n");
-               return ab->irq_num_id_rise;
-       }
-       err = request_threaded_irq(ab->irq_num_id_rise, NULL,
-               ab8500_usb_v1x_common_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-id-rise", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for ID rise irq\n");
-               goto fail0;
-       }
-
-       ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
-       if (ab->irq_num_id_fall < 0) {
-               dev_err(&pdev->dev, "ID fall irq not found\n");
-               return ab->irq_num_id_fall;
-       }
-       err = request_threaded_irq(ab->irq_num_id_fall, NULL,
-               ab8500_usb_v1x_common_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-id-fall", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for ID fall irq\n");
-               goto fail1;
-       }
-
-       ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R");
-       if (ab->irq_num_vbus_rise < 0) {
-               dev_err(&pdev->dev, "VBUS rise irq not found\n");
-               return ab->irq_num_vbus_rise;
-       }
-       err = request_threaded_irq(ab->irq_num_vbus_rise, NULL,
-               ab8500_usb_v1x_common_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-vbus-rise", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for Vbus rise irq\n");
-               goto fail2;
-       }
-
-       ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F");
-       if (ab->irq_num_vbus_fall < 0) {
-               dev_err(&pdev->dev, "VBUS fall irq not found\n");
-               return ab->irq_num_vbus_fall;
-       }
-       err = request_threaded_irq(ab->irq_num_vbus_fall, NULL,
-               ab8500_usb_v1x_vbus_fall_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-vbus-fall", ab);
-       if (err < 0) {
-               dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
-               goto fail3;
-       }
-
-       return 0;
-fail3:
-       free_irq(ab->irq_num_vbus_rise, ab);
-fail2:
-       free_irq(ab->irq_num_id_fall, ab);
-fail1:
-       free_irq(ab->irq_num_id_rise, ab);
-fail0:
-       return err;
-}
-
-static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
-                               struct ab8500_usb *ab)
-{
-       int err;
-
-       ab->irq_num_link_status = platform_get_irq_byname(pdev,
-                                               "USB_LINK_STATUS");
-       if (ab->irq_num_link_status < 0) {
-               dev_err(&pdev->dev, "Link status irq not found\n");
-               return ab->irq_num_link_status;
-       }
-
-       err = request_threaded_irq(ab->irq_num_link_status, NULL,
-               ab8500_usb_v20_irq,
-               IRQF_NO_SUSPEND | IRQF_SHARED,
-               "usb-link-status", ab);
-       if (err < 0) {
-               dev_err(ab->dev,
-                       "request_irq failed for link status irq\n");
-               return err;
-       }
-
-       return 0;
-}
-
-static int ab8500_usb_probe(struct platform_device *pdev)
-{
-       struct ab8500_usb       *ab;
-       struct usb_otg          *otg;
-       int err;
-       int rev;
-
-       rev = abx500_get_chip_id(&pdev->dev);
-       if (rev < 0) {
-               dev_err(&pdev->dev, "Chip id read failed\n");
-               return rev;
-       } else if (rev < 0x10) {
-               dev_err(&pdev->dev, "Unsupported AB8500 chip\n");
-               return -ENODEV;
-       }
-
-       ab = kzalloc(sizeof *ab, GFP_KERNEL);
-       if (!ab)
-               return -ENOMEM;
-
-       otg = kzalloc(sizeof *otg, GFP_KERNEL);
-       if (!otg) {
-               kfree(ab);
-               return -ENOMEM;
-       }
-
-       ab->dev                 = &pdev->dev;
-       ab->rev                 = rev;
-       ab->phy.dev             = ab->dev;
-       ab->phy.otg             = otg;
-       ab->phy.label           = "ab8500";
-       ab->phy.set_suspend     = ab8500_usb_set_suspend;
-       ab->phy.set_power       = ab8500_usb_set_power;
-       ab->phy.state           = OTG_STATE_UNDEFINED;
-
-       otg->phy                = &ab->phy;
-       otg->set_host           = ab8500_usb_set_host;
-       otg->set_peripheral     = ab8500_usb_set_peripheral;
-
-       platform_set_drvdata(pdev, ab);
-
-       ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
-
-       /* v1: Wait for link status to become stable.
-        * all: Updates form set_host and set_peripheral as they are atomic.
-        */
-       INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work);
-
-       /* all: Disable phy when called from set_host and set_peripheral */
-       INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
-
-       if (ab->rev < 0x20) {
-               err = ab8500_usb_v1x_res_setup(pdev, ab);
-               ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT;
-       } else {
-               err = ab8500_usb_v2_res_setup(pdev, ab);
-       }
-
-       if (err < 0)
-               goto fail0;
-
-       err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
-       if (err) {
-               dev_err(&pdev->dev, "Can't register transceiver\n");
-               goto fail1;
-       }
-
-       dev_info(&pdev->dev, "AB8500 usb driver initialized\n");
-
-       return 0;
-fail1:
-       ab8500_usb_irq_free(ab);
-fail0:
-       kfree(otg);
-       kfree(ab);
-       return err;
-}
-
-static int ab8500_usb_remove(struct platform_device *pdev)
-{
-       struct ab8500_usb *ab = platform_get_drvdata(pdev);
-
-       ab8500_usb_irq_free(ab);
-
-       cancel_delayed_work_sync(&ab->dwork);
-
-       cancel_work_sync(&ab->phy_dis_work);
-
-       usb_remove_phy(&ab->phy);
-
-       ab8500_usb_host_phy_dis(ab);
-       ab8500_usb_peri_phy_dis(ab);
-
-       platform_set_drvdata(pdev, NULL);
-
-       kfree(ab->phy.otg);
-       kfree(ab);
-
-       return 0;
-}
-
-static struct platform_driver ab8500_usb_driver = {
-       .probe          = ab8500_usb_probe,
-       .remove         = ab8500_usb_remove,
-       .driver         = {
-               .name   = "ab8500-usb",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init ab8500_usb_init(void)
-{
-       return platform_driver_register(&ab8500_usb_driver);
-}
-subsys_initcall(ab8500_usb_init);
-
-static void __exit ab8500_usb_exit(void)
-{
-       platform_driver_unregister(&ab8500_usb_driver);
-}
-module_exit(ab8500_usb_exit);
-
-MODULE_ALIAS("platform:ab8500_usb");
-MODULE_AUTHOR("ST-Ericsson AB");
-MODULE_DESCRIPTION("AB8500 usb transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
deleted file mode 100644 (file)
index 72a2a00..0000000
+++ /dev/null
@@ -1,1173 +0,0 @@
-/*
- * Copyright (C) 2007,2008 Freescale semiconductor, Inc.
- *
- * Author: Li Yang <LeoLi@freescale.com>
- *         Jerry Huang <Chang-Ming.Huang@freescale.com>
- *
- * Initialization based on code from Shlomi Gridish.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/timer.h>
-#include <linux/usb.h>
-#include <linux/device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/workqueue.h>
-#include <linux/time.h>
-#include <linux/fsl_devices.h>
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-
-#include <asm/unaligned.h>
-
-#include "fsl_otg.h"
-
-#define DRIVER_VERSION "Rev. 1.55"
-#define DRIVER_AUTHOR "Jerry Huang/Li Yang"
-#define DRIVER_DESC "Freescale USB OTG Transceiver Driver"
-#define DRIVER_INFO DRIVER_DESC " " DRIVER_VERSION
-
-static const char driver_name[] = "fsl-usb2-otg";
-
-const pm_message_t otg_suspend_state = {
-       .event = 1,
-};
-
-#define HA_DATA_PULSE
-
-static struct usb_dr_mmap *usb_dr_regs;
-static struct fsl_otg *fsl_otg_dev;
-static int srp_wait_done;
-
-/* FSM timers */
-struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, *a_aidl_bdis_tmr,
-       *b_ase0_brst_tmr, *b_se0_srp_tmr;
-
-/* Driver specific timers */
-struct fsl_otg_timer *b_data_pulse_tmr, *b_vbus_pulse_tmr, *b_srp_fail_tmr,
-       *b_srp_wait_tmr, *a_wait_enum_tmr;
-
-static struct list_head active_timers;
-
-static struct fsl_otg_config fsl_otg_initdata = {
-       .otg_port = 1,
-};
-
-#ifdef CONFIG_PPC32
-static u32 _fsl_readl_be(const unsigned __iomem *p)
-{
-       return in_be32(p);
-}
-
-static u32 _fsl_readl_le(const unsigned __iomem *p)
-{
-       return in_le32(p);
-}
-
-static void _fsl_writel_be(u32 v, unsigned __iomem *p)
-{
-       out_be32(p, v);
-}
-
-static void _fsl_writel_le(u32 v, unsigned __iomem *p)
-{
-       out_le32(p, v);
-}
-
-static u32 (*_fsl_readl)(const unsigned __iomem *p);
-static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
-
-#define fsl_readl(p)           (*_fsl_readl)((p))
-#define fsl_writel(v, p)       (*_fsl_writel)((v), (p))
-
-#else
-#define fsl_readl(addr)                readl(addr)
-#define fsl_writel(val, addr)  writel(val, addr)
-#endif /* CONFIG_PPC32 */
-
-/* Routines to access transceiver ULPI registers */
-u8 view_ulpi(u8 addr)
-{
-       u32 temp;
-
-       temp = 0x40000000 | (addr << 16);
-       fsl_writel(temp, &usb_dr_regs->ulpiview);
-       udelay(1000);
-       while (temp & 0x40)
-               temp = fsl_readl(&usb_dr_regs->ulpiview);
-       return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
-}
-
-int write_ulpi(u8 addr, u8 data)
-{
-       u32 temp;
-
-       temp = 0x60000000 | (addr << 16) | data;
-       fsl_writel(temp, &usb_dr_regs->ulpiview);
-       return 0;
-}
-
-/* -------------------------------------------------------------*/
-/* Operations that will be called from OTG Finite State Machine */
-
-/* Charge vbus for vbus pulsing in SRP */
-void fsl_otg_chrg_vbus(int on)
-{
-       u32 tmp;
-
-       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
-
-       if (on)
-               /* stop discharging, start charging */
-               tmp = (tmp & ~OTGSC_CTRL_VBUS_DISCHARGE) |
-                       OTGSC_CTRL_VBUS_CHARGE;
-       else
-               /* stop charging */
-               tmp &= ~OTGSC_CTRL_VBUS_CHARGE;
-
-       fsl_writel(tmp, &usb_dr_regs->otgsc);
-}
-
-/* Discharge vbus through a resistor to ground */
-void fsl_otg_dischrg_vbus(int on)
-{
-       u32 tmp;
-
-       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
-
-       if (on)
-               /* stop charging, start discharging */
-               tmp = (tmp & ~OTGSC_CTRL_VBUS_CHARGE) |
-                       OTGSC_CTRL_VBUS_DISCHARGE;
-       else
-               /* stop discharging */
-               tmp &= ~OTGSC_CTRL_VBUS_DISCHARGE;
-
-       fsl_writel(tmp, &usb_dr_regs->otgsc);
-}
-
-/* A-device driver vbus, controlled through PP bit in PORTSC */
-void fsl_otg_drv_vbus(int on)
-{
-       u32 tmp;
-
-       if (on) {
-               tmp = fsl_readl(&usb_dr_regs->portsc) & ~PORTSC_W1C_BITS;
-               fsl_writel(tmp | PORTSC_PORT_POWER, &usb_dr_regs->portsc);
-       } else {
-               tmp = fsl_readl(&usb_dr_regs->portsc) &
-                     ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER;
-               fsl_writel(tmp, &usb_dr_regs->portsc);
-       }
-}
-
-/*
- * Pull-up D+, signalling connect by periperal. Also used in
- * data-line pulsing in SRP
- */
-void fsl_otg_loc_conn(int on)
-{
-       u32 tmp;
-
-       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
-
-       if (on)
-               tmp |= OTGSC_CTRL_DATA_PULSING;
-       else
-               tmp &= ~OTGSC_CTRL_DATA_PULSING;
-
-       fsl_writel(tmp, &usb_dr_regs->otgsc);
-}
-
-/*
- * Generate SOF by host.  This is controlled through suspend/resume the
- * port.  In host mode, controller will automatically send SOF.
- * Suspend will block the data on the port.
- */
-void fsl_otg_loc_sof(int on)
-{
-       u32 tmp;
-
-       tmp = fsl_readl(&fsl_otg_dev->dr_mem_map->portsc) & ~PORTSC_W1C_BITS;
-       if (on)
-               tmp |= PORTSC_PORT_FORCE_RESUME;
-       else
-               tmp |= PORTSC_PORT_SUSPEND;
-
-       fsl_writel(tmp, &fsl_otg_dev->dr_mem_map->portsc);
-
-}
-
-/* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */
-void fsl_otg_start_pulse(void)
-{
-       u32 tmp;
-
-       srp_wait_done = 0;
-#ifdef HA_DATA_PULSE
-       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
-       tmp |= OTGSC_HA_DATA_PULSE;
-       fsl_writel(tmp, &usb_dr_regs->otgsc);
-#else
-       fsl_otg_loc_conn(1);
-#endif
-
-       fsl_otg_add_timer(b_data_pulse_tmr);
-}
-
-void b_data_pulse_end(unsigned long foo)
-{
-#ifdef HA_DATA_PULSE
-#else
-       fsl_otg_loc_conn(0);
-#endif
-
-       /* Do VBUS pulse after data pulse */
-       fsl_otg_pulse_vbus();
-}
-
-void fsl_otg_pulse_vbus(void)
-{
-       srp_wait_done = 0;
-       fsl_otg_chrg_vbus(1);
-       /* start the timer to end vbus charge */
-       fsl_otg_add_timer(b_vbus_pulse_tmr);
-}
-
-void b_vbus_pulse_end(unsigned long foo)
-{
-       fsl_otg_chrg_vbus(0);
-
-       /*
-        * As USB3300 using the same a_sess_vld and b_sess_vld voltage
-        * we need to discharge the bus for a while to distinguish
-        * residual voltage of vbus pulsing and A device pull up
-        */
-       fsl_otg_dischrg_vbus(1);
-       fsl_otg_add_timer(b_srp_wait_tmr);
-}
-
-void b_srp_end(unsigned long foo)
-{
-       fsl_otg_dischrg_vbus(0);
-       srp_wait_done = 1;
-
-       if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) &&
-           fsl_otg_dev->fsm.b_sess_vld)
-               fsl_otg_dev->fsm.b_srp_done = 1;
-}
-
-/*
- * Workaround for a_host suspending too fast.  When a_bus_req=0,
- * a_host will start by SRP.  It needs to set b_hnp_enable before
- * actually suspending to start HNP
- */
-void a_wait_enum(unsigned long foo)
-{
-       VDBG("a_wait_enum timeout\n");
-       if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
-               fsl_otg_add_timer(a_wait_enum_tmr);
-       else
-               otg_statemachine(&fsl_otg_dev->fsm);
-}
-
-/* The timeout callback function to set time out bit */
-void set_tmout(unsigned long indicator)
-{
-       *(int *)indicator = 1;
-}
-
-/* Initialize timers */
-int fsl_otg_init_timers(struct otg_fsm *fsm)
-{
-       /* FSM used timers */
-       a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
-                               (unsigned long)&fsm->a_wait_vrise_tmout);
-       if (!a_wait_vrise_tmr)
-               return -ENOMEM;
-
-       a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON,
-                               (unsigned long)&fsm->a_wait_bcon_tmout);
-       if (!a_wait_bcon_tmr)
-               return -ENOMEM;
-
-       a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
-                               (unsigned long)&fsm->a_aidl_bdis_tmout);
-       if (!a_aidl_bdis_tmr)
-               return -ENOMEM;
-
-       b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST,
-                               (unsigned long)&fsm->b_ase0_brst_tmout);
-       if (!b_ase0_brst_tmr)
-               return -ENOMEM;
-
-       b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
-                               (unsigned long)&fsm->b_se0_srp);
-       if (!b_se0_srp_tmr)
-               return -ENOMEM;
-
-       b_srp_fail_tmr = otg_timer_initializer(&set_tmout, TB_SRP_FAIL,
-                               (unsigned long)&fsm->b_srp_done);
-       if (!b_srp_fail_tmr)
-               return -ENOMEM;
-
-       a_wait_enum_tmr = otg_timer_initializer(&a_wait_enum, 10,
-                               (unsigned long)&fsm);
-       if (!a_wait_enum_tmr)
-               return -ENOMEM;
-
-       /* device driver used timers */
-       b_srp_wait_tmr = otg_timer_initializer(&b_srp_end, TB_SRP_WAIT, 0);
-       if (!b_srp_wait_tmr)
-               return -ENOMEM;
-
-       b_data_pulse_tmr = otg_timer_initializer(&b_data_pulse_end,
-                               TB_DATA_PLS, 0);
-       if (!b_data_pulse_tmr)
-               return -ENOMEM;
-
-       b_vbus_pulse_tmr = otg_timer_initializer(&b_vbus_pulse_end,
-                               TB_VBUS_PLS, 0);
-       if (!b_vbus_pulse_tmr)
-               return -ENOMEM;
-
-       return 0;
-}
-
-/* Uninitialize timers */
-void fsl_otg_uninit_timers(void)
-{
-       /* FSM used timers */
-       kfree(a_wait_vrise_tmr);
-       kfree(a_wait_bcon_tmr);
-       kfree(a_aidl_bdis_tmr);
-       kfree(b_ase0_brst_tmr);
-       kfree(b_se0_srp_tmr);
-       kfree(b_srp_fail_tmr);
-       kfree(a_wait_enum_tmr);
-
-       /* device driver used timers */
-       kfree(b_srp_wait_tmr);
-       kfree(b_data_pulse_tmr);
-       kfree(b_vbus_pulse_tmr);
-}
-
-/* Add timer to timer list */
-void fsl_otg_add_timer(void *gtimer)
-{
-       struct fsl_otg_timer *timer = gtimer;
-       struct fsl_otg_timer *tmp_timer;
-
-       /*
-        * Check if the timer is already in the active list,
-        * if so update timer count
-        */
-       list_for_each_entry(tmp_timer, &active_timers, list)
-           if (tmp_timer == timer) {
-               timer->count = timer->expires;
-               return;
-       }
-       timer->count = timer->expires;
-       list_add_tail(&timer->list, &active_timers);
-}
-
-/* Remove timer from the timer list; clear timeout status */
-void fsl_otg_del_timer(void *gtimer)
-{
-       struct fsl_otg_timer *timer = gtimer;
-       struct fsl_otg_timer *tmp_timer, *del_tmp;
-
-       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
-               if (tmp_timer == timer)
-                       list_del(&timer->list);
-}
-
-/*
- * Reduce timer count by 1, and find timeout conditions.
- * Called by fsl_otg 1ms timer interrupt
- */
-int fsl_otg_tick_timer(void)
-{
-       struct fsl_otg_timer *tmp_timer, *del_tmp;
-       int expired = 0;
-
-       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
-               tmp_timer->count--;
-               /* check if timer expires */
-               if (!tmp_timer->count) {
-                       list_del(&tmp_timer->list);
-                       tmp_timer->function(tmp_timer->data);
-                       expired = 1;
-               }
-       }
-
-       return expired;
-}
-
-/* Reset controller, not reset the bus */
-void otg_reset_controller(void)
-{
-       u32 command;
-
-       command = fsl_readl(&usb_dr_regs->usbcmd);
-       command |= (1 << 1);
-       fsl_writel(command, &usb_dr_regs->usbcmd);
-       while (fsl_readl(&usb_dr_regs->usbcmd) & (1 << 1))
-               ;
-}
-
-/* Call suspend/resume routines in host driver */
-int fsl_otg_start_host(struct otg_fsm *fsm, int on)
-{
-       struct usb_otg *otg = fsm->otg;
-       struct device *dev;
-       struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
-       u32 retval = 0;
-
-       if (!otg->host)
-               return -ENODEV;
-       dev = otg->host->controller;
-
-       /*
-        * Update a_vbus_vld state as a_vbus_vld int is disabled
-        * in device mode
-        */
-       fsm->a_vbus_vld =
-               !!(fsl_readl(&usb_dr_regs->otgsc) & OTGSC_STS_A_VBUS_VALID);
-       if (on) {
-               /* start fsl usb host controller */
-               if (otg_dev->host_working)
-                       goto end;
-               else {
-                       otg_reset_controller();
-                       VDBG("host on......\n");
-                       if (dev->driver->pm && dev->driver->pm->resume) {
-                               retval = dev->driver->pm->resume(dev);
-                               if (fsm->id) {
-                                       /* default-b */
-                                       fsl_otg_drv_vbus(1);
-                                       /*
-                                        * Workaround: b_host can't driver
-                                        * vbus, but PP in PORTSC needs to
-                                        * be 1 for host to work.
-                                        * So we set drv_vbus bit in
-                                        * transceiver to 0 thru ULPI.
-                                        */
-                                       write_ulpi(0x0c, 0x20);
-                               }
-                       }
-
-                       otg_dev->host_working = 1;
-               }
-       } else {
-               /* stop fsl usb host controller */
-               if (!otg_dev->host_working)
-                       goto end;
-               else {
-                       VDBG("host off......\n");
-                       if (dev && dev->driver) {
-                               if (dev->driver->pm && dev->driver->pm->suspend)
-                                       retval = dev->driver->pm->suspend(dev);
-                               if (fsm->id)
-                                       /* default-b */
-                                       fsl_otg_drv_vbus(0);
-                       }
-                       otg_dev->host_working = 0;
-               }
-       }
-end:
-       return retval;
-}
-
-/*
- * Call suspend and resume function in udc driver
- * to stop and start udc driver.
- */
-int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
-{
-       struct usb_otg *otg = fsm->otg;
-       struct device *dev;
-
-       if (!otg->gadget || !otg->gadget->dev.parent)
-               return -ENODEV;
-
-       VDBG("gadget %s\n", on ? "on" : "off");
-       dev = otg->gadget->dev.parent;
-
-       if (on) {
-               if (dev->driver->resume)
-                       dev->driver->resume(dev);
-       } else {
-               if (dev->driver->suspend)
-                       dev->driver->suspend(dev, otg_suspend_state);
-       }
-
-       return 0;
-}
-
-/*
- * Called by initialization code of host driver.  Register host controller
- * to the OTG.  Suspend host for OTG role detection.
- */
-static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       struct fsl_otg *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;
-
-       otg_dev->fsm.a_bus_drop = 0;
-       otg_dev->fsm.a_bus_req = 1;
-
-       if (host) {
-               VDBG("host off......\n");
-
-               otg->host->otg_port = fsl_otg_initdata.otg_port;
-               otg->host->is_b_host = otg_dev->fsm.id;
-               /*
-                * must leave time for khubd to finish its thing
-                * before yanking the host driver out from under it,
-                * so suspend the host after a short delay.
-                */
-               otg_dev->host_working = 1;
-               schedule_delayed_work(&otg_dev->otg_event, 100);
-               return 0;
-       } else {
-               /* host driver going away */
-               if (!(fsl_readl(&otg_dev->dr_mem_map->otgsc) &
-                     OTGSC_STS_USB_ID)) {
-                       /* Mini-A cable connected */
-                       struct otg_fsm *fsm = &otg_dev->fsm;
-
-                       otg->phy->state = OTG_STATE_UNDEFINED;
-                       fsm->protocol = PROTO_UNDEF;
-               }
-       }
-
-       otg_dev->host_working = 0;
-
-       otg_statemachine(&otg_dev->fsm);
-
-       return 0;
-}
-
-/* Called by initialization code of udc.  Register udc to OTG. */
-static int fsl_otg_set_peripheral(struct usb_otg *otg,
-                                       struct usb_gadget *gadget)
-{
-       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_dev != fsl_otg_dev)
-               return -ENODEV;
-
-       if (!gadget) {
-               if (!otg->default_a)
-                       otg->gadget->ops->vbus_draw(otg->gadget, 0);
-               usb_gadget_vbus_disconnect(otg->gadget);
-               otg->gadget = 0;
-               otg_dev->fsm.b_bus_req = 0;
-               otg_statemachine(&otg_dev->fsm);
-               return 0;
-       }
-
-       otg->gadget = gadget;
-       otg->gadget->is_a_peripheral = !otg_dev->fsm.id;
-
-       otg_dev->fsm.b_bus_req = 1;
-
-       /* start the gadget right away if the ID pin says Mini-B */
-       DBG("ID pin=%d\n", otg_dev->fsm.id);
-       if (otg_dev->fsm.id == 1) {
-               fsl_otg_start_host(&otg_dev->fsm, 0);
-               otg_drv_vbus(&otg_dev->fsm, 0);
-               fsl_otg_start_gadget(&otg_dev->fsm, 1);
-       }
-
-       return 0;
-}
-
-/* Set OTG port power, only for B-device */
-static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
-{
-       if (!fsl_otg_dev)
-               return -ENODEV;
-       if (phy->state == OTG_STATE_B_PERIPHERAL)
-               pr_info("FSL OTG: Draw %d mA\n", mA);
-
-       return 0;
-}
-
-/*
- * Delayed pin detect interrupt processing.
- *
- * When the Mini-A cable is disconnected from the board,
- * the pin-detect interrupt happens before the disconnect
- * interrupts for the connected device(s).  In order to
- * process the disconnect interrupt(s) prior to switching
- * roles, the pin-detect interrupts are delayed, and handled
- * by this routine.
- */
-static void fsl_otg_event(struct work_struct *work)
-{
-       struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work);
-       struct otg_fsm *fsm = &og->fsm;
-
-       if (fsm->id) {          /* switch to gadget */
-               fsl_otg_start_host(fsm, 0);
-               otg_drv_vbus(fsm, 0);
-               fsl_otg_start_gadget(fsm, 1);
-       }
-}
-
-/* B-device start SRP */
-static int fsl_otg_start_srp(struct usb_otg *otg)
-{
-       struct fsl_otg *otg_dev;
-
-       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;
-       otg_statemachine(&otg_dev->fsm);
-
-       return 0;
-}
-
-/* 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;
-
-       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");
-
-       /* clear a_bus_req to enter a_suspend state */
-       otg_dev->fsm.a_bus_req = 0;
-       otg_statemachine(&otg_dev->fsm);
-
-       return 0;
-}
-
-/*
- * Interrupt handler.  OTG/host/peripheral share the same int line.
- * OTG driver clears OTGSC interrupts and leaves USB interrupts
- * intact.  It needs to have knowledge of some USB interrupts
- * such as port change.
- */
-irqreturn_t fsl_otg_isr(int irq, void *dev_id)
-{
-       struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
-       struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
-       u32 otg_int_src, otg_sc;
-
-       otg_sc = fsl_readl(&usb_dr_regs->otgsc);
-       otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8);
-
-       /* Only clear otg interrupts */
-       fsl_writel(otg_sc, &usb_dr_regs->otgsc);
-
-       /*FIXME: ID change not generate when init to 0 */
-       fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
-       otg->default_a = (fsm->id == 0);
-
-       /* process OTG interrupts */
-       if (otg_int_src) {
-               if (otg_int_src & OTGSC_INTSTS_USB_ID) {
-                       fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
-                       otg->default_a = (fsm->id == 0);
-                       /* clear conn information */
-                       if (fsm->id)
-                               fsm->b_conn = 0;
-                       else
-                               fsm->a_conn = 0;
-
-                       if (otg->host)
-                               otg->host->is_b_host = fsm->id;
-                       if (otg->gadget)
-                               otg->gadget->is_a_peripheral = !fsm->id;
-                       VDBG("ID int (ID is %d)\n", fsm->id);
-
-                       if (fsm->id) {  /* switch to gadget */
-                               schedule_delayed_work(
-                                       &((struct fsl_otg *)dev_id)->otg_event,
-                                       100);
-                       } else {        /* switch to host */
-                               cancel_delayed_work(&
-                                                   ((struct fsl_otg *)dev_id)->
-                                                   otg_event);
-                               fsl_otg_start_gadget(fsm, 0);
-                               otg_drv_vbus(fsm, 1);
-                               fsl_otg_start_host(fsm, 1);
-                       }
-                       return IRQ_HANDLED;
-               }
-       }
-       return IRQ_NONE;
-}
-
-static struct otg_fsm_ops fsl_otg_ops = {
-       .chrg_vbus = fsl_otg_chrg_vbus,
-       .drv_vbus = fsl_otg_drv_vbus,
-       .loc_conn = fsl_otg_loc_conn,
-       .loc_sof = fsl_otg_loc_sof,
-       .start_pulse = fsl_otg_start_pulse,
-
-       .add_timer = fsl_otg_add_timer,
-       .del_timer = fsl_otg_del_timer,
-
-       .start_host = fsl_otg_start_host,
-       .start_gadget = fsl_otg_start_gadget,
-};
-
-/* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
-static int fsl_otg_conf(struct platform_device *pdev)
-{
-       struct fsl_otg *fsl_otg_tc;
-       int status;
-
-       if (fsl_otg_dev)
-               return 0;
-
-       /* allocate space to fsl otg device */
-       fsl_otg_tc = kzalloc(sizeof(struct fsl_otg), GFP_KERNEL);
-       if (!fsl_otg_tc)
-               return -ENOMEM;
-
-       fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
-       if (!fsl_otg_tc->phy.otg) {
-               kfree(fsl_otg_tc);
-               return -ENOMEM;
-       }
-
-       INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event);
-
-       INIT_LIST_HEAD(&active_timers);
-       status = fsl_otg_init_timers(&fsl_otg_tc->fsm);
-       if (status) {
-               pr_info("Couldn't init OTG timers\n");
-               goto err;
-       }
-       spin_lock_init(&fsl_otg_tc->fsm.lock);
-
-       /* Set OTG state machine operations */
-       fsl_otg_tc->fsm.ops = &fsl_otg_ops;
-
-       /* initialize the otg structure */
-       fsl_otg_tc->phy.label = DRIVER_DESC;
-       fsl_otg_tc->phy.set_power = fsl_otg_set_power;
-
-       fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy;
-       fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host;
-       fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral;
-       fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp;
-       fsl_otg_tc->phy.otg->start_srp = fsl_otg_start_srp;
-
-       fsl_otg_dev = fsl_otg_tc;
-
-       /* Store the otg transceiver */
-       status = usb_add_phy(&fsl_otg_tc->phy, USB_PHY_TYPE_USB2);
-       if (status) {
-               pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n");
-               goto err;
-       }
-
-       return 0;
-err:
-       fsl_otg_uninit_timers();
-       kfree(fsl_otg_tc->phy.otg);
-       kfree(fsl_otg_tc);
-       return status;
-}
-
-/* OTG Initialization */
-int usb_otg_start(struct platform_device *pdev)
-{
-       struct fsl_otg *p_otg;
-       struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
-       struct otg_fsm *fsm;
-       int status;
-       struct resource *res;
-       u32 temp;
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-
-       p_otg = container_of(otg_trans, struct fsl_otg, phy);
-       fsm = &p_otg->fsm;
-
-       /* Initialize the state machine structure with default values */
-       SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED);
-       fsm->otg = p_otg->phy.otg;
-
-       /* We don't require predefined MEM/IRQ resource index */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
-
-       /* We don't request_mem_region here to enable resource sharing
-        * with host/device */
-
-       usb_dr_regs = ioremap(res->start, sizeof(struct usb_dr_mmap));
-       p_otg->dr_mem_map = (struct usb_dr_mmap *)usb_dr_regs;
-       pdata->regs = (void *)usb_dr_regs;
-
-       if (pdata->init && pdata->init(pdev) != 0)
-               return -EINVAL;
-
-       if (pdata->big_endian_mmio) {
-               _fsl_readl = _fsl_readl_be;
-               _fsl_writel = _fsl_writel_be;
-       } else {
-               _fsl_readl = _fsl_readl_le;
-               _fsl_writel = _fsl_writel_le;
-       }
-
-       /* request irq */
-       p_otg->irq = platform_get_irq(pdev, 0);
-       status = request_irq(p_otg->irq, fsl_otg_isr,
-                               IRQF_SHARED, driver_name, p_otg);
-       if (status) {
-               dev_dbg(p_otg->phy.dev, "can't get IRQ %d, error %d\n",
-                       p_otg->irq, status);
-               iounmap(p_otg->dr_mem_map);
-               kfree(p_otg->phy.otg);
-               kfree(p_otg);
-               return status;
-       }
-
-       /* stop the controller */
-       temp = fsl_readl(&p_otg->dr_mem_map->usbcmd);
-       temp &= ~USB_CMD_RUN_STOP;
-       fsl_writel(temp, &p_otg->dr_mem_map->usbcmd);
-
-       /* reset the controller */
-       temp = fsl_readl(&p_otg->dr_mem_map->usbcmd);
-       temp |= USB_CMD_CTRL_RESET;
-       fsl_writel(temp, &p_otg->dr_mem_map->usbcmd);
-
-       /* wait reset completed */
-       while (fsl_readl(&p_otg->dr_mem_map->usbcmd) & USB_CMD_CTRL_RESET)
-               ;
-
-       /* configure the VBUSHS as IDLE(both host and device) */
-       temp = USB_MODE_STREAM_DISABLE | (pdata->es ? USB_MODE_ES : 0);
-       fsl_writel(temp, &p_otg->dr_mem_map->usbmode);
-
-       /* configure PHY interface */
-       temp = fsl_readl(&p_otg->dr_mem_map->portsc);
-       temp &= ~(PORTSC_PHY_TYPE_SEL | PORTSC_PTW);
-       switch (pdata->phy_mode) {
-       case FSL_USB2_PHY_ULPI:
-               temp |= PORTSC_PTS_ULPI;
-               break;
-       case FSL_USB2_PHY_UTMI_WIDE:
-               temp |= PORTSC_PTW_16BIT;
-               /* fall through */
-       case FSL_USB2_PHY_UTMI:
-               temp |= PORTSC_PTS_UTMI;
-               /* fall through */
-       default:
-               break;
-       }
-       fsl_writel(temp, &p_otg->dr_mem_map->portsc);
-
-       if (pdata->have_sysif_regs) {
-               /* configure control enable IO output, big endian register */
-               temp = __raw_readl(&p_otg->dr_mem_map->control);
-               temp |= USB_CTRL_IOENB;
-               __raw_writel(temp, &p_otg->dr_mem_map->control);
-       }
-
-       /* disable all interrupt and clear all OTGSC status */
-       temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
-       temp &= ~OTGSC_INTERRUPT_ENABLE_BITS_MASK;
-       temp |= OTGSC_INTERRUPT_STATUS_BITS_MASK | OTGSC_CTRL_VBUS_DISCHARGE;
-       fsl_writel(temp, &p_otg->dr_mem_map->otgsc);
-
-       /*
-        * The identification (id) input is FALSE when a Mini-A plug is inserted
-        * in the devices Mini-AB receptacle. Otherwise, this input is TRUE.
-        * Also: record initial state of ID pin
-        */
-       if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
-               p_otg->phy.state = OTG_STATE_UNDEFINED;
-               p_otg->fsm.id = 1;
-       } else {
-               p_otg->phy.state = OTG_STATE_A_IDLE;
-               p_otg->fsm.id = 0;
-       }
-
-       DBG("initial ID pin=%d\n", p_otg->fsm.id);
-
-       /* enable OTG ID pin interrupt */
-       temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
-       temp |= OTGSC_INTR_USB_ID_EN;
-       temp &= ~(OTGSC_CTRL_VBUS_DISCHARGE | OTGSC_INTR_1MS_TIMER_EN);
-       fsl_writel(temp, &p_otg->dr_mem_map->otgsc);
-
-       return 0;
-}
-
-/*
- * state file in sysfs
- */
-static int show_fsl_usb2_otg_state(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       struct otg_fsm *fsm = &fsl_otg_dev->fsm;
-       char *next = buf;
-       unsigned size = PAGE_SIZE;
-       unsigned long flags;
-       int t;
-
-       spin_lock_irqsave(&fsm->lock, flags);
-
-       /* basic driver infomation */
-       t = scnprintf(next, size,
-                       DRIVER_DESC "\n" "fsl_usb2_otg version: %s\n\n",
-                       DRIVER_VERSION);
-       size -= t;
-       next += t;
-
-       /* Registers */
-       t = scnprintf(next, size,
-                       "OTGSC:   0x%08x\n"
-                       "PORTSC:  0x%08x\n"
-                       "USBMODE: 0x%08x\n"
-                       "USBCMD:  0x%08x\n"
-                       "USBSTS:  0x%08x\n"
-                       "USBINTR: 0x%08x\n",
-                       fsl_readl(&usb_dr_regs->otgsc),
-                       fsl_readl(&usb_dr_regs->portsc),
-                       fsl_readl(&usb_dr_regs->usbmode),
-                       fsl_readl(&usb_dr_regs->usbcmd),
-                       fsl_readl(&usb_dr_regs->usbsts),
-                       fsl_readl(&usb_dr_regs->usbintr));
-       size -= t;
-       next += t;
-
-       /* State */
-       t = scnprintf(next, size,
-                     "OTG state: %s\n\n",
-                     usb_otg_state_string(fsl_otg_dev->phy.state));
-       size -= t;
-       next += t;
-
-       /* State Machine Variables */
-       t = scnprintf(next, size,
-                       "a_bus_req: %d\n"
-                       "b_bus_req: %d\n"
-                       "a_bus_resume: %d\n"
-                       "a_bus_suspend: %d\n"
-                       "a_conn: %d\n"
-                       "a_sess_vld: %d\n"
-                       "a_srp_det: %d\n"
-                       "a_vbus_vld: %d\n"
-                       "b_bus_resume: %d\n"
-                       "b_bus_suspend: %d\n"
-                       "b_conn: %d\n"
-                       "b_se0_srp: %d\n"
-                       "b_sess_end: %d\n"
-                       "b_sess_vld: %d\n"
-                       "id: %d\n",
-                       fsm->a_bus_req,
-                       fsm->b_bus_req,
-                       fsm->a_bus_resume,
-                       fsm->a_bus_suspend,
-                       fsm->a_conn,
-                       fsm->a_sess_vld,
-                       fsm->a_srp_det,
-                       fsm->a_vbus_vld,
-                       fsm->b_bus_resume,
-                       fsm->b_bus_suspend,
-                       fsm->b_conn,
-                       fsm->b_se0_srp,
-                       fsm->b_sess_end,
-                       fsm->b_sess_vld,
-                       fsm->id);
-       size -= t;
-       next += t;
-
-       spin_unlock_irqrestore(&fsm->lock, flags);
-
-       return PAGE_SIZE - size;
-}
-
-static DEVICE_ATTR(fsl_usb2_otg_state, S_IRUGO, show_fsl_usb2_otg_state, NULL);
-
-
-/* Char driver interface to control some OTG input */
-
-/*
- * Handle some ioctl command, such as get otg
- * status and set host suspend
- */
-static long fsl_otg_ioctl(struct file *file, unsigned int cmd,
-                         unsigned long arg)
-{
-       u32 retval = 0;
-
-       switch (cmd) {
-       case GET_OTG_STATUS:
-               retval = fsl_otg_dev->host_working;
-               break;
-
-       case SET_A_SUSPEND_REQ:
-               fsl_otg_dev->fsm.a_suspend_req = arg;
-               break;
-
-       case SET_A_BUS_DROP:
-               fsl_otg_dev->fsm.a_bus_drop = arg;
-               break;
-
-       case SET_A_BUS_REQ:
-               fsl_otg_dev->fsm.a_bus_req = arg;
-               break;
-
-       case SET_B_BUS_REQ:
-               fsl_otg_dev->fsm.b_bus_req = arg;
-               break;
-
-       default:
-               break;
-       }
-
-       otg_statemachine(&fsl_otg_dev->fsm);
-
-       return retval;
-}
-
-static int fsl_otg_open(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int fsl_otg_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static const struct file_operations otg_fops = {
-       .owner = THIS_MODULE,
-       .llseek = NULL,
-       .read = NULL,
-       .write = NULL,
-       .unlocked_ioctl = fsl_otg_ioctl,
-       .open = fsl_otg_open,
-       .release = fsl_otg_release,
-};
-
-static int fsl_otg_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       if (!pdev->dev.platform_data)
-               return -ENODEV;
-
-       /* configure the OTG */
-       ret = fsl_otg_conf(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "Couldn't configure OTG module\n");
-               return ret;
-       }
-
-       /* start OTG */
-       ret = usb_otg_start(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't init FSL OTG device\n");
-               return ret;
-       }
-
-       ret = register_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME, &otg_fops);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to register FSL OTG device\n");
-               return ret;
-       }
-
-       ret = device_create_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
-       if (ret)
-               dev_warn(&pdev->dev, "Can't register sysfs attribute\n");
-
-       return ret;
-}
-
-static int fsl_otg_remove(struct platform_device *pdev)
-{
-       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-
-       usb_remove_phy(&fsl_otg_dev->phy);
-       free_irq(fsl_otg_dev->irq, fsl_otg_dev);
-
-       iounmap((void *)usb_dr_regs);
-
-       fsl_otg_uninit_timers();
-       kfree(fsl_otg_dev->phy.otg);
-       kfree(fsl_otg_dev);
-
-       device_remove_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
-
-       unregister_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME);
-
-       if (pdata->exit)
-               pdata->exit(pdev);
-
-       return 0;
-}
-
-struct platform_driver fsl_otg_driver = {
-       .probe = fsl_otg_probe,
-       .remove = fsl_otg_remove,
-       .driver = {
-               .name = driver_name,
-               .owner = THIS_MODULE,
-       },
-};
-
-module_platform_driver(fsl_otg_driver);
-
-MODULE_DESCRIPTION(DRIVER_INFO);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/otg/fsl_otg.h
deleted file mode 100644 (file)
index ca26628..0000000
+++ /dev/null
@@ -1,406 +0,0 @@
-/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "otg_fsm.h"
-#include <linux/usb/otg.h>
-#include <linux/ioctl.h>
-
-/* USB Command Register Bit Masks */
-#define USB_CMD_RUN_STOP               (0x1<<0)
-#define USB_CMD_CTRL_RESET             (0x1<<1)
-#define USB_CMD_PERIODIC_SCHEDULE_EN   (0x1<<4)
-#define USB_CMD_ASYNC_SCHEDULE_EN      (0x1<<5)
-#define USB_CMD_INT_AA_DOORBELL                (0x1<<6)
-#define USB_CMD_ASP                    (0x3<<8)
-#define USB_CMD_ASYNC_SCH_PARK_EN      (0x1<<11)
-#define USB_CMD_SUTW                   (0x1<<13)
-#define USB_CMD_ATDTW                  (0x1<<14)
-#define USB_CMD_ITC                    (0xFF<<16)
-
-/* bit 15,3,2 are frame list size */
-#define USB_CMD_FRAME_SIZE_1024                (0x0<<15 | 0x0<<2)
-#define USB_CMD_FRAME_SIZE_512         (0x0<<15 | 0x1<<2)
-#define USB_CMD_FRAME_SIZE_256         (0x0<<15 | 0x2<<2)
-#define USB_CMD_FRAME_SIZE_128         (0x0<<15 | 0x3<<2)
-#define USB_CMD_FRAME_SIZE_64          (0x1<<15 | 0x0<<2)
-#define USB_CMD_FRAME_SIZE_32          (0x1<<15 | 0x1<<2)
-#define USB_CMD_FRAME_SIZE_16          (0x1<<15 | 0x2<<2)
-#define USB_CMD_FRAME_SIZE_8           (0x1<<15 | 0x3<<2)
-
-/* bit 9-8 are async schedule park mode count */
-#define USB_CMD_ASP_00                 (0x0<<8)
-#define USB_CMD_ASP_01                 (0x1<<8)
-#define USB_CMD_ASP_10                 (0x2<<8)
-#define USB_CMD_ASP_11                 (0x3<<8)
-#define USB_CMD_ASP_BIT_POS            (8)
-
-/* bit 23-16 are interrupt threshold control */
-#define USB_CMD_ITC_NO_THRESHOLD       (0x00<<16)
-#define USB_CMD_ITC_1_MICRO_FRM                (0x01<<16)
-#define USB_CMD_ITC_2_MICRO_FRM                (0x02<<16)
-#define USB_CMD_ITC_4_MICRO_FRM                (0x04<<16)
-#define USB_CMD_ITC_8_MICRO_FRM                (0x08<<16)
-#define USB_CMD_ITC_16_MICRO_FRM       (0x10<<16)
-#define USB_CMD_ITC_32_MICRO_FRM       (0x20<<16)
-#define USB_CMD_ITC_64_MICRO_FRM       (0x40<<16)
-#define USB_CMD_ITC_BIT_POS            (16)
-
-/* USB Status Register Bit Masks */
-#define USB_STS_INT                    (0x1<<0)
-#define USB_STS_ERR                    (0x1<<1)
-#define USB_STS_PORT_CHANGE            (0x1<<2)
-#define USB_STS_FRM_LST_ROLL           (0x1<<3)
-#define USB_STS_SYS_ERR                        (0x1<<4)
-#define USB_STS_IAA                    (0x1<<5)
-#define USB_STS_RESET_RECEIVED         (0x1<<6)
-#define USB_STS_SOF                    (0x1<<7)
-#define USB_STS_DCSUSPEND              (0x1<<8)
-#define USB_STS_HC_HALTED              (0x1<<12)
-#define USB_STS_RCL                    (0x1<<13)
-#define USB_STS_PERIODIC_SCHEDULE      (0x1<<14)
-#define USB_STS_ASYNC_SCHEDULE         (0x1<<15)
-
-/* USB Interrupt Enable Register Bit Masks */
-#define USB_INTR_INT_EN                        (0x1<<0)
-#define USB_INTR_ERR_INT_EN            (0x1<<1)
-#define USB_INTR_PC_DETECT_EN          (0x1<<2)
-#define USB_INTR_FRM_LST_ROLL_EN       (0x1<<3)
-#define USB_INTR_SYS_ERR_EN            (0x1<<4)
-#define USB_INTR_ASYN_ADV_EN           (0x1<<5)
-#define USB_INTR_RESET_EN              (0x1<<6)
-#define USB_INTR_SOF_EN                        (0x1<<7)
-#define USB_INTR_DEVICE_SUSPEND                (0x1<<8)
-
-/* Device Address bit masks */
-#define USB_DEVICE_ADDRESS_MASK                (0x7F<<25)
-#define USB_DEVICE_ADDRESS_BIT_POS     (25)
-/* PORTSC  Register Bit Masks,Only one PORT in OTG mode*/
-#define PORTSC_CURRENT_CONNECT_STATUS  (0x1<<0)
-#define PORTSC_CONNECT_STATUS_CHANGE   (0x1<<1)
-#define PORTSC_PORT_ENABLE             (0x1<<2)
-#define PORTSC_PORT_EN_DIS_CHANGE      (0x1<<3)
-#define PORTSC_OVER_CURRENT_ACT                (0x1<<4)
-#define PORTSC_OVER_CUURENT_CHG                (0x1<<5)
-#define PORTSC_PORT_FORCE_RESUME       (0x1<<6)
-#define PORTSC_PORT_SUSPEND            (0x1<<7)
-#define PORTSC_PORT_RESET              (0x1<<8)
-#define PORTSC_LINE_STATUS_BITS                (0x3<<10)
-#define PORTSC_PORT_POWER              (0x1<<12)
-#define PORTSC_PORT_INDICTOR_CTRL      (0x3<<14)
-#define PORTSC_PORT_TEST_CTRL          (0xF<<16)
-#define PORTSC_WAKE_ON_CONNECT_EN      (0x1<<20)
-#define PORTSC_WAKE_ON_CONNECT_DIS     (0x1<<21)
-#define PORTSC_WAKE_ON_OVER_CURRENT    (0x1<<22)
-#define PORTSC_PHY_LOW_POWER_SPD       (0x1<<23)
-#define PORTSC_PORT_FORCE_FULL_SPEED   (0x1<<24)
-#define PORTSC_PORT_SPEED_MASK         (0x3<<26)
-#define PORTSC_TRANSCEIVER_WIDTH       (0x1<<28)
-#define PORTSC_PHY_TYPE_SEL            (0x3<<30)
-/* bit 11-10 are line status */
-#define PORTSC_LINE_STATUS_SE0         (0x0<<10)
-#define PORTSC_LINE_STATUS_JSTATE      (0x1<<10)
-#define PORTSC_LINE_STATUS_KSTATE      (0x2<<10)
-#define PORTSC_LINE_STATUS_UNDEF       (0x3<<10)
-#define PORTSC_LINE_STATUS_BIT_POS     (10)
-
-/* bit 15-14 are port indicator control */
-#define PORTSC_PIC_OFF                 (0x0<<14)
-#define PORTSC_PIC_AMBER               (0x1<<14)
-#define PORTSC_PIC_GREEN               (0x2<<14)
-#define PORTSC_PIC_UNDEF               (0x3<<14)
-#define PORTSC_PIC_BIT_POS             (14)
-
-/* bit 19-16 are port test control */
-#define PORTSC_PTC_DISABLE             (0x0<<16)
-#define PORTSC_PTC_JSTATE              (0x1<<16)
-#define PORTSC_PTC_KSTATE              (0x2<<16)
-#define PORTSC_PTC_SEQNAK              (0x3<<16)
-#define PORTSC_PTC_PACKET              (0x4<<16)
-#define PORTSC_PTC_FORCE_EN            (0x5<<16)
-#define PORTSC_PTC_BIT_POS             (16)
-
-/* bit 27-26 are port speed */
-#define PORTSC_PORT_SPEED_FULL         (0x0<<26)
-#define PORTSC_PORT_SPEED_LOW          (0x1<<26)
-#define PORTSC_PORT_SPEED_HIGH         (0x2<<26)
-#define PORTSC_PORT_SPEED_UNDEF                (0x3<<26)
-#define PORTSC_SPEED_BIT_POS           (26)
-
-/* bit 28 is parallel transceiver width for UTMI interface */
-#define PORTSC_PTW                     (0x1<<28)
-#define PORTSC_PTW_8BIT                        (0x0<<28)
-#define PORTSC_PTW_16BIT               (0x1<<28)
-
-/* bit 31-30 are port transceiver select */
-#define PORTSC_PTS_UTMI                        (0x0<<30)
-#define PORTSC_PTS_ULPI                        (0x2<<30)
-#define PORTSC_PTS_FSLS_SERIAL         (0x3<<30)
-#define PORTSC_PTS_BIT_POS             (30)
-
-#define PORTSC_W1C_BITS                        \
-       (PORTSC_CONNECT_STATUS_CHANGE | \
-        PORTSC_PORT_EN_DIS_CHANGE    | \
-        PORTSC_OVER_CUURENT_CHG)
-
-/* OTG Status Control Register Bit Masks */
-#define OTGSC_CTRL_VBUS_DISCHARGE      (0x1<<0)
-#define OTGSC_CTRL_VBUS_CHARGE         (0x1<<1)
-#define OTGSC_CTRL_OTG_TERMINATION     (0x1<<3)
-#define OTGSC_CTRL_DATA_PULSING                (0x1<<4)
-#define OTGSC_CTRL_ID_PULL_EN          (0x1<<5)
-#define OTGSC_HA_DATA_PULSE            (0x1<<6)
-#define OTGSC_HA_BA                    (0x1<<7)
-#define OTGSC_STS_USB_ID               (0x1<<8)
-#define OTGSC_STS_A_VBUS_VALID         (0x1<<9)
-#define OTGSC_STS_A_SESSION_VALID      (0x1<<10)
-#define OTGSC_STS_B_SESSION_VALID      (0x1<<11)
-#define OTGSC_STS_B_SESSION_END                (0x1<<12)
-#define OTGSC_STS_1MS_TOGGLE           (0x1<<13)
-#define OTGSC_STS_DATA_PULSING         (0x1<<14)
-#define OTGSC_INTSTS_USB_ID            (0x1<<16)
-#define OTGSC_INTSTS_A_VBUS_VALID      (0x1<<17)
-#define OTGSC_INTSTS_A_SESSION_VALID   (0x1<<18)
-#define OTGSC_INTSTS_B_SESSION_VALID   (0x1<<19)
-#define OTGSC_INTSTS_B_SESSION_END     (0x1<<20)
-#define OTGSC_INTSTS_1MS               (0x1<<21)
-#define OTGSC_INTSTS_DATA_PULSING      (0x1<<22)
-#define OTGSC_INTR_USB_ID_EN           (0x1<<24)
-#define OTGSC_INTR_A_VBUS_VALID_EN     (0x1<<25)
-#define OTGSC_INTR_A_SESSION_VALID_EN  (0x1<<26)
-#define OTGSC_INTR_B_SESSION_VALID_EN  (0x1<<27)
-#define OTGSC_INTR_B_SESSION_END_EN    (0x1<<28)
-#define OTGSC_INTR_1MS_TIMER_EN                (0x1<<29)
-#define OTGSC_INTR_DATA_PULSING_EN     (0x1<<30)
-#define OTGSC_INTSTS_MASK              (0x00ff0000)
-
-/* USB MODE Register Bit Masks */
-#define  USB_MODE_CTRL_MODE_IDLE       (0x0<<0)
-#define  USB_MODE_CTRL_MODE_DEVICE     (0x2<<0)
-#define  USB_MODE_CTRL_MODE_HOST       (0x3<<0)
-#define  USB_MODE_CTRL_MODE_RSV                (0x1<<0)
-#define  USB_MODE_SETUP_LOCK_OFF       (0x1<<3)
-#define  USB_MODE_STREAM_DISABLE       (0x1<<4)
-#define  USB_MODE_ES                   (0x1<<2) /* Endian Select */
-
-/* control Register Bit Masks */
-#define  USB_CTRL_IOENB                        (0x1<<2)
-#define  USB_CTRL_ULPI_INT0EN          (0x1<<0)
-
-/* BCSR5 */
-#define BCSR5_INT_USB                  (0x02)
-
-/* USB module clk cfg */
-#define SCCR_OFFS                      (0xA08)
-#define SCCR_USB_CLK_DISABLE           (0x00000000)    /* USB clk disable */
-#define SCCR_USB_MPHCM_11              (0x00c00000)
-#define SCCR_USB_MPHCM_01              (0x00400000)
-#define SCCR_USB_MPHCM_10              (0x00800000)
-#define SCCR_USB_DRCM_11               (0x00300000)
-#define SCCR_USB_DRCM_01               (0x00100000)
-#define SCCR_USB_DRCM_10               (0x00200000)
-
-#define SICRL_OFFS                     (0x114)
-#define SICRL_USB0                     (0x40000000)
-#define SICRL_USB1                     (0x20000000)
-
-#define SICRH_OFFS                     (0x118)
-#define SICRH_USB_UTMI                 (0x00020000)
-
-/* OTG interrupt enable bit masks */
-#define  OTGSC_INTERRUPT_ENABLE_BITS_MASK  \
-       (OTGSC_INTR_USB_ID_EN            | \
-       OTGSC_INTR_1MS_TIMER_EN          | \
-       OTGSC_INTR_A_VBUS_VALID_EN       | \
-       OTGSC_INTR_A_SESSION_VALID_EN    | \
-       OTGSC_INTR_B_SESSION_VALID_EN    | \
-       OTGSC_INTR_B_SESSION_END_EN      | \
-       OTGSC_INTR_DATA_PULSING_EN)
-
-/* OTG interrupt status bit masks */
-#define  OTGSC_INTERRUPT_STATUS_BITS_MASK  \
-       (OTGSC_INTSTS_USB_ID          |    \
-       OTGSC_INTR_1MS_TIMER_EN       |    \
-       OTGSC_INTSTS_A_VBUS_VALID     |    \
-       OTGSC_INTSTS_A_SESSION_VALID  |    \
-       OTGSC_INTSTS_B_SESSION_VALID  |    \
-       OTGSC_INTSTS_B_SESSION_END    |    \
-       OTGSC_INTSTS_DATA_PULSING)
-
-/*
- *  A-DEVICE timing  constants
- */
-
-/* Wait for VBUS Rise  */
-#define TA_WAIT_VRISE  (100)   /* a_wait_vrise 100 ms, section: 6.6.5.1 */
-
-/* Wait for B-Connect */
-#define TA_WAIT_BCON   (10000)  /* a_wait_bcon > 1 sec, section: 6.6.5.2
-                                 * This is only used to get out of
-                                 * OTG_STATE_A_WAIT_BCON state if there was
-                                 * no connection for these many milliseconds
-                                 */
-
-/* A-Idle to B-Disconnect */
-/* It is necessary for this timer to be more than 750 ms because of a bug in OPT
- * test 5.4 in which B OPT disconnects after 750 ms instead of 75ms as stated
- * in the test description
- */
-#define TA_AIDL_BDIS   (5000)  /* a_suspend minimum 200 ms, section: 6.6.5.3 */
-
-/* B-Idle to A-Disconnect */
-#define TA_BIDL_ADIS   (12)    /* 3 to 200 ms */
-
-/* B-device timing constants */
-
-
-/* Data-Line Pulse Time*/
-#define TB_DATA_PLS    (10)    /* b_srp_init,continue 5~10ms, section:5.3.3 */
-#define TB_DATA_PLS_MIN        (5)     /* minimum 5 ms */
-#define TB_DATA_PLS_MAX        (10)    /* maximum 10 ms */
-
-/* SRP Initiate Time  */
-#define TB_SRP_INIT    (100)   /* b_srp_init,maximum 100 ms, section:5.3.8 */
-
-/* SRP Fail Time  */
-#define TB_SRP_FAIL    (7000)  /* b_srp_init,Fail time 5~30s, section:6.8.2.2*/
-
-/* SRP result wait time */
-#define TB_SRP_WAIT    (60)
-
-/* VBus time */
-#define TB_VBUS_PLS    (30)    /* time to keep vbus pulsing asserted */
-
-/* Discharge time */
-/* This time should be less than 10ms. It varies from system to system. */
-#define TB_VBUS_DSCHRG (8)
-
-/* A-SE0 to B-Reset  */
-#define TB_ASE0_BRST   (20)    /* b_wait_acon, mini 3.125 ms,section:6.8.2.4 */
-
-/* A bus suspend timer before we can switch to b_wait_aconn */
-#define TB_A_SUSPEND   (7)
-#define TB_BUS_RESUME  (12)
-
-/* SE0 Time Before SRP */
-#define TB_SE0_SRP     (2)     /* b_idle,minimum 2 ms, section:5.3.2 */
-
-#define SET_OTG_STATE(otg_ptr, newstate)       ((otg_ptr)->state = newstate)
-
-struct usb_dr_mmap {
-       /* Capability register */
-       u8 res1[256];
-       u16 caplength;          /* Capability Register Length */
-       u16 hciversion;         /* Host Controller Interface Version */
-       u32 hcsparams;          /* Host Controller Structual Parameters */
-       u32 hccparams;          /* Host Controller Capability Parameters */
-       u8 res2[20];
-       u32 dciversion;         /* Device Controller Interface Version */
-       u32 dccparams;          /* Device Controller Capability Parameters */
-       u8 res3[24];
-       /* Operation register */
-       u32 usbcmd;             /* USB Command Register */
-       u32 usbsts;             /* USB Status Register */
-       u32 usbintr;            /* USB Interrupt Enable Register */
-       u32 frindex;            /* Frame Index Register */
-       u8 res4[4];
-       u32 deviceaddr;         /* Device Address */
-       u32 endpointlistaddr;   /* Endpoint List Address Register */
-       u8 res5[4];
-       u32 burstsize;          /* Master Interface Data Burst Size Register */
-       u32 txttfilltuning;     /* Transmit FIFO Tuning Controls Register */
-       u8 res6[8];
-       u32 ulpiview;           /* ULPI register access */
-       u8 res7[12];
-       u32 configflag;         /* Configure Flag Register */
-       u32 portsc;             /* Port 1 Status and Control Register */
-       u8 res8[28];
-       u32 otgsc;              /* On-The-Go Status and Control */
-       u32 usbmode;            /* USB Mode Register */
-       u32 endptsetupstat;     /* Endpoint Setup Status Register */
-       u32 endpointprime;      /* Endpoint Initialization Register */
-       u32 endptflush;         /* Endpoint Flush Register */
-       u32 endptstatus;        /* Endpoint Status Register */
-       u32 endptcomplete;      /* Endpoint Complete Register */
-       u32 endptctrl[6];       /* Endpoint Control Registers */
-       u8 res9[552];
-       u32 snoop1;
-       u32 snoop2;
-       u32 age_cnt_thresh;     /* Age Count Threshold Register */
-       u32 pri_ctrl;           /* Priority Control Register */
-       u32 si_ctrl;            /* System Interface Control Register */
-       u8 res10[236];
-       u32 control;            /* General Purpose Control Register */
-};
-
-struct fsl_otg_timer {
-       unsigned long expires;  /* Number of count increase to timeout */
-       unsigned long count;    /* Tick counter */
-       void (*function)(unsigned long);        /* Timeout function */
-       unsigned long data;     /* Data passed to function */
-       struct list_head list;
-};
-
-inline struct fsl_otg_timer *otg_timer_initializer
-(void (*function)(unsigned long), unsigned long expires, unsigned long data)
-{
-       struct fsl_otg_timer *timer;
-
-       timer = kmalloc(sizeof(struct fsl_otg_timer), GFP_KERNEL);
-       if (!timer)
-               return NULL;
-       timer->function = function;
-       timer->expires = expires;
-       timer->data = data;
-       return timer;
-}
-
-struct fsl_otg {
-       struct usb_phy phy;
-       struct otg_fsm fsm;
-       struct usb_dr_mmap *dr_mem_map;
-       struct delayed_work otg_event;
-
-       /* used for usb host */
-       struct work_struct work_wq;
-       u8      host_working;
-
-       int irq;
-};
-
-struct fsl_otg_config {
-       u8 otg_port;
-};
-
-/* For SRP and HNP handle */
-#define FSL_OTG_MAJOR          240
-#define FSL_OTG_NAME           "fsl-usb2-otg"
-/* Command to OTG driver ioctl */
-#define OTG_IOCTL_MAGIC                FSL_OTG_MAJOR
-/* if otg work as host, it should return 1, otherwise return 0 */
-#define GET_OTG_STATUS         _IOR(OTG_IOCTL_MAGIC, 1, int)
-#define SET_A_SUSPEND_REQ      _IOW(OTG_IOCTL_MAGIC, 2, int)
-#define SET_A_BUS_DROP         _IOW(OTG_IOCTL_MAGIC, 3, int)
-#define SET_A_BUS_REQ          _IOW(OTG_IOCTL_MAGIC, 4, int)
-#define SET_B_BUS_REQ          _IOW(OTG_IOCTL_MAGIC, 5, int)
-#define GET_A_SUSPEND_REQ      _IOR(OTG_IOCTL_MAGIC, 6, int)
-#define GET_A_BUS_DROP         _IOR(OTG_IOCTL_MAGIC, 7, int)
-#define GET_A_BUS_REQ          _IOR(OTG_IOCTL_MAGIC, 8, int)
-#define GET_B_BUS_REQ          _IOR(OTG_IOCTL_MAGIC, 9, int)
-
-void fsl_otg_add_timer(void *timer);
-void fsl_otg_del_timer(void *timer);
-void fsl_otg_pulse_vbus(void);
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
deleted file mode 100644 (file)
index a7d4ac5..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices
- *
- * Copyright (c) 2008 Philipp Zabel <philipp.zabel@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/usb.h>
-#include <linux/workqueue.h>
-
-#include <linux/regulator/consumer.h>
-
-#include <linux/usb/gadget.h>
-#include <linux/usb/gpio_vbus.h>
-#include <linux/usb/otg.h>
-
-
-/*
- * A simple GPIO VBUS sensing driver for B peripheral only devices
- * with internal transceivers. It can control a D+ pullup GPIO and
- * a regulator to limit the current drawn from VBUS.
- *
- * Needs to be loaded before the UDC driver that will use it.
- */
-struct gpio_vbus_data {
-       struct usb_phy          phy;
-       struct device          *dev;
-       struct regulator       *vbus_draw;
-       int                     vbus_draw_enabled;
-       unsigned                mA;
-       struct delayed_work     work;
-       int                     vbus;
-       int                     irq;
-};
-
-
-/*
- * This driver relies on "both edges" triggering.  VBUS has 100 msec to
- * stabilize, so the peripheral controller driver may need to cope with
- * some bouncing due to current surges (e.g. charging local capacitance)
- * and contact chatter.
- *
- * REVISIT in desperate straits, toggling between rising and falling
- * edges might be workable.
- */
-#define VBUS_IRQ_FLAGS \
-       (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
-
-
-/* interface to regulator framework */
-static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
-{
-       struct regulator *vbus_draw = gpio_vbus->vbus_draw;
-       int enabled;
-
-       if (!vbus_draw)
-               return;
-
-       enabled = gpio_vbus->vbus_draw_enabled;
-       if (mA) {
-               regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
-               if (!enabled) {
-                       regulator_enable(vbus_draw);
-                       gpio_vbus->vbus_draw_enabled = 1;
-               }
-       } else {
-               if (enabled) {
-                       regulator_disable(vbus_draw);
-                       gpio_vbus->vbus_draw_enabled = 0;
-               }
-       }
-       gpio_vbus->mA = mA;
-}
-
-static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
-{
-       int vbus;
-
-       vbus = gpio_get_value(pdata->gpio_vbus);
-       if (pdata->gpio_vbus_inverted)
-               vbus = !vbus;
-
-       return vbus;
-}
-
-static void gpio_vbus_work(struct work_struct *work)
-{
-       struct gpio_vbus_data *gpio_vbus =
-               container_of(work, struct gpio_vbus_data, work.work);
-       struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
-       int gpio, status, vbus;
-
-       if (!gpio_vbus->phy.otg->gadget)
-               return;
-
-       vbus = is_vbus_powered(pdata);
-       if ((vbus ^ gpio_vbus->vbus) == 0)
-               return;
-       gpio_vbus->vbus = vbus;
-
-       /* Peripheral controllers which manage the pullup themselves won't have
-        * gpio_pullup configured here.  If it's configured here, we'll do what
-        * isp1301_omap::b_peripheral() does and enable the pullup here... although
-        * that may complicate usb_gadget_{,dis}connect() support.
-        */
-       gpio = pdata->gpio_pullup;
-
-       if (vbus) {
-               status = USB_EVENT_VBUS;
-               gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
-               gpio_vbus->phy.last_event = status;
-               usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget);
-
-               /* drawing a "unit load" is *always* OK, except for OTG */
-               set_vbus_draw(gpio_vbus, 100);
-
-               /* optionally enable D+ pullup */
-               if (gpio_is_valid(gpio))
-                       gpio_set_value(gpio, !pdata->gpio_pullup_inverted);
-
-               atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
-                                          status, gpio_vbus->phy.otg->gadget);
-       } else {
-               /* optionally disable D+ pullup */
-               if (gpio_is_valid(gpio))
-                       gpio_set_value(gpio, pdata->gpio_pullup_inverted);
-
-               set_vbus_draw(gpio_vbus, 0);
-
-               usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget);
-               status = USB_EVENT_NONE;
-               gpio_vbus->phy.state = OTG_STATE_B_IDLE;
-               gpio_vbus->phy.last_event = status;
-
-               atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
-                                          status, gpio_vbus->phy.otg->gadget);
-       }
-}
-
-/* VBUS change IRQ handler */
-static irqreturn_t gpio_vbus_irq(int irq, void *data)
-{
-       struct platform_device *pdev = data;
-       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
-       struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
-       struct usb_otg *otg = gpio_vbus->phy.otg;
-
-       dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
-               is_vbus_powered(pdata) ? "supplied" : "inactive",
-               otg->gadget ? otg->gadget->name : "none");
-
-       if (otg->gadget)
-               schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100));
-
-       return IRQ_HANDLED;
-}
-
-/* OTG transceiver interface */
-
-/* bind/unbind the peripheral controller */
-static int gpio_vbus_set_peripheral(struct usb_otg *otg,
-                                       struct usb_gadget *gadget)
-{
-       struct gpio_vbus_data *gpio_vbus;
-       struct gpio_vbus_mach_info *pdata;
-       struct platform_device *pdev;
-       int gpio;
-
-       gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
-       pdev = to_platform_device(gpio_vbus->dev);
-       pdata = gpio_vbus->dev->platform_data;
-       gpio = pdata->gpio_pullup;
-
-       if (!gadget) {
-               dev_dbg(&pdev->dev, "unregistering gadget '%s'\n",
-                       otg->gadget->name);
-
-               /* optionally disable D+ pullup */
-               if (gpio_is_valid(gpio))
-                       gpio_set_value(gpio, pdata->gpio_pullup_inverted);
-
-               set_vbus_draw(gpio_vbus, 0);
-
-               usb_gadget_vbus_disconnect(otg->gadget);
-               otg->phy->state = OTG_STATE_UNDEFINED;
-
-               otg->gadget = NULL;
-               return 0;
-       }
-
-       otg->gadget = gadget;
-       dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
-
-       /* initialize connection state */
-       gpio_vbus->vbus = 0; /* start with disconnected */
-       gpio_vbus_irq(gpio_vbus->irq, pdev);
-       return 0;
-}
-
-/* effective for B devices, ignored for A-peripheral */
-static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA)
-{
-       struct gpio_vbus_data *gpio_vbus;
-
-       gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
-
-       if (phy->state == OTG_STATE_B_PERIPHERAL)
-               set_vbus_draw(gpio_vbus, mA);
-       return 0;
-}
-
-/* for non-OTG B devices: set/clear transceiver suspend mode */
-static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
-{
-       struct gpio_vbus_data *gpio_vbus;
-
-       gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
-
-       /* draw max 0 mA from vbus in suspend mode; or the previously
-        * recorded amount of current if not suspended
-        *
-        * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA
-        * if they're wake-enabled ... we don't handle that yet.
-        */
-       return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA);
-}
-
-/* platform driver interface */
-
-static int __init gpio_vbus_probe(struct platform_device *pdev)
-{
-       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
-       struct gpio_vbus_data *gpio_vbus;
-       struct resource *res;
-       int err, gpio, irq;
-       unsigned long irqflags;
-
-       if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
-               return -EINVAL;
-       gpio = pdata->gpio_vbus;
-
-       gpio_vbus = kzalloc(sizeof(struct gpio_vbus_data), GFP_KERNEL);
-       if (!gpio_vbus)
-               return -ENOMEM;
-
-       gpio_vbus->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
-       if (!gpio_vbus->phy.otg) {
-               kfree(gpio_vbus);
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(pdev, gpio_vbus);
-       gpio_vbus->dev = &pdev->dev;
-       gpio_vbus->phy.label = "gpio-vbus";
-       gpio_vbus->phy.set_power = gpio_vbus_set_power;
-       gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
-       gpio_vbus->phy.state = OTG_STATE_UNDEFINED;
-
-       gpio_vbus->phy.otg->phy = &gpio_vbus->phy;
-       gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral;
-
-       err = gpio_request(gpio, "vbus_detect");
-       if (err) {
-               dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n",
-                       gpio, err);
-               goto err_gpio;
-       }
-       gpio_direction_input(gpio);
-
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res) {
-               irq = res->start;
-               irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
-       } else {
-               irq = gpio_to_irq(gpio);
-               irqflags = VBUS_IRQ_FLAGS;
-       }
-
-       gpio_vbus->irq = irq;
-
-       /* if data line pullup is in use, initialize it to "not pulling up" */
-       gpio = pdata->gpio_pullup;
-       if (gpio_is_valid(gpio)) {
-               err = gpio_request(gpio, "udc_pullup");
-               if (err) {
-                       dev_err(&pdev->dev,
-                               "can't request pullup gpio %d, err: %d\n",
-                               gpio, err);
-                       gpio_free(pdata->gpio_vbus);
-                       goto err_gpio;
-               }
-               gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
-       }
-
-       err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev);
-       if (err) {
-               dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
-                       irq, err);
-               goto err_irq;
-       }
-
-       ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);
-
-       INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
-
-       gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
-       if (IS_ERR(gpio_vbus->vbus_draw)) {
-               dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
-                       PTR_ERR(gpio_vbus->vbus_draw));
-               gpio_vbus->vbus_draw = NULL;
-       }
-
-       /* only active when a gadget is registered */
-       err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2);
-       if (err) {
-               dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
-                       err);
-               goto err_otg;
-       }
-
-       device_init_wakeup(&pdev->dev, pdata->wakeup);
-
-       return 0;
-err_otg:
-       regulator_put(gpio_vbus->vbus_draw);
-       free_irq(irq, pdev);
-err_irq:
-       if (gpio_is_valid(pdata->gpio_pullup))
-               gpio_free(pdata->gpio_pullup);
-       gpio_free(pdata->gpio_vbus);
-err_gpio:
-       platform_set_drvdata(pdev, NULL);
-       kfree(gpio_vbus->phy.otg);
-       kfree(gpio_vbus);
-       return err;
-}
-
-static int __exit gpio_vbus_remove(struct platform_device *pdev)
-{
-       struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
-       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
-       int gpio = pdata->gpio_vbus;
-
-       device_init_wakeup(&pdev->dev, 0);
-       cancel_delayed_work_sync(&gpio_vbus->work);
-       regulator_put(gpio_vbus->vbus_draw);
-
-       usb_remove_phy(&gpio_vbus->phy);
-
-       free_irq(gpio_vbus->irq, pdev);
-       if (gpio_is_valid(pdata->gpio_pullup))
-               gpio_free(pdata->gpio_pullup);
-       gpio_free(gpio);
-       platform_set_drvdata(pdev, NULL);
-       kfree(gpio_vbus->phy.otg);
-       kfree(gpio_vbus);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int gpio_vbus_pm_suspend(struct device *dev)
-{
-       struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
-
-       if (device_may_wakeup(dev))
-               enable_irq_wake(gpio_vbus->irq);
-
-       return 0;
-}
-
-static int gpio_vbus_pm_resume(struct device *dev)
-{
-       struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
-
-       if (device_may_wakeup(dev))
-               disable_irq_wake(gpio_vbus->irq);
-
-       return 0;
-}
-
-static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
-       .suspend        = gpio_vbus_pm_suspend,
-       .resume         = gpio_vbus_pm_resume,
-};
-#endif
-
-/* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
-
-MODULE_ALIAS("platform:gpio-vbus");
-
-static struct platform_driver gpio_vbus_driver = {
-       .driver = {
-               .name  = "gpio-vbus",
-               .owner = THIS_MODULE,
-#ifdef CONFIG_PM
-               .pm = &gpio_vbus_dev_pm_ops,
-#endif
-       },
-       .remove  = __exit_p(gpio_vbus_remove),
-};
-
-module_platform_driver_probe(gpio_vbus_driver, gpio_vbus_probe);
-
-MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");
-MODULE_AUTHOR("Philipp Zabel");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
deleted file mode 100644 (file)
index 8fe0c3b..0000000
+++ /dev/null
@@ -1,1656 +0,0 @@
-/*
- * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller
- *
- * Copyright (C) 2004 Texas Instruments
- * Copyright (C) 2004 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb.h>
-#include <linux/usb/otg.h>
-#include <linux/i2c.h>
-#include <linux/workqueue.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <mach/mux.h>
-
-#include <mach/usb.h>
-
-#ifndef        DEBUG
-#undef VERBOSE
-#endif
-
-
-#define        DRIVER_VERSION  "24 August 2004"
-#define        DRIVER_NAME     (isp1301_driver.driver.name)
-
-MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
-MODULE_LICENSE("GPL");
-
-struct isp1301 {
-       struct usb_phy          phy;
-       struct i2c_client       *client;
-       void                    (*i2c_release)(struct device *dev);
-
-       int                     irq_type;
-
-       u32                     last_otg_ctrl;
-       unsigned                working:1;
-
-       struct timer_list       timer;
-
-       /* use keventd context to change the state for us */
-       struct work_struct      work;
-
-       unsigned long           todo;
-#              define WORK_UPDATE_ISP  0       /* update ISP from OTG */
-#              define WORK_UPDATE_OTG  1       /* update OTG from ISP */
-#              define WORK_HOST_RESUME 4       /* resume host */
-#              define WORK_TIMER       6       /* timer fired */
-#              define WORK_STOP        7       /* don't resubmit */
-};
-
-
-/* bits in OTG_CTRL */
-
-#define        OTG_XCEIV_OUTPUTS \
-       (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
-#define        OTG_XCEIV_INPUTS \
-       (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
-#define        OTG_CTRL_BITS \
-       (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
-       /* and OTG_PULLUP is sometimes written */
-
-#define        OTG_CTRL_MASK   (OTG_DRIVER_SEL| \
-       OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \
-       OTG_CTRL_BITS)
-
-
-/*-------------------------------------------------------------------------*/
-
-/* board-specific PM hooks */
-
-#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
-
-#if    defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
-
-#include <linux/i2c/tps65010.h>
-
-#else
-
-static inline int tps65010_set_vbus_draw(unsigned mA)
-{
-       pr_debug("tps65010: draw %d mA (STUB)\n", mA);
-       return 0;
-}
-
-#endif
-
-static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
-{
-       int status = tps65010_set_vbus_draw(mA);
-       if (status < 0)
-               pr_debug("  VBUS %d mA error %d\n", mA, status);
-}
-
-#else
-
-static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
-{
-       /* H4 controls this by DIP switch S2.4; no soft control.
-        * ON means the charger is always enabled.  Leave it OFF
-        * unless the OTG port is used only in B-peripheral mode.
-        */
-}
-
-#endif
-
-static void enable_vbus_source(struct isp1301 *isp)
-{
-       /* this board won't supply more than 8mA vbus power.
-        * some boards can switch a 100ma "unit load" (or more).
-        */
-}
-
-
-/* products will deliver OTG messages with LEDs, GUI, etc */
-static inline void notresponding(struct isp1301 *isp)
-{
-       printk(KERN_NOTICE "OTG device not responding.\n");
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static struct i2c_driver isp1301_driver;
-
-/* smbus apis are used for portability */
-
-static inline u8
-isp1301_get_u8(struct isp1301 *isp, u8 reg)
-{
-       return i2c_smbus_read_byte_data(isp->client, reg + 0);
-}
-
-static inline int
-isp1301_get_u16(struct isp1301 *isp, u8 reg)
-{
-       return i2c_smbus_read_word_data(isp->client, reg);
-}
-
-static inline int
-isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
-{
-       return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
-}
-
-static inline int
-isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
-{
-       return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* identification */
-#define        ISP1301_VENDOR_ID               0x00    /* u16 read */
-#define        ISP1301_PRODUCT_ID              0x02    /* u16 read */
-#define        ISP1301_BCD_DEVICE              0x14    /* u16 read */
-
-#define        I2C_VENDOR_ID_PHILIPS           0x04cc
-#define        I2C_PRODUCT_ID_PHILIPS_1301     0x1301
-
-/* operational registers */
-#define        ISP1301_MODE_CONTROL_1          0x04    /* u8 read, set, +1 clear */
-#      define  MC1_SPEED               (1 << 0)
-#      define  MC1_SUSPEND             (1 << 1)
-#      define  MC1_DAT_SE0             (1 << 2)
-#      define  MC1_TRANSPARENT         (1 << 3)
-#      define  MC1_BDIS_ACON_EN        (1 << 4)
-#      define  MC1_OE_INT_EN           (1 << 5)
-#      define  MC1_UART_EN             (1 << 6)
-#      define  MC1_MASK                0x7f
-#define        ISP1301_MODE_CONTROL_2          0x12    /* u8 read, set, +1 clear */
-#      define  MC2_GLOBAL_PWR_DN       (1 << 0)
-#      define  MC2_SPD_SUSP_CTRL       (1 << 1)
-#      define  MC2_BI_DI               (1 << 2)
-#      define  MC2_TRANSP_BDIR0        (1 << 3)
-#      define  MC2_TRANSP_BDIR1        (1 << 4)
-#      define  MC2_AUDIO_EN            (1 << 5)
-#      define  MC2_PSW_EN              (1 << 6)
-#      define  MC2_EN2V7               (1 << 7)
-#define        ISP1301_OTG_CONTROL_1           0x06    /* u8 read, set, +1 clear */
-#      define  OTG1_DP_PULLUP          (1 << 0)
-#      define  OTG1_DM_PULLUP          (1 << 1)
-#      define  OTG1_DP_PULLDOWN        (1 << 2)
-#      define  OTG1_DM_PULLDOWN        (1 << 3)
-#      define  OTG1_ID_PULLDOWN        (1 << 4)
-#      define  OTG1_VBUS_DRV           (1 << 5)
-#      define  OTG1_VBUS_DISCHRG       (1 << 6)
-#      define  OTG1_VBUS_CHRG          (1 << 7)
-#define        ISP1301_OTG_STATUS              0x10    /* u8 readonly */
-#      define  OTG_B_SESS_END          (1 << 6)
-#      define  OTG_B_SESS_VLD          (1 << 7)
-
-#define        ISP1301_INTERRUPT_SOURCE        0x08    /* u8 read */
-#define        ISP1301_INTERRUPT_LATCH         0x0A    /* u8 read, set, +1 clear */
-
-#define        ISP1301_INTERRUPT_FALLING       0x0C    /* u8 read, set, +1 clear */
-#define        ISP1301_INTERRUPT_RISING        0x0E    /* u8 read, set, +1 clear */
-
-/* same bitfields in all interrupt registers */
-#      define  INTR_VBUS_VLD           (1 << 0)
-#      define  INTR_SESS_VLD           (1 << 1)
-#      define  INTR_DP_HI              (1 << 2)
-#      define  INTR_ID_GND             (1 << 3)
-#      define  INTR_DM_HI              (1 << 4)
-#      define  INTR_ID_FLOAT           (1 << 5)
-#      define  INTR_BDIS_ACON          (1 << 6)
-#      define  INTR_CR_INT             (1 << 7)
-
-/*-------------------------------------------------------------------------*/
-
-static inline const char *state_name(struct isp1301 *isp)
-{
-       return usb_otg_state_string(isp->phy.state);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* NOTE:  some of this ISP1301 setup is specific to H2 boards;
- * not everything is guarded by board-specific checks, or even using
- * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI.
- *
- * ALSO:  this currently doesn't use ISP1301 low-power modes
- * while OTG is running.
- */
-
-static void power_down(struct isp1301 *isp)
-{
-       isp->phy.state = OTG_STATE_UNDEFINED;
-
-       // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
-       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
-
-       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN);
-       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
-}
-
-static void power_up(struct isp1301 *isp)
-{
-       // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
-       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
-
-       /* do this only when cpu is driving transceiver,
-        * so host won't see a low speed device...
-        */
-       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
-}
-
-#define        NO_HOST_SUSPEND
-
-static int host_suspend(struct isp1301 *isp)
-{
-#ifdef NO_HOST_SUSPEND
-       return 0;
-#else
-       struct device   *dev;
-
-       if (!isp->phy.otg->host)
-               return -ENODEV;
-
-       /* Currently ASSUMES only the OTG port matters;
-        * other ports could be active...
-        */
-       dev = isp->phy.otg->host->controller;
-       return dev->driver->suspend(dev, 3, 0);
-#endif
-}
-
-static int host_resume(struct isp1301 *isp)
-{
-#ifdef NO_HOST_SUSPEND
-       return 0;
-#else
-       struct device   *dev;
-
-       if (!isp->phy.otg->host)
-               return -ENODEV;
-
-       dev = isp->phy.otg->host->controller;
-       return dev->driver->resume(dev, 0);
-#endif
-}
-
-static int gadget_suspend(struct isp1301 *isp)
-{
-       isp->phy.otg->gadget->b_hnp_enable = 0;
-       isp->phy.otg->gadget->a_hnp_support = 0;
-       isp->phy.otg->gadget->a_alt_hnp_support = 0;
-       return usb_gadget_vbus_disconnect(isp->phy.otg->gadget);
-}
-
-/*-------------------------------------------------------------------------*/
-
-#define        TIMER_MINUTES   10
-#define        TIMER_JIFFIES   (TIMER_MINUTES * 60 * HZ)
-
-/* Almost all our I2C messaging comes from a work queue's task context.
- * NOTE: guaranteeing certain response times might mean we shouldn't
- * share keventd's work queue; a realtime task might be safest.
- */
-static void isp1301_defer_work(struct isp1301 *isp, int work)
-{
-       int status;
-
-       if (isp && !test_and_set_bit(work, &isp->todo)) {
-               (void) get_device(&isp->client->dev);
-               status = schedule_work(&isp->work);
-               if (!status && !isp->working)
-                       dev_vdbg(&isp->client->dev,
-                               "work item %d may be lost\n", work);
-       }
-}
-
-/* called from irq handlers */
-static void a_idle(struct isp1301 *isp, const char *tag)
-{
-       u32 l;
-
-       if (isp->phy.state == OTG_STATE_A_IDLE)
-               return;
-
-       isp->phy.otg->default_a = 1;
-       if (isp->phy.otg->host) {
-               isp->phy.otg->host->is_b_host = 0;
-               host_suspend(isp);
-       }
-       if (isp->phy.otg->gadget) {
-               isp->phy.otg->gadget->is_a_peripheral = 1;
-               gadget_suspend(isp);
-       }
-       isp->phy.state = OTG_STATE_A_IDLE;
-       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
-       omap_writel(l, OTG_CTRL);
-       isp->last_otg_ctrl = l;
-       pr_debug("  --> %s/%s\n", state_name(isp), tag);
-}
-
-/* called from irq handlers */
-static void b_idle(struct isp1301 *isp, const char *tag)
-{
-       u32 l;
-
-       if (isp->phy.state == OTG_STATE_B_IDLE)
-               return;
-
-       isp->phy.otg->default_a = 0;
-       if (isp->phy.otg->host) {
-               isp->phy.otg->host->is_b_host = 1;
-               host_suspend(isp);
-       }
-       if (isp->phy.otg->gadget) {
-               isp->phy.otg->gadget->is_a_peripheral = 0;
-               gadget_suspend(isp);
-       }
-       isp->phy.state = OTG_STATE_B_IDLE;
-       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
-       omap_writel(l, OTG_CTRL);
-       isp->last_otg_ctrl = l;
-       pr_debug("  --> %s/%s\n", state_name(isp), tag);
-}
-
-static void
-dump_regs(struct isp1301 *isp, const char *label)
-{
-#ifdef DEBUG
-       u8      ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1);
-       u8      status = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
-       u8      src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
-
-       pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n",
-               omap_readl(OTG_CTRL), label, state_name(isp),
-               ctrl, status, src);
-       /* mode control and irq enables don't change much */
-#endif
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef CONFIG_USB_OTG
-
-/*
- * The OMAP OTG controller handles most of the OTG state transitions.
- *
- * We translate isp1301 outputs (mostly voltage comparator status) into
- * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state
- * flags into isp1301 inputs ... and infer state transitions.
- */
-
-#ifdef VERBOSE
-
-static void check_state(struct isp1301 *isp, const char *tag)
-{
-       enum usb_otg_state      state = OTG_STATE_UNDEFINED;
-       u8                      fsm = omap_readw(OTG_TEST) & 0x0ff;
-       unsigned                extra = 0;
-
-       switch (fsm) {
-
-       /* default-b */
-       case 0x0:
-               state = OTG_STATE_B_IDLE;
-               break;
-       case 0x3:
-       case 0x7:
-               extra = 1;
-       case 0x1:
-               state = OTG_STATE_B_PERIPHERAL;
-               break;
-       case 0x11:
-               state = OTG_STATE_B_SRP_INIT;
-               break;
-
-       /* extra dual-role default-b states */
-       case 0x12:
-       case 0x13:
-       case 0x16:
-               extra = 1;
-       case 0x17:
-               state = OTG_STATE_B_WAIT_ACON;
-               break;
-       case 0x34:
-               state = OTG_STATE_B_HOST;
-               break;
-
-       /* default-a */
-       case 0x36:
-               state = OTG_STATE_A_IDLE;
-               break;
-       case 0x3c:
-               state = OTG_STATE_A_WAIT_VFALL;
-               break;
-       case 0x7d:
-               state = OTG_STATE_A_VBUS_ERR;
-               break;
-       case 0x9e:
-       case 0x9f:
-               extra = 1;
-       case 0x89:
-               state = OTG_STATE_A_PERIPHERAL;
-               break;
-       case 0xb7:
-               state = OTG_STATE_A_WAIT_VRISE;
-               break;
-       case 0xb8:
-               state = OTG_STATE_A_WAIT_BCON;
-               break;
-       case 0xb9:
-               state = OTG_STATE_A_HOST;
-               break;
-       case 0xba:
-               state = OTG_STATE_A_SUSPEND;
-               break;
-       default:
-               break;
-       }
-       if (isp->phy.state == state && !extra)
-               return;
-       pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
-               usb_otg_state_string(state), fsm, state_name(isp),
-               omap_readl(OTG_CTRL));
-}
-
-#else
-
-static inline void check_state(struct isp1301 *isp, const char *tag) { }
-
-#endif
-
-/* outputs from ISP1301_INTERRUPT_SOURCE */
-static void update_otg1(struct isp1301 *isp, u8 int_src)
-{
-       u32     otg_ctrl;
-
-       otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
-       otg_ctrl &= ~OTG_XCEIV_INPUTS;
-       otg_ctrl &= ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD);
-
-       if (int_src & INTR_SESS_VLD)
-               otg_ctrl |= OTG_ASESSVLD;
-       else if (isp->phy.state == OTG_STATE_A_WAIT_VFALL) {
-               a_idle(isp, "vfall");
-               otg_ctrl &= ~OTG_CTRL_BITS;
-       }
-       if (int_src & INTR_VBUS_VLD)
-               otg_ctrl |= OTG_VBUSVLD;
-       if (int_src & INTR_ID_GND) {            /* default-A */
-               if (isp->phy.state == OTG_STATE_B_IDLE
-                               || isp->phy.state
-                                       == OTG_STATE_UNDEFINED) {
-                       a_idle(isp, "init");
-                       return;
-               }
-       } else {                                /* default-B */
-               otg_ctrl |= OTG_ID;
-               if (isp->phy.state == OTG_STATE_A_IDLE
-                       || isp->phy.state == OTG_STATE_UNDEFINED) {
-                       b_idle(isp, "init");
-                       return;
-               }
-       }
-       omap_writel(otg_ctrl, OTG_CTRL);
-}
-
-/* outputs from ISP1301_OTG_STATUS */
-static void update_otg2(struct isp1301 *isp, u8 otg_status)
-{
-       u32     otg_ctrl;
-
-       otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
-       otg_ctrl &= ~OTG_XCEIV_INPUTS;
-       otg_ctrl &= ~(OTG_BSESSVLD | OTG_BSESSEND);
-       if (otg_status & OTG_B_SESS_VLD)
-               otg_ctrl |= OTG_BSESSVLD;
-       else if (otg_status & OTG_B_SESS_END)
-               otg_ctrl |= OTG_BSESSEND;
-       omap_writel(otg_ctrl, OTG_CTRL);
-}
-
-/* inputs going to ISP1301 */
-static void otg_update_isp(struct isp1301 *isp)
-{
-       u32     otg_ctrl, otg_change;
-       u8      set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP;
-
-       otg_ctrl = omap_readl(OTG_CTRL);
-       otg_change = otg_ctrl ^ isp->last_otg_ctrl;
-       isp->last_otg_ctrl = otg_ctrl;
-       otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS;
-
-       switch (isp->phy.state) {
-       case OTG_STATE_B_IDLE:
-       case OTG_STATE_B_PERIPHERAL:
-       case OTG_STATE_B_SRP_INIT:
-               if (!(otg_ctrl & OTG_PULLUP)) {
-                       // if (otg_ctrl & OTG_B_HNPEN) {
-                       if (isp->phy.otg->gadget->b_hnp_enable) {
-                               isp->phy.state = OTG_STATE_B_WAIT_ACON;
-                               pr_debug("  --> b_wait_acon\n");
-                       }
-                       goto pulldown;
-               }
-pullup:
-               set |= OTG1_DP_PULLUP;
-               clr |= OTG1_DP_PULLDOWN;
-               break;
-       case OTG_STATE_A_SUSPEND:
-       case OTG_STATE_A_PERIPHERAL:
-               if (otg_ctrl & OTG_PULLUP)
-                       goto pullup;
-               /* FALLTHROUGH */
-       // case OTG_STATE_B_WAIT_ACON:
-       default:
-pulldown:
-               set |= OTG1_DP_PULLDOWN;
-               clr |= OTG1_DP_PULLUP;
-               break;
-       }
-
-#      define toggle(OTG,ISP) do { \
-               if (otg_ctrl & OTG) set |= ISP; \
-               else clr |= ISP; \
-               } while (0)
-
-       if (!(isp->phy.otg->host))
-               otg_ctrl &= ~OTG_DRV_VBUS;
-
-       switch (isp->phy.state) {
-       case OTG_STATE_A_SUSPEND:
-               if (otg_ctrl & OTG_DRV_VBUS) {
-                       set |= OTG1_VBUS_DRV;
-                       break;
-               }
-               /* HNP failed for some reason (A_AIDL_BDIS timeout) */
-               notresponding(isp);
-
-               /* FALLTHROUGH */
-       case OTG_STATE_A_VBUS_ERR:
-               isp->phy.state = OTG_STATE_A_WAIT_VFALL;
-               pr_debug("  --> a_wait_vfall\n");
-               /* FALLTHROUGH */
-       case OTG_STATE_A_WAIT_VFALL:
-               /* FIXME usbcore thinks port power is still on ... */
-               clr |= OTG1_VBUS_DRV;
-               break;
-       case OTG_STATE_A_IDLE:
-               if (otg_ctrl & OTG_DRV_VBUS) {
-                       isp->phy.state = OTG_STATE_A_WAIT_VRISE;
-                       pr_debug("  --> a_wait_vrise\n");
-               }
-               /* FALLTHROUGH */
-       default:
-               toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV);
-       }
-
-       toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG);
-       toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG);
-
-#      undef toggle
-
-       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set);
-       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr);
-
-       /* HNP switch to host or peripheral; and SRP */
-       if (otg_change & OTG_PULLUP) {
-               u32 l;
-
-               switch (isp->phy.state) {
-               case OTG_STATE_B_IDLE:
-                       if (clr & OTG1_DP_PULLUP)
-                               break;
-                       isp->phy.state = OTG_STATE_B_PERIPHERAL;
-                       pr_debug("  --> b_peripheral\n");
-                       break;
-               case OTG_STATE_A_SUSPEND:
-                       if (clr & OTG1_DP_PULLUP)
-                               break;
-                       isp->phy.state = OTG_STATE_A_PERIPHERAL;
-                       pr_debug("  --> a_peripheral\n");
-                       break;
-               default:
-                       break;
-               }
-               l = omap_readl(OTG_CTRL);
-               l |= OTG_PULLUP;
-               omap_writel(l, OTG_CTRL);
-       }
-
-       check_state(isp, __func__);
-       dump_regs(isp, "otg->isp1301");
-}
-
-static irqreturn_t omap_otg_irq(int irq, void *_isp)
-{
-       u16             otg_irq = omap_readw(OTG_IRQ_SRC);
-       u32             otg_ctrl;
-       int             ret = IRQ_NONE;
-       struct isp1301  *isp = _isp;
-       struct usb_otg  *otg = isp->phy.otg;
-
-       /* update ISP1301 transceiver from OTG controller */
-       if (otg_irq & OPRT_CHG) {
-               omap_writew(OPRT_CHG, OTG_IRQ_SRC);
-               isp1301_defer_work(isp, WORK_UPDATE_ISP);
-               ret = IRQ_HANDLED;
-
-       /* SRP to become b_peripheral failed */
-       } else if (otg_irq & B_SRP_TMROUT) {
-               pr_debug("otg: B_SRP_TIMEOUT, %06x\n", omap_readl(OTG_CTRL));
-               notresponding(isp);
-
-               /* gadget drivers that care should monitor all kinds of
-                * remote wakeup (SRP, normal) using their own timer
-                * to give "check cable and A-device" messages.
-                */
-               if (isp->phy.state == OTG_STATE_B_SRP_INIT)
-                       b_idle(isp, "srp_timeout");
-
-               omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
-               ret = IRQ_HANDLED;
-
-       /* HNP to become b_host failed */
-       } else if (otg_irq & B_HNP_FAIL) {
-               pr_debug("otg: %s B_HNP_FAIL, %06x\n",
-                               state_name(isp), omap_readl(OTG_CTRL));
-               notresponding(isp);
-
-               otg_ctrl = omap_readl(OTG_CTRL);
-               otg_ctrl |= OTG_BUSDROP;
-               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
-               omap_writel(otg_ctrl, OTG_CTRL);
-
-               /* subset of b_peripheral()... */
-               isp->phy.state = OTG_STATE_B_PERIPHERAL;
-               pr_debug("  --> b_peripheral\n");
-
-               omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
-               ret = IRQ_HANDLED;
-
-       /* detect SRP from B-device ... */
-       } else if (otg_irq & A_SRP_DETECT) {
-               pr_debug("otg: %s SRP_DETECT, %06x\n",
-                               state_name(isp), omap_readl(OTG_CTRL));
-
-               isp1301_defer_work(isp, WORK_UPDATE_OTG);
-               switch (isp->phy.state) {
-               case OTG_STATE_A_IDLE:
-                       if (!otg->host)
-                               break;
-                       isp1301_defer_work(isp, WORK_HOST_RESUME);
-                       otg_ctrl = omap_readl(OTG_CTRL);
-                       otg_ctrl |= OTG_A_BUSREQ;
-                       otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)
-                                       & ~OTG_XCEIV_INPUTS
-                                       & OTG_CTRL_MASK;
-                       omap_writel(otg_ctrl, OTG_CTRL);
-                       break;
-               default:
-                       break;
-               }
-
-               omap_writew(A_SRP_DETECT, OTG_IRQ_SRC);
-               ret = IRQ_HANDLED;
-
-       /* timer expired:  T(a_wait_bcon) and maybe T(a_wait_vrise)
-        * we don't track them separately
-        */
-       } else if (otg_irq & A_REQ_TMROUT) {
-               otg_ctrl = omap_readl(OTG_CTRL);
-               pr_info("otg: BCON_TMOUT from %s, %06x\n",
-                               state_name(isp), otg_ctrl);
-               notresponding(isp);
-
-               otg_ctrl |= OTG_BUSDROP;
-               otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
-               omap_writel(otg_ctrl, OTG_CTRL);
-               isp->phy.state = OTG_STATE_A_WAIT_VFALL;
-
-               omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
-               ret = IRQ_HANDLED;
-
-       /* A-supplied voltage fell too low; overcurrent */
-       } else if (otg_irq & A_VBUS_ERR) {
-               otg_ctrl = omap_readl(OTG_CTRL);
-               printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n",
-                       state_name(isp), otg_irq, otg_ctrl);
-
-               otg_ctrl |= OTG_BUSDROP;
-               otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
-               omap_writel(otg_ctrl, OTG_CTRL);
-               isp->phy.state = OTG_STATE_A_VBUS_ERR;
-
-               omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
-               ret = IRQ_HANDLED;
-
-       /* switch driver; the transceiver code activates it,
-        * ungating the udc clock or resuming OHCI.
-        */
-       } else if (otg_irq & DRIVER_SWITCH) {
-               int     kick = 0;
-
-               otg_ctrl = omap_readl(OTG_CTRL);
-               printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n",
-                               state_name(isp),
-                               (otg_ctrl & OTG_DRIVER_SEL)
-                                       ? "gadget" : "host",
-                               otg_ctrl);
-               isp1301_defer_work(isp, WORK_UPDATE_ISP);
-
-               /* role is peripheral */
-               if (otg_ctrl & OTG_DRIVER_SEL) {
-                       switch (isp->phy.state) {
-                       case OTG_STATE_A_IDLE:
-                               b_idle(isp, __func__);
-                               break;
-                       default:
-                               break;
-                       }
-                       isp1301_defer_work(isp, WORK_UPDATE_ISP);
-
-               /* role is host */
-               } else {
-                       if (!(otg_ctrl & OTG_ID)) {
-                               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
-                               omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL);
-                       }
-
-                       if (otg->host) {
-                               switch (isp->phy.state) {
-                               case OTG_STATE_B_WAIT_ACON:
-                                       isp->phy.state = OTG_STATE_B_HOST;
-                                       pr_debug("  --> b_host\n");
-                                       kick = 1;
-                                       break;
-                               case OTG_STATE_A_WAIT_BCON:
-                                       isp->phy.state = OTG_STATE_A_HOST;
-                                       pr_debug("  --> a_host\n");
-                                       break;
-                               case OTG_STATE_A_PERIPHERAL:
-                                       isp->phy.state = OTG_STATE_A_WAIT_BCON;
-                                       pr_debug("  --> a_wait_bcon\n");
-                                       break;
-                               default:
-                                       break;
-                               }
-                               isp1301_defer_work(isp, WORK_HOST_RESUME);
-                       }
-               }
-
-               omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC);
-               ret = IRQ_HANDLED;
-
-               if (kick)
-                       usb_bus_start_enum(otg->host, otg->host->otg_port);
-       }
-
-       check_state(isp, __func__);
-       return ret;
-}
-
-static struct platform_device *otg_dev;
-
-static int isp1301_otg_init(struct isp1301 *isp)
-{
-       u32 l;
-
-       if (!otg_dev)
-               return -ENODEV;
-
-       dump_regs(isp, __func__);
-       /* some of these values are board-specific... */
-       l = omap_readl(OTG_SYSCON_2);
-       l |= OTG_EN
-               /* for B-device: */
-               | SRP_GPDATA            /* 9msec Bdev D+ pulse */
-               | SRP_GPDVBUS           /* discharge after VBUS pulse */
-               // | (3 << 24)          /* 2msec VBUS pulse */
-               /* for A-device: */
-               | (0 << 20)             /* 200ms nominal A_WAIT_VRISE timer */
-               | SRP_DPW               /* detect 167+ns SRP pulses */
-               | SRP_DATA | SRP_VBUS   /* accept both kinds of SRP pulse */
-               ;
-       omap_writel(l, OTG_SYSCON_2);
-
-       update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
-       update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
-
-       check_state(isp, __func__);
-       pr_debug("otg: %s, %s %06x\n",
-                       state_name(isp), __func__, omap_readl(OTG_CTRL));
-
-       omap_writew(DRIVER_SWITCH | OPRT_CHG
-                       | B_SRP_TMROUT | B_HNP_FAIL
-                       | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT, OTG_IRQ_EN);
-
-       l = omap_readl(OTG_SYSCON_2);
-       l |= OTG_EN;
-       omap_writel(l, OTG_SYSCON_2);
-
-       return 0;
-}
-
-static int otg_probe(struct platform_device *dev)
-{
-       // struct omap_usb_config *config = dev->platform_data;
-
-       otg_dev = dev;
-       return 0;
-}
-
-static int otg_remove(struct platform_device *dev)
-{
-       otg_dev = NULL;
-       return 0;
-}
-
-static struct platform_driver omap_otg_driver = {
-       .probe          = otg_probe,
-       .remove         = otg_remove,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "omap_otg",
-       },
-};
-
-static int otg_bind(struct isp1301 *isp)
-{
-       int     status;
-
-       if (otg_dev)
-               return -EBUSY;
-
-       status = platform_driver_register(&omap_otg_driver);
-       if (status < 0)
-               return status;
-
-       if (otg_dev)
-               status = request_irq(otg_dev->resource[1].start, omap_otg_irq,
-                               0, DRIVER_NAME, isp);
-       else
-               status = -ENODEV;
-
-       if (status < 0)
-               platform_driver_unregister(&omap_otg_driver);
-       return status;
-}
-
-static void otg_unbind(struct isp1301 *isp)
-{
-       if (!otg_dev)
-               return;
-       free_irq(otg_dev->resource[1].start, isp);
-}
-
-#else
-
-/* OTG controller isn't clocked */
-
-#endif /* CONFIG_USB_OTG */
-
-/*-------------------------------------------------------------------------*/
-
-static void b_peripheral(struct isp1301 *isp)
-{
-       u32 l;
-
-       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
-       omap_writel(l, OTG_CTRL);
-
-       usb_gadget_vbus_connect(isp->phy.otg->gadget);
-
-#ifdef CONFIG_USB_OTG
-       enable_vbus_draw(isp, 8);
-       otg_update_isp(isp);
-#else
-       enable_vbus_draw(isp, 100);
-       /* UDC driver just set OTG_BSESSVLD */
-       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP);
-       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN);
-       isp->phy.state = OTG_STATE_B_PERIPHERAL;
-       pr_debug("  --> b_peripheral\n");
-       dump_regs(isp, "2periph");
-#endif
-}
-
-static void isp_update_otg(struct isp1301 *isp, u8 stat)
-{
-       struct usb_otg          *otg = isp->phy.otg;
-       u8                      isp_stat, isp_bstat;
-       enum usb_otg_state      state = isp->phy.state;
-
-       if (stat & INTR_BDIS_ACON)
-               pr_debug("OTG:  BDIS_ACON, %s\n", state_name(isp));
-
-       /* start certain state transitions right away */
-       isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
-       if (isp_stat & INTR_ID_GND) {
-               if (otg->default_a) {
-                       switch (state) {
-                       case OTG_STATE_B_IDLE:
-                               a_idle(isp, "idle");
-                               /* FALLTHROUGH */
-                       case OTG_STATE_A_IDLE:
-                               enable_vbus_source(isp);
-                               /* FALLTHROUGH */
-                       case OTG_STATE_A_WAIT_VRISE:
-                               /* we skip over OTG_STATE_A_WAIT_BCON, since
-                                * the HC will transition to A_HOST (or
-                                * A_SUSPEND!) without our noticing except
-                                * when HNP is used.
-                                */
-                               if (isp_stat & INTR_VBUS_VLD)
-                                       isp->phy.state = OTG_STATE_A_HOST;
-                               break;
-                       case OTG_STATE_A_WAIT_VFALL:
-                               if (!(isp_stat & INTR_SESS_VLD))
-                                       a_idle(isp, "vfell");
-                               break;
-                       default:
-                               if (!(isp_stat & INTR_VBUS_VLD))
-                                       isp->phy.state = OTG_STATE_A_VBUS_ERR;
-                               break;
-                       }
-                       isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
-               } else {
-                       switch (state) {
-                       case OTG_STATE_B_PERIPHERAL:
-                       case OTG_STATE_B_HOST:
-                       case OTG_STATE_B_WAIT_ACON:
-                               usb_gadget_vbus_disconnect(otg->gadget);
-                               break;
-                       default:
-                               break;
-                       }
-                       if (state != OTG_STATE_A_IDLE)
-                               a_idle(isp, "id");
-                       if (otg->host && state == OTG_STATE_A_IDLE)
-                               isp1301_defer_work(isp, WORK_HOST_RESUME);
-                       isp_bstat = 0;
-               }
-       } else {
-               u32 l;
-
-               /* if user unplugged mini-A end of cable,
-                * don't bypass A_WAIT_VFALL.
-                */
-               if (otg->default_a) {
-                       switch (state) {
-                       default:
-                               isp->phy.state = OTG_STATE_A_WAIT_VFALL;
-                               break;
-                       case OTG_STATE_A_WAIT_VFALL:
-                               state = OTG_STATE_A_IDLE;
-                               /* khubd may take a while to notice and
-                                * handle this disconnect, so don't go
-                                * to B_IDLE quite yet.
-                                */
-                               break;
-                       case OTG_STATE_A_IDLE:
-                               host_suspend(isp);
-                               isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1,
-                                               MC1_BDIS_ACON_EN);
-                               isp->phy.state = OTG_STATE_B_IDLE;
-                               l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
-                               l &= ~OTG_CTRL_BITS;
-                               omap_writel(l, OTG_CTRL);
-                               break;
-                       case OTG_STATE_B_IDLE:
-                               break;
-                       }
-               }
-               isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
-
-               switch (isp->phy.state) {
-               case OTG_STATE_B_PERIPHERAL:
-               case OTG_STATE_B_WAIT_ACON:
-               case OTG_STATE_B_HOST:
-                       if (likely(isp_bstat & OTG_B_SESS_VLD))
-                               break;
-                       enable_vbus_draw(isp, 0);
-#ifndef        CONFIG_USB_OTG
-                       /* UDC driver will clear OTG_BSESSVLD */
-                       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
-                                               OTG1_DP_PULLDOWN);
-                       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
-                                               OTG1_DP_PULLUP);
-                       dump_regs(isp, __func__);
-#endif
-                       /* FALLTHROUGH */
-               case OTG_STATE_B_SRP_INIT:
-                       b_idle(isp, __func__);
-                       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
-                       omap_writel(l, OTG_CTRL);
-                       /* FALLTHROUGH */
-               case OTG_STATE_B_IDLE:
-                       if (otg->gadget && (isp_bstat & OTG_B_SESS_VLD)) {
-#ifdef CONFIG_USB_OTG
-                               update_otg1(isp, isp_stat);
-                               update_otg2(isp, isp_bstat);
-#endif
-                               b_peripheral(isp);
-                       } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD)))
-                               isp_bstat |= OTG_B_SESS_END;
-                       break;
-               case OTG_STATE_A_WAIT_VFALL:
-                       break;
-               default:
-                       pr_debug("otg: unsupported b-device %s\n",
-                               state_name(isp));
-                       break;
-               }
-       }
-
-       if (state != isp->phy.state)
-               pr_debug("  isp, %s -> %s\n",
-                               usb_otg_state_string(state), state_name(isp));
-
-#ifdef CONFIG_USB_OTG
-       /* update the OTG controller state to match the isp1301; may
-        * trigger OPRT_CHG irqs for changes going to the isp1301.
-        */
-       update_otg1(isp, isp_stat);
-       update_otg2(isp, isp_bstat);
-       check_state(isp, __func__);
-#endif
-
-       dump_regs(isp, "isp1301->otg");
-}
-
-/*-------------------------------------------------------------------------*/
-
-static u8 isp1301_clear_latch(struct isp1301 *isp)
-{
-       u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH);
-       isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch);
-       return latch;
-}
-
-static void
-isp1301_work(struct work_struct *work)
-{
-       struct isp1301  *isp = container_of(work, struct isp1301, work);
-       int             stop;
-
-       /* implicit lock:  we're the only task using this device */
-       isp->working = 1;
-       do {
-               stop = test_bit(WORK_STOP, &isp->todo);
-
-#ifdef CONFIG_USB_OTG
-               /* transfer state from otg engine to isp1301 */
-               if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
-                       otg_update_isp(isp);
-                       put_device(&isp->client->dev);
-               }
-#endif
-               /* transfer state from isp1301 to otg engine */
-               if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) {
-                       u8              stat = isp1301_clear_latch(isp);
-
-                       isp_update_otg(isp, stat);
-                       put_device(&isp->client->dev);
-               }
-
-               if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
-                       u32     otg_ctrl;
-
-                       /*
-                        * skip A_WAIT_VRISE; hc transitions invisibly
-                        * skip A_WAIT_BCON; same.
-                        */
-                       switch (isp->phy.state) {
-                       case OTG_STATE_A_WAIT_BCON:
-                       case OTG_STATE_A_WAIT_VRISE:
-                               isp->phy.state = OTG_STATE_A_HOST;
-                               pr_debug("  --> a_host\n");
-                               otg_ctrl = omap_readl(OTG_CTRL);
-                               otg_ctrl |= OTG_A_BUSREQ;
-                               otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)
-                                               & OTG_CTRL_MASK;
-                               omap_writel(otg_ctrl, OTG_CTRL);
-                               break;
-                       case OTG_STATE_B_WAIT_ACON:
-                               isp->phy.state = OTG_STATE_B_HOST;
-                               pr_debug("  --> b_host (acon)\n");
-                               break;
-                       case OTG_STATE_B_HOST:
-                       case OTG_STATE_B_IDLE:
-                       case OTG_STATE_A_IDLE:
-                               break;
-                       default:
-                               pr_debug("  host resume in %s\n",
-                                               state_name(isp));
-                       }
-                       host_resume(isp);
-                       // mdelay(10);
-                       put_device(&isp->client->dev);
-               }
-
-               if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
-#ifdef VERBOSE
-                       dump_regs(isp, "timer");
-                       if (!stop)
-                               mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
-#endif
-                       put_device(&isp->client->dev);
-               }
-
-               if (isp->todo)
-                       dev_vdbg(&isp->client->dev,
-                               "work done, todo = 0x%lx\n",
-                               isp->todo);
-               if (stop) {
-                       dev_dbg(&isp->client->dev, "stop\n");
-                       break;
-               }
-       } while (isp->todo);
-       isp->working = 0;
-}
-
-static irqreturn_t isp1301_irq(int irq, void *isp)
-{
-       isp1301_defer_work(isp, WORK_UPDATE_OTG);
-       return IRQ_HANDLED;
-}
-
-static void isp1301_timer(unsigned long _isp)
-{
-       isp1301_defer_work((void *)_isp, WORK_TIMER);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void isp1301_release(struct device *dev)
-{
-       struct isp1301  *isp;
-
-       isp = dev_get_drvdata(dev);
-
-       /* FIXME -- not with a "new style" driver, it doesn't!! */
-
-       /* ugly -- i2c hijacks our memory hook to wait_for_completion() */
-       if (isp->i2c_release)
-               isp->i2c_release(dev);
-       kfree(isp->phy.otg);
-       kfree (isp);
-}
-
-static struct isp1301 *the_transceiver;
-
-static int __exit isp1301_remove(struct i2c_client *i2c)
-{
-       struct isp1301  *isp;
-
-       isp = i2c_get_clientdata(i2c);
-
-       isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
-       isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
-       free_irq(i2c->irq, isp);
-#ifdef CONFIG_USB_OTG
-       otg_unbind(isp);
-#endif
-       if (machine_is_omap_h2())
-               gpio_free(2);
-
-       isp->timer.data = 0;
-       set_bit(WORK_STOP, &isp->todo);
-       del_timer_sync(&isp->timer);
-       flush_work(&isp->work);
-
-       put_device(&i2c->dev);
-       the_transceiver = NULL;
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* NOTE:  three modes are possible here, only one of which
- * will be standards-conformant on any given system:
- *
- *  - OTG mode (dual-role), required if there's a Mini-AB connector
- *  - HOST mode, for when there's one or more A (host) connectors
- *  - DEVICE mode, for when there's a B/Mini-B (device) connector
- *
- * As a rule, you won't have an isp1301 chip unless it's there to
- * support the OTG mode.  Other modes help testing USB controllers
- * in isolation from (full) OTG support, or maybe so later board
- * revisions can help to support those feature.
- */
-
-#ifdef CONFIG_USB_OTG
-
-static int isp1301_otg_enable(struct isp1301 *isp)
-{
-       power_up(isp);
-       isp1301_otg_init(isp);
-
-       /* NOTE:  since we don't change this, this provides
-        * a few more interrupts than are strictly needed.
-        */
-       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
-       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
-
-       dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
-
-       return 0;
-}
-
-#endif
-
-/* add or disable the host device+driver */
-static int
-isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
-
-       if (!otg || isp != the_transceiver)
-               return -ENODEV;
-
-       if (!host) {
-               omap_writew(0, OTG_IRQ_EN);
-               power_down(isp);
-               otg->host = NULL;
-               return 0;
-       }
-
-#ifdef CONFIG_USB_OTG
-       otg->host = host;
-       dev_dbg(&isp->client->dev, "registered host\n");
-       host_suspend(isp);
-       if (otg->gadget)
-               return isp1301_otg_enable(isp);
-       return 0;
-
-#elif  !defined(CONFIG_USB_GADGET_OMAP)
-       // FIXME update its refcount
-       otg->host = host;
-
-       power_up(isp);
-
-       if (machine_is_omap_h2())
-               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
-
-       dev_info(&isp->client->dev, "A-Host sessions ok\n");
-       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-               INTR_ID_GND);
-       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-               INTR_ID_GND);
-
-       /* If this has a Mini-AB connector, this mode is highly
-        * nonstandard ... but can be handy for testing, especially with
-        * the Mini-A end of an OTG cable.  (Or something nonstandard
-        * like MiniB-to-StandardB, maybe built with a gender mender.)
-        */
-       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV);
-
-       dump_regs(isp, __func__);
-
-       return 0;
-
-#else
-       dev_dbg(&isp->client->dev, "host sessions not allowed\n");
-       return -EINVAL;
-#endif
-
-}
-
-static int
-isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
-{
-       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
-
-       if (!otg || isp != the_transceiver)
-               return -ENODEV;
-
-       if (!gadget) {
-               omap_writew(0, OTG_IRQ_EN);
-               if (!otg->default_a)
-                       enable_vbus_draw(isp, 0);
-               usb_gadget_vbus_disconnect(otg->gadget);
-               otg->gadget = NULL;
-               power_down(isp);
-               return 0;
-       }
-
-#ifdef CONFIG_USB_OTG
-       otg->gadget = gadget;
-       dev_dbg(&isp->client->dev, "registered gadget\n");
-       /* gadget driver may be suspended until vbus_connect () */
-       if (otg->host)
-               return isp1301_otg_enable(isp);
-       return 0;
-
-#elif  !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE)
-       otg->gadget = gadget;
-       // FIXME update its refcount
-
-       {
-               u32 l;
-
-               l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
-               l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS);
-               l |= OTG_ID;
-               omap_writel(l, OTG_CTRL);
-       }
-
-       power_up(isp);
-       isp->phy.state = OTG_STATE_B_IDLE;
-
-       if (machine_is_omap_h2() || machine_is_omap_h3())
-               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
-
-       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-               INTR_SESS_VLD);
-       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-               INTR_VBUS_VLD);
-       dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
-       dump_regs(isp, __func__);
-
-       /* If this has a Mini-AB connector, this mode is highly
-        * nonstandard ... but can be handy for testing, so long
-        * as you don't plug a Mini-A cable into the jack.
-        */
-       if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD)
-               b_peripheral(isp);
-
-       return 0;
-
-#else
-       dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
-       return -EINVAL;
-#endif
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int
-isp1301_set_power(struct usb_phy *dev, unsigned mA)
-{
-       if (!the_transceiver)
-               return -ENODEV;
-       if (dev->state == OTG_STATE_B_PERIPHERAL)
-               enable_vbus_draw(the_transceiver, mA);
-       return 0;
-}
-
-static int
-isp1301_start_srp(struct usb_otg *otg)
-{
-       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
-       u32             otg_ctrl;
-
-       if (!otg || isp != the_transceiver
-                       || isp->phy.state != OTG_STATE_B_IDLE)
-               return -ENODEV;
-
-       otg_ctrl = omap_readl(OTG_CTRL);
-       if (!(otg_ctrl & OTG_BSESSEND))
-               return -EINVAL;
-
-       otg_ctrl |= OTG_B_BUSREQ;
-       otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK;
-       omap_writel(otg_ctrl, OTG_CTRL);
-       isp->phy.state = OTG_STATE_B_SRP_INIT;
-
-       pr_debug("otg: SRP, %s ... %06x\n", state_name(isp),
-                       omap_readl(OTG_CTRL));
-#ifdef CONFIG_USB_OTG
-       check_state(isp, __func__);
-#endif
-       return 0;
-}
-
-static int
-isp1301_start_hnp(struct usb_otg *otg)
-{
-#ifdef CONFIG_USB_OTG
-       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
-       u32 l;
-
-       if (!otg || isp != the_transceiver)
-               return -ENODEV;
-       if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable))
-               return -ENOTCONN;
-       if (!otg->default_a && (otg->gadget == NULL
-                       || !otg->gadget->b_hnp_enable))
-               return -ENOTCONN;
-
-       /* We want hardware to manage most HNP protocol timings.
-        * So do this part as early as possible...
-        */
-       switch (isp->phy.state) {
-       case OTG_STATE_B_HOST:
-               isp->phy.state = OTG_STATE_B_PERIPHERAL;
-               /* caller will suspend next */
-               break;
-       case OTG_STATE_A_HOST:
-#if 0
-               /* autoconnect mode avoids irq latency bugs */
-               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
-                               MC1_BDIS_ACON_EN);
-#endif
-               /* caller must suspend then clear A_BUSREQ */
-               usb_gadget_vbus_connect(otg->gadget);
-               l = omap_readl(OTG_CTRL);
-               l |= OTG_A_SETB_HNPEN;
-               omap_writel(l, OTG_CTRL);
-
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               /* initiated by B-Host suspend */
-               break;
-       default:
-               return -EILSEQ;
-       }
-       pr_debug("otg: HNP %s, %06x ...\n",
-               state_name(isp), omap_readl(OTG_CTRL));
-       check_state(isp, __func__);
-       return 0;
-#else
-       /* srp-only */
-       return -EINVAL;
-#endif
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int
-isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
-{
-       int                     status;
-       struct isp1301          *isp;
-
-       if (the_transceiver)
-               return 0;
-
-       isp = kzalloc(sizeof *isp, GFP_KERNEL);
-       if (!isp)
-               return 0;
-
-       isp->phy.otg = kzalloc(sizeof *isp->phy.otg, GFP_KERNEL);
-       if (!isp->phy.otg) {
-               kfree(isp);
-               return 0;
-       }
-
-       INIT_WORK(&isp->work, isp1301_work);
-       init_timer(&isp->timer);
-       isp->timer.function = isp1301_timer;
-       isp->timer.data = (unsigned long) isp;
-
-       i2c_set_clientdata(i2c, isp);
-       isp->client = i2c;
-
-       /* verify the chip (shouldn't be necessary) */
-       status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
-       if (status != I2C_VENDOR_ID_PHILIPS) {
-               dev_dbg(&i2c->dev, "not philips id: %d\n", status);
-               goto fail;
-       }
-       status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
-       if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
-               dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
-               goto fail;
-       }
-       isp->i2c_release = i2c->dev.release;
-       i2c->dev.release = isp1301_release;
-
-       /* initial development used chiprev 2.00 */
-       status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE);
-       dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n",
-               status >> 8, status & 0xff);
-
-       /* make like power-on reset */
-       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK);
-
-       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI);
-       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI);
-
-       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
-                               OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
-       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
-                               ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
-
-       isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0);
-       isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
-       isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
-
-#ifdef CONFIG_USB_OTG
-       status = otg_bind(isp);
-       if (status < 0) {
-               dev_dbg(&i2c->dev, "can't bind OTG\n");
-               goto fail;
-       }
-#endif
-
-       if (machine_is_omap_h2()) {
-               /* full speed signaling by default */
-               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
-                       MC1_SPEED);
-               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
-                       MC2_SPD_SUSP_CTRL);
-
-               /* IRQ wired at M14 */
-               omap_cfg_reg(M14_1510_GPIO2);
-               if (gpio_request(2, "isp1301") == 0)
-                       gpio_direction_input(2);
-               isp->irq_type = IRQF_TRIGGER_FALLING;
-       }
-
-       status = request_irq(i2c->irq, isp1301_irq,
-                       isp->irq_type, DRIVER_NAME, isp);
-       if (status < 0) {
-               dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
-                               i2c->irq, status);
-               goto fail;
-       }
-
-       isp->phy.dev = &i2c->dev;
-       isp->phy.label = DRIVER_NAME;
-       isp->phy.set_power = isp1301_set_power,
-
-       isp->phy.otg->phy = &isp->phy;
-       isp->phy.otg->set_host = isp1301_set_host,
-       isp->phy.otg->set_peripheral = isp1301_set_peripheral,
-       isp->phy.otg->start_srp = isp1301_start_srp,
-       isp->phy.otg->start_hnp = isp1301_start_hnp,
-
-       enable_vbus_draw(isp, 0);
-       power_down(isp);
-       the_transceiver = isp;
-
-#ifdef CONFIG_USB_OTG
-       update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
-       update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
-#endif
-
-       dump_regs(isp, __func__);
-
-#ifdef VERBOSE
-       mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
-       dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
-#endif
-
-       status = usb_add_phy(&isp->phy, USB_PHY_TYPE_USB2);
-       if (status < 0)
-               dev_err(&i2c->dev, "can't register transceiver, %d\n",
-                       status);
-
-       return 0;
-
-fail:
-       kfree(isp->phy.otg);
-       kfree(isp);
-       return -ENODEV;
-}
-
-static const struct i2c_device_id isp1301_id[] = {
-       { "isp1301_omap", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, isp1301_id);
-
-static struct i2c_driver isp1301_driver = {
-       .driver = {
-               .name   = "isp1301_omap",
-       },
-       .probe          = isp1301_probe,
-       .remove         = __exit_p(isp1301_remove),
-       .id_table       = isp1301_id,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init isp_init(void)
-{
-       return i2c_add_driver(&isp1301_driver);
-}
-subsys_initcall(isp_init);
-
-static void __exit isp_exit(void)
-{
-       if (the_transceiver)
-               usb_remove_phy(&the_transceiver->phy);
-       i2c_del_driver(&isp1301_driver);
-}
-module_exit(isp_exit);
-
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
deleted file mode 100644 (file)
index 749fbf4..0000000
+++ /dev/null
@@ -1,1762 +0,0 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/uaccess.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/usb.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/hcd.h>
-#include <linux/usb/msm_hsusb.h>
-#include <linux/usb/msm_hsusb_hw.h>
-#include <linux/regulator/consumer.h>
-
-#include <mach/clk.h>
-
-#define MSM_USB_BASE   (motg->regs)
-#define DRIVER_NAME    "msm_otg"
-
-#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
-
-#define USB_PHY_3P3_VOL_MIN    3050000 /* uV */
-#define USB_PHY_3P3_VOL_MAX    3300000 /* uV */
-#define USB_PHY_3P3_HPM_LOAD   50000   /* uA */
-#define USB_PHY_3P3_LPM_LOAD   4000    /* uA */
-
-#define USB_PHY_1P8_VOL_MIN    1800000 /* uV */
-#define USB_PHY_1P8_VOL_MAX    1800000 /* uV */
-#define USB_PHY_1P8_HPM_LOAD   50000   /* uA */
-#define USB_PHY_1P8_LPM_LOAD   4000    /* uA */
-
-#define USB_PHY_VDD_DIG_VOL_MIN        1000000 /* uV */
-#define USB_PHY_VDD_DIG_VOL_MAX        1320000 /* uV */
-
-static struct regulator *hsusb_3p3;
-static struct regulator *hsusb_1p8;
-static struct regulator *hsusb_vddcx;
-
-static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
-{
-       int ret = 0;
-
-       if (init) {
-               hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX");
-               if (IS_ERR(hsusb_vddcx)) {
-                       dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
-                       return PTR_ERR(hsusb_vddcx);
-               }
-
-               ret = regulator_set_voltage(hsusb_vddcx,
-                               USB_PHY_VDD_DIG_VOL_MIN,
-                               USB_PHY_VDD_DIG_VOL_MAX);
-               if (ret) {
-                       dev_err(motg->phy.dev, "unable to set the voltage "
-                                       "for hsusb vddcx\n");
-                       regulator_put(hsusb_vddcx);
-                       return ret;
-               }
-
-               ret = regulator_enable(hsusb_vddcx);
-               if (ret) {
-                       dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
-                       regulator_put(hsusb_vddcx);
-               }
-       } else {
-               ret = regulator_set_voltage(hsusb_vddcx, 0,
-                       USB_PHY_VDD_DIG_VOL_MAX);
-               if (ret)
-                       dev_err(motg->phy.dev, "unable to set the voltage "
-                                       "for hsusb vddcx\n");
-               ret = regulator_disable(hsusb_vddcx);
-               if (ret)
-                       dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
-
-               regulator_put(hsusb_vddcx);
-       }
-
-       return ret;
-}
-
-static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
-{
-       int rc = 0;
-
-       if (init) {
-               hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3");
-               if (IS_ERR(hsusb_3p3)) {
-                       dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
-                       return PTR_ERR(hsusb_3p3);
-               }
-
-               rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
-                               USB_PHY_3P3_VOL_MAX);
-               if (rc) {
-                       dev_err(motg->phy.dev, "unable to set voltage level "
-                                       "for hsusb 3p3\n");
-                       goto put_3p3;
-               }
-               rc = regulator_enable(hsusb_3p3);
-               if (rc) {
-                       dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
-                       goto put_3p3;
-               }
-               hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8");
-               if (IS_ERR(hsusb_1p8)) {
-                       dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
-                       rc = PTR_ERR(hsusb_1p8);
-                       goto disable_3p3;
-               }
-               rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
-                               USB_PHY_1P8_VOL_MAX);
-               if (rc) {
-                       dev_err(motg->phy.dev, "unable to set voltage level "
-                                       "for hsusb 1p8\n");
-                       goto put_1p8;
-               }
-               rc = regulator_enable(hsusb_1p8);
-               if (rc) {
-                       dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
-                       goto put_1p8;
-               }
-
-               return 0;
-       }
-
-       regulator_disable(hsusb_1p8);
-put_1p8:
-       regulator_put(hsusb_1p8);
-disable_3p3:
-       regulator_disable(hsusb_3p3);
-put_3p3:
-       regulator_put(hsusb_3p3);
-       return rc;
-}
-
-#ifdef CONFIG_PM_SLEEP
-#define USB_PHY_SUSP_DIG_VOL  500000
-static int msm_hsusb_config_vddcx(int high)
-{
-       int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
-       int min_vol;
-       int ret;
-
-       if (high)
-               min_vol = USB_PHY_VDD_DIG_VOL_MIN;
-       else
-               min_vol = USB_PHY_SUSP_DIG_VOL;
-
-       ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
-       if (ret) {
-               pr_err("%s: unable to set the voltage for regulator "
-                       "HSUSB_VDDCX\n", __func__);
-               return ret;
-       }
-
-       pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
-
-       return ret;
-}
-#endif
-
-static int msm_hsusb_ldo_set_mode(int on)
-{
-       int ret = 0;
-
-       if (!hsusb_1p8 || IS_ERR(hsusb_1p8)) {
-               pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
-               return -ENODEV;
-       }
-
-       if (!hsusb_3p3 || IS_ERR(hsusb_3p3)) {
-               pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
-               return -ENODEV;
-       }
-
-       if (on) {
-               ret = regulator_set_optimum_mode(hsusb_1p8,
-                               USB_PHY_1P8_HPM_LOAD);
-               if (ret < 0) {
-                       pr_err("%s: Unable to set HPM of the regulator "
-                               "HSUSB_1p8\n", __func__);
-                       return ret;
-               }
-               ret = regulator_set_optimum_mode(hsusb_3p3,
-                               USB_PHY_3P3_HPM_LOAD);
-               if (ret < 0) {
-                       pr_err("%s: Unable to set HPM of the regulator "
-                               "HSUSB_3p3\n", __func__);
-                       regulator_set_optimum_mode(hsusb_1p8,
-                               USB_PHY_1P8_LPM_LOAD);
-                       return ret;
-               }
-       } else {
-               ret = regulator_set_optimum_mode(hsusb_1p8,
-                               USB_PHY_1P8_LPM_LOAD);
-               if (ret < 0)
-                       pr_err("%s: Unable to set LPM of the regulator "
-                               "HSUSB_1p8\n", __func__);
-               ret = regulator_set_optimum_mode(hsusb_3p3,
-                               USB_PHY_3P3_LPM_LOAD);
-               if (ret < 0)
-                       pr_err("%s: Unable to set LPM of the regulator "
-                               "HSUSB_3p3\n", __func__);
-       }
-
-       pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
-       return ret < 0 ? ret : 0;
-}
-
-static int ulpi_read(struct usb_phy *phy, u32 reg)
-{
-       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
-       int cnt = 0;
-
-       /* initiate read operation */
-       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
-              USB_ULPI_VIEWPORT);
-
-       /* wait for completion */
-       while (cnt < ULPI_IO_TIMEOUT_USEC) {
-               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
-                       break;
-               udelay(1);
-               cnt++;
-       }
-
-       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
-               dev_err(phy->dev, "ulpi_read: timeout %08x\n",
-                       readl(USB_ULPI_VIEWPORT));
-               return -ETIMEDOUT;
-       }
-       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
-}
-
-static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
-{
-       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
-       int cnt = 0;
-
-       /* initiate write operation */
-       writel(ULPI_RUN | ULPI_WRITE |
-              ULPI_ADDR(reg) | ULPI_DATA(val),
-              USB_ULPI_VIEWPORT);
-
-       /* wait for completion */
-       while (cnt < ULPI_IO_TIMEOUT_USEC) {
-               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
-                       break;
-               udelay(1);
-               cnt++;
-       }
-
-       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
-               dev_err(phy->dev, "ulpi_write: timeout\n");
-               return -ETIMEDOUT;
-       }
-       return 0;
-}
-
-static struct usb_phy_io_ops msm_otg_io_ops = {
-       .read = ulpi_read,
-       .write = ulpi_write,
-};
-
-static void ulpi_init(struct msm_otg *motg)
-{
-       struct msm_otg_platform_data *pdata = motg->pdata;
-       int *seq = pdata->phy_init_seq;
-
-       if (!seq)
-               return;
-
-       while (seq[0] >= 0) {
-               dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
-                               seq[0], seq[1]);
-               ulpi_write(&motg->phy, seq[0], seq[1]);
-               seq += 2;
-       }
-}
-
-static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
-{
-       int ret;
-
-       if (assert) {
-               ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
-               if (ret)
-                       dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
-       } else {
-               ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
-               if (ret)
-                       dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
-       }
-       return ret;
-}
-
-static int msm_otg_phy_clk_reset(struct msm_otg *motg)
-{
-       int ret;
-
-       ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
-       if (ret) {
-               dev_err(motg->phy.dev, "usb phy clk assert failed\n");
-               return ret;
-       }
-       usleep_range(10000, 12000);
-       ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
-       if (ret)
-               dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
-       return ret;
-}
-
-static int msm_otg_phy_reset(struct msm_otg *motg)
-{
-       u32 val;
-       int ret;
-       int retries;
-
-       ret = msm_otg_link_clk_reset(motg, 1);
-       if (ret)
-               return ret;
-       ret = msm_otg_phy_clk_reset(motg);
-       if (ret)
-               return ret;
-       ret = msm_otg_link_clk_reset(motg, 0);
-       if (ret)
-               return ret;
-
-       val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
-       writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
-
-       for (retries = 3; retries > 0; retries--) {
-               ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
-                               ULPI_CLR(ULPI_FUNC_CTRL));
-               if (!ret)
-                       break;
-               ret = msm_otg_phy_clk_reset(motg);
-               if (ret)
-                       return ret;
-       }
-       if (!retries)
-               return -ETIMEDOUT;
-
-       /* This reset calibrates the phy, if the above write succeeded */
-       ret = msm_otg_phy_clk_reset(motg);
-       if (ret)
-               return ret;
-
-       for (retries = 3; retries > 0; retries--) {
-               ret = ulpi_read(&motg->phy, ULPI_DEBUG);
-               if (ret != -ETIMEDOUT)
-                       break;
-               ret = msm_otg_phy_clk_reset(motg);
-               if (ret)
-                       return ret;
-       }
-       if (!retries)
-               return -ETIMEDOUT;
-
-       dev_info(motg->phy.dev, "phy_reset: success\n");
-       return 0;
-}
-
-#define LINK_RESET_TIMEOUT_USEC                (250 * 1000)
-static int msm_otg_reset(struct usb_phy *phy)
-{
-       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
-       struct msm_otg_platform_data *pdata = motg->pdata;
-       int cnt = 0;
-       int ret;
-       u32 val = 0;
-       u32 ulpi_val = 0;
-
-       ret = msm_otg_phy_reset(motg);
-       if (ret) {
-               dev_err(phy->dev, "phy_reset failed\n");
-               return ret;
-       }
-
-       ulpi_init(motg);
-
-       writel(USBCMD_RESET, USB_USBCMD);
-       while (cnt < LINK_RESET_TIMEOUT_USEC) {
-               if (!(readl(USB_USBCMD) & USBCMD_RESET))
-                       break;
-               udelay(1);
-               cnt++;
-       }
-       if (cnt >= LINK_RESET_TIMEOUT_USEC)
-               return -ETIMEDOUT;
-
-       /* select ULPI phy */
-       writel(0x80000000, USB_PORTSC);
-
-       msleep(100);
-
-       writel(0x0, USB_AHBBURST);
-       writel(0x00, USB_AHBMODE);
-
-       if (pdata->otg_control == OTG_PHY_CONTROL) {
-               val = readl(USB_OTGSC);
-               if (pdata->mode == USB_OTG) {
-                       ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
-                       val |= OTGSC_IDIE | OTGSC_BSVIE;
-               } else if (pdata->mode == USB_PERIPHERAL) {
-                       ulpi_val = ULPI_INT_SESS_VALID;
-                       val |= OTGSC_BSVIE;
-               }
-               writel(val, USB_OTGSC);
-               ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
-               ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
-       }
-
-       return 0;
-}
-
-#define PHY_SUSPEND_TIMEOUT_USEC       (500 * 1000)
-#define PHY_RESUME_TIMEOUT_USEC        (100 * 1000)
-
-#ifdef CONFIG_PM_SLEEP
-static int msm_otg_suspend(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       struct usb_bus *bus = phy->otg->host;
-       struct msm_otg_platform_data *pdata = motg->pdata;
-       int cnt = 0;
-
-       if (atomic_read(&motg->in_lpm))
-               return 0;
-
-       disable_irq(motg->irq);
-       /*
-        * Chipidea 45-nm PHY suspend sequence:
-        *
-        * Interrupt Latch Register auto-clear feature is not present
-        * in all PHY versions. Latch register is clear on read type.
-        * Clear latch register to avoid spurious wakeup from
-        * low power mode (LPM).
-        *
-        * PHY comparators are disabled when PHY enters into low power
-        * mode (LPM). Keep PHY comparators ON in LPM only when we expect
-        * VBUS/Id notifications from USB PHY. Otherwise turn off USB
-        * PHY comparators. This save significant amount of power.
-        *
-        * PLL is not turned off when PHY enters into low power mode (LPM).
-        * Disable PLL for maximum power savings.
-        */
-
-       if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
-               ulpi_read(phy, 0x14);
-               if (pdata->otg_control == OTG_PHY_CONTROL)
-                       ulpi_write(phy, 0x01, 0x30);
-               ulpi_write(phy, 0x08, 0x09);
-       }
-
-       /*
-        * PHY may take some time or even fail to enter into low power
-        * mode (LPM). Hence poll for 500 msec and reset the PHY and link
-        * in failure case.
-        */
-       writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
-       while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
-               if (readl(USB_PORTSC) & PORTSC_PHCD)
-                       break;
-               udelay(1);
-               cnt++;
-       }
-
-       if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
-               dev_err(phy->dev, "Unable to suspend PHY\n");
-               msm_otg_reset(phy);
-               enable_irq(motg->irq);
-               return -ETIMEDOUT;
-       }
-
-       /*
-        * PHY has capability to generate interrupt asynchronously in low
-        * power mode (LPM). This interrupt is level triggered. So USB IRQ
-        * line must be disabled till async interrupt enable bit is cleared
-        * in USBCMD register. Assert STP (ULPI interface STOP signal) to
-        * block data communication from PHY.
-        */
-       writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
-
-       if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
-                       motg->pdata->otg_control == OTG_PMIC_CONTROL)
-               writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL);
-
-       clk_disable(motg->pclk);
-       clk_disable(motg->clk);
-       if (motg->core_clk)
-               clk_disable(motg->core_clk);
-
-       if (!IS_ERR(motg->pclk_src))
-               clk_disable(motg->pclk_src);
-
-       if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
-                       motg->pdata->otg_control == OTG_PMIC_CONTROL) {
-               msm_hsusb_ldo_set_mode(0);
-               msm_hsusb_config_vddcx(0);
-       }
-
-       if (device_may_wakeup(phy->dev))
-               enable_irq_wake(motg->irq);
-       if (bus)
-               clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
-
-       atomic_set(&motg->in_lpm, 1);
-       enable_irq(motg->irq);
-
-       dev_info(phy->dev, "USB in low power mode\n");
-
-       return 0;
-}
-
-static int msm_otg_resume(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       struct usb_bus *bus = phy->otg->host;
-       int cnt = 0;
-       unsigned temp;
-
-       if (!atomic_read(&motg->in_lpm))
-               return 0;
-
-       if (!IS_ERR(motg->pclk_src))
-               clk_enable(motg->pclk_src);
-
-       clk_enable(motg->pclk);
-       clk_enable(motg->clk);
-       if (motg->core_clk)
-               clk_enable(motg->core_clk);
-
-       if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
-                       motg->pdata->otg_control == OTG_PMIC_CONTROL) {
-               msm_hsusb_ldo_set_mode(1);
-               msm_hsusb_config_vddcx(1);
-               writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL);
-       }
-
-       temp = readl(USB_USBCMD);
-       temp &= ~ASYNC_INTR_CTRL;
-       temp &= ~ULPI_STP_CTRL;
-       writel(temp, USB_USBCMD);
-
-       /*
-        * PHY comes out of low power mode (LPM) in case of wakeup
-        * from asynchronous interrupt.
-        */
-       if (!(readl(USB_PORTSC) & PORTSC_PHCD))
-               goto skip_phy_resume;
-
-       writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
-       while (cnt < PHY_RESUME_TIMEOUT_USEC) {
-               if (!(readl(USB_PORTSC) & PORTSC_PHCD))
-                       break;
-               udelay(1);
-               cnt++;
-       }
-
-       if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
-               /*
-                * This is a fatal error. Reset the link and
-                * PHY. USB state can not be restored. Re-insertion
-                * of USB cable is the only way to get USB working.
-                */
-               dev_err(phy->dev, "Unable to resume USB."
-                               "Re-plugin the cable\n");
-               msm_otg_reset(phy);
-       }
-
-skip_phy_resume:
-       if (device_may_wakeup(phy->dev))
-               disable_irq_wake(motg->irq);
-       if (bus)
-               set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
-
-       atomic_set(&motg->in_lpm, 0);
-
-       if (motg->async_int) {
-               motg->async_int = 0;
-               pm_runtime_put(phy->dev);
-               enable_irq(motg->irq);
-       }
-
-       dev_info(phy->dev, "USB exited from low power mode\n");
-
-       return 0;
-}
-#endif
-
-static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
-{
-       if (motg->cur_power == mA)
-               return;
-
-       /* TODO: Notify PMIC about available current */
-       dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
-       motg->cur_power = mA;
-}
-
-static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
-{
-       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
-
-       /*
-        * Gadget driver uses set_power method to notify about the
-        * available current based on suspend/configured states.
-        *
-        * IDEV_CHG can be drawn irrespective of suspend/un-configured
-        * states when CDP/ACA is connected.
-        */
-       if (motg->chg_type == USB_SDP_CHARGER)
-               msm_otg_notify_charger(motg, mA);
-
-       return 0;
-}
-
-static void msm_otg_start_host(struct usb_phy *phy, int on)
-{
-       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
-       struct msm_otg_platform_data *pdata = motg->pdata;
-       struct usb_hcd *hcd;
-
-       if (!phy->otg->host)
-               return;
-
-       hcd = bus_to_hcd(phy->otg->host);
-
-       if (on) {
-               dev_dbg(phy->dev, "host on\n");
-
-               if (pdata->vbus_power)
-                       pdata->vbus_power(1);
-               /*
-                * Some boards have a switch cotrolled by gpio
-                * to enable/disable internal HUB. Enable internal
-                * HUB before kicking the host.
-                */
-               if (pdata->setup_gpio)
-                       pdata->setup_gpio(OTG_STATE_A_HOST);
-#ifdef CONFIG_USB
-               usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
-#endif
-       } else {
-               dev_dbg(phy->dev, "host off\n");
-
-#ifdef CONFIG_USB
-               usb_remove_hcd(hcd);
-#endif
-               if (pdata->setup_gpio)
-                       pdata->setup_gpio(OTG_STATE_UNDEFINED);
-               if (pdata->vbus_power)
-                       pdata->vbus_power(0);
-       }
-}
-
-static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
-       struct usb_hcd *hcd;
-
-       /*
-        * Fail host registration if this board can support
-        * only peripheral configuration.
-        */
-       if (motg->pdata->mode == USB_PERIPHERAL) {
-               dev_info(otg->phy->dev, "Host mode is not supported\n");
-               return -ENODEV;
-       }
-
-       if (!host) {
-               if (otg->phy->state == OTG_STATE_A_HOST) {
-                       pm_runtime_get_sync(otg->phy->dev);
-                       msm_otg_start_host(otg->phy, 0);
-                       otg->host = NULL;
-                       otg->phy->state = OTG_STATE_UNDEFINED;
-                       schedule_work(&motg->sm_work);
-               } else {
-                       otg->host = NULL;
-               }
-
-               return 0;
-       }
-
-       hcd = bus_to_hcd(host);
-       hcd->power_budget = motg->pdata->power_budget;
-
-       otg->host = host;
-       dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
-
-       /*
-        * Kick the state machine work, if peripheral is not supported
-        * or peripheral is already registered with us.
-        */
-       if (motg->pdata->mode == USB_HOST || otg->gadget) {
-               pm_runtime_get_sync(otg->phy->dev);
-               schedule_work(&motg->sm_work);
-       }
-
-       return 0;
-}
-
-static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
-{
-       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
-       struct msm_otg_platform_data *pdata = motg->pdata;
-
-       if (!phy->otg->gadget)
-               return;
-
-       if (on) {
-               dev_dbg(phy->dev, "gadget on\n");
-               /*
-                * Some boards have a switch cotrolled by gpio
-                * to enable/disable internal HUB. Disable internal
-                * HUB before kicking the gadget.
-                */
-               if (pdata->setup_gpio)
-                       pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
-               usb_gadget_vbus_connect(phy->otg->gadget);
-       } else {
-               dev_dbg(phy->dev, "gadget off\n");
-               usb_gadget_vbus_disconnect(phy->otg->gadget);
-               if (pdata->setup_gpio)
-                       pdata->setup_gpio(OTG_STATE_UNDEFINED);
-       }
-
-}
-
-static int msm_otg_set_peripheral(struct usb_otg *otg,
-                                       struct usb_gadget *gadget)
-{
-       struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
-
-       /*
-        * Fail peripheral registration if this board can support
-        * only host configuration.
-        */
-       if (motg->pdata->mode == USB_HOST) {
-               dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
-               return -ENODEV;
-       }
-
-       if (!gadget) {
-               if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
-                       pm_runtime_get_sync(otg->phy->dev);
-                       msm_otg_start_peripheral(otg->phy, 0);
-                       otg->gadget = NULL;
-                       otg->phy->state = OTG_STATE_UNDEFINED;
-                       schedule_work(&motg->sm_work);
-               } else {
-                       otg->gadget = NULL;
-               }
-
-               return 0;
-       }
-       otg->gadget = gadget;
-       dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
-
-       /*
-        * Kick the state machine work, if host is not supported
-        * or host is already registered with us.
-        */
-       if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
-               pm_runtime_get_sync(otg->phy->dev);
-               schedule_work(&motg->sm_work);
-       }
-
-       return 0;
-}
-
-static bool msm_chg_check_secondary_det(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 chg_det;
-       bool ret = false;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               ret = chg_det & (1 << 4);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x87);
-               ret = chg_det & 1;
-               break;
-       default:
-               break;
-       }
-       return ret;
-}
-
-static void msm_chg_enable_secondary_det(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 chg_det;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               /* Turn off charger block */
-               chg_det |= ~(1 << 1);
-               ulpi_write(phy, chg_det, 0x34);
-               udelay(20);
-               /* control chg block via ULPI */
-               chg_det &= ~(1 << 3);
-               ulpi_write(phy, chg_det, 0x34);
-               /* put it in host mode for enabling D- source */
-               chg_det &= ~(1 << 2);
-               ulpi_write(phy, chg_det, 0x34);
-               /* Turn on chg detect block */
-               chg_det &= ~(1 << 1);
-               ulpi_write(phy, chg_det, 0x34);
-               udelay(20);
-               /* enable chg detection */
-               chg_det &= ~(1 << 0);
-               ulpi_write(phy, chg_det, 0x34);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               /*
-                * Configure DM as current source, DP as current sink
-                * and enable battery charging comparators.
-                */
-               ulpi_write(phy, 0x8, 0x85);
-               ulpi_write(phy, 0x2, 0x85);
-               ulpi_write(phy, 0x1, 0x85);
-               break;
-       default:
-               break;
-       }
-}
-
-static bool msm_chg_check_primary_det(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 chg_det;
-       bool ret = false;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               ret = chg_det & (1 << 4);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x87);
-               ret = chg_det & 1;
-               break;
-       default:
-               break;
-       }
-       return ret;
-}
-
-static void msm_chg_enable_primary_det(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 chg_det;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               /* enable chg detection */
-               chg_det &= ~(1 << 0);
-               ulpi_write(phy, chg_det, 0x34);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               /*
-                * Configure DP as current source, DM as current sink
-                * and enable battery charging comparators.
-                */
-               ulpi_write(phy, 0x2, 0x85);
-               ulpi_write(phy, 0x1, 0x85);
-               break;
-       default:
-               break;
-       }
-}
-
-static bool msm_chg_check_dcd(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 line_state;
-       bool ret = false;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               line_state = ulpi_read(phy, 0x15);
-               ret = !(line_state & 1);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               line_state = ulpi_read(phy, 0x87);
-               ret = line_state & 2;
-               break;
-       default:
-               break;
-       }
-       return ret;
-}
-
-static void msm_chg_disable_dcd(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 chg_det;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               chg_det &= ~(1 << 5);
-               ulpi_write(phy, chg_det, 0x34);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               ulpi_write(phy, 0x10, 0x86);
-               break;
-       default:
-               break;
-       }
-}
-
-static void msm_chg_enable_dcd(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 chg_det;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               /* Turn on D+ current source */
-               chg_det |= (1 << 5);
-               ulpi_write(phy, chg_det, 0x34);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               /* Data contact detection enable */
-               ulpi_write(phy, 0x10, 0x85);
-               break;
-       default:
-               break;
-       }
-}
-
-static void msm_chg_block_on(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 func_ctrl, chg_det;
-
-       /* put the controller in non-driving mode */
-       func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
-       func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
-       func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
-       ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               /* control chg block via ULPI */
-               chg_det &= ~(1 << 3);
-               ulpi_write(phy, chg_det, 0x34);
-               /* Turn on chg detect block */
-               chg_det &= ~(1 << 1);
-               ulpi_write(phy, chg_det, 0x34);
-               udelay(20);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               /* Clear charger detecting control bits */
-               ulpi_write(phy, 0x3F, 0x86);
-               /* Clear alt interrupt latch and enable bits */
-               ulpi_write(phy, 0x1F, 0x92);
-               ulpi_write(phy, 0x1F, 0x95);
-               udelay(100);
-               break;
-       default:
-               break;
-       }
-}
-
-static void msm_chg_block_off(struct msm_otg *motg)
-{
-       struct usb_phy *phy = &motg->phy;
-       u32 func_ctrl, chg_det;
-
-       switch (motg->pdata->phy_type) {
-       case CI_45NM_INTEGRATED_PHY:
-               chg_det = ulpi_read(phy, 0x34);
-               /* Turn off charger block */
-               chg_det |= ~(1 << 1);
-               ulpi_write(phy, chg_det, 0x34);
-               break;
-       case SNPS_28NM_INTEGRATED_PHY:
-               /* Clear charger detecting control bits */
-               ulpi_write(phy, 0x3F, 0x86);
-               /* Clear alt interrupt latch and enable bits */
-               ulpi_write(phy, 0x1F, 0x92);
-               ulpi_write(phy, 0x1F, 0x95);
-               break;
-       default:
-               break;
-       }
-
-       /* put the controller in normal mode */
-       func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
-       func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
-       func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
-       ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
-}
-
-#define MSM_CHG_DCD_POLL_TIME          (100 * HZ/1000) /* 100 msec */
-#define MSM_CHG_DCD_MAX_RETRIES                6 /* Tdcd_tmout = 6 * 100 msec */
-#define MSM_CHG_PRIMARY_DET_TIME       (40 * HZ/1000) /* TVDPSRC_ON */
-#define MSM_CHG_SECONDARY_DET_TIME     (40 * HZ/1000) /* TVDMSRC_ON */
-static void msm_chg_detect_work(struct work_struct *w)
-{
-       struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
-       struct usb_phy *phy = &motg->phy;
-       bool is_dcd, tmout, vout;
-       unsigned long delay;
-
-       dev_dbg(phy->dev, "chg detection work\n");
-       switch (motg->chg_state) {
-       case USB_CHG_STATE_UNDEFINED:
-               pm_runtime_get_sync(phy->dev);
-               msm_chg_block_on(motg);
-               msm_chg_enable_dcd(motg);
-               motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
-               motg->dcd_retries = 0;
-               delay = MSM_CHG_DCD_POLL_TIME;
-               break;
-       case USB_CHG_STATE_WAIT_FOR_DCD:
-               is_dcd = msm_chg_check_dcd(motg);
-               tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
-               if (is_dcd || tmout) {
-                       msm_chg_disable_dcd(motg);
-                       msm_chg_enable_primary_det(motg);
-                       delay = MSM_CHG_PRIMARY_DET_TIME;
-                       motg->chg_state = USB_CHG_STATE_DCD_DONE;
-               } else {
-                       delay = MSM_CHG_DCD_POLL_TIME;
-               }
-               break;
-       case USB_CHG_STATE_DCD_DONE:
-               vout = msm_chg_check_primary_det(motg);
-               if (vout) {
-                       msm_chg_enable_secondary_det(motg);
-                       delay = MSM_CHG_SECONDARY_DET_TIME;
-                       motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
-               } else {
-                       motg->chg_type = USB_SDP_CHARGER;
-                       motg->chg_state = USB_CHG_STATE_DETECTED;
-                       delay = 0;
-               }
-               break;
-       case USB_CHG_STATE_PRIMARY_DONE:
-               vout = msm_chg_check_secondary_det(motg);
-               if (vout)
-                       motg->chg_type = USB_DCP_CHARGER;
-               else
-                       motg->chg_type = USB_CDP_CHARGER;
-               motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
-               /* fall through */
-       case USB_CHG_STATE_SECONDARY_DONE:
-               motg->chg_state = USB_CHG_STATE_DETECTED;
-       case USB_CHG_STATE_DETECTED:
-               msm_chg_block_off(motg);
-               dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
-               schedule_work(&motg->sm_work);
-               return;
-       default:
-               return;
-       }
-
-       schedule_delayed_work(&motg->chg_work, delay);
-}
-
-/*
- * We support OTG, Peripheral only and Host only configurations. In case
- * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
- * via Id pin status or user request (debugfs). Id/BSV interrupts are not
- * enabled when switch is controlled by user and default mode is supplied
- * by board file, which can be changed by userspace later.
- */
-static void msm_otg_init_sm(struct msm_otg *motg)
-{
-       struct msm_otg_platform_data *pdata = motg->pdata;
-       u32 otgsc = readl(USB_OTGSC);
-
-       switch (pdata->mode) {
-       case USB_OTG:
-               if (pdata->otg_control == OTG_PHY_CONTROL) {
-                       if (otgsc & OTGSC_ID)
-                               set_bit(ID, &motg->inputs);
-                       else
-                               clear_bit(ID, &motg->inputs);
-
-                       if (otgsc & OTGSC_BSV)
-                               set_bit(B_SESS_VLD, &motg->inputs);
-                       else
-                               clear_bit(B_SESS_VLD, &motg->inputs);
-               } else if (pdata->otg_control == OTG_USER_CONTROL) {
-                       if (pdata->default_mode == USB_HOST) {
-                               clear_bit(ID, &motg->inputs);
-                       } else if (pdata->default_mode == USB_PERIPHERAL) {
-                               set_bit(ID, &motg->inputs);
-                               set_bit(B_SESS_VLD, &motg->inputs);
-                       } else {
-                               set_bit(ID, &motg->inputs);
-                               clear_bit(B_SESS_VLD, &motg->inputs);
-                       }
-               }
-               break;
-       case USB_HOST:
-               clear_bit(ID, &motg->inputs);
-               break;
-       case USB_PERIPHERAL:
-               set_bit(ID, &motg->inputs);
-               if (otgsc & OTGSC_BSV)
-                       set_bit(B_SESS_VLD, &motg->inputs);
-               else
-                       clear_bit(B_SESS_VLD, &motg->inputs);
-               break;
-       default:
-               break;
-       }
-}
-
-static void msm_otg_sm_work(struct work_struct *w)
-{
-       struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
-       struct usb_otg *otg = motg->phy.otg;
-
-       switch (otg->phy->state) {
-       case OTG_STATE_UNDEFINED:
-               dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n");
-               msm_otg_reset(otg->phy);
-               msm_otg_init_sm(motg);
-               otg->phy->state = OTG_STATE_B_IDLE;
-               /* FALL THROUGH */
-       case OTG_STATE_B_IDLE:
-               dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n");
-               if (!test_bit(ID, &motg->inputs) && otg->host) {
-                       /* disable BSV bit */
-                       writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
-                       msm_otg_start_host(otg->phy, 1);
-                       otg->phy->state = OTG_STATE_A_HOST;
-               } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
-                       switch (motg->chg_state) {
-                       case USB_CHG_STATE_UNDEFINED:
-                               msm_chg_detect_work(&motg->chg_work.work);
-                               break;
-                       case USB_CHG_STATE_DETECTED:
-                               switch (motg->chg_type) {
-                               case USB_DCP_CHARGER:
-                                       msm_otg_notify_charger(motg,
-                                                       IDEV_CHG_MAX);
-                                       break;
-                               case USB_CDP_CHARGER:
-                                       msm_otg_notify_charger(motg,
-                                                       IDEV_CHG_MAX);
-                                       msm_otg_start_peripheral(otg->phy, 1);
-                                       otg->phy->state
-                                               = OTG_STATE_B_PERIPHERAL;
-                                       break;
-                               case USB_SDP_CHARGER:
-                                       msm_otg_notify_charger(motg, IUNIT);
-                                       msm_otg_start_peripheral(otg->phy, 1);
-                                       otg->phy->state
-                                               = OTG_STATE_B_PERIPHERAL;
-                                       break;
-                               default:
-                                       break;
-                               }
-                               break;
-                       default:
-                               break;
-                       }
-               } else {
-                       /*
-                        * If charger detection work is pending, decrement
-                        * the pm usage counter to balance with the one that
-                        * is incremented in charger detection work.
-                        */
-                       if (cancel_delayed_work_sync(&motg->chg_work)) {
-                               pm_runtime_put_sync(otg->phy->dev);
-                               msm_otg_reset(otg->phy);
-                       }
-                       msm_otg_notify_charger(motg, 0);
-                       motg->chg_state = USB_CHG_STATE_UNDEFINED;
-                       motg->chg_type = USB_INVALID_CHARGER;
-               }
-               pm_runtime_put_sync(otg->phy->dev);
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
-               if (!test_bit(B_SESS_VLD, &motg->inputs) ||
-                               !test_bit(ID, &motg->inputs)) {
-                       msm_otg_notify_charger(motg, 0);
-                       msm_otg_start_peripheral(otg->phy, 0);
-                       motg->chg_state = USB_CHG_STATE_UNDEFINED;
-                       motg->chg_type = USB_INVALID_CHARGER;
-                       otg->phy->state = OTG_STATE_B_IDLE;
-                       msm_otg_reset(otg->phy);
-                       schedule_work(w);
-               }
-               break;
-       case OTG_STATE_A_HOST:
-               dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n");
-               if (test_bit(ID, &motg->inputs)) {
-                       msm_otg_start_host(otg->phy, 0);
-                       otg->phy->state = OTG_STATE_B_IDLE;
-                       msm_otg_reset(otg->phy);
-                       schedule_work(w);
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static irqreturn_t msm_otg_irq(int irq, void *data)
-{
-       struct msm_otg *motg = data;
-       struct usb_phy *phy = &motg->phy;
-       u32 otgsc = 0;
-
-       if (atomic_read(&motg->in_lpm)) {
-               disable_irq_nosync(irq);
-               motg->async_int = 1;
-               pm_runtime_get(phy->dev);
-               return IRQ_HANDLED;
-       }
-
-       otgsc = readl(USB_OTGSC);
-       if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
-               return IRQ_NONE;
-
-       if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
-               if (otgsc & OTGSC_ID)
-                       set_bit(ID, &motg->inputs);
-               else
-                       clear_bit(ID, &motg->inputs);
-               dev_dbg(phy->dev, "ID set/clear\n");
-               pm_runtime_get_noresume(phy->dev);
-       } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
-               if (otgsc & OTGSC_BSV)
-                       set_bit(B_SESS_VLD, &motg->inputs);
-               else
-                       clear_bit(B_SESS_VLD, &motg->inputs);
-               dev_dbg(phy->dev, "BSV set/clear\n");
-               pm_runtime_get_noresume(phy->dev);
-       }
-
-       writel(otgsc, USB_OTGSC);
-       schedule_work(&motg->sm_work);
-       return IRQ_HANDLED;
-}
-
-static int msm_otg_mode_show(struct seq_file *s, void *unused)
-{
-       struct msm_otg *motg = s->private;
-       struct usb_otg *otg = motg->phy.otg;
-
-       switch (otg->phy->state) {
-       case OTG_STATE_A_HOST:
-               seq_printf(s, "host\n");
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               seq_printf(s, "peripheral\n");
-               break;
-       default:
-               seq_printf(s, "none\n");
-               break;
-       }
-
-       return 0;
-}
-
-static int msm_otg_mode_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, msm_otg_mode_show, inode->i_private);
-}
-
-static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
-                               size_t count, loff_t *ppos)
-{
-       struct seq_file *s = file->private_data;
-       struct msm_otg *motg = s->private;
-       char buf[16];
-       struct usb_otg *otg = motg->phy.otg;
-       int status = count;
-       enum usb_mode_type req_mode;
-
-       memset(buf, 0x00, sizeof(buf));
-
-       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
-               status = -EFAULT;
-               goto out;
-       }
-
-       if (!strncmp(buf, "host", 4)) {
-               req_mode = USB_HOST;
-       } else if (!strncmp(buf, "peripheral", 10)) {
-               req_mode = USB_PERIPHERAL;
-       } else if (!strncmp(buf, "none", 4)) {
-               req_mode = USB_NONE;
-       } else {
-               status = -EINVAL;
-               goto out;
-       }
-
-       switch (req_mode) {
-       case USB_NONE:
-               switch (otg->phy->state) {
-               case OTG_STATE_A_HOST:
-               case OTG_STATE_B_PERIPHERAL:
-                       set_bit(ID, &motg->inputs);
-                       clear_bit(B_SESS_VLD, &motg->inputs);
-                       break;
-               default:
-                       goto out;
-               }
-               break;
-       case USB_PERIPHERAL:
-               switch (otg->phy->state) {
-               case OTG_STATE_B_IDLE:
-               case OTG_STATE_A_HOST:
-                       set_bit(ID, &motg->inputs);
-                       set_bit(B_SESS_VLD, &motg->inputs);
-                       break;
-               default:
-                       goto out;
-               }
-               break;
-       case USB_HOST:
-               switch (otg->phy->state) {
-               case OTG_STATE_B_IDLE:
-               case OTG_STATE_B_PERIPHERAL:
-                       clear_bit(ID, &motg->inputs);
-                       break;
-               default:
-                       goto out;
-               }
-               break;
-       default:
-               goto out;
-       }
-
-       pm_runtime_get_sync(otg->phy->dev);
-       schedule_work(&motg->sm_work);
-out:
-       return status;
-}
-
-const struct file_operations msm_otg_mode_fops = {
-       .open = msm_otg_mode_open,
-       .read = seq_read,
-       .write = msm_otg_mode_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static struct dentry *msm_otg_dbg_root;
-static struct dentry *msm_otg_dbg_mode;
-
-static int msm_otg_debugfs_init(struct msm_otg *motg)
-{
-       msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
-
-       if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
-               return -ENODEV;
-
-       msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
-                               msm_otg_dbg_root, motg, &msm_otg_mode_fops);
-       if (!msm_otg_dbg_mode) {
-               debugfs_remove(msm_otg_dbg_root);
-               msm_otg_dbg_root = NULL;
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static void msm_otg_debugfs_cleanup(void)
-{
-       debugfs_remove(msm_otg_dbg_mode);
-       debugfs_remove(msm_otg_dbg_root);
-}
-
-static int __init msm_otg_probe(struct platform_device *pdev)
-{
-       int ret = 0;
-       struct resource *res;
-       struct msm_otg *motg;
-       struct usb_phy *phy;
-
-       dev_info(&pdev->dev, "msm_otg probe\n");
-       if (!pdev->dev.platform_data) {
-               dev_err(&pdev->dev, "No platform data given. Bailing out\n");
-               return -ENODEV;
-       }
-
-       motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
-       if (!motg) {
-               dev_err(&pdev->dev, "unable to allocate msm_otg\n");
-               return -ENOMEM;
-       }
-
-       motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
-       if (!motg->phy.otg) {
-               dev_err(&pdev->dev, "unable to allocate msm_otg\n");
-               return -ENOMEM;
-       }
-
-       motg->pdata = pdev->dev.platform_data;
-       phy = &motg->phy;
-       phy->dev = &pdev->dev;
-
-       motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
-       if (IS_ERR(motg->phy_reset_clk)) {
-               dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
-               ret = PTR_ERR(motg->phy_reset_clk);
-               goto free_motg;
-       }
-
-       motg->clk = clk_get(&pdev->dev, "usb_hs_clk");
-       if (IS_ERR(motg->clk)) {
-               dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
-               ret = PTR_ERR(motg->clk);
-               goto put_phy_reset_clk;
-       }
-       clk_set_rate(motg->clk, 60000000);
-
-       /*
-        * If USB Core is running its protocol engine based on CORE CLK,
-        * CORE CLK  must be running at >55Mhz for correct HSUSB
-        * operation and USB core cannot tolerate frequency changes on
-        * CORE CLK. For such USB cores, vote for maximum clk frequency
-        * on pclk source
-        */
-        if (motg->pdata->pclk_src_name) {
-               motg->pclk_src = clk_get(&pdev->dev,
-                       motg->pdata->pclk_src_name);
-               if (IS_ERR(motg->pclk_src))
-                       goto put_clk;
-               clk_set_rate(motg->pclk_src, INT_MAX);
-               clk_enable(motg->pclk_src);
-       } else
-               motg->pclk_src = ERR_PTR(-ENOENT);
-
-
-       motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
-       if (IS_ERR(motg->pclk)) {
-               dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
-               ret = PTR_ERR(motg->pclk);
-               goto put_pclk_src;
-       }
-
-       /*
-        * USB core clock is not present on all MSM chips. This
-        * clock is introduced to remove the dependency on AXI
-        * bus frequency.
-        */
-       motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk");
-       if (IS_ERR(motg->core_clk))
-               motg->core_clk = NULL;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get platform resource mem\n");
-               ret = -ENODEV;
-               goto put_core_clk;
-       }
-
-       motg->regs = ioremap(res->start, resource_size(res));
-       if (!motg->regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENOMEM;
-               goto put_core_clk;
-       }
-       dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
-
-       motg->irq = platform_get_irq(pdev, 0);
-       if (!motg->irq) {
-               dev_err(&pdev->dev, "platform_get_irq failed\n");
-               ret = -ENODEV;
-               goto free_regs;
-       }
-
-       clk_enable(motg->clk);
-       clk_enable(motg->pclk);
-
-       ret = msm_hsusb_init_vddcx(motg, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
-               goto free_regs;
-       }
-
-       ret = msm_hsusb_ldo_init(motg, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
-               goto vddcx_exit;
-       }
-       ret = msm_hsusb_ldo_set_mode(1);
-       if (ret) {
-               dev_err(&pdev->dev, "hsusb vreg enable failed\n");
-               goto ldo_exit;
-       }
-
-       if (motg->core_clk)
-               clk_enable(motg->core_clk);
-
-       writel(0, USB_USBINTR);
-       writel(0, USB_OTGSC);
-
-       INIT_WORK(&motg->sm_work, msm_otg_sm_work);
-       INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
-       ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
-                                       "msm_otg", motg);
-       if (ret) {
-               dev_err(&pdev->dev, "request irq failed\n");
-               goto disable_clks;
-       }
-
-       phy->init = msm_otg_reset;
-       phy->set_power = msm_otg_set_power;
-
-       phy->io_ops = &msm_otg_io_ops;
-
-       phy->otg->phy = &motg->phy;
-       phy->otg->set_host = msm_otg_set_host;
-       phy->otg->set_peripheral = msm_otg_set_peripheral;
-
-       ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
-       if (ret) {
-               dev_err(&pdev->dev, "usb_add_phy failed\n");
-               goto free_irq;
-       }
-
-       platform_set_drvdata(pdev, motg);
-       device_init_wakeup(&pdev->dev, 1);
-
-       if (motg->pdata->mode == USB_OTG &&
-                       motg->pdata->otg_control == OTG_USER_CONTROL) {
-               ret = msm_otg_debugfs_init(motg);
-               if (ret)
-                       dev_dbg(&pdev->dev, "mode debugfs file is"
-                                       "not available\n");
-       }
-
-       pm_runtime_set_active(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
-
-       return 0;
-free_irq:
-       free_irq(motg->irq, motg);
-disable_clks:
-       clk_disable(motg->pclk);
-       clk_disable(motg->clk);
-ldo_exit:
-       msm_hsusb_ldo_init(motg, 0);
-vddcx_exit:
-       msm_hsusb_init_vddcx(motg, 0);
-free_regs:
-       iounmap(motg->regs);
-put_core_clk:
-       if (motg->core_clk)
-               clk_put(motg->core_clk);
-       clk_put(motg->pclk);
-put_pclk_src:
-       if (!IS_ERR(motg->pclk_src)) {
-               clk_disable(motg->pclk_src);
-               clk_put(motg->pclk_src);
-       }
-put_clk:
-       clk_put(motg->clk);
-put_phy_reset_clk:
-       clk_put(motg->phy_reset_clk);
-free_motg:
-       kfree(motg->phy.otg);
-       kfree(motg);
-       return ret;
-}
-
-static int msm_otg_remove(struct platform_device *pdev)
-{
-       struct msm_otg *motg = platform_get_drvdata(pdev);
-       struct usb_phy *phy = &motg->phy;
-       int cnt = 0;
-
-       if (phy->otg->host || phy->otg->gadget)
-               return -EBUSY;
-
-       msm_otg_debugfs_cleanup();
-       cancel_delayed_work_sync(&motg->chg_work);
-       cancel_work_sync(&motg->sm_work);
-
-       pm_runtime_resume(&pdev->dev);
-
-       device_init_wakeup(&pdev->dev, 0);
-       pm_runtime_disable(&pdev->dev);
-
-       usb_remove_phy(phy);
-       free_irq(motg->irq, motg);
-
-       /*
-        * Put PHY in low power mode.
-        */
-       ulpi_read(phy, 0x14);
-       ulpi_write(phy, 0x08, 0x09);
-
-       writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
-       while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
-               if (readl(USB_PORTSC) & PORTSC_PHCD)
-                       break;
-               udelay(1);
-               cnt++;
-       }
-       if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
-               dev_err(phy->dev, "Unable to suspend PHY\n");
-
-       clk_disable(motg->pclk);
-       clk_disable(motg->clk);
-       if (motg->core_clk)
-               clk_disable(motg->core_clk);
-       if (!IS_ERR(motg->pclk_src)) {
-               clk_disable(motg->pclk_src);
-               clk_put(motg->pclk_src);
-       }
-       msm_hsusb_ldo_init(motg, 0);
-
-       iounmap(motg->regs);
-       pm_runtime_set_suspended(&pdev->dev);
-
-       clk_put(motg->phy_reset_clk);
-       clk_put(motg->pclk);
-       clk_put(motg->clk);
-       if (motg->core_clk)
-               clk_put(motg->core_clk);
-
-       kfree(motg->phy.otg);
-       kfree(motg);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_RUNTIME
-static int msm_otg_runtime_idle(struct device *dev)
-{
-       struct msm_otg *motg = dev_get_drvdata(dev);
-       struct usb_otg *otg = motg->phy.otg;
-
-       dev_dbg(dev, "OTG runtime idle\n");
-
-       /*
-        * It is observed some times that a spurious interrupt
-        * comes when PHY is put into LPM immediately after PHY reset.
-        * This 1 sec delay also prevents entering into LPM immediately
-        * after asynchronous interrupt.
-        */
-       if (otg->phy->state != OTG_STATE_UNDEFINED)
-               pm_schedule_suspend(dev, 1000);
-
-       return -EAGAIN;
-}
-
-static int msm_otg_runtime_suspend(struct device *dev)
-{
-       struct msm_otg *motg = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "OTG runtime suspend\n");
-       return msm_otg_suspend(motg);
-}
-
-static int msm_otg_runtime_resume(struct device *dev)
-{
-       struct msm_otg *motg = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "OTG runtime resume\n");
-       return msm_otg_resume(motg);
-}
-#endif
-
-#ifdef CONFIG_PM_SLEEP
-static int msm_otg_pm_suspend(struct device *dev)
-{
-       struct msm_otg *motg = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "OTG PM suspend\n");
-       return msm_otg_suspend(motg);
-}
-
-static int msm_otg_pm_resume(struct device *dev)
-{
-       struct msm_otg *motg = dev_get_drvdata(dev);
-       int ret;
-
-       dev_dbg(dev, "OTG PM resume\n");
-
-       ret = msm_otg_resume(motg);
-       if (ret)
-               return ret;
-
-       /*
-        * Runtime PM Documentation recommends bringing the
-        * device to full powered state upon resume.
-        */
-       pm_runtime_disable(dev);
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
-
-       return 0;
-}
-#endif
-
-#ifdef CONFIG_PM
-static const struct dev_pm_ops msm_otg_dev_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
-       SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
-                               msm_otg_runtime_idle)
-};
-#endif
-
-static struct platform_driver msm_otg_driver = {
-       .remove = msm_otg_remove,
-       .driver = {
-               .name = DRIVER_NAME,
-               .owner = THIS_MODULE,
-#ifdef CONFIG_PM
-               .pm = &msm_otg_dev_pm_ops,
-#endif
-       },
-};
-
-module_platform_driver_probe(msm_otg_driver, msm_otg_probe);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MSM USB transceiver driver");
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
deleted file mode 100644 (file)
index b6a9be3..0000000
+++ /dev/null
@@ -1,923 +0,0 @@
-/*
- * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
- * Author: Chao Xie <chao.xie@marvell.com>
- *        Neil Zhang <zhangwm@marvell.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.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-#include <linux/device.h>
-#include <linux/proc_fs.h>
-#include <linux/clk.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-
-#include <linux/usb.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/hcd.h>
-#include <linux/platform_data/mv_usb.h>
-
-#include "mv_otg.h"
-
-#define        DRIVER_DESC     "Marvell USB OTG transceiver driver"
-#define        DRIVER_VERSION  "Jan 20, 2010"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
-static const char driver_name[] = "mv-otg";
-
-static char *state_string[] = {
-       "undefined",
-       "b_idle",
-       "b_srp_init",
-       "b_peripheral",
-       "b_wait_acon",
-       "b_host",
-       "a_idle",
-       "a_wait_vrise",
-       "a_wait_bcon",
-       "a_host",
-       "a_suspend",
-       "a_peripheral",
-       "a_wait_vfall",
-       "a_vbus_err"
-};
-
-static int mv_otg_set_vbus(struct usb_otg *otg, bool on)
-{
-       struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy);
-       if (mvotg->pdata->set_vbus == NULL)
-               return -ENODEV;
-
-       return mvotg->pdata->set_vbus(on);
-}
-
-static int mv_otg_set_host(struct usb_otg *otg,
-                          struct usb_bus *host)
-{
-       otg->host = host;
-
-       return 0;
-}
-
-static int mv_otg_set_peripheral(struct usb_otg *otg,
-                                struct usb_gadget *gadget)
-{
-       otg->gadget = gadget;
-
-       return 0;
-}
-
-static void mv_otg_run_state_machine(struct mv_otg *mvotg,
-                                    unsigned long delay)
-{
-       dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n");
-       if (!mvotg->qwork)
-               return;
-
-       queue_delayed_work(mvotg->qwork, &mvotg->work, delay);
-}
-
-static void mv_otg_timer_await_bcon(unsigned long data)
-{
-       struct mv_otg *mvotg = (struct mv_otg *) data;
-
-       mvotg->otg_ctrl.a_wait_bcon_timeout = 1;
-
-       dev_info(&mvotg->pdev->dev, "B Device No Response!\n");
-
-       if (spin_trylock(&mvotg->wq_lock)) {
-               mv_otg_run_state_machine(mvotg, 0);
-               spin_unlock(&mvotg->wq_lock);
-       }
-}
-
-static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id)
-{
-       struct timer_list *timer;
-
-       if (id >= OTG_TIMER_NUM)
-               return -EINVAL;
-
-       timer = &mvotg->otg_ctrl.timer[id];
-
-       if (timer_pending(timer))
-               del_timer(timer);
-
-       return 0;
-}
-
-static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id,
-                           unsigned long interval,
-                           void (*callback) (unsigned long))
-{
-       struct timer_list *timer;
-
-       if (id >= OTG_TIMER_NUM)
-               return -EINVAL;
-
-       timer = &mvotg->otg_ctrl.timer[id];
-       if (timer_pending(timer)) {
-               dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id);
-               return -EBUSY;
-       }
-
-       init_timer(timer);
-       timer->data = (unsigned long) mvotg;
-       timer->function = callback;
-       timer->expires = jiffies + interval;
-       add_timer(timer);
-
-       return 0;
-}
-
-static int mv_otg_reset(struct mv_otg *mvotg)
-{
-       unsigned int loops;
-       u32 tmp;
-
-       /* Stop the controller */
-       tmp = readl(&mvotg->op_regs->usbcmd);
-       tmp &= ~USBCMD_RUN_STOP;
-       writel(tmp, &mvotg->op_regs->usbcmd);
-
-       /* Reset the controller to get default values */
-       writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd);
-
-       loops = 500;
-       while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) {
-               if (loops == 0) {
-                       dev_err(&mvotg->pdev->dev,
-                               "Wait for RESET completed TIMEOUT\n");
-                       return -ETIMEDOUT;
-               }
-               loops--;
-               udelay(20);
-       }
-
-       writel(0x0, &mvotg->op_regs->usbintr);
-       tmp = readl(&mvotg->op_regs->usbsts);
-       writel(tmp, &mvotg->op_regs->usbsts);
-
-       return 0;
-}
-
-static void mv_otg_init_irq(struct mv_otg *mvotg)
-{
-       u32 otgsc;
-
-       mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID
-           | OTGSC_INTR_A_VBUS_VALID;
-       mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID
-           | OTGSC_INTSTS_A_VBUS_VALID;
-
-       if (mvotg->pdata->vbus == NULL) {
-               mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID
-                   | OTGSC_INTR_B_SESSION_END;
-               mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID
-                   | OTGSC_INTSTS_B_SESSION_END;
-       }
-
-       if (mvotg->pdata->id == NULL) {
-               mvotg->irq_en |= OTGSC_INTR_USB_ID;
-               mvotg->irq_status |= OTGSC_INTSTS_USB_ID;
-       }
-
-       otgsc = readl(&mvotg->op_regs->otgsc);
-       otgsc |= mvotg->irq_en;
-       writel(otgsc, &mvotg->op_regs->otgsc);
-}
-
-static void mv_otg_start_host(struct mv_otg *mvotg, int on)
-{
-#ifdef CONFIG_USB
-       struct usb_otg *otg = mvotg->phy.otg;
-       struct usb_hcd *hcd;
-
-       if (!otg->host)
-               return;
-
-       dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop");
-
-       hcd = bus_to_hcd(otg->host);
-
-       if (on)
-               usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
-       else
-               usb_remove_hcd(hcd);
-#endif /* CONFIG_USB */
-}
-
-static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
-{
-       struct usb_otg *otg = mvotg->phy.otg;
-
-       if (!otg->gadget)
-               return;
-
-       dev_info(mvotg->phy.dev, "gadget %s\n", on ? "on" : "off");
-
-       if (on)
-               usb_gadget_vbus_connect(otg->gadget);
-       else
-               usb_gadget_vbus_disconnect(otg->gadget);
-}
-
-static void otg_clock_enable(struct mv_otg *mvotg)
-{
-       unsigned int i;
-
-       for (i = 0; i < mvotg->clknum; i++)
-               clk_prepare_enable(mvotg->clk[i]);
-}
-
-static void otg_clock_disable(struct mv_otg *mvotg)
-{
-       unsigned int i;
-
-       for (i = 0; i < mvotg->clknum; i++)
-               clk_disable_unprepare(mvotg->clk[i]);
-}
-
-static int mv_otg_enable_internal(struct mv_otg *mvotg)
-{
-       int retval = 0;
-
-       if (mvotg->active)
-               return 0;
-
-       dev_dbg(&mvotg->pdev->dev, "otg enabled\n");
-
-       otg_clock_enable(mvotg);
-       if (mvotg->pdata->phy_init) {
-               retval = mvotg->pdata->phy_init(mvotg->phy_regs);
-               if (retval) {
-                       dev_err(&mvotg->pdev->dev,
-                               "init phy error %d\n", retval);
-                       otg_clock_disable(mvotg);
-                       return retval;
-               }
-       }
-       mvotg->active = 1;
-
-       return 0;
-
-}
-
-static int mv_otg_enable(struct mv_otg *mvotg)
-{
-       if (mvotg->clock_gating)
-               return mv_otg_enable_internal(mvotg);
-
-       return 0;
-}
-
-static void mv_otg_disable_internal(struct mv_otg *mvotg)
-{
-       if (mvotg->active) {
-               dev_dbg(&mvotg->pdev->dev, "otg disabled\n");
-               if (mvotg->pdata->phy_deinit)
-                       mvotg->pdata->phy_deinit(mvotg->phy_regs);
-               otg_clock_disable(mvotg);
-               mvotg->active = 0;
-       }
-}
-
-static void mv_otg_disable(struct mv_otg *mvotg)
-{
-       if (mvotg->clock_gating)
-               mv_otg_disable_internal(mvotg);
-}
-
-static void mv_otg_update_inputs(struct mv_otg *mvotg)
-{
-       struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
-       u32 otgsc;
-
-       otgsc = readl(&mvotg->op_regs->otgsc);
-
-       if (mvotg->pdata->vbus) {
-               if (mvotg->pdata->vbus->poll() == VBUS_HIGH) {
-                       otg_ctrl->b_sess_vld = 1;
-                       otg_ctrl->b_sess_end = 0;
-               } else {
-                       otg_ctrl->b_sess_vld = 0;
-                       otg_ctrl->b_sess_end = 1;
-               }
-       } else {
-               otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID);
-               otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END);
-       }
-
-       if (mvotg->pdata->id)
-               otg_ctrl->id = !!mvotg->pdata->id->poll();
-       else
-               otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID);
-
-       if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id)
-               otg_ctrl->a_bus_req = 1;
-
-       otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID);
-       otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID);
-
-       dev_dbg(&mvotg->pdev->dev, "%s: ", __func__);
-       dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id);
-       dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld);
-       dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end);
-       dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld);
-       dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld);
-}
-
-static void mv_otg_update_state(struct mv_otg *mvotg)
-{
-       struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
-       struct usb_phy *phy = &mvotg->phy;
-       int old_state = phy->state;
-
-       switch (old_state) {
-       case OTG_STATE_UNDEFINED:
-               phy->state = OTG_STATE_B_IDLE;
-               /* FALL THROUGH */
-       case OTG_STATE_B_IDLE:
-               if (otg_ctrl->id == 0)
-                       phy->state = OTG_STATE_A_IDLE;
-               else if (otg_ctrl->b_sess_vld)
-                       phy->state = OTG_STATE_B_PERIPHERAL;
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
-                       phy->state = OTG_STATE_B_IDLE;
-               break;
-       case OTG_STATE_A_IDLE:
-               if (otg_ctrl->id)
-                       phy->state = OTG_STATE_B_IDLE;
-               else if (!(otg_ctrl->a_bus_drop) &&
-                        (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
-                       phy->state = OTG_STATE_A_WAIT_VRISE;
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               if (otg_ctrl->a_vbus_vld)
-                       phy->state = OTG_STATE_A_WAIT_BCON;
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               if (otg_ctrl->id || otg_ctrl->a_bus_drop
-                   || otg_ctrl->a_wait_bcon_timeout) {
-                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
-                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
-                       phy->state = OTG_STATE_A_WAIT_VFALL;
-                       otg_ctrl->a_bus_req = 0;
-               } else if (!otg_ctrl->a_vbus_vld) {
-                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
-                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
-                       phy->state = OTG_STATE_A_VBUS_ERR;
-               } else if (otg_ctrl->b_conn) {
-                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
-                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
-                       phy->state = OTG_STATE_A_HOST;
-               }
-               break;
-       case OTG_STATE_A_HOST:
-               if (otg_ctrl->id || !otg_ctrl->b_conn
-                   || otg_ctrl->a_bus_drop)
-                       phy->state = OTG_STATE_A_WAIT_BCON;
-               else if (!otg_ctrl->a_vbus_vld)
-                       phy->state = OTG_STATE_A_VBUS_ERR;
-               break;
-       case OTG_STATE_A_WAIT_VFALL:
-               if (otg_ctrl->id
-                   || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
-                   || otg_ctrl->a_bus_req)
-                       phy->state = OTG_STATE_A_IDLE;
-               break;
-       case OTG_STATE_A_VBUS_ERR:
-               if (otg_ctrl->id || otg_ctrl->a_clr_err
-                   || otg_ctrl->a_bus_drop) {
-                       otg_ctrl->a_clr_err = 0;
-                       phy->state = OTG_STATE_A_WAIT_VFALL;
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static void mv_otg_work(struct work_struct *work)
-{
-       struct mv_otg *mvotg;
-       struct usb_phy *phy;
-       struct usb_otg *otg;
-       int old_state;
-
-       mvotg = container_of(to_delayed_work(work), struct mv_otg, work);
-
-run:
-       /* work queue is single thread, or we need spin_lock to protect */
-       phy = &mvotg->phy;
-       otg = phy->otg;
-       old_state = phy->state;
-
-       if (!mvotg->active)
-               return;
-
-       mv_otg_update_inputs(mvotg);
-       mv_otg_update_state(mvotg);
-
-       if (old_state != phy->state) {
-               dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
-                        state_string[old_state],
-                        state_string[phy->state]);
-
-               switch (phy->state) {
-               case OTG_STATE_B_IDLE:
-                       otg->default_a = 0;
-                       if (old_state == OTG_STATE_B_PERIPHERAL)
-                               mv_otg_start_periphrals(mvotg, 0);
-                       mv_otg_reset(mvotg);
-                       mv_otg_disable(mvotg);
-                       break;
-               case OTG_STATE_B_PERIPHERAL:
-                       mv_otg_enable(mvotg);
-                       mv_otg_start_periphrals(mvotg, 1);
-                       break;
-               case OTG_STATE_A_IDLE:
-                       otg->default_a = 1;
-                       mv_otg_enable(mvotg);
-                       if (old_state == OTG_STATE_A_WAIT_VFALL)
-                               mv_otg_start_host(mvotg, 0);
-                       mv_otg_reset(mvotg);
-                       break;
-               case OTG_STATE_A_WAIT_VRISE:
-                       mv_otg_set_vbus(otg, 1);
-                       break;
-               case OTG_STATE_A_WAIT_BCON:
-                       if (old_state != OTG_STATE_A_HOST)
-                               mv_otg_start_host(mvotg, 1);
-                       mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER,
-                                        T_A_WAIT_BCON,
-                                        mv_otg_timer_await_bcon);
-                       /*
-                        * Now, we directly enter A_HOST. So set b_conn = 1
-                        * here. In fact, it need host driver to notify us.
-                        */
-                       mvotg->otg_ctrl.b_conn = 1;
-                       break;
-               case OTG_STATE_A_HOST:
-                       break;
-               case OTG_STATE_A_WAIT_VFALL:
-                       /*
-                        * Now, we has exited A_HOST. So set b_conn = 0
-                        * here. In fact, it need host driver to notify us.
-                        */
-                       mvotg->otg_ctrl.b_conn = 0;
-                       mv_otg_set_vbus(otg, 0);
-                       break;
-               case OTG_STATE_A_VBUS_ERR:
-                       break;
-               default:
-                       break;
-               }
-               goto run;
-       }
-}
-
-static irqreturn_t mv_otg_irq(int irq, void *dev)
-{
-       struct mv_otg *mvotg = dev;
-       u32 otgsc;
-
-       otgsc = readl(&mvotg->op_regs->otgsc);
-       writel(otgsc, &mvotg->op_regs->otgsc);
-
-       /*
-        * if we have vbus, then the vbus detection for B-device
-        * will be done by mv_otg_inputs_irq().
-        */
-       if (mvotg->pdata->vbus)
-               if ((otgsc & OTGSC_STS_USB_ID) &&
-                   !(otgsc & OTGSC_INTSTS_USB_ID))
-                       return IRQ_NONE;
-
-       if ((otgsc & mvotg->irq_status) == 0)
-               return IRQ_NONE;
-
-       mv_otg_run_state_machine(mvotg, 0);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
-{
-       struct mv_otg *mvotg = dev;
-
-       /* The clock may disabled at this time */
-       if (!mvotg->active) {
-               mv_otg_enable(mvotg);
-               mv_otg_init_irq(mvotg);
-       }
-
-       mv_otg_run_state_machine(mvotg, 0);
-
-       return IRQ_HANDLED;
-}
-
-static ssize_t
-get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct mv_otg *mvotg = dev_get_drvdata(dev);
-       return scnprintf(buf, PAGE_SIZE, "%d\n",
-                        mvotg->otg_ctrl.a_bus_req);
-}
-
-static ssize_t
-set_a_bus_req(struct device *dev, struct device_attribute *attr,
-             const char *buf, size_t count)
-{
-       struct mv_otg *mvotg = dev_get_drvdata(dev);
-
-       if (count > 2)
-               return -1;
-
-       /* We will use this interface to change to A device */
-       if (mvotg->phy.state != OTG_STATE_B_IDLE
-           && mvotg->phy.state != OTG_STATE_A_IDLE)
-               return -1;
-
-       /* The clock may disabled and we need to set irq for ID detected */
-       mv_otg_enable(mvotg);
-       mv_otg_init_irq(mvotg);
-
-       if (buf[0] == '1') {
-               mvotg->otg_ctrl.a_bus_req = 1;
-               mvotg->otg_ctrl.a_bus_drop = 0;
-               dev_dbg(&mvotg->pdev->dev,
-                       "User request: a_bus_req = 1\n");
-
-               if (spin_trylock(&mvotg->wq_lock)) {
-                       mv_otg_run_state_machine(mvotg, 0);
-                       spin_unlock(&mvotg->wq_lock);
-               }
-       }
-
-       return count;
-}
-
-static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req,
-                  set_a_bus_req);
-
-static ssize_t
-set_a_clr_err(struct device *dev, struct device_attribute *attr,
-             const char *buf, size_t count)
-{
-       struct mv_otg *mvotg = dev_get_drvdata(dev);
-       if (!mvotg->phy.otg->default_a)
-               return -1;
-
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '1') {
-               mvotg->otg_ctrl.a_clr_err = 1;
-               dev_dbg(&mvotg->pdev->dev,
-                       "User request: a_clr_err = 1\n");
-       }
-
-       if (spin_trylock(&mvotg->wq_lock)) {
-               mv_otg_run_state_machine(mvotg, 0);
-               spin_unlock(&mvotg->wq_lock);
-       }
-
-       return count;
-}
-
-static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
-
-static ssize_t
-get_a_bus_drop(struct device *dev, struct device_attribute *attr,
-              char *buf)
-{
-       struct mv_otg *mvotg = dev_get_drvdata(dev);
-       return scnprintf(buf, PAGE_SIZE, "%d\n",
-                        mvotg->otg_ctrl.a_bus_drop);
-}
-
-static ssize_t
-set_a_bus_drop(struct device *dev, struct device_attribute *attr,
-              const char *buf, size_t count)
-{
-       struct mv_otg *mvotg = dev_get_drvdata(dev);
-       if (!mvotg->phy.otg->default_a)
-               return -1;
-
-       if (count > 2)
-               return -1;
-
-       if (buf[0] == '0') {
-               mvotg->otg_ctrl.a_bus_drop = 0;
-               dev_dbg(&mvotg->pdev->dev,
-                       "User request: a_bus_drop = 0\n");
-       } else if (buf[0] == '1') {
-               mvotg->otg_ctrl.a_bus_drop = 1;
-               mvotg->otg_ctrl.a_bus_req = 0;
-               dev_dbg(&mvotg->pdev->dev,
-                       "User request: a_bus_drop = 1\n");
-               dev_dbg(&mvotg->pdev->dev,
-                       "User request: and a_bus_req = 0\n");
-       }
-
-       if (spin_trylock(&mvotg->wq_lock)) {
-               mv_otg_run_state_machine(mvotg, 0);
-               spin_unlock(&mvotg->wq_lock);
-       }
-
-       return count;
-}
-
-static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR,
-                  get_a_bus_drop, set_a_bus_drop);
-
-static struct attribute *inputs_attrs[] = {
-       &dev_attr_a_bus_req.attr,
-       &dev_attr_a_clr_err.attr,
-       &dev_attr_a_bus_drop.attr,
-       NULL,
-};
-
-static struct attribute_group inputs_attr_group = {
-       .name = "inputs",
-       .attrs = inputs_attrs,
-};
-
-int mv_otg_remove(struct platform_device *pdev)
-{
-       struct mv_otg *mvotg = platform_get_drvdata(pdev);
-
-       sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group);
-
-       if (mvotg->qwork) {
-               flush_workqueue(mvotg->qwork);
-               destroy_workqueue(mvotg->qwork);
-       }
-
-       mv_otg_disable(mvotg);
-
-       usb_remove_phy(&mvotg->phy);
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
-static int mv_otg_probe(struct platform_device *pdev)
-{
-       struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
-       struct mv_otg *mvotg;
-       struct usb_otg *otg;
-       struct resource *r;
-       int retval = 0, clk_i, i;
-       size_t size;
-
-       if (pdata == NULL) {
-               dev_err(&pdev->dev, "failed to get platform data\n");
-               return -ENODEV;
-       }
-
-       size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum;
-       mvotg = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!mvotg) {
-               dev_err(&pdev->dev, "failed to allocate memory!\n");
-               return -ENOMEM;
-       }
-
-       otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
-       if (!otg)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, mvotg);
-
-       mvotg->pdev = pdev;
-       mvotg->pdata = pdata;
-
-       mvotg->clknum = pdata->clknum;
-       for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) {
-               mvotg->clk[clk_i] = devm_clk_get(&pdev->dev,
-                                               pdata->clkname[clk_i]);
-               if (IS_ERR(mvotg->clk[clk_i])) {
-                       retval = PTR_ERR(mvotg->clk[clk_i]);
-                       return retval;
-               }
-       }
-
-       mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
-       if (!mvotg->qwork) {
-               dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n");
-               return -ENOMEM;
-       }
-
-       INIT_DELAYED_WORK(&mvotg->work, mv_otg_work);
-
-       /* OTG common part */
-       mvotg->pdev = pdev;
-       mvotg->phy.dev = &pdev->dev;
-       mvotg->phy.otg = otg;
-       mvotg->phy.label = driver_name;
-       mvotg->phy.state = OTG_STATE_UNDEFINED;
-
-       otg->phy = &mvotg->phy;
-       otg->set_host = mv_otg_set_host;
-       otg->set_peripheral = mv_otg_set_peripheral;
-       otg->set_vbus = mv_otg_set_vbus;
-
-       for (i = 0; i < OTG_TIMER_NUM; i++)
-               init_timer(&mvotg->otg_ctrl.timer[i]);
-
-       r = platform_get_resource_byname(mvotg->pdev,
-                                        IORESOURCE_MEM, "phyregs");
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
-               retval = -ENODEV;
-               goto err_destroy_workqueue;
-       }
-
-       mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
-       if (mvotg->phy_regs == NULL) {
-               dev_err(&pdev->dev, "failed to map phy I/O memory\n");
-               retval = -EFAULT;
-               goto err_destroy_workqueue;
-       }
-
-       r = platform_get_resource_byname(mvotg->pdev,
-                                        IORESOURCE_MEM, "capregs");
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no I/O memory resource defined\n");
-               retval = -ENODEV;
-               goto err_destroy_workqueue;
-       }
-
-       mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
-       if (mvotg->cap_regs == NULL) {
-               dev_err(&pdev->dev, "failed to map I/O memory\n");
-               retval = -EFAULT;
-               goto err_destroy_workqueue;
-       }
-
-       /* we will acces controller register, so enable the udc controller */
-       retval = mv_otg_enable_internal(mvotg);
-       if (retval) {
-               dev_err(&pdev->dev, "mv otg enable error %d\n", retval);
-               goto err_destroy_workqueue;
-       }
-
-       mvotg->op_regs =
-               (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs
-                       + (readl(mvotg->cap_regs) & CAPLENGTH_MASK));
-
-       if (pdata->id) {
-               retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq,
-                                               NULL, mv_otg_inputs_irq,
-                                               IRQF_ONESHOT, "id", mvotg);
-               if (retval) {
-                       dev_info(&pdev->dev,
-                                "Failed to request irq for ID\n");
-                       pdata->id = NULL;
-               }
-       }
-
-       if (pdata->vbus) {
-               mvotg->clock_gating = 1;
-               retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq,
-                                               NULL, mv_otg_inputs_irq,
-                                               IRQF_ONESHOT, "vbus", mvotg);
-               if (retval) {
-                       dev_info(&pdev->dev,
-                                "Failed to request irq for VBUS, "
-                                "disable clock gating\n");
-                       mvotg->clock_gating = 0;
-                       pdata->vbus = NULL;
-               }
-       }
-
-       if (pdata->disable_otg_clock_gating)
-               mvotg->clock_gating = 0;
-
-       mv_otg_reset(mvotg);
-       mv_otg_init_irq(mvotg);
-
-       r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no IRQ resource defined\n");
-               retval = -ENODEV;
-               goto err_disable_clk;
-       }
-
-       mvotg->irq = r->start;
-       if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED,
-                       driver_name, mvotg)) {
-               dev_err(&pdev->dev, "Request irq %d for OTG failed\n",
-                       mvotg->irq);
-               mvotg->irq = 0;
-               retval = -ENODEV;
-               goto err_disable_clk;
-       }
-
-       retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2);
-       if (retval < 0) {
-               dev_err(&pdev->dev, "can't register transceiver, %d\n",
-                       retval);
-               goto err_disable_clk;
-       }
-
-       retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group);
-       if (retval < 0) {
-               dev_dbg(&pdev->dev,
-                       "Can't register sysfs attr group: %d\n", retval);
-               goto err_remove_phy;
-       }
-
-       spin_lock_init(&mvotg->wq_lock);
-       if (spin_trylock(&mvotg->wq_lock)) {
-               mv_otg_run_state_machine(mvotg, 2 * HZ);
-               spin_unlock(&mvotg->wq_lock);
-       }
-
-       dev_info(&pdev->dev,
-                "successful probe OTG device %s clock gating.\n",
-                mvotg->clock_gating ? "with" : "without");
-
-       return 0;
-
-err_remove_phy:
-       usb_remove_phy(&mvotg->phy);
-err_disable_clk:
-       mv_otg_disable_internal(mvotg);
-err_destroy_workqueue:
-       flush_workqueue(mvotg->qwork);
-       destroy_workqueue(mvotg->qwork);
-
-       platform_set_drvdata(pdev, NULL);
-
-       return retval;
-}
-
-#ifdef CONFIG_PM
-static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct mv_otg *mvotg = platform_get_drvdata(pdev);
-
-       if (mvotg->phy.state != OTG_STATE_B_IDLE) {
-               dev_info(&pdev->dev,
-                        "OTG state is not B_IDLE, it is %d!\n",
-                        mvotg->phy.state);
-               return -EAGAIN;
-       }
-
-       if (!mvotg->clock_gating)
-               mv_otg_disable_internal(mvotg);
-
-       return 0;
-}
-
-static int mv_otg_resume(struct platform_device *pdev)
-{
-       struct mv_otg *mvotg = platform_get_drvdata(pdev);
-       u32 otgsc;
-
-       if (!mvotg->clock_gating) {
-               mv_otg_enable_internal(mvotg);
-
-               otgsc = readl(&mvotg->op_regs->otgsc);
-               otgsc |= mvotg->irq_en;
-               writel(otgsc, &mvotg->op_regs->otgsc);
-
-               if (spin_trylock(&mvotg->wq_lock)) {
-                       mv_otg_run_state_machine(mvotg, 0);
-                       spin_unlock(&mvotg->wq_lock);
-               }
-       }
-       return 0;
-}
-#endif
-
-static struct platform_driver mv_otg_driver = {
-       .probe = mv_otg_probe,
-       .remove = __exit_p(mv_otg_remove),
-       .driver = {
-                  .owner = THIS_MODULE,
-                  .name = driver_name,
-                  },
-#ifdef CONFIG_PM
-       .suspend = mv_otg_suspend,
-       .resume = mv_otg_resume,
-#endif
-};
-module_platform_driver(mv_otg_driver);
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h
deleted file mode 100644 (file)
index 8a9e351..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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 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.
- */
-
-#ifndef        __MV_USB_OTG_CONTROLLER__
-#define        __MV_USB_OTG_CONTROLLER__
-
-#include <linux/types.h>
-
-/* Command Register Bit Masks */
-#define USBCMD_RUN_STOP                        (0x00000001)
-#define USBCMD_CTRL_RESET              (0x00000002)
-
-/* otgsc Register Bit Masks */
-#define OTGSC_CTRL_VUSB_DISCHARGE              0x00000001
-#define OTGSC_CTRL_VUSB_CHARGE                 0x00000002
-#define OTGSC_CTRL_OTG_TERM                    0x00000008
-#define OTGSC_CTRL_DATA_PULSING                        0x00000010
-#define OTGSC_STS_USB_ID                       0x00000100
-#define OTGSC_STS_A_VBUS_VALID                 0x00000200
-#define OTGSC_STS_A_SESSION_VALID              0x00000400
-#define OTGSC_STS_B_SESSION_VALID              0x00000800
-#define OTGSC_STS_B_SESSION_END                        0x00001000
-#define OTGSC_STS_1MS_TOGGLE                   0x00002000
-#define OTGSC_STS_DATA_PULSING                 0x00004000
-#define OTGSC_INTSTS_USB_ID                    0x00010000
-#define OTGSC_INTSTS_A_VBUS_VALID              0x00020000
-#define OTGSC_INTSTS_A_SESSION_VALID           0x00040000
-#define OTGSC_INTSTS_B_SESSION_VALID           0x00080000
-#define OTGSC_INTSTS_B_SESSION_END             0x00100000
-#define OTGSC_INTSTS_1MS                       0x00200000
-#define OTGSC_INTSTS_DATA_PULSING              0x00400000
-#define OTGSC_INTR_USB_ID                      0x01000000
-#define OTGSC_INTR_A_VBUS_VALID                        0x02000000
-#define OTGSC_INTR_A_SESSION_VALID             0x04000000
-#define OTGSC_INTR_B_SESSION_VALID             0x08000000
-#define OTGSC_INTR_B_SESSION_END               0x10000000
-#define OTGSC_INTR_1MS_TIMER                   0x20000000
-#define OTGSC_INTR_DATA_PULSING                        0x40000000
-
-#define CAPLENGTH_MASK         (0xff)
-
-/* Timer's interval, unit 10ms */
-#define T_A_WAIT_VRISE         100
-#define T_A_WAIT_BCON          2000
-#define T_A_AIDL_BDIS          100
-#define T_A_BIDL_ADIS          20
-#define T_B_ASE0_BRST          400
-#define T_B_SE0_SRP            300
-#define T_B_SRP_FAIL           2000
-#define T_B_DATA_PLS           10
-#define T_B_SRP_INIT           100
-#define T_A_SRP_RSPNS          10
-#define T_A_DRV_RSM            5
-
-enum otg_function {
-       OTG_B_DEVICE = 0,
-       OTG_A_DEVICE
-};
-
-enum mv_otg_timer {
-       A_WAIT_BCON_TIMER = 0,
-       OTG_TIMER_NUM
-};
-
-/* PXA OTG state machine */
-struct mv_otg_ctrl {
-       /* internal variables */
-       u8 a_set_b_hnp_en;      /* A-Device set b_hnp_en */
-       u8 b_srp_done;
-       u8 b_hnp_en;
-
-       /* OTG inputs */
-       u8 a_bus_drop;
-       u8 a_bus_req;
-       u8 a_clr_err;
-       u8 a_bus_resume;
-       u8 a_bus_suspend;
-       u8 a_conn;
-       u8 a_sess_vld;
-       u8 a_srp_det;
-       u8 a_vbus_vld;
-       u8 b_bus_req;           /* B-Device Require Bus */
-       u8 b_bus_resume;
-       u8 b_bus_suspend;
-       u8 b_conn;
-       u8 b_se0_srp;
-       u8 b_sess_end;
-       u8 b_sess_vld;
-       u8 id;
-       u8 a_suspend_req;
-
-       /*Timer event */
-       u8 a_aidl_bdis_timeout;
-       u8 b_ase0_brst_timeout;
-       u8 a_bidl_adis_timeout;
-       u8 a_wait_bcon_timeout;
-
-       struct timer_list timer[OTG_TIMER_NUM];
-};
-
-#define VUSBHS_MAX_PORTS       8
-
-struct mv_otg_regs {
-       u32 usbcmd;             /* Command register */
-       u32 usbsts;             /* Status register */
-       u32 usbintr;            /* Interrupt enable */
-       u32 frindex;            /* Frame index */
-       u32 reserved1[1];
-       u32 deviceaddr;         /* Device Address */
-       u32 eplistaddr;         /* Endpoint List Address */
-       u32 ttctrl;             /* HOST TT status and control */
-       u32 burstsize;          /* Programmable Burst Size */
-       u32 txfilltuning;       /* Host Transmit Pre-Buffer Packet Tuning */
-       u32 reserved[4];
-       u32 epnak;              /* Endpoint NAK */
-       u32 epnaken;            /* Endpoint NAK Enable */
-       u32 configflag;         /* Configured Flag register */
-       u32 portsc[VUSBHS_MAX_PORTS];   /* Port Status/Control x, x = 1..8 */
-       u32 otgsc;
-       u32 usbmode;            /* USB Host/Device mode */
-       u32 epsetupstat;        /* Endpoint Setup Status */
-       u32 epprime;            /* Endpoint Initialize */
-       u32 epflush;            /* Endpoint De-initialize */
-       u32 epstatus;           /* Endpoint Status */
-       u32 epcomplete;         /* Endpoint Interrupt On Complete */
-       u32 epctrlx[16];        /* Endpoint Control, where x = 0.. 15 */
-       u32 mcr;                /* Mux Control */
-       u32 isr;                /* Interrupt Status */
-       u32 ier;                /* Interrupt Enable */
-};
-
-struct mv_otg {
-       struct usb_phy phy;
-       struct mv_otg_ctrl otg_ctrl;
-
-       /* base address */
-       void __iomem *phy_regs;
-       void __iomem *cap_regs;
-       struct mv_otg_regs __iomem *op_regs;
-
-       struct platform_device *pdev;
-       int irq;
-       u32 irq_status;
-       u32 irq_en;
-
-       struct delayed_work work;
-       struct workqueue_struct *qwork;
-
-       spinlock_t wq_lock;
-
-       struct mv_usb_platform_data *pdata;
-
-       unsigned int active;
-       unsigned int clock_gating;
-       unsigned int clknum;
-       struct clk *clk[0];
-};
-
-#endif
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c
deleted file mode 100644 (file)
index 9d4381e..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Marek Vasut <marex@denx.de>
- * on behalf of DENX Software Engineering GmbH
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/usb/otg.h>
-#include <linux/stmp_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#define DRIVER_NAME "mxs_phy"
-
-#define HW_USBPHY_PWD                          0x00
-#define HW_USBPHY_CTRL                         0x30
-#define HW_USBPHY_CTRL_SET                     0x34
-#define HW_USBPHY_CTRL_CLR                     0x38
-
-#define BM_USBPHY_CTRL_SFTRST                  BIT(31)
-#define BM_USBPHY_CTRL_CLKGATE                 BIT(30)
-#define BM_USBPHY_CTRL_ENUTMILEVEL3            BIT(15)
-#define BM_USBPHY_CTRL_ENUTMILEVEL2            BIT(14)
-#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT      BIT(1)
-
-struct mxs_phy {
-       struct usb_phy phy;
-       struct clk *clk;
-};
-
-#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
-
-static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
-{
-       void __iomem *base = mxs_phy->phy.io_priv;
-
-       stmp_reset_block(base + HW_USBPHY_CTRL);
-
-       /* Power up the PHY */
-       writel(0, base + HW_USBPHY_PWD);
-
-       /* enable FS/LS device */
-       writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
-              BM_USBPHY_CTRL_ENUTMILEVEL3,
-              base + HW_USBPHY_CTRL_SET);
-}
-
-static int mxs_phy_init(struct usb_phy *phy)
-{
-       struct mxs_phy *mxs_phy = to_mxs_phy(phy);
-
-       clk_prepare_enable(mxs_phy->clk);
-       mxs_phy_hw_init(mxs_phy);
-
-       return 0;
-}
-
-static void mxs_phy_shutdown(struct usb_phy *phy)
-{
-       struct mxs_phy *mxs_phy = to_mxs_phy(phy);
-
-       writel(BM_USBPHY_CTRL_CLKGATE,
-              phy->io_priv + HW_USBPHY_CTRL_SET);
-
-       clk_disable_unprepare(mxs_phy->clk);
-}
-
-static int mxs_phy_suspend(struct usb_phy *x, int suspend)
-{
-       struct mxs_phy *mxs_phy = to_mxs_phy(x);
-
-       if (suspend) {
-               writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
-               writel(BM_USBPHY_CTRL_CLKGATE,
-                      x->io_priv + HW_USBPHY_CTRL_SET);
-               clk_disable_unprepare(mxs_phy->clk);
-       } else {
-               clk_prepare_enable(mxs_phy->clk);
-               writel(BM_USBPHY_CTRL_CLKGATE,
-                      x->io_priv + HW_USBPHY_CTRL_CLR);
-               writel(0, x->io_priv + HW_USBPHY_PWD);
-       }
-
-       return 0;
-}
-
-static int mxs_phy_on_connect(struct usb_phy *phy,
-               enum usb_device_speed speed)
-{
-       dev_dbg(phy->dev, "%s speed device has connected\n",
-               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
-
-       if (speed == USB_SPEED_HIGH)
-               writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
-                      phy->io_priv + HW_USBPHY_CTRL_SET);
-
-       return 0;
-}
-
-static int mxs_phy_on_disconnect(struct usb_phy *phy,
-               enum usb_device_speed speed)
-{
-       dev_dbg(phy->dev, "%s speed device has disconnected\n",
-               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
-
-       if (speed == USB_SPEED_HIGH)
-               writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
-                      phy->io_priv + HW_USBPHY_CTRL_CLR);
-
-       return 0;
-}
-
-static int mxs_phy_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       void __iomem *base;
-       struct clk *clk;
-       struct mxs_phy *mxs_phy;
-       int ret;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "can't get device resources\n");
-               return -ENOENT;
-       }
-
-       base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-
-       clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(clk)) {
-               dev_err(&pdev->dev,
-                       "can't get the clock, err=%ld", PTR_ERR(clk));
-               return PTR_ERR(clk);
-       }
-
-       mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
-       if (!mxs_phy) {
-               dev_err(&pdev->dev, "Failed to allocate USB PHY structure!\n");
-               return -ENOMEM;
-       }
-
-       mxs_phy->phy.io_priv            = base;
-       mxs_phy->phy.dev                = &pdev->dev;
-       mxs_phy->phy.label              = DRIVER_NAME;
-       mxs_phy->phy.init               = mxs_phy_init;
-       mxs_phy->phy.shutdown           = mxs_phy_shutdown;
-       mxs_phy->phy.set_suspend        = mxs_phy_suspend;
-       mxs_phy->phy.notify_connect     = mxs_phy_on_connect;
-       mxs_phy->phy.notify_disconnect  = mxs_phy_on_disconnect;
-
-       ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier);
-
-       mxs_phy->clk = clk;
-
-       platform_set_drvdata(pdev, &mxs_phy->phy);
-
-       ret = usb_add_phy_dev(&mxs_phy->phy);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int mxs_phy_remove(struct platform_device *pdev)
-{
-       struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
-
-       usb_remove_phy(&mxs_phy->phy);
-
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id mxs_phy_dt_ids[] = {
-       { .compatible = "fsl,imx23-usbphy", },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
-
-static struct platform_driver mxs_phy_driver = {
-       .probe = mxs_phy_probe,
-       .remove = mxs_phy_remove,
-       .driver = {
-               .name = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-               .of_match_table = mxs_phy_dt_ids,
-        },
-};
-
-static int __init mxs_phy_module_init(void)
-{
-       return platform_driver_register(&mxs_phy_driver);
-}
-postcore_initcall(mxs_phy_module_init);
-
-static void __exit mxs_phy_module_exit(void)
-{
-       platform_driver_unregister(&mxs_phy_driver);
-}
-module_exit(mxs_phy_module_exit);
-
-MODULE_ALIAS("platform:mxs-usb-phy");
-MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
-MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
-MODULE_DESCRIPTION("Freescale MXS USB PHY driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
deleted file mode 100644 (file)
index 2b10cc9..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * drivers/usb/otg/nop-usb-xceiv.c
- *
- * NOP USB transceiver for all USB transceiver which are either built-in
- * into USB IP or which are mostly autonomous.
- *
- * Copyright (C) 2009 Texas Instruments Inc
- * Author: Ajay Kumar Gupta <ajay.gupta@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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Current status:
- *     This provides a "nop" transceiver for PHYs which are
- *     autonomous such as isp1504, isp1707, etc.
- */
-
-#include <linux/module.h>
-#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>
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
-#include <linux/of.h>
-
-struct nop_usb_xceiv {
-       struct usb_phy phy;
-       struct device *dev;
-       struct clk *clk;
-       struct regulator *vcc;
-       struct regulator *reset;
-};
-
-static struct platform_device *pd;
-
-void usb_nop_xceiv_register(void)
-{
-       if (pd)
-               return;
-       pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
-       if (!pd) {
-               printk(KERN_ERR "Unable to register usb nop transceiver\n");
-               return;
-       }
-}
-EXPORT_SYMBOL(usb_nop_xceiv_register);
-
-void usb_nop_xceiv_unregister(void)
-{
-       platform_device_unregister(pd);
-       pd = NULL;
-}
-EXPORT_SYMBOL(usb_nop_xceiv_unregister);
-
-static int nop_set_suspend(struct usb_phy *x, int suspend)
-{
-       return 0;
-}
-
-static int nop_init(struct usb_phy *phy)
-{
-       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
-
-       if (!IS_ERR(nop->vcc)) {
-               if (regulator_enable(nop->vcc))
-                       dev_err(phy->dev, "Failed to enable power\n");
-       }
-
-       if (!IS_ERR(nop->clk))
-               clk_enable(nop->clk);
-
-       if (!IS_ERR(nop->reset)) {
-               /* De-assert RESET */
-               if (regulator_enable(nop->reset))
-                       dev_err(phy->dev, "Failed to de-assert reset\n");
-       }
-
-       return 0;
-}
-
-static void nop_shutdown(struct usb_phy *phy)
-{
-       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
-
-       if (!IS_ERR(nop->reset)) {
-               /* Assert RESET */
-               if (regulator_disable(nop->reset))
-                       dev_err(phy->dev, "Failed to assert reset\n");
-       }
-
-       if (!IS_ERR(nop->clk))
-               clk_disable(nop->clk);
-
-       if (!IS_ERR(nop->vcc)) {
-               if (regulator_disable(nop->vcc))
-                       dev_err(phy->dev, "Failed to disable power\n");
-       }
-}
-
-static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
-{
-       if (!otg)
-               return -ENODEV;
-
-       if (!gadget) {
-               otg->gadget = NULL;
-               return -ENODEV;
-       }
-
-       otg->gadget = gadget;
-       otg->phy->state = OTG_STATE_B_IDLE;
-       return 0;
-}
-
-static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       if (!otg)
-               return -ENODEV;
-
-       if (!host) {
-               otg->host = NULL;
-               return -ENODEV;
-       }
-
-       otg->host = host;
-       return 0;
-}
-
-static int nop_usb_xceiv_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       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;
-       u32 clk_rate = 0;
-       bool needs_vcc = false;
-       bool needs_reset = false;
-
-       nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
-       if (!nop)
-               return -ENOMEM;
-
-       nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
-                                                       GFP_KERNEL);
-       if (!nop->phy.otg)
-               return -ENOMEM;
-
-       if (dev->of_node) {
-               struct device_node *node = dev->of_node;
-
-               if (of_property_read_u32(node, "clock-frequency", &clk_rate))
-                       clk_rate = 0;
-
-               needs_vcc = of_property_read_bool(node, "vcc-supply");
-               needs_reset = of_property_read_bool(node, "reset-supply");
-
-       } else if (pdata) {
-               type = pdata->type;
-               clk_rate = pdata->clk_rate;
-               needs_vcc = pdata->needs_vcc;
-               needs_reset = pdata->needs_reset;
-       }
-
-       nop->clk = devm_clk_get(&pdev->dev, "main_clk");
-       if (IS_ERR(nop->clk)) {
-               dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
-                                       PTR_ERR(nop->clk));
-       }
-
-       if (!IS_ERR(nop->clk) && clk_rate) {
-               err = clk_set_rate(nop->clk, clk_rate);
-               if (err) {
-                       dev_err(&pdev->dev, "Error setting clock rate\n");
-                       return err;
-               }
-       }
-
-       if (!IS_ERR(nop->clk)) {
-               err = clk_prepare(nop->clk);
-               if (err) {
-                       dev_err(&pdev->dev, "Error preparing clock\n");
-                       return err;
-               }
-       }
-
-       nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
-       if (IS_ERR(nop->vcc)) {
-               dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
-                                       PTR_ERR(nop->vcc));
-               if (needs_vcc)
-                       return -EPROBE_DEFER;
-       }
-
-       nop->reset = devm_regulator_get(&pdev->dev, "reset");
-       if (IS_ERR(nop->reset)) {
-               dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
-                                       PTR_ERR(nop->reset));
-               if (needs_reset)
-                       return -EPROBE_DEFER;
-       }
-
-       nop->dev                = &pdev->dev;
-       nop->phy.dev            = nop->dev;
-       nop->phy.label          = "nop-xceiv";
-       nop->phy.set_suspend    = nop_set_suspend;
-       nop->phy.init           = nop_init;
-       nop->phy.shutdown       = nop_shutdown;
-       nop->phy.state          = OTG_STATE_UNDEFINED;
-       nop->phy.type           = type;
-
-       nop->phy.otg->phy               = &nop->phy;
-       nop->phy.otg->set_host          = nop_set_host;
-       nop->phy.otg->set_peripheral    = nop_set_peripheral;
-
-       err = usb_add_phy_dev(&nop->phy);
-       if (err) {
-               dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
-                       err);
-               goto err_add;
-       }
-
-       platform_set_drvdata(pdev, nop);
-
-       ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
-
-       return 0;
-
-err_add:
-       if (!IS_ERR(nop->clk))
-               clk_unprepare(nop->clk);
-       return err;
-}
-
-static int nop_usb_xceiv_remove(struct platform_device *pdev)
-{
-       struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
-
-       if (!IS_ERR(nop->clk))
-               clk_unprepare(nop->clk);
-
-       usb_remove_phy(&nop->phy);
-
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id nop_xceiv_dt_ids[] = {
-       { .compatible = "usb-nop-xceiv" },
-       { }
-};
-
-MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
-
-static struct platform_driver nop_usb_xceiv_driver = {
-       .probe          = nop_usb_xceiv_probe,
-       .remove         = nop_usb_xceiv_remove,
-       .driver         = {
-               .name   = "nop_usb_xceiv",
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(nop_xceiv_dt_ids),
-       },
-};
-
-static int __init nop_usb_xceiv_init(void)
-{
-       return platform_driver_register(&nop_usb_xceiv_driver);
-}
-subsys_initcall(nop_usb_xceiv_init);
-
-static void __exit nop_usb_xceiv_exit(void)
-{
-       platform_driver_unregister(&nop_usb_xceiv_driver);
-}
-module_exit(nop_usb_xceiv_exit);
-
-MODULE_ALIAS("platform:nop_usb_xceiv");
-MODULE_AUTHOR("Texas Instruments Inc");
-MODULE_DESCRIPTION("NOP USB Transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/otg_fsm.c b/drivers/usb/otg/otg_fsm.c
deleted file mode 100644 (file)
index 1f729a1..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * OTG Finite State Machine from OTG spec
- *
- * Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
- *
- * Author:     Li Yang <LeoLi@freescale.com>
- *             Jerry Huang <Chang-Ming.Huang@freescale.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.
- *
- * 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.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-
-#include "otg_fsm.h"
-
-/* Change USB protocol when there is a protocol change */
-static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
-{
-       int ret = 0;
-
-       if (fsm->protocol != protocol) {
-               VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
-                       fsm->protocol, protocol);
-               /* stop old protocol */
-               if (fsm->protocol == PROTO_HOST)
-                       ret = fsm->ops->start_host(fsm, 0);
-               else if (fsm->protocol == PROTO_GADGET)
-                       ret = fsm->ops->start_gadget(fsm, 0);
-               if (ret)
-                       return ret;
-
-               /* start new protocol */
-               if (protocol == PROTO_HOST)
-                       ret = fsm->ops->start_host(fsm, 1);
-               else if (protocol == PROTO_GADGET)
-                       ret = fsm->ops->start_gadget(fsm, 1);
-               if (ret)
-                       return ret;
-
-               fsm->protocol = protocol;
-               return 0;
-       }
-
-       return 0;
-}
-
-static int state_changed;
-
-/* Called when leaving a state.  Do state clean up jobs here */
-void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
-{
-       switch (old_state) {
-       case OTG_STATE_B_IDLE:
-               otg_del_timer(fsm, b_se0_srp_tmr);
-               fsm->b_se0_srp = 0;
-               break;
-       case OTG_STATE_B_SRP_INIT:
-               fsm->b_srp_done = 0;
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               break;
-       case OTG_STATE_B_WAIT_ACON:
-               otg_del_timer(fsm, b_ase0_brst_tmr);
-               fsm->b_ase0_brst_tmout = 0;
-               break;
-       case OTG_STATE_B_HOST:
-               break;
-       case OTG_STATE_A_IDLE:
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               otg_del_timer(fsm, a_wait_vrise_tmr);
-               fsm->a_wait_vrise_tmout = 0;
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               otg_del_timer(fsm, a_wait_bcon_tmr);
-               fsm->a_wait_bcon_tmout = 0;
-               break;
-       case OTG_STATE_A_HOST:
-               otg_del_timer(fsm, a_wait_enum_tmr);
-               break;
-       case OTG_STATE_A_SUSPEND:
-               otg_del_timer(fsm, a_aidl_bdis_tmr);
-               fsm->a_aidl_bdis_tmout = 0;
-               fsm->a_suspend_req = 0;
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               break;
-       case OTG_STATE_A_WAIT_VFALL:
-               otg_del_timer(fsm, a_wait_vrise_tmr);
-               break;
-       case OTG_STATE_A_VBUS_ERR:
-               break;
-       default:
-               break;
-       }
-}
-
-/* Called when entering a state */
-int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
-{
-       state_changed = 1;
-       if (fsm->otg->phy->state == new_state)
-               return 0;
-       VDBG("Set state: %s\n", usb_otg_state_string(new_state));
-       otg_leave_state(fsm, fsm->otg->phy->state);
-       switch (new_state) {
-       case OTG_STATE_B_IDLE:
-               otg_drv_vbus(fsm, 0);
-               otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_UNDEF);
-               otg_add_timer(fsm, b_se0_srp_tmr);
-               break;
-       case OTG_STATE_B_SRP_INIT:
-               otg_start_pulse(fsm);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_UNDEF);
-               otg_add_timer(fsm, b_srp_fail_tmr);
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 1);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_GADGET);
-               break;
-       case OTG_STATE_B_WAIT_ACON:
-               otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_HOST);
-               otg_add_timer(fsm, b_ase0_brst_tmr);
-               fsm->a_bus_suspend = 0;
-               break;
-       case OTG_STATE_B_HOST:
-               otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 1);
-               otg_set_protocol(fsm, PROTO_HOST);
-               usb_bus_start_enum(fsm->otg->host,
-                               fsm->otg->host->otg_port);
-               break;
-       case OTG_STATE_A_IDLE:
-               otg_drv_vbus(fsm, 0);
-               otg_chrg_vbus(fsm, 0);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_HOST);
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               otg_drv_vbus(fsm, 1);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_HOST);
-               otg_add_timer(fsm, a_wait_vrise_tmr);
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               otg_drv_vbus(fsm, 1);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_HOST);
-               otg_add_timer(fsm, a_wait_bcon_tmr);
-               break;
-       case OTG_STATE_A_HOST:
-               otg_drv_vbus(fsm, 1);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 1);
-               otg_set_protocol(fsm, PROTO_HOST);
-               /*
-                * When HNP is triggered while a_bus_req = 0, a_host will
-                * suspend too fast to complete a_set_b_hnp_en
-                */
-               if (!fsm->a_bus_req || fsm->a_suspend_req)
-                       otg_add_timer(fsm, a_wait_enum_tmr);
-               break;
-       case OTG_STATE_A_SUSPEND:
-               otg_drv_vbus(fsm, 1);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_HOST);
-               otg_add_timer(fsm, a_aidl_bdis_tmr);
-
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               otg_loc_conn(fsm, 1);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_GADGET);
-               otg_drv_vbus(fsm, 1);
-               break;
-       case OTG_STATE_A_WAIT_VFALL:
-               otg_drv_vbus(fsm, 0);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_HOST);
-               break;
-       case OTG_STATE_A_VBUS_ERR:
-               otg_drv_vbus(fsm, 0);
-               otg_loc_conn(fsm, 0);
-               otg_loc_sof(fsm, 0);
-               otg_set_protocol(fsm, PROTO_UNDEF);
-               break;
-       default:
-               break;
-       }
-
-       fsm->otg->phy->state = new_state;
-       return 0;
-}
-
-/* State change judgement */
-int otg_statemachine(struct otg_fsm *fsm)
-{
-       enum usb_otg_state state;
-       unsigned long flags;
-
-       spin_lock_irqsave(&fsm->lock, flags);
-
-       state = fsm->otg->phy->state;
-       state_changed = 0;
-       /* State machine state change judgement */
-
-       switch (state) {
-       case OTG_STATE_UNDEFINED:
-               VDBG("fsm->id = %d\n", fsm->id);
-               if (fsm->id)
-                       otg_set_state(fsm, OTG_STATE_B_IDLE);
-               else
-                       otg_set_state(fsm, OTG_STATE_A_IDLE);
-               break;
-       case OTG_STATE_B_IDLE:
-               if (!fsm->id)
-                       otg_set_state(fsm, OTG_STATE_A_IDLE);
-               else if (fsm->b_sess_vld && fsm->otg->gadget)
-                       otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
-               else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp)
-                       otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
-               break;
-       case OTG_STATE_B_SRP_INIT:
-               if (!fsm->id || fsm->b_srp_done)
-                       otg_set_state(fsm, OTG_STATE_B_IDLE);
-               break;
-       case OTG_STATE_B_PERIPHERAL:
-               if (!fsm->id || !fsm->b_sess_vld)
-                       otg_set_state(fsm, OTG_STATE_B_IDLE);
-               else if (fsm->b_bus_req && fsm->otg->
-                               gadget->b_hnp_enable && fsm->a_bus_suspend)
-                       otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
-               break;
-       case OTG_STATE_B_WAIT_ACON:
-               if (fsm->a_conn)
-                       otg_set_state(fsm, OTG_STATE_B_HOST);
-               else if (!fsm->id || !fsm->b_sess_vld)
-                       otg_set_state(fsm, OTG_STATE_B_IDLE);
-               else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) {
-                       fsm->b_ase0_brst_tmout = 0;
-                       otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
-               }
-               break;
-       case OTG_STATE_B_HOST:
-               if (!fsm->id || !fsm->b_sess_vld)
-                       otg_set_state(fsm, OTG_STATE_B_IDLE);
-               else if (!fsm->b_bus_req || !fsm->a_conn)
-                       otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
-               break;
-       case OTG_STATE_A_IDLE:
-               if (fsm->id)
-                       otg_set_state(fsm, OTG_STATE_B_IDLE);
-               else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det))
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);
-               break;
-       case OTG_STATE_A_WAIT_VRISE:
-               if (fsm->id || fsm->a_bus_drop || fsm->a_vbus_vld ||
-                               fsm->a_wait_vrise_tmout) {
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
-               }
-               break;
-       case OTG_STATE_A_WAIT_BCON:
-               if (!fsm->a_vbus_vld)
-                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
-               else if (fsm->b_conn)
-                       otg_set_state(fsm, OTG_STATE_A_HOST);
-               else if (fsm->id | fsm->a_bus_drop | fsm->a_wait_bcon_tmout)
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
-               break;
-       case OTG_STATE_A_HOST:
-               if ((!fsm->a_bus_req || fsm->a_suspend_req) &&
-                               fsm->otg->host->b_hnp_enable)
-                       otg_set_state(fsm, OTG_STATE_A_SUSPEND);
-               else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop)
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
-               else if (!fsm->a_vbus_vld)
-                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
-               break;
-       case OTG_STATE_A_SUSPEND:
-               if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
-                       otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
-               else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
-               else if (fsm->a_bus_req || fsm->b_bus_resume)
-                       otg_set_state(fsm, OTG_STATE_A_HOST);
-               else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout)
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
-               else if (!fsm->a_vbus_vld)
-                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
-               break;
-       case OTG_STATE_A_PERIPHERAL:
-               if (fsm->id || fsm->a_bus_drop)
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
-               else if (fsm->b_bus_suspend)
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
-               else if (!fsm->a_vbus_vld)
-                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
-               break;
-       case OTG_STATE_A_WAIT_VFALL:
-               if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld &&
-                                       !fsm->b_conn))
-                       otg_set_state(fsm, OTG_STATE_A_IDLE);
-               break;
-       case OTG_STATE_A_VBUS_ERR:
-               if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err)
-                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
-               break;
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&fsm->lock, flags);
-
-       VDBG("quit statemachine, changed = %d\n", state_changed);
-       return state_changed;
-}
diff --git a/drivers/usb/otg/otg_fsm.h b/drivers/usb/otg/otg_fsm.h
deleted file mode 100644 (file)
index c30a2e1..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#undef DEBUG
-#undef VERBOSE
-
-#ifdef DEBUG
-#define DBG(fmt, args...) printk(KERN_DEBUG "[%s]  " fmt , \
-                                __func__, ## args)
-#else
-#define DBG(fmt, args...)      do {} while (0)
-#endif
-
-#ifdef VERBOSE
-#define VDBG           DBG
-#else
-#define VDBG(stuff...) do {} while (0)
-#endif
-
-#ifdef VERBOSE
-#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__)
-#else
-#define MPC_LOC do {} while (0)
-#endif
-
-#define PROTO_UNDEF    (0)
-#define PROTO_HOST     (1)
-#define PROTO_GADGET   (2)
-
-/* OTG state machine according to the OTG spec */
-struct otg_fsm {
-       /* Input */
-       int a_bus_resume;
-       int a_bus_suspend;
-       int a_conn;
-       int a_sess_vld;
-       int a_srp_det;
-       int a_vbus_vld;
-       int b_bus_resume;
-       int b_bus_suspend;
-       int b_conn;
-       int b_se0_srp;
-       int b_sess_end;
-       int b_sess_vld;
-       int id;
-
-       /* Internal variables */
-       int a_set_b_hnp_en;
-       int b_srp_done;
-       int b_hnp_enable;
-
-       /* Timeout indicator for timers */
-       int a_wait_vrise_tmout;
-       int a_wait_bcon_tmout;
-       int a_aidl_bdis_tmout;
-       int b_ase0_brst_tmout;
-
-       /* Informative variables */
-       int a_bus_drop;
-       int a_bus_req;
-       int a_clr_err;
-       int a_suspend_req;
-       int b_bus_req;
-
-       /* Output */
-       int drv_vbus;
-       int loc_conn;
-       int loc_sof;
-
-       struct otg_fsm_ops *ops;
-       struct usb_otg *otg;
-
-       /* Current usb protocol used: 0:undefine; 1:host; 2:client */
-       int protocol;
-       spinlock_t lock;
-};
-
-struct otg_fsm_ops {
-       void    (*chrg_vbus)(int on);
-       void    (*drv_vbus)(int on);
-       void    (*loc_conn)(int on);
-       void    (*loc_sof)(int on);
-       void    (*start_pulse)(void);
-       void    (*add_timer)(void *timer);
-       void    (*del_timer)(void *timer);
-       int     (*start_host)(struct otg_fsm *fsm, int on);
-       int     (*start_gadget)(struct otg_fsm *fsm, int on);
-};
-
-
-static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on)
-{
-       fsm->ops->chrg_vbus(on);
-}
-
-static inline void otg_drv_vbus(struct otg_fsm *fsm, int on)
-{
-       if (fsm->drv_vbus != on) {
-               fsm->drv_vbus = on;
-               fsm->ops->drv_vbus(on);
-       }
-}
-
-static inline void otg_loc_conn(struct otg_fsm *fsm, int on)
-{
-       if (fsm->loc_conn != on) {
-               fsm->loc_conn = on;
-               fsm->ops->loc_conn(on);
-       }
-}
-
-static inline void otg_loc_sof(struct otg_fsm *fsm, int on)
-{
-       if (fsm->loc_sof != on) {
-               fsm->loc_sof = on;
-               fsm->ops->loc_sof(on);
-       }
-}
-
-static inline void otg_start_pulse(struct otg_fsm *fsm)
-{
-       fsm->ops->start_pulse();
-}
-
-static inline void otg_add_timer(struct otg_fsm *fsm, void *timer)
-{
-       fsm->ops->add_timer(timer);
-}
-
-static inline void otg_del_timer(struct otg_fsm *fsm, void *timer)
-{
-       fsm->ops->del_timer(timer);
-}
-
-int otg_statemachine(struct otg_fsm *fsm);
-
-/* Defined by device specific driver, for different timer implementation */
-extern struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr,
-       *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_fail_tmr,
-       *a_wait_enum_tmr;
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
deleted file mode 100644 (file)
index a994715..0000000
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller
- *
- * Copyright (C) 2004-2007 Texas Instruments
- * Copyright (C) 2008 Nokia Corporation
- * Contact: Felipe Balbi <felipe.balbi@nokia.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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Current status:
- *     - HS USB ULPI mode works.
- *     - 3-pin mode support may be added in future.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/musb-omap.h>
-#include <linux/usb/ulpi.h>
-#include <linux/i2c/twl.h>
-#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-
-/* Register defines */
-
-#define MCPC_CTRL                      0x30
-#define MCPC_CTRL_RTSOL                        (1 << 7)
-#define MCPC_CTRL_EXTSWR               (1 << 6)
-#define MCPC_CTRL_EXTSWC               (1 << 5)
-#define MCPC_CTRL_VOICESW              (1 << 4)
-#define MCPC_CTRL_OUT64K               (1 << 3)
-#define MCPC_CTRL_RTSCTSSW             (1 << 2)
-#define MCPC_CTRL_HS_UART              (1 << 0)
-
-#define MCPC_IO_CTRL                   0x33
-#define MCPC_IO_CTRL_MICBIASEN         (1 << 5)
-#define MCPC_IO_CTRL_CTS_NPU           (1 << 4)
-#define MCPC_IO_CTRL_RXD_PU            (1 << 3)
-#define MCPC_IO_CTRL_TXDTYP            (1 << 2)
-#define MCPC_IO_CTRL_CTSTYP            (1 << 1)
-#define MCPC_IO_CTRL_RTSTYP            (1 << 0)
-
-#define MCPC_CTRL2                     0x36
-#define MCPC_CTRL2_MCPC_CK_EN          (1 << 0)
-
-#define OTHER_FUNC_CTRL                        0x80
-#define OTHER_FUNC_CTRL_BDIS_ACON_EN   (1 << 4)
-#define OTHER_FUNC_CTRL_FIVEWIRE_MODE  (1 << 2)
-
-#define OTHER_IFC_CTRL                 0x83
-#define OTHER_IFC_CTRL_OE_INT_EN       (1 << 6)
-#define OTHER_IFC_CTRL_CEA2011_MODE    (1 << 5)
-#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN     (1 << 4)
-#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT      (1 << 3)
-#define OTHER_IFC_CTRL_HIZ_ULPI                (1 << 2)
-#define OTHER_IFC_CTRL_ALT_INT_REROUTE (1 << 0)
-
-#define OTHER_INT_EN_RISE              0x86
-#define OTHER_INT_EN_FALL              0x89
-#define OTHER_INT_STS                  0x8C
-#define OTHER_INT_LATCH                        0x8D
-#define OTHER_INT_VB_SESS_VLD          (1 << 7)
-#define OTHER_INT_DM_HI                        (1 << 6) /* not valid for "latch" reg */
-#define OTHER_INT_DP_HI                        (1 << 5) /* not valid for "latch" reg */
-#define OTHER_INT_BDIS_ACON            (1 << 3) /* not valid for "fall" regs */
-#define OTHER_INT_MANU                 (1 << 1)
-#define OTHER_INT_ABNORMAL_STRESS      (1 << 0)
-
-#define ID_STATUS                      0x96
-#define ID_RES_FLOAT                   (1 << 4)
-#define ID_RES_440K                    (1 << 3)
-#define ID_RES_200K                    (1 << 2)
-#define ID_RES_102K                    (1 << 1)
-#define ID_RES_GND                     (1 << 0)
-
-#define POWER_CTRL                     0xAC
-#define POWER_CTRL_OTG_ENAB            (1 << 5)
-
-#define OTHER_IFC_CTRL2                        0xAF
-#define OTHER_IFC_CTRL2_ULPI_STP_LOW   (1 << 4)
-#define OTHER_IFC_CTRL2_ULPI_TXEN_POL  (1 << 3)
-#define OTHER_IFC_CTRL2_ULPI_4PIN_2430 (1 << 2)
-#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK    (3 << 0) /* bits 0 and 1 */
-#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N   (0 << 0)
-#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N   (1 << 0)
-
-#define REG_CTRL_EN                    0xB2
-#define REG_CTRL_ERROR                 0xB5
-#define ULPI_I2C_CONFLICT_INTEN                (1 << 0)
-
-#define OTHER_FUNC_CTRL2               0xB8
-#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN (1 << 0)
-
-/* following registers do not have separate _clr and _set registers */
-#define VBUS_DEBOUNCE                  0xC0
-#define ID_DEBOUNCE                    0xC1
-#define VBAT_TIMER                     0xD3
-#define PHY_PWR_CTRL                   0xFD
-#define PHY_PWR_PHYPWD                 (1 << 0)
-#define PHY_CLK_CTRL                   0xFE
-#define PHY_CLK_CTRL_CLOCKGATING_EN    (1 << 2)
-#define PHY_CLK_CTRL_CLK32K_EN         (1 << 1)
-#define REQ_PHY_DPLL_CLK               (1 << 0)
-#define PHY_CLK_CTRL_STS               0xFF
-#define PHY_DPLL_CLK                   (1 << 0)
-
-/* In module TWL_MODULE_PM_MASTER */
-#define STS_HW_CONDITIONS              0x0F
-
-/* In module TWL_MODULE_PM_RECEIVER */
-#define VUSB_DEDICATED1                        0x7D
-#define VUSB_DEDICATED2                        0x7E
-#define VUSB1V5_DEV_GRP                        0x71
-#define VUSB1V5_TYPE                   0x72
-#define VUSB1V5_REMAP                  0x73
-#define VUSB1V8_DEV_GRP                        0x74
-#define VUSB1V8_TYPE                   0x75
-#define VUSB1V8_REMAP                  0x76
-#define VUSB3V1_DEV_GRP                        0x77
-#define VUSB3V1_TYPE                   0x78
-#define VUSB3V1_REMAP                  0x79
-
-/* In module TWL4030_MODULE_INTBR */
-#define PMBR1                          0x0D
-#define GPIO_USB_4PIN_ULPI_2430C       (3 << 0)
-
-struct twl4030_usb {
-       struct usb_phy          phy;
-       struct device           *dev;
-
-       /* TWL4030 internal USB regulator supplies */
-       struct regulator        *usb1v5;
-       struct regulator        *usb1v8;
-       struct regulator        *usb3v1;
-
-       /* for vbus reporting with irqs disabled */
-       spinlock_t              lock;
-
-       /* pin configuration */
-       enum twl4030_usb_mode   usb_mode;
-
-       int                     irq;
-       enum omap_musb_vbus_id_status linkstat;
-       bool                    vbus_supplied;
-       u8                      asleep;
-       bool                    irq_enabled;
-};
-
-/* internal define on top of container_of */
-#define phy_to_twl(x)          container_of((x), struct twl4030_usb, phy)
-
-/*-------------------------------------------------------------------------*/
-
-static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl,
-               u8 module, u8 data, u8 address)
-{
-       u8 check;
-
-       if ((twl_i2c_write_u8(module, data, address) >= 0) &&
-           (twl_i2c_read_u8(module, &check, address) >= 0) &&
-                                               (check == data))
-               return 0;
-       dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
-                       1, module, address, check, data);
-
-       /* Failed once: Try again */
-       if ((twl_i2c_write_u8(module, data, address) >= 0) &&
-           (twl_i2c_read_u8(module, &check, address) >= 0) &&
-                                               (check == data))
-               return 0;
-       dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
-                       2, module, address, check, data);
-
-       /* Failed again: Return error */
-       return -EBUSY;
-}
-
-#define twl4030_usb_write_verify(twl, address, data)   \
-       twl4030_i2c_write_u8_verify(twl, TWL_MODULE_USB, (data), (address))
-
-static inline int twl4030_usb_write(struct twl4030_usb *twl,
-               u8 address, u8 data)
-{
-       int ret = 0;
-
-       ret = twl_i2c_write_u8(TWL_MODULE_USB, data, address);
-       if (ret < 0)
-               dev_dbg(twl->dev,
-                       "TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
-       return ret;
-}
-
-static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address)
-{
-       u8 data;
-       int ret = 0;
-
-       ret = twl_i2c_read_u8(module, &data, address);
-       if (ret >= 0)
-               ret = data;
-       else
-               dev_dbg(twl->dev,
-                       "TWL4030:readb[0x%x,0x%x] Error %d\n",
-                                       module, address, ret);
-
-       return ret;
-}
-
-static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address)
-{
-       return twl4030_readb(twl, TWL_MODULE_USB, address);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static inline int
-twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
-{
-       return twl4030_usb_write(twl, ULPI_SET(reg), bits);
-}
-
-static inline int
-twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
-{
-       return twl4030_usb_write(twl, ULPI_CLR(reg), bits);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static enum omap_musb_vbus_id_status
-       twl4030_usb_linkstat(struct twl4030_usb *twl)
-{
-       int     status;
-       enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN;
-
-       twl->vbus_supplied = false;
-
-       /*
-        * For ID/VBUS sensing, see manual section 15.4.8 ...
-        * except when using only battery backup power, two
-        * comparators produce VBUS_PRES and ID_PRES signals,
-        * which don't match docs elsewhere.  But ... BIT(7)
-        * and BIT(2) of STS_HW_CONDITIONS, respectively, do
-        * seem to match up.  If either is true the USB_PRES
-        * signal is active, the OTG module is activated, and
-        * its interrupt may be raised (may wake the system).
-        */
-       status = twl4030_readb(twl, TWL_MODULE_PM_MASTER, STS_HW_CONDITIONS);
-       if (status < 0)
-               dev_err(twl->dev, "USB link status err %d\n", status);
-       else if (status & (BIT(7) | BIT(2))) {
-               if (status & (BIT(7)))
-                        twl->vbus_supplied = true;
-
-               if (status & BIT(2))
-                       linkstat = OMAP_MUSB_ID_GROUND;
-               else
-                       linkstat = OMAP_MUSB_VBUS_VALID;
-       } else {
-               if (twl->linkstat != OMAP_MUSB_UNKNOWN)
-                       linkstat = OMAP_MUSB_VBUS_OFF;
-       }
-
-       dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
-                       status, status, linkstat);
-
-       /* REVISIT this assumes host and peripheral controllers
-        * are registered, and that both are active...
-        */
-
-       spin_lock_irq(&twl->lock);
-       twl->linkstat = linkstat;
-       spin_unlock_irq(&twl->lock);
-
-       return linkstat;
-}
-
-static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
-{
-       twl->usb_mode = mode;
-
-       switch (mode) {
-       case T2_USB_MODE_ULPI:
-               twl4030_usb_clear_bits(twl, ULPI_IFC_CTRL,
-                                       ULPI_IFC_CTRL_CARKITMODE);
-               twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
-               twl4030_usb_clear_bits(twl, ULPI_FUNC_CTRL,
-                                       ULPI_FUNC_CTRL_XCVRSEL_MASK |
-                                       ULPI_FUNC_CTRL_OPMODE_MASK);
-               break;
-       case -1:
-               /* FIXME: power on defaults */
-               break;
-       default:
-               dev_err(twl->dev, "unsupported T2 transceiver mode %d\n",
-                               mode);
-               break;
-       };
-}
-
-static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
-{
-       unsigned long timeout;
-       int val = twl4030_usb_read(twl, PHY_CLK_CTRL);
-
-       if (val >= 0) {
-               if (on) {
-                       /* enable DPLL to access PHY registers over I2C */
-                       val |= REQ_PHY_DPLL_CLK;
-                       WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
-                                               (u8)val) < 0);
-
-                       timeout = jiffies + HZ;
-                       while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
-                                                       PHY_DPLL_CLK)
-                               && time_before(jiffies, timeout))
-                                       udelay(10);
-                       if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
-                                                       PHY_DPLL_CLK))
-                               dev_err(twl->dev, "Timeout setting T2 HSUSB "
-                                               "PHY DPLL clock\n");
-               } else {
-                       /* let ULPI control the DPLL clock */
-                       val &= ~REQ_PHY_DPLL_CLK;
-                       WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
-                                               (u8)val) < 0);
-               }
-       }
-}
-
-static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
-{
-       u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
-
-       if (on)
-               pwr &= ~PHY_PWR_PHYPWD;
-       else
-               pwr |= PHY_PWR_PHYPWD;
-
-       WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
-}
-
-static void twl4030_phy_power(struct twl4030_usb *twl, int on)
-{
-       if (on) {
-               regulator_enable(twl->usb3v1);
-               regulator_enable(twl->usb1v8);
-               /*
-                * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
-                * in twl4030) resets the VUSB_DEDICATED2 register. This reset
-                * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to
-                * SLEEP. We work around this by clearing the bit after usv3v1
-                * is re-activated. This ensures that VUSB3V1 is really active.
-                */
-               twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
-               regulator_enable(twl->usb1v5);
-               __twl4030_phy_power(twl, 1);
-               twl4030_usb_write(twl, PHY_CLK_CTRL,
-                                 twl4030_usb_read(twl, PHY_CLK_CTRL) |
-                                       (PHY_CLK_CTRL_CLOCKGATING_EN |
-                                               PHY_CLK_CTRL_CLK32K_EN));
-       } else {
-               __twl4030_phy_power(twl, 0);
-               regulator_disable(twl->usb1v5);
-               regulator_disable(twl->usb1v8);
-               regulator_disable(twl->usb3v1);
-       }
-}
-
-static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off)
-{
-       if (twl->asleep)
-               return;
-
-       twl4030_phy_power(twl, 0);
-       twl->asleep = 1;
-       dev_dbg(twl->dev, "%s\n", __func__);
-}
-
-static void __twl4030_phy_resume(struct twl4030_usb *twl)
-{
-       twl4030_phy_power(twl, 1);
-       twl4030_i2c_access(twl, 1);
-       twl4030_usb_set_mode(twl, twl->usb_mode);
-       if (twl->usb_mode == T2_USB_MODE_ULPI)
-               twl4030_i2c_access(twl, 0);
-}
-
-static void twl4030_phy_resume(struct twl4030_usb *twl)
-{
-       if (!twl->asleep)
-               return;
-       __twl4030_phy_resume(twl);
-       twl->asleep = 0;
-       dev_dbg(twl->dev, "%s\n", __func__);
-}
-
-static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
-{
-       /* Enable writing to power configuration registers */
-       twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
-                        TWL4030_PM_MASTER_PROTECT_KEY);
-
-       twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
-                        TWL4030_PM_MASTER_PROTECT_KEY);
-
-       /* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/
-       /*twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/
-
-       /* input to VUSB3V1 LDO is from VBAT, not VBUS */
-       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
-
-       /* Initialize 3.1V regulator */
-       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
-
-       twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
-       if (IS_ERR(twl->usb3v1))
-               return -ENODEV;
-
-       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
-
-       /* Initialize 1.5V regulator */
-       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
-
-       twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
-       if (IS_ERR(twl->usb1v5))
-               goto fail1;
-
-       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
-
-       /* Initialize 1.8V regulator */
-       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
-
-       twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
-       if (IS_ERR(twl->usb1v8))
-               goto fail2;
-
-       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
-
-       /* disable access to power configuration registers */
-       twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
-                        TWL4030_PM_MASTER_PROTECT_KEY);
-
-       return 0;
-
-fail2:
-       regulator_put(twl->usb1v5);
-       twl->usb1v5 = NULL;
-fail1:
-       regulator_put(twl->usb3v1);
-       twl->usb3v1 = NULL;
-       return -ENODEV;
-}
-
-static ssize_t twl4030_usb_vbus_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct twl4030_usb *twl = dev_get_drvdata(dev);
-       unsigned long flags;
-       int ret = -EINVAL;
-
-       spin_lock_irqsave(&twl->lock, flags);
-       ret = sprintf(buf, "%s\n",
-                       twl->vbus_supplied ? "on" : "off");
-       spin_unlock_irqrestore(&twl->lock, flags);
-
-       return ret;
-}
-static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
-
-static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
-{
-       struct twl4030_usb *twl = _twl;
-       enum omap_musb_vbus_id_status status;
-
-       status = twl4030_usb_linkstat(twl);
-       if (status > 0) {
-               /* FIXME add a set_power() method so that B-devices can
-                * configure the charger appropriately.  It's not always
-                * correct to consume VBUS power, and how much current to
-                * consume is a function of the USB configuration chosen
-                * by the host.
-                *
-                * REVISIT usb_gadget_vbus_connect(...) as needed, ditto
-                * its disconnect() sibling, when changing to/from the
-                * USB_LINK_VBUS state.  musb_hdrc won't care until it
-                * starts to handle softconnect right.
-                */
-               if (status == OMAP_MUSB_VBUS_OFF ||
-                               status == OMAP_MUSB_ID_FLOAT)
-                       twl4030_phy_suspend(twl, 0);
-               else
-                       twl4030_phy_resume(twl);
-
-               omap_musb_mailbox(twl->linkstat);
-       }
-       sysfs_notify(&twl->dev->kobj, NULL, "vbus");
-
-       return IRQ_HANDLED;
-}
-
-static void twl4030_usb_phy_init(struct twl4030_usb *twl)
-{
-       enum omap_musb_vbus_id_status status;
-
-       status = twl4030_usb_linkstat(twl);
-       if (status > 0) {
-               if (status == OMAP_MUSB_VBUS_OFF ||
-                               status == OMAP_MUSB_ID_FLOAT) {
-                       __twl4030_phy_power(twl, 0);
-                       twl->asleep = 1;
-               } else {
-                       __twl4030_phy_resume(twl);
-                       twl->asleep = 0;
-               }
-
-               omap_musb_mailbox(twl->linkstat);
-       }
-       sysfs_notify(&twl->dev->kobj, NULL, "vbus");
-}
-
-static int twl4030_set_suspend(struct usb_phy *x, int suspend)
-{
-       struct twl4030_usb *twl = phy_to_twl(x);
-
-       if (suspend)
-               twl4030_phy_suspend(twl, 1);
-       else
-               twl4030_phy_resume(twl);
-
-       return 0;
-}
-
-static int twl4030_set_peripheral(struct usb_otg *otg,
-                                       struct usb_gadget *gadget)
-{
-       if (!otg)
-               return -ENODEV;
-
-       otg->gadget = gadget;
-       if (!gadget)
-               otg->phy->state = OTG_STATE_UNDEFINED;
-
-       return 0;
-}
-
-static int twl4030_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 twl4030_usb_probe(struct platform_device *pdev)
-{
-       struct twl4030_usb_data *pdata = pdev->dev.platform_data;
-       struct twl4030_usb      *twl;
-       int                     status, err;
-       struct usb_otg          *otg;
-       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->vbus_supplied      = false;
-       twl->asleep             = 1;
-       twl->linkstat           = OMAP_MUSB_UNKNOWN;
-
-       twl->phy.dev            = twl->dev;
-       twl->phy.label          = "twl4030";
-       twl->phy.otg            = otg;
-       twl->phy.type           = USB_PHY_TYPE_USB2;
-       twl->phy.set_suspend    = twl4030_set_suspend;
-
-       otg->phy                = &twl->phy;
-       otg->set_host           = twl4030_set_host;
-       otg->set_peripheral     = twl4030_set_peripheral;
-
-       /* init spinlock for workqueue */
-       spin_lock_init(&twl->lock);
-
-       err = twl4030_usb_ldo_init(twl);
-       if (err) {
-               dev_err(&pdev->dev, "ldo init failed\n");
-               return err;
-       }
-       usb_add_phy_dev(&twl->phy);
-
-       platform_set_drvdata(pdev, twl);
-       if (device_create_file(&pdev->dev, &dev_attr_vbus))
-               dev_warn(&pdev->dev, "could not create sysfs file\n");
-
-       /* Our job is to use irqs and status from the power module
-        * to keep the transceiver disabled when nothing's connected.
-        *
-        * FIXME we actually shouldn't start enabling it until the
-        * USB controller drivers have said they're ready, by calling
-        * set_host() and/or set_peripheral() ... OTG_capable boards
-        * need both handles, otherwise just one suffices.
-        */
-       twl->irq_enabled = true;
-       status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
-                       IRQF_ONESHOT, "twl4030_usb", twl);
-       if (status < 0) {
-               dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
-                       twl->irq, status);
-               return status;
-       }
-
-       /* Power down phy or make it work according to
-        * current link state.
-        */
-       twl4030_usb_phy_init(twl);
-
-       dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
-       return 0;
-}
-
-static int __exit twl4030_usb_remove(struct platform_device *pdev)
-{
-       struct twl4030_usb *twl = platform_get_drvdata(pdev);
-       int val;
-
-       free_irq(twl->irq, twl);
-       device_remove_file(twl->dev, &dev_attr_vbus);
-
-       /* set transceiver mode to power on defaults */
-       twl4030_usb_set_mode(twl, -1);
-
-       /* autogate 60MHz ULPI clock,
-        * clear dpll clock request for i2c access,
-        * disable 32KHz
-        */
-       val = twl4030_usb_read(twl, PHY_CLK_CTRL);
-       if (val >= 0) {
-               val |= PHY_CLK_CTRL_CLOCKGATING_EN;
-               val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK);
-               twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val);
-       }
-
-       /* disable complete OTG block */
-       twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
-
-       if (!twl->asleep)
-               twl4030_phy_power(twl, 0);
-       regulator_put(twl->usb1v5);
-       regulator_put(twl->usb1v8);
-       regulator_put(twl->usb3v1);
-
-       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),
-       },
-};
-
-static int __init twl4030_usb_init(void)
-{
-       return platform_driver_register(&twl4030_usb_driver);
-}
-subsys_initcall(twl4030_usb_init);
-
-static void __exit twl4030_usb_exit(void)
-{
-       platform_driver_unregister(&twl4030_usb_driver);
-}
-module_exit(twl4030_usb_exit);
-
-MODULE_ALIAS("platform:twl4030_usb");
-MODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation");
-MODULE_DESCRIPTION("TWL4030 USB transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
deleted file mode 100644 (file)
index 8cd6cf4..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver.
- *
- * Copyright (C) 2010 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: Hema HK <hemahk@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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/io.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>
-#include <linux/slab.h>
-#include <linux/delay.h>
-
-/* usb register definitions */
-#define USB_VENDOR_ID_LSB              0x00
-#define USB_VENDOR_ID_MSB              0x01
-#define USB_PRODUCT_ID_LSB             0x02
-#define USB_PRODUCT_ID_MSB             0x03
-#define USB_VBUS_CTRL_SET              0x04
-#define USB_VBUS_CTRL_CLR              0x05
-#define USB_ID_CTRL_SET                        0x06
-#define USB_ID_CTRL_CLR                        0x07
-#define USB_VBUS_INT_SRC               0x08
-#define USB_VBUS_INT_LATCH_SET         0x09
-#define USB_VBUS_INT_LATCH_CLR         0x0A
-#define USB_VBUS_INT_EN_LO_SET         0x0B
-#define USB_VBUS_INT_EN_LO_CLR         0x0C
-#define USB_VBUS_INT_EN_HI_SET         0x0D
-#define USB_VBUS_INT_EN_HI_CLR         0x0E
-#define USB_ID_INT_SRC                 0x0F
-#define USB_ID_INT_LATCH_SET           0x10
-#define USB_ID_INT_LATCH_CLR           0x11
-
-#define USB_ID_INT_EN_LO_SET           0x12
-#define USB_ID_INT_EN_LO_CLR           0x13
-#define USB_ID_INT_EN_HI_SET           0x14
-#define USB_ID_INT_EN_HI_CLR           0x15
-#define USB_OTG_ADP_CTRL               0x16
-#define USB_OTG_ADP_HIGH               0x17
-#define USB_OTG_ADP_LOW                        0x18
-#define USB_OTG_ADP_RISE               0x19
-#define USB_OTG_REVISION               0x1A
-
-/* to be moved to LDO */
-#define TWL6030_MISC2                  0xE5
-#define TWL6030_CFG_LDO_PD2            0xF5
-#define TWL6030_BACKUP_REG             0xFA
-
-#define STS_HW_CONDITIONS              0x21
-
-/* In module TWL6030_MODULE_PM_MASTER */
-#define STS_HW_CONDITIONS              0x21
-#define STS_USB_ID                     BIT(2)
-
-/* In module TWL6030_MODULE_PM_RECEIVER */
-#define VUSB_CFG_TRANS                 0x71
-#define VUSB_CFG_STATE                 0x72
-#define VUSB_CFG_VOLTAGE               0x73
-
-/* in module TWL6030_MODULE_MAIN_CHARGE */
-
-#define CHARGERUSB_CTRL1               0x8
-
-#define CONTROLLER_STAT1               0x03
-#define        VBUS_DET                        BIT(2)
-
-struct twl6030_usb {
-       struct phy_companion    comparator;
-       struct device           *dev;
-
-       /* for vbus reporting with irqs disabled */
-       spinlock_t              lock;
-
-       struct regulator                *usb3v3;
-
-       /* used to set vbus, in atomic path */
-       struct work_struct      set_vbus_work;
-
-       int                     irq1;
-       int                     irq2;
-       enum omap_musb_vbus_id_status linkstat;
-       u8                      asleep;
-       bool                    irq_enabled;
-       bool                    vbus_enable;
-       const char              *regulator;
-};
-
-#define        comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
-
-/*-------------------------------------------------------------------------*/
-
-static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,
-                                               u8 data, u8 address)
-{
-       int ret = 0;
-
-       ret = twl_i2c_write_u8(module, data, address);
-       if (ret < 0)
-               dev_err(twl->dev,
-                       "Write[0x%x] Error %d\n", address, ret);
-       return ret;
-}
-
-static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
-{
-       u8 data, ret = 0;
-
-       ret = twl_i2c_read_u8(module, &data, address);
-       if (ret >= 0)
-               ret = data;
-       else
-               dev_err(twl->dev,
-                       "readb[0x%x,0x%x] Error %d\n",
-                                       module, address, ret);
-       return ret;
-}
-
-static int twl6030_start_srp(struct phy_companion *comparator)
-{
-       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);
-
-       mdelay(100);
-       twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR);
-
-       return 0;
-}
-
-static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
-{
-       /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
-       twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
-
-       /* Program CFG_LDO_PD2 register and set VUSB bit */
-       twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2);
-
-       /* Program MISC2 register and set bit VUSB_IN_VBAT */
-       twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
-
-       twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
-       if (IS_ERR(twl->usb3v3))
-               return -ENODEV;
-
-       /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
-       twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);
-
-       /*
-        * Program the USB_ID_CTRL_SET register to enable GND drive
-        * and the ID comparators
-        */
-       twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);
-
-       return 0;
-}
-
-static ssize_t twl6030_usb_vbus_show(struct device *dev,
-                       struct device_attribute *attr, char *buf)
-{
-       struct twl6030_usb *twl = dev_get_drvdata(dev);
-       unsigned long flags;
-       int ret = -EINVAL;
-
-       spin_lock_irqsave(&twl->lock, flags);
-
-       switch (twl->linkstat) {
-       case OMAP_MUSB_VBUS_VALID:
-              ret = snprintf(buf, PAGE_SIZE, "vbus\n");
-              break;
-       case OMAP_MUSB_ID_GROUND:
-              ret = snprintf(buf, PAGE_SIZE, "id\n");
-              break;
-       case OMAP_MUSB_VBUS_OFF:
-              ret = snprintf(buf, PAGE_SIZE, "none\n");
-              break;
-       default:
-              ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
-       }
-       spin_unlock_irqrestore(&twl->lock, flags);
-
-       return ret;
-}
-static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
-
-static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
-{
-       struct twl6030_usb *twl = _twl;
-       enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
-       u8 vbus_state, hw_state;
-
-       hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
-
-       vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
-                                               CONTROLLER_STAT1);
-       if (!(hw_state & STS_USB_ID)) {
-               if (vbus_state & VBUS_DET) {
-                       regulator_enable(twl->usb3v3);
-                       twl->asleep = 1;
-                       status = OMAP_MUSB_VBUS_VALID;
-                       twl->linkstat = status;
-                       omap_musb_mailbox(status);
-               } else {
-                       if (twl->linkstat != OMAP_MUSB_UNKNOWN) {
-                               status = OMAP_MUSB_VBUS_OFF;
-                               twl->linkstat = status;
-                               omap_musb_mailbox(status);
-                               if (twl->asleep) {
-                                       regulator_disable(twl->usb3v3);
-                                       twl->asleep = 0;
-                               }
-                       }
-               }
-       }
-       sysfs_notify(&twl->dev->kobj, NULL, "vbus");
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
-{
-       struct twl6030_usb *twl = _twl;
-       enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
-       u8 hw_state;
-
-       hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
-
-       if (hw_state & STS_USB_ID) {
-
-               regulator_enable(twl->usb3v3);
-               twl->asleep = 1;
-               twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
-               twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
-               status = OMAP_MUSB_ID_GROUND;
-               twl->linkstat = status;
-               omap_musb_mailbox(status);
-       } else  {
-               twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
-               twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
-       }
-       twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
-
-       return IRQ_HANDLED;
-}
-
-static int twl6030_enable_irq(struct twl6030_usb *twl)
-{
-       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);
-
-       twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
-                               REG_INT_MSK_LINE_C);
-       twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
-                               REG_INT_MSK_STS_C);
-       twl6030_usb_irq(twl->irq2, twl);
-       twl6030_usbotg_irq(twl->irq1, twl);
-
-       return 0;
-}
-
-static void otg_set_vbus_work(struct work_struct *data)
-{
-       struct twl6030_usb *twl = container_of(data, struct twl6030_usb,
-                                                               set_vbus_work);
-
-       /*
-        * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
-        * register. This enables boost mode.
-        */
-
-       if (twl->vbus_enable)
-               twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
-                                                       CHARGERUSB_CTRL1);
-       else
-               twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
-                                                       CHARGERUSB_CTRL1);
-}
-
-static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
-{
-       struct twl6030_usb *twl = comparator_to_twl(comparator);
-
-       twl->vbus_enable = enabled;
-       schedule_work(&twl->set_vbus_work);
-
-       return 0;
-}
-
-static int twl6030_usb_probe(struct platform_device *pdev)
-{
-       u32 ret;
-       struct twl6030_usb      *twl;
-       int                     status, err;
-       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;
-
-       twl->dev                = &pdev->dev;
-       twl->irq1               = platform_get_irq(pdev, 0);
-       twl->irq2               = platform_get_irq(pdev, 1);
-       twl->linkstat           = OMAP_MUSB_UNKNOWN;
-
-       twl->comparator.set_vbus        = twl6030_set_vbus;
-       twl->comparator.start_srp       = twl6030_start_srp;
-
-       ret = omap_usb2_set_comparator(&twl->comparator);
-       if (ret == -ENODEV) {
-               dev_info(&pdev->dev, "phy not ready, deferring probe");
-               return -EPROBE_DEFER;
-       }
-
-       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);
-
-       err = twl6030_usb_ldo_init(twl);
-       if (err) {
-               dev_err(&pdev->dev, "ldo init failed\n");
-               return err;
-       }
-
-       platform_set_drvdata(pdev, twl);
-       if (device_create_file(&pdev->dev, &dev_attr_vbus))
-               dev_warn(&pdev->dev, "could not create sysfs file\n");
-
-       INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
-
-       twl->irq_enabled = true;
-       status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                       "twl6030_usb", twl);
-       if (status < 0) {
-               dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
-                       twl->irq1, status);
-               device_remove_file(twl->dev, &dev_attr_vbus);
-               return status;
-       }
-
-       status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                       "twl6030_usb", twl);
-       if (status < 0) {
-               dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
-                       twl->irq2, status);
-               free_irq(twl->irq1, twl);
-               device_remove_file(twl->dev, &dev_attr_vbus);
-               return status;
-       }
-
-       twl->asleep = 0;
-       twl6030_enable_irq(twl);
-       dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
-
-       return 0;
-}
-
-static int __exit twl6030_usb_remove(struct platform_device *pdev)
-{
-       struct twl6030_usb *twl = platform_get_drvdata(pdev);
-
-       twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
-               REG_INT_MSK_LINE_C);
-       twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
-                       REG_INT_MSK_STS_C);
-       free_irq(twl->irq1, twl);
-       free_irq(twl->irq2, twl);
-       regulator_put(twl->usb3v3);
-       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),
-       },
-};
-
-static int __init twl6030_usb_init(void)
-{
-       return platform_driver_register(&twl6030_usb_driver);
-}
-subsys_initcall(twl6030_usb_init);
-
-static void __exit twl6030_usb_exit(void)
-{
-       platform_driver_unregister(&twl6030_usb_driver);
-}
-module_exit(twl6030_usb_exit);
-
-MODULE_ALIAS("platform:twl6030_usb");
-MODULE_AUTHOR("Hema HK <hemahk@ti.com>");
-MODULE_DESCRIPTION("TWL6030 USB transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c
deleted file mode 100644 (file)
index 217339d..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Generic ULPI USB transceiver support
- *
- * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
- *
- * Based on sources from
- *
- *   Sascha Hauer <s.hauer@pengutronix.de>
- *   Freescale Semiconductors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/usb.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-
-
-struct ulpi_info {
-       unsigned int    id;
-       char            *name;
-};
-
-#define ULPI_ID(vendor, product) (((vendor) << 16) | (product))
-#define ULPI_INFO(_id, _name)          \
-       {                               \
-               .id     = (_id),        \
-               .name   = (_name),      \
-       }
-
-/* ULPI hardcoded IDs, used for probing */
-static struct ulpi_info ulpi_ids[] = {
-       ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
-       ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
-};
-
-static int ulpi_set_otg_flags(struct usb_phy *phy)
-{
-       unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
-                            ULPI_OTG_CTRL_DM_PULLDOWN;
-
-       if (phy->flags & ULPI_OTG_ID_PULLUP)
-               flags |= ULPI_OTG_CTRL_ID_PULLUP;
-
-       /*
-        * ULPI Specification rev.1.1 default
-        * for Dp/DmPulldown is enabled.
-        */
-       if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS)
-               flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN;
-
-       if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS)
-               flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN;
-
-       if (phy->flags & ULPI_OTG_EXTVBUSIND)
-               flags |= ULPI_OTG_CTRL_EXTVBUSIND;
-
-       return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
-}
-
-static int ulpi_set_fc_flags(struct usb_phy *phy)
-{
-       unsigned int flags = 0;
-
-       /*
-        * ULPI Specification rev.1.1 default
-        * for XcvrSelect is Full Speed.
-        */
-       if (phy->flags & ULPI_FC_HS)
-               flags |= ULPI_FUNC_CTRL_HIGH_SPEED;
-       else if (phy->flags & ULPI_FC_LS)
-               flags |= ULPI_FUNC_CTRL_LOW_SPEED;
-       else if (phy->flags & ULPI_FC_FS4LS)
-               flags |= ULPI_FUNC_CTRL_FS4LS;
-       else
-               flags |= ULPI_FUNC_CTRL_FULL_SPEED;
-
-       if (phy->flags & ULPI_FC_TERMSEL)
-               flags |= ULPI_FUNC_CTRL_TERMSELECT;
-
-       /*
-        * ULPI Specification rev.1.1 default
-        * for OpMode is Normal Operation.
-        */
-       if (phy->flags & ULPI_FC_OP_NODRV)
-               flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
-       else if (phy->flags & ULPI_FC_OP_DIS_NRZI)
-               flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI;
-       else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP)
-               flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP;
-       else
-               flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
-
-       /*
-        * ULPI Specification rev.1.1 default
-        * for SuspendM is Powered.
-        */
-       flags |= ULPI_FUNC_CTRL_SUSPENDM;
-
-       return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL);
-}
-
-static int ulpi_set_ic_flags(struct usb_phy *phy)
-{
-       unsigned int flags = 0;
-
-       if (phy->flags & ULPI_IC_AUTORESUME)
-               flags |= ULPI_IFC_CTRL_AUTORESUME;
-
-       if (phy->flags & ULPI_IC_EXTVBUS_INDINV)
-               flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS;
-
-       if (phy->flags & ULPI_IC_IND_PASSTHRU)
-               flags |= ULPI_IFC_CTRL_PASSTHRU;
-
-       if (phy->flags & ULPI_IC_PROTECT_DIS)
-               flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE;
-
-       return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
-}
-
-static int ulpi_set_flags(struct usb_phy *phy)
-{
-       int ret;
-
-       ret = ulpi_set_otg_flags(phy);
-       if (ret)
-               return ret;
-
-       ret = ulpi_set_ic_flags(phy);
-       if (ret)
-               return ret;
-
-       return ulpi_set_fc_flags(phy);
-}
-
-static int ulpi_check_integrity(struct usb_phy *phy)
-{
-       int ret, i;
-       unsigned int val = 0x55;
-
-       for (i = 0; i < 2; i++) {
-               ret = usb_phy_io_write(phy, val, ULPI_SCRATCH);
-               if (ret < 0)
-                       return ret;
-
-               ret = usb_phy_io_read(phy, ULPI_SCRATCH);
-               if (ret < 0)
-                       return ret;
-
-               if (ret != val) {
-                       pr_err("ULPI integrity check: failed!");
-                       return -ENODEV;
-               }
-               val = val << 1;
-       }
-
-       pr_info("ULPI integrity check: passed.\n");
-
-       return 0;
-}
-
-static int ulpi_init(struct usb_phy *phy)
-{
-       int i, vid, pid, ret;
-       u32 ulpi_id = 0;
-
-       for (i = 0; i < 4; i++) {
-               ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i);
-               if (ret < 0)
-                       return ret;
-               ulpi_id = (ulpi_id << 8) | ret;
-       }
-       vid = ulpi_id & 0xffff;
-       pid = ulpi_id >> 16;
-
-       pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);
-
-       for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) {
-               if (ulpi_ids[i].id == ULPI_ID(vid, pid)) {
-                       pr_info("Found %s ULPI transceiver.\n",
-                               ulpi_ids[i].name);
-                       break;
-               }
-       }
-
-       ret = ulpi_check_integrity(phy);
-       if (ret)
-               return ret;
-
-       return ulpi_set_flags(phy);
-}
-
-static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       struct usb_phy *phy = otg->phy;
-       unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);
-
-       if (!host) {
-               otg->host = NULL;
-               return 0;
-       }
-
-       otg->host = host;
-
-       flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE |
-                  ULPI_IFC_CTRL_3_PIN_SERIAL_MODE |
-                  ULPI_IFC_CTRL_CARKITMODE);
-
-       if (phy->flags & ULPI_IC_6PIN_SERIAL)
-               flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE;
-       else if (phy->flags & ULPI_IC_3PIN_SERIAL)
-               flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE;
-       else if (phy->flags & ULPI_IC_CARKIT)
-               flags |= ULPI_IFC_CTRL_CARKITMODE;
-
-       return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
-}
-
-static int ulpi_set_vbus(struct usb_otg *otg, bool on)
-{
-       struct usb_phy *phy = otg->phy;
-       unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
-
-       flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
-
-       if (on) {
-               if (phy->flags & ULPI_OTG_DRVVBUS)
-                       flags |= ULPI_OTG_CTRL_DRVVBUS;
-
-               if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
-                       flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
-       }
-
-       return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
-}
-
-struct usb_phy *
-otg_ulpi_create(struct usb_phy_io_ops *ops,
-               unsigned int flags)
-{
-       struct usb_phy *phy;
-       struct usb_otg *otg;
-
-       phy = kzalloc(sizeof(*phy), GFP_KERNEL);
-       if (!phy)
-               return NULL;
-
-       otg = kzalloc(sizeof(*otg), GFP_KERNEL);
-       if (!otg) {
-               kfree(phy);
-               return NULL;
-       }
-
-       phy->label      = "ULPI";
-       phy->flags      = flags;
-       phy->io_ops     = ops;
-       phy->otg        = otg;
-       phy->init       = ulpi_init;
-
-       otg->phy        = phy;
-       otg->set_host   = ulpi_set_host;
-       otg->set_vbus   = ulpi_set_vbus;
-
-       return phy;
-}
-EXPORT_SYMBOL_GPL(otg_ulpi_create);
-
diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/otg/ulpi_viewport.c
deleted file mode 100644 (file)
index c5ba7e5..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/kernel.h>
-#include <linux/usb.h>
-#include <linux/io.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-
-#define ULPI_VIEW_WAKEUP       (1 << 31)
-#define ULPI_VIEW_RUN          (1 << 30)
-#define ULPI_VIEW_WRITE                (1 << 29)
-#define ULPI_VIEW_READ         (0 << 29)
-#define ULPI_VIEW_ADDR(x)      (((x) & 0xff) << 16)
-#define ULPI_VIEW_DATA_READ(x) (((x) >> 8) & 0xff)
-#define ULPI_VIEW_DATA_WRITE(x)        ((x) & 0xff)
-
-static int ulpi_viewport_wait(void __iomem *view, u32 mask)
-{
-       unsigned long usec = 2000;
-
-       while (usec--) {
-               if (!(readl(view) & mask))
-                       return 0;
-
-               udelay(1);
-       };
-
-       return -ETIMEDOUT;
-}
-
-static int ulpi_viewport_read(struct usb_phy *otg, u32 reg)
-{
-       int ret;
-       void __iomem *view = otg->io_priv;
-
-       writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view);
-       ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP);
-       if (ret)
-               return ret;
-
-       writel(ULPI_VIEW_RUN | ULPI_VIEW_READ | ULPI_VIEW_ADDR(reg), view);
-       ret = ulpi_viewport_wait(view, ULPI_VIEW_RUN);
-       if (ret)
-               return ret;
-
-       return ULPI_VIEW_DATA_READ(readl(view));
-}
-
-static int ulpi_viewport_write(struct usb_phy *otg, u32 val, u32 reg)
-{
-       int ret;
-       void __iomem *view = otg->io_priv;
-
-       writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view);
-       ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP);
-       if (ret)
-               return ret;
-
-       writel(ULPI_VIEW_RUN | ULPI_VIEW_WRITE | ULPI_VIEW_DATA_WRITE(val) |
-                                                ULPI_VIEW_ADDR(reg), view);
-
-       return ulpi_viewport_wait(view, ULPI_VIEW_RUN);
-}
-
-struct usb_phy_io_ops ulpi_viewport_access_ops = {
-       .read   = ulpi_viewport_read,
-       .write  = ulpi_viewport_write,
-};
index 65217a5900689028e68a61e28c8011fbc9cbbaea..32ce740a9dd501751064c6342989ed273cc94c76 100644 (file)
@@ -4,6 +4,73 @@
 comment "USB Physical Layer drivers"
        depends on USB || USB_GADGET
 
+config USB_OTG_UTILS
+       bool
+       help
+         Select this to make sure the build includes objects from
+         the OTG infrastructure directory.
+
+if USB || USB_GADGET
+
+#
+# USB Transceiver Drivers
+#
+config AB8500_USB
+       tristate "AB8500 USB Transceiver Driver"
+       depends on AB8500_CORE
+       select USB_OTG_UTILS
+       help
+         Enable this to support the USB OTG transceiver in AB8500 chip.
+         This transceiver supports high and full speed devices plus,
+         in host mode, low speed.
+
+config FSL_USB2_OTG
+       bool "Freescale USB OTG Transceiver Driver"
+       depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
+       select USB_OTG
+       select USB_OTG_UTILS
+       help
+         Enable this to support Freescale USB OTG transceiver.
+
+config ISP1301_OMAP
+       tristate "Philips ISP1301 with OMAP OTG"
+       depends on I2C && ARCH_OMAP_OTG
+       select USB_OTG_UTILS
+       help
+         If you say yes here you get support for the Philips ISP1301
+         USB-On-The-Go transceiver working with the OMAP OTG controller.
+         The ISP1301 is a full speed USB  transceiver which is used in
+         products including H2, H3, and H4 development boards for Texas
+         Instruments OMAP processors.
+
+         This driver can also be built as a module.  If so, the module
+         will be called isp1301_omap.
+
+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.
+
+config NOP_USB_XCEIV
+       tristate "NOP USB Transceiver Driver"
+       select USB_OTG_UTILS
+       help
+         This driver is to be used by all the usb transceiver which are either
+         built-in with usb ip or which are autonomous and doesn't require any
+         phy programming such as ISP1x04 etc.
+
+config OMAP_CONTROL_USB
+       tristate "OMAP CONTROL USB Driver"
+       help
+         Enable this to add support for the USB part present in the control
+         module. This driver has API to power on the USB2 PHY and to write to
+         the mailbox. The mailbox is present only in omap4 and the register to
+         power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+         additional register to power on USB3 PHY.
+
 config OMAP_USB2
        tristate "OMAP USB2 PHY Driver"
        depends on ARCH_OMAP2PLUS
@@ -25,14 +92,45 @@ config OMAP_USB3
          This driver interacts with the "OMAP Control USB Driver" to power
          on/off the PHY.
 
-config OMAP_CONTROL_USB
-       tristate "OMAP CONTROL USB Driver"
+config SAMSUNG_USBPHY
+       bool "Samsung USB PHY controller Driver"
+       depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS
+       select USB_OTG_UTILS
        help
-         Enable this to add support for the USB part present in the control
-         module. This driver has API to power on the USB2 PHY and to write to
-         the mailbox. The mailbox is present only in omap4 and the register to
-         power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
-         additional register to power on USB3 PHY.
+         Enable this to support Samsung USB phy controller for samsung
+         SoCs.
+
+config TWL4030_USB
+       tristate "TWL4030 USB Transceiver Driver"
+       depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+       select USB_OTG_UTILS
+       help
+         Enable this to support the USB OTG transceiver on TWL4030
+         family chips (including the TWL5030 and TPS659x0 devices).
+         This transceiver supports high and full speed devices plus,
+         in host mode, low speed.
+
+config TWL6030_USB
+       tristate "TWL6030 USB Transceiver Driver"
+       depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
+       select USB_OTG_UTILS
+       help
+         Enable this to support the USB OTG transceiver on TWL6030
+         family chips. This TWL6030 transceiver has the VBUS and ID GND
+         and OTG SRP events capabilities. For all other transceiver functionality
+         UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
+         are hooked to this driver through platform_data structure.
+         The definition of internal PHY APIs are in the mach-omap2 layer.
+
+config USB_GPIO_VBUS
+       tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
+       depends on GENERIC_GPIO
+       select USB_OTG_UTILS
+       help
+         Provides simple GPIO VBUS sensing for controllers with an
+         internal transceiver via the usb_phy interface, and
+         optionally control of a D+ pullup GPIO as well as a VBUS
+         current limit regulator.
 
 config USB_ISP1301
        tristate "NXP ISP1301 USB transceiver support"
@@ -46,13 +144,40 @@ 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
+config USB_MSM_OTG
+       tristate "OTG support for Qualcomm on-chip USB controller"
+       depends on (USB || USB_GADGET) && ARCH_MSM
        select USB_OTG_UTILS
        help
-         Enable this to support Marvell USB 3.0 phy controller for Marvell
-         SoC.
+         Enable this to support the USB OTG transceiver on MSM chips. It
+         handles PHY initialization, clock management, and workarounds
+         required after resetting the hardware and power management.
+         This driver is required even for peripheral only or host only
+         mode configurations.
+         This driver is not supported on boards like trout which
+         has an external PHY.
+
+config USB_MV_OTG
+       tristate "Marvell USB OTG support"
+       depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
+       select USB_OTG
+       select USB_OTG_UTILS
+       help
+         Say Y here if you want to build Marvell USB OTG transciever
+         driver in kernel (including PXA and MMP series). This driver
+         implements role switch between EHCI host driver and gadget driver.
+
+         To compile this driver as a module, choose M here.
+
+config USB_MXS_PHY
+       tristate "Freescale MXS USB PHY support"
+       depends on ARCH_MXC || ARCH_MXS
+       select STMP_DEVICE
+       select USB_OTG_UTILS
+       help
+         Enable this to support the Freescale MXS USB PHY.
+
+         MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
 
 config USB_RCAR_PHY
        tristate "Renesas R-Car USB phy support"
@@ -66,10 +191,19 @@ config USB_RCAR_PHY
          To compile this driver as a module, choose M here: the
          module will be called rcar-phy.
 
-config SAMSUNG_USBPHY
-       bool "Samsung USB PHY controller Driver"
-       depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS
+config USB_ULPI
+       bool "Generic ULPI Transceiver Driver"
+       depends on ARM
        select USB_OTG_UTILS
        help
-         Enable this to support Samsung USB phy controller for samsung
-         SoCs.
+         Enable this to support ULPI connected USB OTG transceivers which
+         are likely found on embedded boards.
+
+config USB_ULPI_VIEWPORT
+       bool
+       depends on USB_ULPI
+       help
+         Provides read/write operations to the ULPI phy register set for
+         controllers with a viewport register (e.g. Chipidea/ARC controllers).
+
+endif # USB || OTG
index 9fa6327d4c5243deabe1ce874e7a7748196ffc2c..34488ceef4916651f88aba78f27509101caf1778 100644 (file)
@@ -5,11 +5,27 @@
 ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_USB_OTG_UTILS)            += phy.o
+
+# transceiver drivers, keep the list sorted
+
+obj-$(CONFIG_AB8500_USB)               += ab8500-usb.o
+fsl_usb2_otg-objs                      := fsl_otg.o otg_fsm.o
+obj-$(CONFIG_FSL_USB2_OTG)             += fsl_usb2_otg.o
+obj-$(CONFIG_ISP1301_OMAP)             += isp1301_omap.o
+obj-$(CONFIG_MV_U3D_PHY)               += mv_u3d_phy.o
+obj-$(CONFIG_NOP_USB_XCEIV)            += nop-usb-xceiv.o
+obj-$(CONFIG_OMAP_CONTROL_USB)         += omap-control-usb.o
 obj-$(CONFIG_OMAP_USB2)                        += omap-usb2.o
 obj-$(CONFIG_OMAP_USB3)                        += omap-usb3.o
-obj-$(CONFIG_OMAP_CONTROL_USB)         += omap-control-usb.o
+obj-$(CONFIG_SAMSUNG_USBPHY)           += samsung-usbphy.o
+obj-$(CONFIG_TWL4030_USB)              += twl4030-usb.o
+obj-$(CONFIG_TWL6030_USB)              += twl6030-usb.o
+obj-$(CONFIG_USB_EHCI_TEGRA)           += tegra_usb_phy.o
+obj-$(CONFIG_USB_GPIO_VBUS)            += gpio_vbus.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
+obj-$(CONFIG_USB_MSM_OTG)              += msm_otg.o
+obj-$(CONFIG_USB_MV_OTG)               += mv_otg.o
+obj-$(CONFIG_USB_MXS_PHY)              += mxs-phy.o
 obj-$(CONFIG_USB_RCAR_PHY)             += rcar-phy.o
-obj-$(CONFIG_SAMSUNG_USBPHY)           += samsung-usbphy.o
+obj-$(CONFIG_USB_ULPI)                 += ulpi.o
+obj-$(CONFIG_USB_ULPI_VIEWPORT)                += ulpi_viewport.o
diff --git a/drivers/usb/phy/ab8500-usb.c b/drivers/usb/phy/ab8500-usb.c
new file mode 100644 (file)
index 0000000..2d86f26
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * drivers/usb/otg/ab8500_usb.c
+ *
+ * USB transceiver driver for AB8500 chip
+ *
+ * Copyright (C) 2010 ST-Ericsson AB
+ * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb/otg.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+
+#define AB8500_MAIN_WD_CTRL_REG 0x01
+#define AB8500_USB_LINE_STAT_REG 0x80
+#define AB8500_USB_PHY_CTRL_REG 0x8A
+
+#define AB8500_BIT_OTG_STAT_ID (1 << 0)
+#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
+#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
+#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
+#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
+
+#define AB8500_V1x_LINK_STAT_WAIT (HZ/10)
+#define AB8500_WD_KICK_DELAY_US 100 /* usec */
+#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
+#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */
+
+/* Usb line status register */
+enum ab8500_usb_link_status {
+       USB_LINK_NOT_CONFIGURED = 0,
+       USB_LINK_STD_HOST_NC,
+       USB_LINK_STD_HOST_C_NS,
+       USB_LINK_STD_HOST_C_S,
+       USB_LINK_HOST_CHG_NM,
+       USB_LINK_HOST_CHG_HS,
+       USB_LINK_HOST_CHG_HS_CHIRP,
+       USB_LINK_DEDICATED_CHG,
+       USB_LINK_ACA_RID_A,
+       USB_LINK_ACA_RID_B,
+       USB_LINK_ACA_RID_C_NM,
+       USB_LINK_ACA_RID_C_HS,
+       USB_LINK_ACA_RID_C_HS_CHIRP,
+       USB_LINK_HM_IDGND,
+       USB_LINK_RESERVED,
+       USB_LINK_NOT_VALID_LINK
+};
+
+struct ab8500_usb {
+       struct usb_phy phy;
+       struct device *dev;
+       int irq_num_id_rise;
+       int irq_num_id_fall;
+       int irq_num_vbus_rise;
+       int irq_num_vbus_fall;
+       int irq_num_link_status;
+       unsigned vbus_draw;
+       struct delayed_work dwork;
+       struct work_struct phy_dis_work;
+       unsigned long link_status_wait;
+       int rev;
+};
+
+static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
+{
+       return container_of(x, struct ab8500_usb, phy);
+}
+
+static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
+{
+       abx500_set_register_interruptible(ab->dev,
+               AB8500_SYS_CTRL2_BLOCK,
+               AB8500_MAIN_WD_CTRL_REG,
+               AB8500_BIT_WD_CTRL_ENABLE);
+
+       udelay(AB8500_WD_KICK_DELAY_US);
+
+       abx500_set_register_interruptible(ab->dev,
+               AB8500_SYS_CTRL2_BLOCK,
+               AB8500_MAIN_WD_CTRL_REG,
+               (AB8500_BIT_WD_CTRL_ENABLE
+               | AB8500_BIT_WD_CTRL_KICK));
+
+       if (ab->rev > 0x10) /* v1.1 v2.0 */
+               udelay(AB8500_WD_V11_DISABLE_DELAY_US);
+       else /* v1.0 */
+               msleep(AB8500_WD_V10_DISABLE_DELAY_MS);
+
+       abx500_set_register_interruptible(ab->dev,
+               AB8500_SYS_CTRL2_BLOCK,
+               AB8500_MAIN_WD_CTRL_REG,
+               0);
+}
+
+static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
+                                       bool enable)
+{
+       u8 ctrl_reg;
+       abx500_get_register_interruptible(ab->dev,
+                               AB8500_USB,
+                               AB8500_USB_PHY_CTRL_REG,
+                               &ctrl_reg);
+       if (sel_host) {
+               if (enable)
+                       ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN;
+               else
+                       ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN;
+       } else {
+               if (enable)
+                       ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN;
+               else
+                       ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN;
+       }
+
+       abx500_set_register_interruptible(ab->dev,
+                               AB8500_USB,
+                               AB8500_USB_PHY_CTRL_REG,
+                               ctrl_reg);
+
+       /* Needed to enable the phy.*/
+       if (enable)
+               ab8500_usb_wd_workaround(ab);
+}
+
+#define ab8500_usb_host_phy_en(ab)     ab8500_usb_phy_ctrl(ab, true, true)
+#define ab8500_usb_host_phy_dis(ab)    ab8500_usb_phy_ctrl(ab, true, false)
+#define ab8500_usb_peri_phy_en(ab)     ab8500_usb_phy_ctrl(ab, false, true)
+#define ab8500_usb_peri_phy_dis(ab)    ab8500_usb_phy_ctrl(ab, false, false)
+
+static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
+{
+       u8 reg;
+       enum ab8500_usb_link_status lsts;
+       void *v = NULL;
+       enum usb_phy_events event;
+
+       abx500_get_register_interruptible(ab->dev,
+                       AB8500_USB,
+                       AB8500_USB_LINE_STAT_REG,
+                       &reg);
+
+       lsts = (reg >> 3) & 0x0F;
+
+       switch (lsts) {
+       case USB_LINK_NOT_CONFIGURED:
+       case USB_LINK_RESERVED:
+       case USB_LINK_NOT_VALID_LINK:
+               /* TODO: Disable regulators. */
+               ab8500_usb_host_phy_dis(ab);
+               ab8500_usb_peri_phy_dis(ab);
+               ab->phy.state = OTG_STATE_B_IDLE;
+               ab->phy.otg->default_a = false;
+               ab->vbus_draw = 0;
+               event = USB_EVENT_NONE;
+               break;
+
+       case USB_LINK_STD_HOST_NC:
+       case USB_LINK_STD_HOST_C_NS:
+       case USB_LINK_STD_HOST_C_S:
+       case USB_LINK_HOST_CHG_NM:
+       case USB_LINK_HOST_CHG_HS:
+       case USB_LINK_HOST_CHG_HS_CHIRP:
+               if (ab->phy.otg->gadget) {
+                       /* TODO: Enable regulators. */
+                       ab8500_usb_peri_phy_en(ab);
+                       v = ab->phy.otg->gadget;
+               }
+               event = USB_EVENT_VBUS;
+               break;
+
+       case USB_LINK_HM_IDGND:
+               if (ab->phy.otg->host) {
+                       /* TODO: Enable regulators. */
+                       ab8500_usb_host_phy_en(ab);
+                       v = ab->phy.otg->host;
+               }
+               ab->phy.state = OTG_STATE_A_IDLE;
+               ab->phy.otg->default_a = true;
+               event = USB_EVENT_ID;
+               break;
+
+       case USB_LINK_ACA_RID_A:
+       case USB_LINK_ACA_RID_B:
+               /* TODO */
+       case USB_LINK_ACA_RID_C_NM:
+       case USB_LINK_ACA_RID_C_HS:
+       case USB_LINK_ACA_RID_C_HS_CHIRP:
+       case USB_LINK_DEDICATED_CHG:
+               /* TODO: vbus_draw */
+               event = USB_EVENT_CHARGER;
+               break;
+       }
+
+       atomic_notifier_call_chain(&ab->phy.notifier, event, v);
+
+       return 0;
+}
+
+static void ab8500_usb_delayed_work(struct work_struct *work)
+{
+       struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
+                                               dwork.work);
+
+       ab8500_usb_link_status_update(ab);
+}
+
+static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data)
+{
+       struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+       /* Wait for link status to become stable. */
+       schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data)
+{
+       struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+       /* Link status will not be updated till phy is disabled. */
+       ab8500_usb_peri_phy_dis(ab);
+
+       /* Wait for link status to become stable. */
+       schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ab8500_usb_v20_irq(int irq, void *data)
+{
+       struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+       ab8500_usb_link_status_update(ab);
+
+       return IRQ_HANDLED;
+}
+
+static void ab8500_usb_phy_disable_work(struct work_struct *work)
+{
+       struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
+                                               phy_dis_work);
+
+       if (!ab->phy.otg->host)
+               ab8500_usb_host_phy_dis(ab);
+
+       if (!ab->phy.otg->gadget)
+               ab8500_usb_peri_phy_dis(ab);
+}
+
+static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
+{
+       struct ab8500_usb *ab;
+
+       if (!phy)
+               return -ENODEV;
+
+       ab = phy_to_ab(phy);
+
+       ab->vbus_draw = mA;
+
+       if (mA)
+               atomic_notifier_call_chain(&ab->phy.notifier,
+                               USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
+       return 0;
+}
+
+/* TODO: Implement some way for charging or other drivers to read
+ * ab->vbus_draw.
+ */
+
+static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
+{
+       /* TODO */
+       return 0;
+}
+
+static int ab8500_usb_set_peripheral(struct usb_otg *otg,
+                                       struct usb_gadget *gadget)
+{
+       struct ab8500_usb *ab;
+
+       if (!otg)
+               return -ENODEV;
+
+       ab = phy_to_ab(otg->phy);
+
+       /* Some drivers call this function in atomic context.
+        * Do not update ab8500 registers directly till this
+        * is fixed.
+        */
+
+       if (!gadget) {
+               /* TODO: Disable regulators. */
+               otg->gadget = NULL;
+               schedule_work(&ab->phy_dis_work);
+       } else {
+               otg->gadget = gadget;
+               otg->phy->state = OTG_STATE_B_IDLE;
+
+               /* Phy will not be enabled if cable is already
+                * plugged-in. Schedule to enable phy.
+                * Use same delay to avoid any race condition.
+                */
+               schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+       }
+
+       return 0;
+}
+
+static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct ab8500_usb *ab;
+
+       if (!otg)
+               return -ENODEV;
+
+       ab = phy_to_ab(otg->phy);
+
+       /* Some drivers call this function in atomic context.
+        * Do not update ab8500 registers directly till this
+        * is fixed.
+        */
+
+       if (!host) {
+               /* TODO: Disable regulators. */
+               otg->host = NULL;
+               schedule_work(&ab->phy_dis_work);
+       } else {
+               otg->host = host;
+               /* Phy will not be enabled if cable is already
+                * plugged-in. Schedule to enable phy.
+                * Use same delay to avoid any race condition.
+                */
+               schedule_delayed_work(&ab->dwork, ab->link_status_wait);
+       }
+
+       return 0;
+}
+
+static void ab8500_usb_irq_free(struct ab8500_usb *ab)
+{
+       if (ab->rev < 0x20) {
+               free_irq(ab->irq_num_id_rise, ab);
+               free_irq(ab->irq_num_id_fall, ab);
+               free_irq(ab->irq_num_vbus_rise, ab);
+               free_irq(ab->irq_num_vbus_fall, ab);
+       } else {
+               free_irq(ab->irq_num_link_status, ab);
+       }
+}
+
+static int ab8500_usb_v1x_res_setup(struct platform_device *pdev,
+                               struct ab8500_usb *ab)
+{
+       int err;
+
+       ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R");
+       if (ab->irq_num_id_rise < 0) {
+               dev_err(&pdev->dev, "ID rise irq not found\n");
+               return ab->irq_num_id_rise;
+       }
+       err = request_threaded_irq(ab->irq_num_id_rise, NULL,
+               ab8500_usb_v1x_common_irq,
+               IRQF_NO_SUSPEND | IRQF_SHARED,
+               "usb-id-rise", ab);
+       if (err < 0) {
+               dev_err(ab->dev, "request_irq failed for ID rise irq\n");
+               goto fail0;
+       }
+
+       ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
+       if (ab->irq_num_id_fall < 0) {
+               dev_err(&pdev->dev, "ID fall irq not found\n");
+               return ab->irq_num_id_fall;
+       }
+       err = request_threaded_irq(ab->irq_num_id_fall, NULL,
+               ab8500_usb_v1x_common_irq,
+               IRQF_NO_SUSPEND | IRQF_SHARED,
+               "usb-id-fall", ab);
+       if (err < 0) {
+               dev_err(ab->dev, "request_irq failed for ID fall irq\n");
+               goto fail1;
+       }
+
+       ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R");
+       if (ab->irq_num_vbus_rise < 0) {
+               dev_err(&pdev->dev, "VBUS rise irq not found\n");
+               return ab->irq_num_vbus_rise;
+       }
+       err = request_threaded_irq(ab->irq_num_vbus_rise, NULL,
+               ab8500_usb_v1x_common_irq,
+               IRQF_NO_SUSPEND | IRQF_SHARED,
+               "usb-vbus-rise", ab);
+       if (err < 0) {
+               dev_err(ab->dev, "request_irq failed for Vbus rise irq\n");
+               goto fail2;
+       }
+
+       ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F");
+       if (ab->irq_num_vbus_fall < 0) {
+               dev_err(&pdev->dev, "VBUS fall irq not found\n");
+               return ab->irq_num_vbus_fall;
+       }
+       err = request_threaded_irq(ab->irq_num_vbus_fall, NULL,
+               ab8500_usb_v1x_vbus_fall_irq,
+               IRQF_NO_SUSPEND | IRQF_SHARED,
+               "usb-vbus-fall", ab);
+       if (err < 0) {
+               dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
+               goto fail3;
+       }
+
+       return 0;
+fail3:
+       free_irq(ab->irq_num_vbus_rise, ab);
+fail2:
+       free_irq(ab->irq_num_id_fall, ab);
+fail1:
+       free_irq(ab->irq_num_id_rise, ab);
+fail0:
+       return err;
+}
+
+static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
+                               struct ab8500_usb *ab)
+{
+       int err;
+
+       ab->irq_num_link_status = platform_get_irq_byname(pdev,
+                                               "USB_LINK_STATUS");
+       if (ab->irq_num_link_status < 0) {
+               dev_err(&pdev->dev, "Link status irq not found\n");
+               return ab->irq_num_link_status;
+       }
+
+       err = request_threaded_irq(ab->irq_num_link_status, NULL,
+               ab8500_usb_v20_irq,
+               IRQF_NO_SUSPEND | IRQF_SHARED,
+               "usb-link-status", ab);
+       if (err < 0) {
+               dev_err(ab->dev,
+                       "request_irq failed for link status irq\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int ab8500_usb_probe(struct platform_device *pdev)
+{
+       struct ab8500_usb       *ab;
+       struct usb_otg          *otg;
+       int err;
+       int rev;
+
+       rev = abx500_get_chip_id(&pdev->dev);
+       if (rev < 0) {
+               dev_err(&pdev->dev, "Chip id read failed\n");
+               return rev;
+       } else if (rev < 0x10) {
+               dev_err(&pdev->dev, "Unsupported AB8500 chip\n");
+               return -ENODEV;
+       }
+
+       ab = kzalloc(sizeof *ab, GFP_KERNEL);
+       if (!ab)
+               return -ENOMEM;
+
+       otg = kzalloc(sizeof *otg, GFP_KERNEL);
+       if (!otg) {
+               kfree(ab);
+               return -ENOMEM;
+       }
+
+       ab->dev                 = &pdev->dev;
+       ab->rev                 = rev;
+       ab->phy.dev             = ab->dev;
+       ab->phy.otg             = otg;
+       ab->phy.label           = "ab8500";
+       ab->phy.set_suspend     = ab8500_usb_set_suspend;
+       ab->phy.set_power       = ab8500_usb_set_power;
+       ab->phy.state           = OTG_STATE_UNDEFINED;
+
+       otg->phy                = &ab->phy;
+       otg->set_host           = ab8500_usb_set_host;
+       otg->set_peripheral     = ab8500_usb_set_peripheral;
+
+       platform_set_drvdata(pdev, ab);
+
+       ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
+
+       /* v1: Wait for link status to become stable.
+        * all: Updates form set_host and set_peripheral as they are atomic.
+        */
+       INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work);
+
+       /* all: Disable phy when called from set_host and set_peripheral */
+       INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
+
+       if (ab->rev < 0x20) {
+               err = ab8500_usb_v1x_res_setup(pdev, ab);
+               ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT;
+       } else {
+               err = ab8500_usb_v2_res_setup(pdev, ab);
+       }
+
+       if (err < 0)
+               goto fail0;
+
+       err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
+       if (err) {
+               dev_err(&pdev->dev, "Can't register transceiver\n");
+               goto fail1;
+       }
+
+       dev_info(&pdev->dev, "AB8500 usb driver initialized\n");
+
+       return 0;
+fail1:
+       ab8500_usb_irq_free(ab);
+fail0:
+       kfree(otg);
+       kfree(ab);
+       return err;
+}
+
+static int ab8500_usb_remove(struct platform_device *pdev)
+{
+       struct ab8500_usb *ab = platform_get_drvdata(pdev);
+
+       ab8500_usb_irq_free(ab);
+
+       cancel_delayed_work_sync(&ab->dwork);
+
+       cancel_work_sync(&ab->phy_dis_work);
+
+       usb_remove_phy(&ab->phy);
+
+       ab8500_usb_host_phy_dis(ab);
+       ab8500_usb_peri_phy_dis(ab);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(ab->phy.otg);
+       kfree(ab);
+
+       return 0;
+}
+
+static struct platform_driver ab8500_usb_driver = {
+       .probe          = ab8500_usb_probe,
+       .remove         = ab8500_usb_remove,
+       .driver         = {
+               .name   = "ab8500-usb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init ab8500_usb_init(void)
+{
+       return platform_driver_register(&ab8500_usb_driver);
+}
+subsys_initcall(ab8500_usb_init);
+
+static void __exit ab8500_usb_exit(void)
+{
+       platform_driver_unregister(&ab8500_usb_driver);
+}
+module_exit(ab8500_usb_exit);
+
+MODULE_ALIAS("platform:ab8500_usb");
+MODULE_AUTHOR("ST-Ericsson AB");
+MODULE_DESCRIPTION("AB8500 usb transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/fsl_otg.c b/drivers/usb/phy/fsl_otg.c
new file mode 100644 (file)
index 0000000..72a2a00
--- /dev/null
@@ -0,0 +1,1173 @@
+/*
+ * Copyright (C) 2007,2008 Freescale semiconductor, Inc.
+ *
+ * Author: Li Yang <LeoLi@freescale.com>
+ *         Jerry Huang <Chang-Ming.Huang@freescale.com>
+ *
+ * Initialization based on code from Shlomi Gridish.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+#include <linux/time.h>
+#include <linux/fsl_devices.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+
+#include <asm/unaligned.h>
+
+#include "fsl_otg.h"
+
+#define DRIVER_VERSION "Rev. 1.55"
+#define DRIVER_AUTHOR "Jerry Huang/Li Yang"
+#define DRIVER_DESC "Freescale USB OTG Transceiver Driver"
+#define DRIVER_INFO DRIVER_DESC " " DRIVER_VERSION
+
+static const char driver_name[] = "fsl-usb2-otg";
+
+const pm_message_t otg_suspend_state = {
+       .event = 1,
+};
+
+#define HA_DATA_PULSE
+
+static struct usb_dr_mmap *usb_dr_regs;
+static struct fsl_otg *fsl_otg_dev;
+static int srp_wait_done;
+
+/* FSM timers */
+struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, *a_aidl_bdis_tmr,
+       *b_ase0_brst_tmr, *b_se0_srp_tmr;
+
+/* Driver specific timers */
+struct fsl_otg_timer *b_data_pulse_tmr, *b_vbus_pulse_tmr, *b_srp_fail_tmr,
+       *b_srp_wait_tmr, *a_wait_enum_tmr;
+
+static struct list_head active_timers;
+
+static struct fsl_otg_config fsl_otg_initdata = {
+       .otg_port = 1,
+};
+
+#ifdef CONFIG_PPC32
+static u32 _fsl_readl_be(const unsigned __iomem *p)
+{
+       return in_be32(p);
+}
+
+static u32 _fsl_readl_le(const unsigned __iomem *p)
+{
+       return in_le32(p);
+}
+
+static void _fsl_writel_be(u32 v, unsigned __iomem *p)
+{
+       out_be32(p, v);
+}
+
+static void _fsl_writel_le(u32 v, unsigned __iomem *p)
+{
+       out_le32(p, v);
+}
+
+static u32 (*_fsl_readl)(const unsigned __iomem *p);
+static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
+
+#define fsl_readl(p)           (*_fsl_readl)((p))
+#define fsl_writel(v, p)       (*_fsl_writel)((v), (p))
+
+#else
+#define fsl_readl(addr)                readl(addr)
+#define fsl_writel(val, addr)  writel(val, addr)
+#endif /* CONFIG_PPC32 */
+
+/* Routines to access transceiver ULPI registers */
+u8 view_ulpi(u8 addr)
+{
+       u32 temp;
+
+       temp = 0x40000000 | (addr << 16);
+       fsl_writel(temp, &usb_dr_regs->ulpiview);
+       udelay(1000);
+       while (temp & 0x40)
+               temp = fsl_readl(&usb_dr_regs->ulpiview);
+       return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
+}
+
+int write_ulpi(u8 addr, u8 data)
+{
+       u32 temp;
+
+       temp = 0x60000000 | (addr << 16) | data;
+       fsl_writel(temp, &usb_dr_regs->ulpiview);
+       return 0;
+}
+
+/* -------------------------------------------------------------*/
+/* Operations that will be called from OTG Finite State Machine */
+
+/* Charge vbus for vbus pulsing in SRP */
+void fsl_otg_chrg_vbus(int on)
+{
+       u32 tmp;
+
+       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
+
+       if (on)
+               /* stop discharging, start charging */
+               tmp = (tmp & ~OTGSC_CTRL_VBUS_DISCHARGE) |
+                       OTGSC_CTRL_VBUS_CHARGE;
+       else
+               /* stop charging */
+               tmp &= ~OTGSC_CTRL_VBUS_CHARGE;
+
+       fsl_writel(tmp, &usb_dr_regs->otgsc);
+}
+
+/* Discharge vbus through a resistor to ground */
+void fsl_otg_dischrg_vbus(int on)
+{
+       u32 tmp;
+
+       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
+
+       if (on)
+               /* stop charging, start discharging */
+               tmp = (tmp & ~OTGSC_CTRL_VBUS_CHARGE) |
+                       OTGSC_CTRL_VBUS_DISCHARGE;
+       else
+               /* stop discharging */
+               tmp &= ~OTGSC_CTRL_VBUS_DISCHARGE;
+
+       fsl_writel(tmp, &usb_dr_regs->otgsc);
+}
+
+/* A-device driver vbus, controlled through PP bit in PORTSC */
+void fsl_otg_drv_vbus(int on)
+{
+       u32 tmp;
+
+       if (on) {
+               tmp = fsl_readl(&usb_dr_regs->portsc) & ~PORTSC_W1C_BITS;
+               fsl_writel(tmp | PORTSC_PORT_POWER, &usb_dr_regs->portsc);
+       } else {
+               tmp = fsl_readl(&usb_dr_regs->portsc) &
+                     ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER;
+               fsl_writel(tmp, &usb_dr_regs->portsc);
+       }
+}
+
+/*
+ * Pull-up D+, signalling connect by periperal. Also used in
+ * data-line pulsing in SRP
+ */
+void fsl_otg_loc_conn(int on)
+{
+       u32 tmp;
+
+       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
+
+       if (on)
+               tmp |= OTGSC_CTRL_DATA_PULSING;
+       else
+               tmp &= ~OTGSC_CTRL_DATA_PULSING;
+
+       fsl_writel(tmp, &usb_dr_regs->otgsc);
+}
+
+/*
+ * Generate SOF by host.  This is controlled through suspend/resume the
+ * port.  In host mode, controller will automatically send SOF.
+ * Suspend will block the data on the port.
+ */
+void fsl_otg_loc_sof(int on)
+{
+       u32 tmp;
+
+       tmp = fsl_readl(&fsl_otg_dev->dr_mem_map->portsc) & ~PORTSC_W1C_BITS;
+       if (on)
+               tmp |= PORTSC_PORT_FORCE_RESUME;
+       else
+               tmp |= PORTSC_PORT_SUSPEND;
+
+       fsl_writel(tmp, &fsl_otg_dev->dr_mem_map->portsc);
+
+}
+
+/* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */
+void fsl_otg_start_pulse(void)
+{
+       u32 tmp;
+
+       srp_wait_done = 0;
+#ifdef HA_DATA_PULSE
+       tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
+       tmp |= OTGSC_HA_DATA_PULSE;
+       fsl_writel(tmp, &usb_dr_regs->otgsc);
+#else
+       fsl_otg_loc_conn(1);
+#endif
+
+       fsl_otg_add_timer(b_data_pulse_tmr);
+}
+
+void b_data_pulse_end(unsigned long foo)
+{
+#ifdef HA_DATA_PULSE
+#else
+       fsl_otg_loc_conn(0);
+#endif
+
+       /* Do VBUS pulse after data pulse */
+       fsl_otg_pulse_vbus();
+}
+
+void fsl_otg_pulse_vbus(void)
+{
+       srp_wait_done = 0;
+       fsl_otg_chrg_vbus(1);
+       /* start the timer to end vbus charge */
+       fsl_otg_add_timer(b_vbus_pulse_tmr);
+}
+
+void b_vbus_pulse_end(unsigned long foo)
+{
+       fsl_otg_chrg_vbus(0);
+
+       /*
+        * As USB3300 using the same a_sess_vld and b_sess_vld voltage
+        * we need to discharge the bus for a while to distinguish
+        * residual voltage of vbus pulsing and A device pull up
+        */
+       fsl_otg_dischrg_vbus(1);
+       fsl_otg_add_timer(b_srp_wait_tmr);
+}
+
+void b_srp_end(unsigned long foo)
+{
+       fsl_otg_dischrg_vbus(0);
+       srp_wait_done = 1;
+
+       if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) &&
+           fsl_otg_dev->fsm.b_sess_vld)
+               fsl_otg_dev->fsm.b_srp_done = 1;
+}
+
+/*
+ * Workaround for a_host suspending too fast.  When a_bus_req=0,
+ * a_host will start by SRP.  It needs to set b_hnp_enable before
+ * actually suspending to start HNP
+ */
+void a_wait_enum(unsigned long foo)
+{
+       VDBG("a_wait_enum timeout\n");
+       if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
+               fsl_otg_add_timer(a_wait_enum_tmr);
+       else
+               otg_statemachine(&fsl_otg_dev->fsm);
+}
+
+/* The timeout callback function to set time out bit */
+void set_tmout(unsigned long indicator)
+{
+       *(int *)indicator = 1;
+}
+
+/* Initialize timers */
+int fsl_otg_init_timers(struct otg_fsm *fsm)
+{
+       /* FSM used timers */
+       a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
+                               (unsigned long)&fsm->a_wait_vrise_tmout);
+       if (!a_wait_vrise_tmr)
+               return -ENOMEM;
+
+       a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON,
+                               (unsigned long)&fsm->a_wait_bcon_tmout);
+       if (!a_wait_bcon_tmr)
+               return -ENOMEM;
+
+       a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
+                               (unsigned long)&fsm->a_aidl_bdis_tmout);
+       if (!a_aidl_bdis_tmr)
+               return -ENOMEM;
+
+       b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST,
+                               (unsigned long)&fsm->b_ase0_brst_tmout);
+       if (!b_ase0_brst_tmr)
+               return -ENOMEM;
+
+       b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
+                               (unsigned long)&fsm->b_se0_srp);
+       if (!b_se0_srp_tmr)
+               return -ENOMEM;
+
+       b_srp_fail_tmr = otg_timer_initializer(&set_tmout, TB_SRP_FAIL,
+                               (unsigned long)&fsm->b_srp_done);
+       if (!b_srp_fail_tmr)
+               return -ENOMEM;
+
+       a_wait_enum_tmr = otg_timer_initializer(&a_wait_enum, 10,
+                               (unsigned long)&fsm);
+       if (!a_wait_enum_tmr)
+               return -ENOMEM;
+
+       /* device driver used timers */
+       b_srp_wait_tmr = otg_timer_initializer(&b_srp_end, TB_SRP_WAIT, 0);
+       if (!b_srp_wait_tmr)
+               return -ENOMEM;
+
+       b_data_pulse_tmr = otg_timer_initializer(&b_data_pulse_end,
+                               TB_DATA_PLS, 0);
+       if (!b_data_pulse_tmr)
+               return -ENOMEM;
+
+       b_vbus_pulse_tmr = otg_timer_initializer(&b_vbus_pulse_end,
+                               TB_VBUS_PLS, 0);
+       if (!b_vbus_pulse_tmr)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/* Uninitialize timers */
+void fsl_otg_uninit_timers(void)
+{
+       /* FSM used timers */
+       kfree(a_wait_vrise_tmr);
+       kfree(a_wait_bcon_tmr);
+       kfree(a_aidl_bdis_tmr);
+       kfree(b_ase0_brst_tmr);
+       kfree(b_se0_srp_tmr);
+       kfree(b_srp_fail_tmr);
+       kfree(a_wait_enum_tmr);
+
+       /* device driver used timers */
+       kfree(b_srp_wait_tmr);
+       kfree(b_data_pulse_tmr);
+       kfree(b_vbus_pulse_tmr);
+}
+
+/* Add timer to timer list */
+void fsl_otg_add_timer(void *gtimer)
+{
+       struct fsl_otg_timer *timer = gtimer;
+       struct fsl_otg_timer *tmp_timer;
+
+       /*
+        * Check if the timer is already in the active list,
+        * if so update timer count
+        */
+       list_for_each_entry(tmp_timer, &active_timers, list)
+           if (tmp_timer == timer) {
+               timer->count = timer->expires;
+               return;
+       }
+       timer->count = timer->expires;
+       list_add_tail(&timer->list, &active_timers);
+}
+
+/* Remove timer from the timer list; clear timeout status */
+void fsl_otg_del_timer(void *gtimer)
+{
+       struct fsl_otg_timer *timer = gtimer;
+       struct fsl_otg_timer *tmp_timer, *del_tmp;
+
+       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
+               if (tmp_timer == timer)
+                       list_del(&timer->list);
+}
+
+/*
+ * Reduce timer count by 1, and find timeout conditions.
+ * Called by fsl_otg 1ms timer interrupt
+ */
+int fsl_otg_tick_timer(void)
+{
+       struct fsl_otg_timer *tmp_timer, *del_tmp;
+       int expired = 0;
+
+       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
+               tmp_timer->count--;
+               /* check if timer expires */
+               if (!tmp_timer->count) {
+                       list_del(&tmp_timer->list);
+                       tmp_timer->function(tmp_timer->data);
+                       expired = 1;
+               }
+       }
+
+       return expired;
+}
+
+/* Reset controller, not reset the bus */
+void otg_reset_controller(void)
+{
+       u32 command;
+
+       command = fsl_readl(&usb_dr_regs->usbcmd);
+       command |= (1 << 1);
+       fsl_writel(command, &usb_dr_regs->usbcmd);
+       while (fsl_readl(&usb_dr_regs->usbcmd) & (1 << 1))
+               ;
+}
+
+/* Call suspend/resume routines in host driver */
+int fsl_otg_start_host(struct otg_fsm *fsm, int on)
+{
+       struct usb_otg *otg = fsm->otg;
+       struct device *dev;
+       struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       u32 retval = 0;
+
+       if (!otg->host)
+               return -ENODEV;
+       dev = otg->host->controller;
+
+       /*
+        * Update a_vbus_vld state as a_vbus_vld int is disabled
+        * in device mode
+        */
+       fsm->a_vbus_vld =
+               !!(fsl_readl(&usb_dr_regs->otgsc) & OTGSC_STS_A_VBUS_VALID);
+       if (on) {
+               /* start fsl usb host controller */
+               if (otg_dev->host_working)
+                       goto end;
+               else {
+                       otg_reset_controller();
+                       VDBG("host on......\n");
+                       if (dev->driver->pm && dev->driver->pm->resume) {
+                               retval = dev->driver->pm->resume(dev);
+                               if (fsm->id) {
+                                       /* default-b */
+                                       fsl_otg_drv_vbus(1);
+                                       /*
+                                        * Workaround: b_host can't driver
+                                        * vbus, but PP in PORTSC needs to
+                                        * be 1 for host to work.
+                                        * So we set drv_vbus bit in
+                                        * transceiver to 0 thru ULPI.
+                                        */
+                                       write_ulpi(0x0c, 0x20);
+                               }
+                       }
+
+                       otg_dev->host_working = 1;
+               }
+       } else {
+               /* stop fsl usb host controller */
+               if (!otg_dev->host_working)
+                       goto end;
+               else {
+                       VDBG("host off......\n");
+                       if (dev && dev->driver) {
+                               if (dev->driver->pm && dev->driver->pm->suspend)
+                                       retval = dev->driver->pm->suspend(dev);
+                               if (fsm->id)
+                                       /* default-b */
+                                       fsl_otg_drv_vbus(0);
+                       }
+                       otg_dev->host_working = 0;
+               }
+       }
+end:
+       return retval;
+}
+
+/*
+ * Call suspend and resume function in udc driver
+ * to stop and start udc driver.
+ */
+int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
+{
+       struct usb_otg *otg = fsm->otg;
+       struct device *dev;
+
+       if (!otg->gadget || !otg->gadget->dev.parent)
+               return -ENODEV;
+
+       VDBG("gadget %s\n", on ? "on" : "off");
+       dev = otg->gadget->dev.parent;
+
+       if (on) {
+               if (dev->driver->resume)
+                       dev->driver->resume(dev);
+       } else {
+               if (dev->driver->suspend)
+                       dev->driver->suspend(dev, otg_suspend_state);
+       }
+
+       return 0;
+}
+
+/*
+ * Called by initialization code of host driver.  Register host controller
+ * to the OTG.  Suspend host for OTG role detection.
+ */
+static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct fsl_otg *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;
+
+       otg_dev->fsm.a_bus_drop = 0;
+       otg_dev->fsm.a_bus_req = 1;
+
+       if (host) {
+               VDBG("host off......\n");
+
+               otg->host->otg_port = fsl_otg_initdata.otg_port;
+               otg->host->is_b_host = otg_dev->fsm.id;
+               /*
+                * must leave time for khubd to finish its thing
+                * before yanking the host driver out from under it,
+                * so suspend the host after a short delay.
+                */
+               otg_dev->host_working = 1;
+               schedule_delayed_work(&otg_dev->otg_event, 100);
+               return 0;
+       } else {
+               /* host driver going away */
+               if (!(fsl_readl(&otg_dev->dr_mem_map->otgsc) &
+                     OTGSC_STS_USB_ID)) {
+                       /* Mini-A cable connected */
+                       struct otg_fsm *fsm = &otg_dev->fsm;
+
+                       otg->phy->state = OTG_STATE_UNDEFINED;
+                       fsm->protocol = PROTO_UNDEF;
+               }
+       }
+
+       otg_dev->host_working = 0;
+
+       otg_statemachine(&otg_dev->fsm);
+
+       return 0;
+}
+
+/* Called by initialization code of udc.  Register udc to OTG. */
+static int fsl_otg_set_peripheral(struct usb_otg *otg,
+                                       struct usb_gadget *gadget)
+{
+       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_dev != fsl_otg_dev)
+               return -ENODEV;
+
+       if (!gadget) {
+               if (!otg->default_a)
+                       otg->gadget->ops->vbus_draw(otg->gadget, 0);
+               usb_gadget_vbus_disconnect(otg->gadget);
+               otg->gadget = 0;
+               otg_dev->fsm.b_bus_req = 0;
+               otg_statemachine(&otg_dev->fsm);
+               return 0;
+       }
+
+       otg->gadget = gadget;
+       otg->gadget->is_a_peripheral = !otg_dev->fsm.id;
+
+       otg_dev->fsm.b_bus_req = 1;
+
+       /* start the gadget right away if the ID pin says Mini-B */
+       DBG("ID pin=%d\n", otg_dev->fsm.id);
+       if (otg_dev->fsm.id == 1) {
+               fsl_otg_start_host(&otg_dev->fsm, 0);
+               otg_drv_vbus(&otg_dev->fsm, 0);
+               fsl_otg_start_gadget(&otg_dev->fsm, 1);
+       }
+
+       return 0;
+}
+
+/* Set OTG port power, only for B-device */
+static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
+{
+       if (!fsl_otg_dev)
+               return -ENODEV;
+       if (phy->state == OTG_STATE_B_PERIPHERAL)
+               pr_info("FSL OTG: Draw %d mA\n", mA);
+
+       return 0;
+}
+
+/*
+ * Delayed pin detect interrupt processing.
+ *
+ * When the Mini-A cable is disconnected from the board,
+ * the pin-detect interrupt happens before the disconnect
+ * interrupts for the connected device(s).  In order to
+ * process the disconnect interrupt(s) prior to switching
+ * roles, the pin-detect interrupts are delayed, and handled
+ * by this routine.
+ */
+static void fsl_otg_event(struct work_struct *work)
+{
+       struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work);
+       struct otg_fsm *fsm = &og->fsm;
+
+       if (fsm->id) {          /* switch to gadget */
+               fsl_otg_start_host(fsm, 0);
+               otg_drv_vbus(fsm, 0);
+               fsl_otg_start_gadget(fsm, 1);
+       }
+}
+
+/* B-device start SRP */
+static int fsl_otg_start_srp(struct usb_otg *otg)
+{
+       struct fsl_otg *otg_dev;
+
+       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;
+       otg_statemachine(&otg_dev->fsm);
+
+       return 0;
+}
+
+/* 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;
+
+       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");
+
+       /* clear a_bus_req to enter a_suspend state */
+       otg_dev->fsm.a_bus_req = 0;
+       otg_statemachine(&otg_dev->fsm);
+
+       return 0;
+}
+
+/*
+ * Interrupt handler.  OTG/host/peripheral share the same int line.
+ * OTG driver clears OTGSC interrupts and leaves USB interrupts
+ * intact.  It needs to have knowledge of some USB interrupts
+ * such as port change.
+ */
+irqreturn_t fsl_otg_isr(int irq, void *dev_id)
+{
+       struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
+       struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
+       u32 otg_int_src, otg_sc;
+
+       otg_sc = fsl_readl(&usb_dr_regs->otgsc);
+       otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8);
+
+       /* Only clear otg interrupts */
+       fsl_writel(otg_sc, &usb_dr_regs->otgsc);
+
+       /*FIXME: ID change not generate when init to 0 */
+       fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
+       otg->default_a = (fsm->id == 0);
+
+       /* process OTG interrupts */
+       if (otg_int_src) {
+               if (otg_int_src & OTGSC_INTSTS_USB_ID) {
+                       fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
+                       otg->default_a = (fsm->id == 0);
+                       /* clear conn information */
+                       if (fsm->id)
+                               fsm->b_conn = 0;
+                       else
+                               fsm->a_conn = 0;
+
+                       if (otg->host)
+                               otg->host->is_b_host = fsm->id;
+                       if (otg->gadget)
+                               otg->gadget->is_a_peripheral = !fsm->id;
+                       VDBG("ID int (ID is %d)\n", fsm->id);
+
+                       if (fsm->id) {  /* switch to gadget */
+                               schedule_delayed_work(
+                                       &((struct fsl_otg *)dev_id)->otg_event,
+                                       100);
+                       } else {        /* switch to host */
+                               cancel_delayed_work(&
+                                                   ((struct fsl_otg *)dev_id)->
+                                                   otg_event);
+                               fsl_otg_start_gadget(fsm, 0);
+                               otg_drv_vbus(fsm, 1);
+                               fsl_otg_start_host(fsm, 1);
+                       }
+                       return IRQ_HANDLED;
+               }
+       }
+       return IRQ_NONE;
+}
+
+static struct otg_fsm_ops fsl_otg_ops = {
+       .chrg_vbus = fsl_otg_chrg_vbus,
+       .drv_vbus = fsl_otg_drv_vbus,
+       .loc_conn = fsl_otg_loc_conn,
+       .loc_sof = fsl_otg_loc_sof,
+       .start_pulse = fsl_otg_start_pulse,
+
+       .add_timer = fsl_otg_add_timer,
+       .del_timer = fsl_otg_del_timer,
+
+       .start_host = fsl_otg_start_host,
+       .start_gadget = fsl_otg_start_gadget,
+};
+
+/* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
+static int fsl_otg_conf(struct platform_device *pdev)
+{
+       struct fsl_otg *fsl_otg_tc;
+       int status;
+
+       if (fsl_otg_dev)
+               return 0;
+
+       /* allocate space to fsl otg device */
+       fsl_otg_tc = kzalloc(sizeof(struct fsl_otg), GFP_KERNEL);
+       if (!fsl_otg_tc)
+               return -ENOMEM;
+
+       fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+       if (!fsl_otg_tc->phy.otg) {
+               kfree(fsl_otg_tc);
+               return -ENOMEM;
+       }
+
+       INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event);
+
+       INIT_LIST_HEAD(&active_timers);
+       status = fsl_otg_init_timers(&fsl_otg_tc->fsm);
+       if (status) {
+               pr_info("Couldn't init OTG timers\n");
+               goto err;
+       }
+       spin_lock_init(&fsl_otg_tc->fsm.lock);
+
+       /* Set OTG state machine operations */
+       fsl_otg_tc->fsm.ops = &fsl_otg_ops;
+
+       /* initialize the otg structure */
+       fsl_otg_tc->phy.label = DRIVER_DESC;
+       fsl_otg_tc->phy.set_power = fsl_otg_set_power;
+
+       fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy;
+       fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host;
+       fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral;
+       fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp;
+       fsl_otg_tc->phy.otg->start_srp = fsl_otg_start_srp;
+
+       fsl_otg_dev = fsl_otg_tc;
+
+       /* Store the otg transceiver */
+       status = usb_add_phy(&fsl_otg_tc->phy, USB_PHY_TYPE_USB2);
+       if (status) {
+               pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       fsl_otg_uninit_timers();
+       kfree(fsl_otg_tc->phy.otg);
+       kfree(fsl_otg_tc);
+       return status;
+}
+
+/* OTG Initialization */
+int usb_otg_start(struct platform_device *pdev)
+{
+       struct fsl_otg *p_otg;
+       struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
+       struct otg_fsm *fsm;
+       int status;
+       struct resource *res;
+       u32 temp;
+       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+       p_otg = container_of(otg_trans, struct fsl_otg, phy);
+       fsm = &p_otg->fsm;
+
+       /* Initialize the state machine structure with default values */
+       SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED);
+       fsm->otg = p_otg->phy.otg;
+
+       /* We don't require predefined MEM/IRQ resource index */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       /* We don't request_mem_region here to enable resource sharing
+        * with host/device */
+
+       usb_dr_regs = ioremap(res->start, sizeof(struct usb_dr_mmap));
+       p_otg->dr_mem_map = (struct usb_dr_mmap *)usb_dr_regs;
+       pdata->regs = (void *)usb_dr_regs;
+
+       if (pdata->init && pdata->init(pdev) != 0)
+               return -EINVAL;
+
+       if (pdata->big_endian_mmio) {
+               _fsl_readl = _fsl_readl_be;
+               _fsl_writel = _fsl_writel_be;
+       } else {
+               _fsl_readl = _fsl_readl_le;
+               _fsl_writel = _fsl_writel_le;
+       }
+
+       /* request irq */
+       p_otg->irq = platform_get_irq(pdev, 0);
+       status = request_irq(p_otg->irq, fsl_otg_isr,
+                               IRQF_SHARED, driver_name, p_otg);
+       if (status) {
+               dev_dbg(p_otg->phy.dev, "can't get IRQ %d, error %d\n",
+                       p_otg->irq, status);
+               iounmap(p_otg->dr_mem_map);
+               kfree(p_otg->phy.otg);
+               kfree(p_otg);
+               return status;
+       }
+
+       /* stop the controller */
+       temp = fsl_readl(&p_otg->dr_mem_map->usbcmd);
+       temp &= ~USB_CMD_RUN_STOP;
+       fsl_writel(temp, &p_otg->dr_mem_map->usbcmd);
+
+       /* reset the controller */
+       temp = fsl_readl(&p_otg->dr_mem_map->usbcmd);
+       temp |= USB_CMD_CTRL_RESET;
+       fsl_writel(temp, &p_otg->dr_mem_map->usbcmd);
+
+       /* wait reset completed */
+       while (fsl_readl(&p_otg->dr_mem_map->usbcmd) & USB_CMD_CTRL_RESET)
+               ;
+
+       /* configure the VBUSHS as IDLE(both host and device) */
+       temp = USB_MODE_STREAM_DISABLE | (pdata->es ? USB_MODE_ES : 0);
+       fsl_writel(temp, &p_otg->dr_mem_map->usbmode);
+
+       /* configure PHY interface */
+       temp = fsl_readl(&p_otg->dr_mem_map->portsc);
+       temp &= ~(PORTSC_PHY_TYPE_SEL | PORTSC_PTW);
+       switch (pdata->phy_mode) {
+       case FSL_USB2_PHY_ULPI:
+               temp |= PORTSC_PTS_ULPI;
+               break;
+       case FSL_USB2_PHY_UTMI_WIDE:
+               temp |= PORTSC_PTW_16BIT;
+               /* fall through */
+       case FSL_USB2_PHY_UTMI:
+               temp |= PORTSC_PTS_UTMI;
+               /* fall through */
+       default:
+               break;
+       }
+       fsl_writel(temp, &p_otg->dr_mem_map->portsc);
+
+       if (pdata->have_sysif_regs) {
+               /* configure control enable IO output, big endian register */
+               temp = __raw_readl(&p_otg->dr_mem_map->control);
+               temp |= USB_CTRL_IOENB;
+               __raw_writel(temp, &p_otg->dr_mem_map->control);
+       }
+
+       /* disable all interrupt and clear all OTGSC status */
+       temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
+       temp &= ~OTGSC_INTERRUPT_ENABLE_BITS_MASK;
+       temp |= OTGSC_INTERRUPT_STATUS_BITS_MASK | OTGSC_CTRL_VBUS_DISCHARGE;
+       fsl_writel(temp, &p_otg->dr_mem_map->otgsc);
+
+       /*
+        * The identification (id) input is FALSE when a Mini-A plug is inserted
+        * in the devices Mini-AB receptacle. Otherwise, this input is TRUE.
+        * Also: record initial state of ID pin
+        */
+       if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
+               p_otg->phy.state = OTG_STATE_UNDEFINED;
+               p_otg->fsm.id = 1;
+       } else {
+               p_otg->phy.state = OTG_STATE_A_IDLE;
+               p_otg->fsm.id = 0;
+       }
+
+       DBG("initial ID pin=%d\n", p_otg->fsm.id);
+
+       /* enable OTG ID pin interrupt */
+       temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
+       temp |= OTGSC_INTR_USB_ID_EN;
+       temp &= ~(OTGSC_CTRL_VBUS_DISCHARGE | OTGSC_INTR_1MS_TIMER_EN);
+       fsl_writel(temp, &p_otg->dr_mem_map->otgsc);
+
+       return 0;
+}
+
+/*
+ * state file in sysfs
+ */
+static int show_fsl_usb2_otg_state(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct otg_fsm *fsm = &fsl_otg_dev->fsm;
+       char *next = buf;
+       unsigned size = PAGE_SIZE;
+       unsigned long flags;
+       int t;
+
+       spin_lock_irqsave(&fsm->lock, flags);
+
+       /* basic driver infomation */
+       t = scnprintf(next, size,
+                       DRIVER_DESC "\n" "fsl_usb2_otg version: %s\n\n",
+                       DRIVER_VERSION);
+       size -= t;
+       next += t;
+
+       /* Registers */
+       t = scnprintf(next, size,
+                       "OTGSC:   0x%08x\n"
+                       "PORTSC:  0x%08x\n"
+                       "USBMODE: 0x%08x\n"
+                       "USBCMD:  0x%08x\n"
+                       "USBSTS:  0x%08x\n"
+                       "USBINTR: 0x%08x\n",
+                       fsl_readl(&usb_dr_regs->otgsc),
+                       fsl_readl(&usb_dr_regs->portsc),
+                       fsl_readl(&usb_dr_regs->usbmode),
+                       fsl_readl(&usb_dr_regs->usbcmd),
+                       fsl_readl(&usb_dr_regs->usbsts),
+                       fsl_readl(&usb_dr_regs->usbintr));
+       size -= t;
+       next += t;
+
+       /* State */
+       t = scnprintf(next, size,
+                     "OTG state: %s\n\n",
+                     usb_otg_state_string(fsl_otg_dev->phy.state));
+       size -= t;
+       next += t;
+
+       /* State Machine Variables */
+       t = scnprintf(next, size,
+                       "a_bus_req: %d\n"
+                       "b_bus_req: %d\n"
+                       "a_bus_resume: %d\n"
+                       "a_bus_suspend: %d\n"
+                       "a_conn: %d\n"
+                       "a_sess_vld: %d\n"
+                       "a_srp_det: %d\n"
+                       "a_vbus_vld: %d\n"
+                       "b_bus_resume: %d\n"
+                       "b_bus_suspend: %d\n"
+                       "b_conn: %d\n"
+                       "b_se0_srp: %d\n"
+                       "b_sess_end: %d\n"
+                       "b_sess_vld: %d\n"
+                       "id: %d\n",
+                       fsm->a_bus_req,
+                       fsm->b_bus_req,
+                       fsm->a_bus_resume,
+                       fsm->a_bus_suspend,
+                       fsm->a_conn,
+                       fsm->a_sess_vld,
+                       fsm->a_srp_det,
+                       fsm->a_vbus_vld,
+                       fsm->b_bus_resume,
+                       fsm->b_bus_suspend,
+                       fsm->b_conn,
+                       fsm->b_se0_srp,
+                       fsm->b_sess_end,
+                       fsm->b_sess_vld,
+                       fsm->id);
+       size -= t;
+       next += t;
+
+       spin_unlock_irqrestore(&fsm->lock, flags);
+
+       return PAGE_SIZE - size;
+}
+
+static DEVICE_ATTR(fsl_usb2_otg_state, S_IRUGO, show_fsl_usb2_otg_state, NULL);
+
+
+/* Char driver interface to control some OTG input */
+
+/*
+ * Handle some ioctl command, such as get otg
+ * status and set host suspend
+ */
+static long fsl_otg_ioctl(struct file *file, unsigned int cmd,
+                         unsigned long arg)
+{
+       u32 retval = 0;
+
+       switch (cmd) {
+       case GET_OTG_STATUS:
+               retval = fsl_otg_dev->host_working;
+               break;
+
+       case SET_A_SUSPEND_REQ:
+               fsl_otg_dev->fsm.a_suspend_req = arg;
+               break;
+
+       case SET_A_BUS_DROP:
+               fsl_otg_dev->fsm.a_bus_drop = arg;
+               break;
+
+       case SET_A_BUS_REQ:
+               fsl_otg_dev->fsm.a_bus_req = arg;
+               break;
+
+       case SET_B_BUS_REQ:
+               fsl_otg_dev->fsm.b_bus_req = arg;
+               break;
+
+       default:
+               break;
+       }
+
+       otg_statemachine(&fsl_otg_dev->fsm);
+
+       return retval;
+}
+
+static int fsl_otg_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int fsl_otg_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static const struct file_operations otg_fops = {
+       .owner = THIS_MODULE,
+       .llseek = NULL,
+       .read = NULL,
+       .write = NULL,
+       .unlocked_ioctl = fsl_otg_ioctl,
+       .open = fsl_otg_open,
+       .release = fsl_otg_release,
+};
+
+static int fsl_otg_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       if (!pdev->dev.platform_data)
+               return -ENODEV;
+
+       /* configure the OTG */
+       ret = fsl_otg_conf(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Couldn't configure OTG module\n");
+               return ret;
+       }
+
+       /* start OTG */
+       ret = usb_otg_start(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't init FSL OTG device\n");
+               return ret;
+       }
+
+       ret = register_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME, &otg_fops);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to register FSL OTG device\n");
+               return ret;
+       }
+
+       ret = device_create_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
+       if (ret)
+               dev_warn(&pdev->dev, "Can't register sysfs attribute\n");
+
+       return ret;
+}
+
+static int fsl_otg_remove(struct platform_device *pdev)
+{
+       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+       usb_remove_phy(&fsl_otg_dev->phy);
+       free_irq(fsl_otg_dev->irq, fsl_otg_dev);
+
+       iounmap((void *)usb_dr_regs);
+
+       fsl_otg_uninit_timers();
+       kfree(fsl_otg_dev->phy.otg);
+       kfree(fsl_otg_dev);
+
+       device_remove_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
+
+       unregister_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME);
+
+       if (pdata->exit)
+               pdata->exit(pdev);
+
+       return 0;
+}
+
+struct platform_driver fsl_otg_driver = {
+       .probe = fsl_otg_probe,
+       .remove = fsl_otg_remove,
+       .driver = {
+               .name = driver_name,
+               .owner = THIS_MODULE,
+       },
+};
+
+module_platform_driver(fsl_otg_driver);
+
+MODULE_DESCRIPTION(DRIVER_INFO);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/fsl_otg.h b/drivers/usb/phy/fsl_otg.h
new file mode 100644 (file)
index 0000000..ca26628
--- /dev/null
@@ -0,0 +1,406 @@
+/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "otg_fsm.h"
+#include <linux/usb/otg.h>
+#include <linux/ioctl.h>
+
+/* USB Command Register Bit Masks */
+#define USB_CMD_RUN_STOP               (0x1<<0)
+#define USB_CMD_CTRL_RESET             (0x1<<1)
+#define USB_CMD_PERIODIC_SCHEDULE_EN   (0x1<<4)
+#define USB_CMD_ASYNC_SCHEDULE_EN      (0x1<<5)
+#define USB_CMD_INT_AA_DOORBELL                (0x1<<6)
+#define USB_CMD_ASP                    (0x3<<8)
+#define USB_CMD_ASYNC_SCH_PARK_EN      (0x1<<11)
+#define USB_CMD_SUTW                   (0x1<<13)
+#define USB_CMD_ATDTW                  (0x1<<14)
+#define USB_CMD_ITC                    (0xFF<<16)
+
+/* bit 15,3,2 are frame list size */
+#define USB_CMD_FRAME_SIZE_1024                (0x0<<15 | 0x0<<2)
+#define USB_CMD_FRAME_SIZE_512         (0x0<<15 | 0x1<<2)
+#define USB_CMD_FRAME_SIZE_256         (0x0<<15 | 0x2<<2)
+#define USB_CMD_FRAME_SIZE_128         (0x0<<15 | 0x3<<2)
+#define USB_CMD_FRAME_SIZE_64          (0x1<<15 | 0x0<<2)
+#define USB_CMD_FRAME_SIZE_32          (0x1<<15 | 0x1<<2)
+#define USB_CMD_FRAME_SIZE_16          (0x1<<15 | 0x2<<2)
+#define USB_CMD_FRAME_SIZE_8           (0x1<<15 | 0x3<<2)
+
+/* bit 9-8 are async schedule park mode count */
+#define USB_CMD_ASP_00                 (0x0<<8)
+#define USB_CMD_ASP_01                 (0x1<<8)
+#define USB_CMD_ASP_10                 (0x2<<8)
+#define USB_CMD_ASP_11                 (0x3<<8)
+#define USB_CMD_ASP_BIT_POS            (8)
+
+/* bit 23-16 are interrupt threshold control */
+#define USB_CMD_ITC_NO_THRESHOLD       (0x00<<16)
+#define USB_CMD_ITC_1_MICRO_FRM                (0x01<<16)
+#define USB_CMD_ITC_2_MICRO_FRM                (0x02<<16)
+#define USB_CMD_ITC_4_MICRO_FRM                (0x04<<16)
+#define USB_CMD_ITC_8_MICRO_FRM                (0x08<<16)
+#define USB_CMD_ITC_16_MICRO_FRM       (0x10<<16)
+#define USB_CMD_ITC_32_MICRO_FRM       (0x20<<16)
+#define USB_CMD_ITC_64_MICRO_FRM       (0x40<<16)
+#define USB_CMD_ITC_BIT_POS            (16)
+
+/* USB Status Register Bit Masks */
+#define USB_STS_INT                    (0x1<<0)
+#define USB_STS_ERR                    (0x1<<1)
+#define USB_STS_PORT_CHANGE            (0x1<<2)
+#define USB_STS_FRM_LST_ROLL           (0x1<<3)
+#define USB_STS_SYS_ERR                        (0x1<<4)
+#define USB_STS_IAA                    (0x1<<5)
+#define USB_STS_RESET_RECEIVED         (0x1<<6)
+#define USB_STS_SOF                    (0x1<<7)
+#define USB_STS_DCSUSPEND              (0x1<<8)
+#define USB_STS_HC_HALTED              (0x1<<12)
+#define USB_STS_RCL                    (0x1<<13)
+#define USB_STS_PERIODIC_SCHEDULE      (0x1<<14)
+#define USB_STS_ASYNC_SCHEDULE         (0x1<<15)
+
+/* USB Interrupt Enable Register Bit Masks */
+#define USB_INTR_INT_EN                        (0x1<<0)
+#define USB_INTR_ERR_INT_EN            (0x1<<1)
+#define USB_INTR_PC_DETECT_EN          (0x1<<2)
+#define USB_INTR_FRM_LST_ROLL_EN       (0x1<<3)
+#define USB_INTR_SYS_ERR_EN            (0x1<<4)
+#define USB_INTR_ASYN_ADV_EN           (0x1<<5)
+#define USB_INTR_RESET_EN              (0x1<<6)
+#define USB_INTR_SOF_EN                        (0x1<<7)
+#define USB_INTR_DEVICE_SUSPEND                (0x1<<8)
+
+/* Device Address bit masks */
+#define USB_DEVICE_ADDRESS_MASK                (0x7F<<25)
+#define USB_DEVICE_ADDRESS_BIT_POS     (25)
+/* PORTSC  Register Bit Masks,Only one PORT in OTG mode*/
+#define PORTSC_CURRENT_CONNECT_STATUS  (0x1<<0)
+#define PORTSC_CONNECT_STATUS_CHANGE   (0x1<<1)
+#define PORTSC_PORT_ENABLE             (0x1<<2)
+#define PORTSC_PORT_EN_DIS_CHANGE      (0x1<<3)
+#define PORTSC_OVER_CURRENT_ACT                (0x1<<4)
+#define PORTSC_OVER_CUURENT_CHG                (0x1<<5)
+#define PORTSC_PORT_FORCE_RESUME       (0x1<<6)
+#define PORTSC_PORT_SUSPEND            (0x1<<7)
+#define PORTSC_PORT_RESET              (0x1<<8)
+#define PORTSC_LINE_STATUS_BITS                (0x3<<10)
+#define PORTSC_PORT_POWER              (0x1<<12)
+#define PORTSC_PORT_INDICTOR_CTRL      (0x3<<14)
+#define PORTSC_PORT_TEST_CTRL          (0xF<<16)
+#define PORTSC_WAKE_ON_CONNECT_EN      (0x1<<20)
+#define PORTSC_WAKE_ON_CONNECT_DIS     (0x1<<21)
+#define PORTSC_WAKE_ON_OVER_CURRENT    (0x1<<22)
+#define PORTSC_PHY_LOW_POWER_SPD       (0x1<<23)
+#define PORTSC_PORT_FORCE_FULL_SPEED   (0x1<<24)
+#define PORTSC_PORT_SPEED_MASK         (0x3<<26)
+#define PORTSC_TRANSCEIVER_WIDTH       (0x1<<28)
+#define PORTSC_PHY_TYPE_SEL            (0x3<<30)
+/* bit 11-10 are line status */
+#define PORTSC_LINE_STATUS_SE0         (0x0<<10)
+#define PORTSC_LINE_STATUS_JSTATE      (0x1<<10)
+#define PORTSC_LINE_STATUS_KSTATE      (0x2<<10)
+#define PORTSC_LINE_STATUS_UNDEF       (0x3<<10)
+#define PORTSC_LINE_STATUS_BIT_POS     (10)
+
+/* bit 15-14 are port indicator control */
+#define PORTSC_PIC_OFF                 (0x0<<14)
+#define PORTSC_PIC_AMBER               (0x1<<14)
+#define PORTSC_PIC_GREEN               (0x2<<14)
+#define PORTSC_PIC_UNDEF               (0x3<<14)
+#define PORTSC_PIC_BIT_POS             (14)
+
+/* bit 19-16 are port test control */
+#define PORTSC_PTC_DISABLE             (0x0<<16)
+#define PORTSC_PTC_JSTATE              (0x1<<16)
+#define PORTSC_PTC_KSTATE              (0x2<<16)
+#define PORTSC_PTC_SEQNAK              (0x3<<16)
+#define PORTSC_PTC_PACKET              (0x4<<16)
+#define PORTSC_PTC_FORCE_EN            (0x5<<16)
+#define PORTSC_PTC_BIT_POS             (16)
+
+/* bit 27-26 are port speed */
+#define PORTSC_PORT_SPEED_FULL         (0x0<<26)
+#define PORTSC_PORT_SPEED_LOW          (0x1<<26)
+#define PORTSC_PORT_SPEED_HIGH         (0x2<<26)
+#define PORTSC_PORT_SPEED_UNDEF                (0x3<<26)
+#define PORTSC_SPEED_BIT_POS           (26)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define PORTSC_PTW                     (0x1<<28)
+#define PORTSC_PTW_8BIT                        (0x0<<28)
+#define PORTSC_PTW_16BIT               (0x1<<28)
+
+/* bit 31-30 are port transceiver select */
+#define PORTSC_PTS_UTMI                        (0x0<<30)
+#define PORTSC_PTS_ULPI                        (0x2<<30)
+#define PORTSC_PTS_FSLS_SERIAL         (0x3<<30)
+#define PORTSC_PTS_BIT_POS             (30)
+
+#define PORTSC_W1C_BITS                        \
+       (PORTSC_CONNECT_STATUS_CHANGE | \
+        PORTSC_PORT_EN_DIS_CHANGE    | \
+        PORTSC_OVER_CUURENT_CHG)
+
+/* OTG Status Control Register Bit Masks */
+#define OTGSC_CTRL_VBUS_DISCHARGE      (0x1<<0)
+#define OTGSC_CTRL_VBUS_CHARGE         (0x1<<1)
+#define OTGSC_CTRL_OTG_TERMINATION     (0x1<<3)
+#define OTGSC_CTRL_DATA_PULSING                (0x1<<4)
+#define OTGSC_CTRL_ID_PULL_EN          (0x1<<5)
+#define OTGSC_HA_DATA_PULSE            (0x1<<6)
+#define OTGSC_HA_BA                    (0x1<<7)
+#define OTGSC_STS_USB_ID               (0x1<<8)
+#define OTGSC_STS_A_VBUS_VALID         (0x1<<9)
+#define OTGSC_STS_A_SESSION_VALID      (0x1<<10)
+#define OTGSC_STS_B_SESSION_VALID      (0x1<<11)
+#define OTGSC_STS_B_SESSION_END                (0x1<<12)
+#define OTGSC_STS_1MS_TOGGLE           (0x1<<13)
+#define OTGSC_STS_DATA_PULSING         (0x1<<14)
+#define OTGSC_INTSTS_USB_ID            (0x1<<16)
+#define OTGSC_INTSTS_A_VBUS_VALID      (0x1<<17)
+#define OTGSC_INTSTS_A_SESSION_VALID   (0x1<<18)
+#define OTGSC_INTSTS_B_SESSION_VALID   (0x1<<19)
+#define OTGSC_INTSTS_B_SESSION_END     (0x1<<20)
+#define OTGSC_INTSTS_1MS               (0x1<<21)
+#define OTGSC_INTSTS_DATA_PULSING      (0x1<<22)
+#define OTGSC_INTR_USB_ID_EN           (0x1<<24)
+#define OTGSC_INTR_A_VBUS_VALID_EN     (0x1<<25)
+#define OTGSC_INTR_A_SESSION_VALID_EN  (0x1<<26)
+#define OTGSC_INTR_B_SESSION_VALID_EN  (0x1<<27)
+#define OTGSC_INTR_B_SESSION_END_EN    (0x1<<28)
+#define OTGSC_INTR_1MS_TIMER_EN                (0x1<<29)
+#define OTGSC_INTR_DATA_PULSING_EN     (0x1<<30)
+#define OTGSC_INTSTS_MASK              (0x00ff0000)
+
+/* USB MODE Register Bit Masks */
+#define  USB_MODE_CTRL_MODE_IDLE       (0x0<<0)
+#define  USB_MODE_CTRL_MODE_DEVICE     (0x2<<0)
+#define  USB_MODE_CTRL_MODE_HOST       (0x3<<0)
+#define  USB_MODE_CTRL_MODE_RSV                (0x1<<0)
+#define  USB_MODE_SETUP_LOCK_OFF       (0x1<<3)
+#define  USB_MODE_STREAM_DISABLE       (0x1<<4)
+#define  USB_MODE_ES                   (0x1<<2) /* Endian Select */
+
+/* control Register Bit Masks */
+#define  USB_CTRL_IOENB                        (0x1<<2)
+#define  USB_CTRL_ULPI_INT0EN          (0x1<<0)
+
+/* BCSR5 */
+#define BCSR5_INT_USB                  (0x02)
+
+/* USB module clk cfg */
+#define SCCR_OFFS                      (0xA08)
+#define SCCR_USB_CLK_DISABLE           (0x00000000)    /* USB clk disable */
+#define SCCR_USB_MPHCM_11              (0x00c00000)
+#define SCCR_USB_MPHCM_01              (0x00400000)
+#define SCCR_USB_MPHCM_10              (0x00800000)
+#define SCCR_USB_DRCM_11               (0x00300000)
+#define SCCR_USB_DRCM_01               (0x00100000)
+#define SCCR_USB_DRCM_10               (0x00200000)
+
+#define SICRL_OFFS                     (0x114)
+#define SICRL_USB0                     (0x40000000)
+#define SICRL_USB1                     (0x20000000)
+
+#define SICRH_OFFS                     (0x118)
+#define SICRH_USB_UTMI                 (0x00020000)
+
+/* OTG interrupt enable bit masks */
+#define  OTGSC_INTERRUPT_ENABLE_BITS_MASK  \
+       (OTGSC_INTR_USB_ID_EN            | \
+       OTGSC_INTR_1MS_TIMER_EN          | \
+       OTGSC_INTR_A_VBUS_VALID_EN       | \
+       OTGSC_INTR_A_SESSION_VALID_EN    | \
+       OTGSC_INTR_B_SESSION_VALID_EN    | \
+       OTGSC_INTR_B_SESSION_END_EN      | \
+       OTGSC_INTR_DATA_PULSING_EN)
+
+/* OTG interrupt status bit masks */
+#define  OTGSC_INTERRUPT_STATUS_BITS_MASK  \
+       (OTGSC_INTSTS_USB_ID          |    \
+       OTGSC_INTR_1MS_TIMER_EN       |    \
+       OTGSC_INTSTS_A_VBUS_VALID     |    \
+       OTGSC_INTSTS_A_SESSION_VALID  |    \
+       OTGSC_INTSTS_B_SESSION_VALID  |    \
+       OTGSC_INTSTS_B_SESSION_END    |    \
+       OTGSC_INTSTS_DATA_PULSING)
+
+/*
+ *  A-DEVICE timing  constants
+ */
+
+/* Wait for VBUS Rise  */
+#define TA_WAIT_VRISE  (100)   /* a_wait_vrise 100 ms, section: 6.6.5.1 */
+
+/* Wait for B-Connect */
+#define TA_WAIT_BCON   (10000)  /* a_wait_bcon > 1 sec, section: 6.6.5.2
+                                 * This is only used to get out of
+                                 * OTG_STATE_A_WAIT_BCON state if there was
+                                 * no connection for these many milliseconds
+                                 */
+
+/* A-Idle to B-Disconnect */
+/* It is necessary for this timer to be more than 750 ms because of a bug in OPT
+ * test 5.4 in which B OPT disconnects after 750 ms instead of 75ms as stated
+ * in the test description
+ */
+#define TA_AIDL_BDIS   (5000)  /* a_suspend minimum 200 ms, section: 6.6.5.3 */
+
+/* B-Idle to A-Disconnect */
+#define TA_BIDL_ADIS   (12)    /* 3 to 200 ms */
+
+/* B-device timing constants */
+
+
+/* Data-Line Pulse Time*/
+#define TB_DATA_PLS    (10)    /* b_srp_init,continue 5~10ms, section:5.3.3 */
+#define TB_DATA_PLS_MIN        (5)     /* minimum 5 ms */
+#define TB_DATA_PLS_MAX        (10)    /* maximum 10 ms */
+
+/* SRP Initiate Time  */
+#define TB_SRP_INIT    (100)   /* b_srp_init,maximum 100 ms, section:5.3.8 */
+
+/* SRP Fail Time  */
+#define TB_SRP_FAIL    (7000)  /* b_srp_init,Fail time 5~30s, section:6.8.2.2*/
+
+/* SRP result wait time */
+#define TB_SRP_WAIT    (60)
+
+/* VBus time */
+#define TB_VBUS_PLS    (30)    /* time to keep vbus pulsing asserted */
+
+/* Discharge time */
+/* This time should be less than 10ms. It varies from system to system. */
+#define TB_VBUS_DSCHRG (8)
+
+/* A-SE0 to B-Reset  */
+#define TB_ASE0_BRST   (20)    /* b_wait_acon, mini 3.125 ms,section:6.8.2.4 */
+
+/* A bus suspend timer before we can switch to b_wait_aconn */
+#define TB_A_SUSPEND   (7)
+#define TB_BUS_RESUME  (12)
+
+/* SE0 Time Before SRP */
+#define TB_SE0_SRP     (2)     /* b_idle,minimum 2 ms, section:5.3.2 */
+
+#define SET_OTG_STATE(otg_ptr, newstate)       ((otg_ptr)->state = newstate)
+
+struct usb_dr_mmap {
+       /* Capability register */
+       u8 res1[256];
+       u16 caplength;          /* Capability Register Length */
+       u16 hciversion;         /* Host Controller Interface Version */
+       u32 hcsparams;          /* Host Controller Structual Parameters */
+       u32 hccparams;          /* Host Controller Capability Parameters */
+       u8 res2[20];
+       u32 dciversion;         /* Device Controller Interface Version */
+       u32 dccparams;          /* Device Controller Capability Parameters */
+       u8 res3[24];
+       /* Operation register */
+       u32 usbcmd;             /* USB Command Register */
+       u32 usbsts;             /* USB Status Register */
+       u32 usbintr;            /* USB Interrupt Enable Register */
+       u32 frindex;            /* Frame Index Register */
+       u8 res4[4];
+       u32 deviceaddr;         /* Device Address */
+       u32 endpointlistaddr;   /* Endpoint List Address Register */
+       u8 res5[4];
+       u32 burstsize;          /* Master Interface Data Burst Size Register */
+       u32 txttfilltuning;     /* Transmit FIFO Tuning Controls Register */
+       u8 res6[8];
+       u32 ulpiview;           /* ULPI register access */
+       u8 res7[12];
+       u32 configflag;         /* Configure Flag Register */
+       u32 portsc;             /* Port 1 Status and Control Register */
+       u8 res8[28];
+       u32 otgsc;              /* On-The-Go Status and Control */
+       u32 usbmode;            /* USB Mode Register */
+       u32 endptsetupstat;     /* Endpoint Setup Status Register */
+       u32 endpointprime;      /* Endpoint Initialization Register */
+       u32 endptflush;         /* Endpoint Flush Register */
+       u32 endptstatus;        /* Endpoint Status Register */
+       u32 endptcomplete;      /* Endpoint Complete Register */
+       u32 endptctrl[6];       /* Endpoint Control Registers */
+       u8 res9[552];
+       u32 snoop1;
+       u32 snoop2;
+       u32 age_cnt_thresh;     /* Age Count Threshold Register */
+       u32 pri_ctrl;           /* Priority Control Register */
+       u32 si_ctrl;            /* System Interface Control Register */
+       u8 res10[236];
+       u32 control;            /* General Purpose Control Register */
+};
+
+struct fsl_otg_timer {
+       unsigned long expires;  /* Number of count increase to timeout */
+       unsigned long count;    /* Tick counter */
+       void (*function)(unsigned long);        /* Timeout function */
+       unsigned long data;     /* Data passed to function */
+       struct list_head list;
+};
+
+inline struct fsl_otg_timer *otg_timer_initializer
+(void (*function)(unsigned long), unsigned long expires, unsigned long data)
+{
+       struct fsl_otg_timer *timer;
+
+       timer = kmalloc(sizeof(struct fsl_otg_timer), GFP_KERNEL);
+       if (!timer)
+               return NULL;
+       timer->function = function;
+       timer->expires = expires;
+       timer->data = data;
+       return timer;
+}
+
+struct fsl_otg {
+       struct usb_phy phy;
+       struct otg_fsm fsm;
+       struct usb_dr_mmap *dr_mem_map;
+       struct delayed_work otg_event;
+
+       /* used for usb host */
+       struct work_struct work_wq;
+       u8      host_working;
+
+       int irq;
+};
+
+struct fsl_otg_config {
+       u8 otg_port;
+};
+
+/* For SRP and HNP handle */
+#define FSL_OTG_MAJOR          240
+#define FSL_OTG_NAME           "fsl-usb2-otg"
+/* Command to OTG driver ioctl */
+#define OTG_IOCTL_MAGIC                FSL_OTG_MAJOR
+/* if otg work as host, it should return 1, otherwise return 0 */
+#define GET_OTG_STATUS         _IOR(OTG_IOCTL_MAGIC, 1, int)
+#define SET_A_SUSPEND_REQ      _IOW(OTG_IOCTL_MAGIC, 2, int)
+#define SET_A_BUS_DROP         _IOW(OTG_IOCTL_MAGIC, 3, int)
+#define SET_A_BUS_REQ          _IOW(OTG_IOCTL_MAGIC, 4, int)
+#define SET_B_BUS_REQ          _IOW(OTG_IOCTL_MAGIC, 5, int)
+#define GET_A_SUSPEND_REQ      _IOR(OTG_IOCTL_MAGIC, 6, int)
+#define GET_A_BUS_DROP         _IOR(OTG_IOCTL_MAGIC, 7, int)
+#define GET_A_BUS_REQ          _IOR(OTG_IOCTL_MAGIC, 8, int)
+#define GET_B_BUS_REQ          _IOR(OTG_IOCTL_MAGIC, 9, int)
+
+void fsl_otg_add_timer(void *timer);
+void fsl_otg_del_timer(void *timer);
+void fsl_otg_pulse_vbus(void);
diff --git a/drivers/usb/phy/gpio_vbus.c b/drivers/usb/phy/gpio_vbus.c
new file mode 100644 (file)
index 0000000..a7d4ac5
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices
+ *
+ * Copyright (c) 2008 Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+#include <linux/regulator/consumer.h>
+
+#include <linux/usb/gadget.h>
+#include <linux/usb/gpio_vbus.h>
+#include <linux/usb/otg.h>
+
+
+/*
+ * A simple GPIO VBUS sensing driver for B peripheral only devices
+ * with internal transceivers. It can control a D+ pullup GPIO and
+ * a regulator to limit the current drawn from VBUS.
+ *
+ * Needs to be loaded before the UDC driver that will use it.
+ */
+struct gpio_vbus_data {
+       struct usb_phy          phy;
+       struct device          *dev;
+       struct regulator       *vbus_draw;
+       int                     vbus_draw_enabled;
+       unsigned                mA;
+       struct delayed_work     work;
+       int                     vbus;
+       int                     irq;
+};
+
+
+/*
+ * This driver relies on "both edges" triggering.  VBUS has 100 msec to
+ * stabilize, so the peripheral controller driver may need to cope with
+ * some bouncing due to current surges (e.g. charging local capacitance)
+ * and contact chatter.
+ *
+ * REVISIT in desperate straits, toggling between rising and falling
+ * edges might be workable.
+ */
+#define VBUS_IRQ_FLAGS \
+       (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
+
+
+/* interface to regulator framework */
+static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
+{
+       struct regulator *vbus_draw = gpio_vbus->vbus_draw;
+       int enabled;
+
+       if (!vbus_draw)
+               return;
+
+       enabled = gpio_vbus->vbus_draw_enabled;
+       if (mA) {
+               regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
+               if (!enabled) {
+                       regulator_enable(vbus_draw);
+                       gpio_vbus->vbus_draw_enabled = 1;
+               }
+       } else {
+               if (enabled) {
+                       regulator_disable(vbus_draw);
+                       gpio_vbus->vbus_draw_enabled = 0;
+               }
+       }
+       gpio_vbus->mA = mA;
+}
+
+static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
+{
+       int vbus;
+
+       vbus = gpio_get_value(pdata->gpio_vbus);
+       if (pdata->gpio_vbus_inverted)
+               vbus = !vbus;
+
+       return vbus;
+}
+
+static void gpio_vbus_work(struct work_struct *work)
+{
+       struct gpio_vbus_data *gpio_vbus =
+               container_of(work, struct gpio_vbus_data, work.work);
+       struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
+       int gpio, status, vbus;
+
+       if (!gpio_vbus->phy.otg->gadget)
+               return;
+
+       vbus = is_vbus_powered(pdata);
+       if ((vbus ^ gpio_vbus->vbus) == 0)
+               return;
+       gpio_vbus->vbus = vbus;
+
+       /* Peripheral controllers which manage the pullup themselves won't have
+        * gpio_pullup configured here.  If it's configured here, we'll do what
+        * isp1301_omap::b_peripheral() does and enable the pullup here... although
+        * that may complicate usb_gadget_{,dis}connect() support.
+        */
+       gpio = pdata->gpio_pullup;
+
+       if (vbus) {
+               status = USB_EVENT_VBUS;
+               gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
+               gpio_vbus->phy.last_event = status;
+               usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget);
+
+               /* drawing a "unit load" is *always* OK, except for OTG */
+               set_vbus_draw(gpio_vbus, 100);
+
+               /* optionally enable D+ pullup */
+               if (gpio_is_valid(gpio))
+                       gpio_set_value(gpio, !pdata->gpio_pullup_inverted);
+
+               atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
+                                          status, gpio_vbus->phy.otg->gadget);
+       } else {
+               /* optionally disable D+ pullup */
+               if (gpio_is_valid(gpio))
+                       gpio_set_value(gpio, pdata->gpio_pullup_inverted);
+
+               set_vbus_draw(gpio_vbus, 0);
+
+               usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget);
+               status = USB_EVENT_NONE;
+               gpio_vbus->phy.state = OTG_STATE_B_IDLE;
+               gpio_vbus->phy.last_event = status;
+
+               atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
+                                          status, gpio_vbus->phy.otg->gadget);
+       }
+}
+
+/* VBUS change IRQ handler */
+static irqreturn_t gpio_vbus_irq(int irq, void *data)
+{
+       struct platform_device *pdev = data;
+       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+       struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+       struct usb_otg *otg = gpio_vbus->phy.otg;
+
+       dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
+               is_vbus_powered(pdata) ? "supplied" : "inactive",
+               otg->gadget ? otg->gadget->name : "none");
+
+       if (otg->gadget)
+               schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100));
+
+       return IRQ_HANDLED;
+}
+
+/* OTG transceiver interface */
+
+/* bind/unbind the peripheral controller */
+static int gpio_vbus_set_peripheral(struct usb_otg *otg,
+                                       struct usb_gadget *gadget)
+{
+       struct gpio_vbus_data *gpio_vbus;
+       struct gpio_vbus_mach_info *pdata;
+       struct platform_device *pdev;
+       int gpio;
+
+       gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
+       pdev = to_platform_device(gpio_vbus->dev);
+       pdata = gpio_vbus->dev->platform_data;
+       gpio = pdata->gpio_pullup;
+
+       if (!gadget) {
+               dev_dbg(&pdev->dev, "unregistering gadget '%s'\n",
+                       otg->gadget->name);
+
+               /* optionally disable D+ pullup */
+               if (gpio_is_valid(gpio))
+                       gpio_set_value(gpio, pdata->gpio_pullup_inverted);
+
+               set_vbus_draw(gpio_vbus, 0);
+
+               usb_gadget_vbus_disconnect(otg->gadget);
+               otg->phy->state = OTG_STATE_UNDEFINED;
+
+               otg->gadget = NULL;
+               return 0;
+       }
+
+       otg->gadget = gadget;
+       dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
+
+       /* initialize connection state */
+       gpio_vbus->vbus = 0; /* start with disconnected */
+       gpio_vbus_irq(gpio_vbus->irq, pdev);
+       return 0;
+}
+
+/* effective for B devices, ignored for A-peripheral */
+static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA)
+{
+       struct gpio_vbus_data *gpio_vbus;
+
+       gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
+
+       if (phy->state == OTG_STATE_B_PERIPHERAL)
+               set_vbus_draw(gpio_vbus, mA);
+       return 0;
+}
+
+/* for non-OTG B devices: set/clear transceiver suspend mode */
+static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
+{
+       struct gpio_vbus_data *gpio_vbus;
+
+       gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
+
+       /* draw max 0 mA from vbus in suspend mode; or the previously
+        * recorded amount of current if not suspended
+        *
+        * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA
+        * if they're wake-enabled ... we don't handle that yet.
+        */
+       return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA);
+}
+
+/* platform driver interface */
+
+static int __init gpio_vbus_probe(struct platform_device *pdev)
+{
+       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+       struct gpio_vbus_data *gpio_vbus;
+       struct resource *res;
+       int err, gpio, irq;
+       unsigned long irqflags;
+
+       if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
+               return -EINVAL;
+       gpio = pdata->gpio_vbus;
+
+       gpio_vbus = kzalloc(sizeof(struct gpio_vbus_data), GFP_KERNEL);
+       if (!gpio_vbus)
+               return -ENOMEM;
+
+       gpio_vbus->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+       if (!gpio_vbus->phy.otg) {
+               kfree(gpio_vbus);
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, gpio_vbus);
+       gpio_vbus->dev = &pdev->dev;
+       gpio_vbus->phy.label = "gpio-vbus";
+       gpio_vbus->phy.set_power = gpio_vbus_set_power;
+       gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
+       gpio_vbus->phy.state = OTG_STATE_UNDEFINED;
+
+       gpio_vbus->phy.otg->phy = &gpio_vbus->phy;
+       gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral;
+
+       err = gpio_request(gpio, "vbus_detect");
+       if (err) {
+               dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n",
+                       gpio, err);
+               goto err_gpio;
+       }
+       gpio_direction_input(gpio);
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res) {
+               irq = res->start;
+               irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
+       } else {
+               irq = gpio_to_irq(gpio);
+               irqflags = VBUS_IRQ_FLAGS;
+       }
+
+       gpio_vbus->irq = irq;
+
+       /* if data line pullup is in use, initialize it to "not pulling up" */
+       gpio = pdata->gpio_pullup;
+       if (gpio_is_valid(gpio)) {
+               err = gpio_request(gpio, "udc_pullup");
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "can't request pullup gpio %d, err: %d\n",
+                               gpio, err);
+                       gpio_free(pdata->gpio_vbus);
+                       goto err_gpio;
+               }
+               gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
+       }
+
+       err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev);
+       if (err) {
+               dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
+                       irq, err);
+               goto err_irq;
+       }
+
+       ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);
+
+       INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
+
+       gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
+       if (IS_ERR(gpio_vbus->vbus_draw)) {
+               dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
+                       PTR_ERR(gpio_vbus->vbus_draw));
+               gpio_vbus->vbus_draw = NULL;
+       }
+
+       /* only active when a gadget is registered */
+       err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2);
+       if (err) {
+               dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
+                       err);
+               goto err_otg;
+       }
+
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+       return 0;
+err_otg:
+       regulator_put(gpio_vbus->vbus_draw);
+       free_irq(irq, pdev);
+err_irq:
+       if (gpio_is_valid(pdata->gpio_pullup))
+               gpio_free(pdata->gpio_pullup);
+       gpio_free(pdata->gpio_vbus);
+err_gpio:
+       platform_set_drvdata(pdev, NULL);
+       kfree(gpio_vbus->phy.otg);
+       kfree(gpio_vbus);
+       return err;
+}
+
+static int __exit gpio_vbus_remove(struct platform_device *pdev)
+{
+       struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+       struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+       int gpio = pdata->gpio_vbus;
+
+       device_init_wakeup(&pdev->dev, 0);
+       cancel_delayed_work_sync(&gpio_vbus->work);
+       regulator_put(gpio_vbus->vbus_draw);
+
+       usb_remove_phy(&gpio_vbus->phy);
+
+       free_irq(gpio_vbus->irq, pdev);
+       if (gpio_is_valid(pdata->gpio_pullup))
+               gpio_free(pdata->gpio_pullup);
+       gpio_free(gpio);
+       platform_set_drvdata(pdev, NULL);
+       kfree(gpio_vbus->phy.otg);
+       kfree(gpio_vbus);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_vbus_pm_suspend(struct device *dev)
+{
+       struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(gpio_vbus->irq);
+
+       return 0;
+}
+
+static int gpio_vbus_pm_resume(struct device *dev)
+{
+       struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(gpio_vbus->irq);
+
+       return 0;
+}
+
+static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
+       .suspend        = gpio_vbus_pm_suspend,
+       .resume         = gpio_vbus_pm_resume,
+};
+#endif
+
+/* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
+
+MODULE_ALIAS("platform:gpio-vbus");
+
+static struct platform_driver gpio_vbus_driver = {
+       .driver = {
+               .name  = "gpio-vbus",
+               .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm = &gpio_vbus_dev_pm_ops,
+#endif
+       },
+       .remove  = __exit_p(gpio_vbus_remove),
+};
+
+module_platform_driver_probe(gpio_vbus_driver, gpio_vbus_probe);
+
+MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/isp1301_omap.c b/drivers/usb/phy/isp1301_omap.c
new file mode 100644 (file)
index 0000000..8fe0c3b
--- /dev/null
@@ -0,0 +1,1656 @@
+/*
+ * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller
+ *
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/mux.h>
+
+#include <mach/usb.h>
+
+#ifndef        DEBUG
+#undef VERBOSE
+#endif
+
+
+#define        DRIVER_VERSION  "24 August 2004"
+#define        DRIVER_NAME     (isp1301_driver.driver.name)
+
+MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
+MODULE_LICENSE("GPL");
+
+struct isp1301 {
+       struct usb_phy          phy;
+       struct i2c_client       *client;
+       void                    (*i2c_release)(struct device *dev);
+
+       int                     irq_type;
+
+       u32                     last_otg_ctrl;
+       unsigned                working:1;
+
+       struct timer_list       timer;
+
+       /* use keventd context to change the state for us */
+       struct work_struct      work;
+
+       unsigned long           todo;
+#              define WORK_UPDATE_ISP  0       /* update ISP from OTG */
+#              define WORK_UPDATE_OTG  1       /* update OTG from ISP */
+#              define WORK_HOST_RESUME 4       /* resume host */
+#              define WORK_TIMER       6       /* timer fired */
+#              define WORK_STOP        7       /* don't resubmit */
+};
+
+
+/* bits in OTG_CTRL */
+
+#define        OTG_XCEIV_OUTPUTS \
+       (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+#define        OTG_XCEIV_INPUTS \
+       (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+#define        OTG_CTRL_BITS \
+       (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
+       /* and OTG_PULLUP is sometimes written */
+
+#define        OTG_CTRL_MASK   (OTG_DRIVER_SEL| \
+       OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \
+       OTG_CTRL_BITS)
+
+
+/*-------------------------------------------------------------------------*/
+
+/* board-specific PM hooks */
+
+#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
+
+#if    defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
+
+#include <linux/i2c/tps65010.h>
+
+#else
+
+static inline int tps65010_set_vbus_draw(unsigned mA)
+{
+       pr_debug("tps65010: draw %d mA (STUB)\n", mA);
+       return 0;
+}
+
+#endif
+
+static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
+{
+       int status = tps65010_set_vbus_draw(mA);
+       if (status < 0)
+               pr_debug("  VBUS %d mA error %d\n", mA, status);
+}
+
+#else
+
+static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
+{
+       /* H4 controls this by DIP switch S2.4; no soft control.
+        * ON means the charger is always enabled.  Leave it OFF
+        * unless the OTG port is used only in B-peripheral mode.
+        */
+}
+
+#endif
+
+static void enable_vbus_source(struct isp1301 *isp)
+{
+       /* this board won't supply more than 8mA vbus power.
+        * some boards can switch a 100ma "unit load" (or more).
+        */
+}
+
+
+/* products will deliver OTG messages with LEDs, GUI, etc */
+static inline void notresponding(struct isp1301 *isp)
+{
+       printk(KERN_NOTICE "OTG device not responding.\n");
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_driver isp1301_driver;
+
+/* smbus apis are used for portability */
+
+static inline u8
+isp1301_get_u8(struct isp1301 *isp, u8 reg)
+{
+       return i2c_smbus_read_byte_data(isp->client, reg + 0);
+}
+
+static inline int
+isp1301_get_u16(struct isp1301 *isp, u8 reg)
+{
+       return i2c_smbus_read_word_data(isp->client, reg);
+}
+
+static inline int
+isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+       return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
+}
+
+static inline int
+isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+       return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* identification */
+#define        ISP1301_VENDOR_ID               0x00    /* u16 read */
+#define        ISP1301_PRODUCT_ID              0x02    /* u16 read */
+#define        ISP1301_BCD_DEVICE              0x14    /* u16 read */
+
+#define        I2C_VENDOR_ID_PHILIPS           0x04cc
+#define        I2C_PRODUCT_ID_PHILIPS_1301     0x1301
+
+/* operational registers */
+#define        ISP1301_MODE_CONTROL_1          0x04    /* u8 read, set, +1 clear */
+#      define  MC1_SPEED               (1 << 0)
+#      define  MC1_SUSPEND             (1 << 1)
+#      define  MC1_DAT_SE0             (1 << 2)
+#      define  MC1_TRANSPARENT         (1 << 3)
+#      define  MC1_BDIS_ACON_EN        (1 << 4)
+#      define  MC1_OE_INT_EN           (1 << 5)
+#      define  MC1_UART_EN             (1 << 6)
+#      define  MC1_MASK                0x7f
+#define        ISP1301_MODE_CONTROL_2          0x12    /* u8 read, set, +1 clear */
+#      define  MC2_GLOBAL_PWR_DN       (1 << 0)
+#      define  MC2_SPD_SUSP_CTRL       (1 << 1)
+#      define  MC2_BI_DI               (1 << 2)
+#      define  MC2_TRANSP_BDIR0        (1 << 3)
+#      define  MC2_TRANSP_BDIR1        (1 << 4)
+#      define  MC2_AUDIO_EN            (1 << 5)
+#      define  MC2_PSW_EN              (1 << 6)
+#      define  MC2_EN2V7               (1 << 7)
+#define        ISP1301_OTG_CONTROL_1           0x06    /* u8 read, set, +1 clear */
+#      define  OTG1_DP_PULLUP          (1 << 0)
+#      define  OTG1_DM_PULLUP          (1 << 1)
+#      define  OTG1_DP_PULLDOWN        (1 << 2)
+#      define  OTG1_DM_PULLDOWN        (1 << 3)
+#      define  OTG1_ID_PULLDOWN        (1 << 4)
+#      define  OTG1_VBUS_DRV           (1 << 5)
+#      define  OTG1_VBUS_DISCHRG       (1 << 6)
+#      define  OTG1_VBUS_CHRG          (1 << 7)
+#define        ISP1301_OTG_STATUS              0x10    /* u8 readonly */
+#      define  OTG_B_SESS_END          (1 << 6)
+#      define  OTG_B_SESS_VLD          (1 << 7)
+
+#define        ISP1301_INTERRUPT_SOURCE        0x08    /* u8 read */
+#define        ISP1301_INTERRUPT_LATCH         0x0A    /* u8 read, set, +1 clear */
+
+#define        ISP1301_INTERRUPT_FALLING       0x0C    /* u8 read, set, +1 clear */
+#define        ISP1301_INTERRUPT_RISING        0x0E    /* u8 read, set, +1 clear */
+
+/* same bitfields in all interrupt registers */
+#      define  INTR_VBUS_VLD           (1 << 0)
+#      define  INTR_SESS_VLD           (1 << 1)
+#      define  INTR_DP_HI              (1 << 2)
+#      define  INTR_ID_GND             (1 << 3)
+#      define  INTR_DM_HI              (1 << 4)
+#      define  INTR_ID_FLOAT           (1 << 5)
+#      define  INTR_BDIS_ACON          (1 << 6)
+#      define  INTR_CR_INT             (1 << 7)
+
+/*-------------------------------------------------------------------------*/
+
+static inline const char *state_name(struct isp1301 *isp)
+{
+       return usb_otg_state_string(isp->phy.state);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* NOTE:  some of this ISP1301 setup is specific to H2 boards;
+ * not everything is guarded by board-specific checks, or even using
+ * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI.
+ *
+ * ALSO:  this currently doesn't use ISP1301 low-power modes
+ * while OTG is running.
+ */
+
+static void power_down(struct isp1301 *isp)
+{
+       isp->phy.state = OTG_STATE_UNDEFINED;
+
+       // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
+       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
+
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN);
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+}
+
+static void power_up(struct isp1301 *isp)
+{
+       // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
+
+       /* do this only when cpu is driving transceiver,
+        * so host won't see a low speed device...
+        */
+       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+}
+
+#define        NO_HOST_SUSPEND
+
+static int host_suspend(struct isp1301 *isp)
+{
+#ifdef NO_HOST_SUSPEND
+       return 0;
+#else
+       struct device   *dev;
+
+       if (!isp->phy.otg->host)
+               return -ENODEV;
+
+       /* Currently ASSUMES only the OTG port matters;
+        * other ports could be active...
+        */
+       dev = isp->phy.otg->host->controller;
+       return dev->driver->suspend(dev, 3, 0);
+#endif
+}
+
+static int host_resume(struct isp1301 *isp)
+{
+#ifdef NO_HOST_SUSPEND
+       return 0;
+#else
+       struct device   *dev;
+
+       if (!isp->phy.otg->host)
+               return -ENODEV;
+
+       dev = isp->phy.otg->host->controller;
+       return dev->driver->resume(dev, 0);
+#endif
+}
+
+static int gadget_suspend(struct isp1301 *isp)
+{
+       isp->phy.otg->gadget->b_hnp_enable = 0;
+       isp->phy.otg->gadget->a_hnp_support = 0;
+       isp->phy.otg->gadget->a_alt_hnp_support = 0;
+       return usb_gadget_vbus_disconnect(isp->phy.otg->gadget);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define        TIMER_MINUTES   10
+#define        TIMER_JIFFIES   (TIMER_MINUTES * 60 * HZ)
+
+/* Almost all our I2C messaging comes from a work queue's task context.
+ * NOTE: guaranteeing certain response times might mean we shouldn't
+ * share keventd's work queue; a realtime task might be safest.
+ */
+static void isp1301_defer_work(struct isp1301 *isp, int work)
+{
+       int status;
+
+       if (isp && !test_and_set_bit(work, &isp->todo)) {
+               (void) get_device(&isp->client->dev);
+               status = schedule_work(&isp->work);
+               if (!status && !isp->working)
+                       dev_vdbg(&isp->client->dev,
+                               "work item %d may be lost\n", work);
+       }
+}
+
+/* called from irq handlers */
+static void a_idle(struct isp1301 *isp, const char *tag)
+{
+       u32 l;
+
+       if (isp->phy.state == OTG_STATE_A_IDLE)
+               return;
+
+       isp->phy.otg->default_a = 1;
+       if (isp->phy.otg->host) {
+               isp->phy.otg->host->is_b_host = 0;
+               host_suspend(isp);
+       }
+       if (isp->phy.otg->gadget) {
+               isp->phy.otg->gadget->is_a_peripheral = 1;
+               gadget_suspend(isp);
+       }
+       isp->phy.state = OTG_STATE_A_IDLE;
+       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
+       omap_writel(l, OTG_CTRL);
+       isp->last_otg_ctrl = l;
+       pr_debug("  --> %s/%s\n", state_name(isp), tag);
+}
+
+/* called from irq handlers */
+static void b_idle(struct isp1301 *isp, const char *tag)
+{
+       u32 l;
+
+       if (isp->phy.state == OTG_STATE_B_IDLE)
+               return;
+
+       isp->phy.otg->default_a = 0;
+       if (isp->phy.otg->host) {
+               isp->phy.otg->host->is_b_host = 1;
+               host_suspend(isp);
+       }
+       if (isp->phy.otg->gadget) {
+               isp->phy.otg->gadget->is_a_peripheral = 0;
+               gadget_suspend(isp);
+       }
+       isp->phy.state = OTG_STATE_B_IDLE;
+       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
+       omap_writel(l, OTG_CTRL);
+       isp->last_otg_ctrl = l;
+       pr_debug("  --> %s/%s\n", state_name(isp), tag);
+}
+
+static void
+dump_regs(struct isp1301 *isp, const char *label)
+{
+#ifdef DEBUG
+       u8      ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1);
+       u8      status = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
+       u8      src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
+
+       pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n",
+               omap_readl(OTG_CTRL), label, state_name(isp),
+               ctrl, status, src);
+       /* mode control and irq enables don't change much */
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_OTG
+
+/*
+ * The OMAP OTG controller handles most of the OTG state transitions.
+ *
+ * We translate isp1301 outputs (mostly voltage comparator status) into
+ * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state
+ * flags into isp1301 inputs ... and infer state transitions.
+ */
+
+#ifdef VERBOSE
+
+static void check_state(struct isp1301 *isp, const char *tag)
+{
+       enum usb_otg_state      state = OTG_STATE_UNDEFINED;
+       u8                      fsm = omap_readw(OTG_TEST) & 0x0ff;
+       unsigned                extra = 0;
+
+       switch (fsm) {
+
+       /* default-b */
+       case 0x0:
+               state = OTG_STATE_B_IDLE;
+               break;
+       case 0x3:
+       case 0x7:
+               extra = 1;
+       case 0x1:
+               state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case 0x11:
+               state = OTG_STATE_B_SRP_INIT;
+               break;
+
+       /* extra dual-role default-b states */
+       case 0x12:
+       case 0x13:
+       case 0x16:
+               extra = 1;
+       case 0x17:
+               state = OTG_STATE_B_WAIT_ACON;
+               break;
+       case 0x34:
+               state = OTG_STATE_B_HOST;
+               break;
+
+       /* default-a */
+       case 0x36:
+               state = OTG_STATE_A_IDLE;
+               break;
+       case 0x3c:
+               state = OTG_STATE_A_WAIT_VFALL;
+               break;
+       case 0x7d:
+               state = OTG_STATE_A_VBUS_ERR;
+               break;
+       case 0x9e:
+       case 0x9f:
+               extra = 1;
+       case 0x89:
+               state = OTG_STATE_A_PERIPHERAL;
+               break;
+       case 0xb7:
+               state = OTG_STATE_A_WAIT_VRISE;
+               break;
+       case 0xb8:
+               state = OTG_STATE_A_WAIT_BCON;
+               break;
+       case 0xb9:
+               state = OTG_STATE_A_HOST;
+               break;
+       case 0xba:
+               state = OTG_STATE_A_SUSPEND;
+               break;
+       default:
+               break;
+       }
+       if (isp->phy.state == state && !extra)
+               return;
+       pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
+               usb_otg_state_string(state), fsm, state_name(isp),
+               omap_readl(OTG_CTRL));
+}
+
+#else
+
+static inline void check_state(struct isp1301 *isp, const char *tag) { }
+
+#endif
+
+/* outputs from ISP1301_INTERRUPT_SOURCE */
+static void update_otg1(struct isp1301 *isp, u8 int_src)
+{
+       u32     otg_ctrl;
+
+       otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
+       otg_ctrl &= ~OTG_XCEIV_INPUTS;
+       otg_ctrl &= ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD);
+
+       if (int_src & INTR_SESS_VLD)
+               otg_ctrl |= OTG_ASESSVLD;
+       else if (isp->phy.state == OTG_STATE_A_WAIT_VFALL) {
+               a_idle(isp, "vfall");
+               otg_ctrl &= ~OTG_CTRL_BITS;
+       }
+       if (int_src & INTR_VBUS_VLD)
+               otg_ctrl |= OTG_VBUSVLD;
+       if (int_src & INTR_ID_GND) {            /* default-A */
+               if (isp->phy.state == OTG_STATE_B_IDLE
+                               || isp->phy.state
+                                       == OTG_STATE_UNDEFINED) {
+                       a_idle(isp, "init");
+                       return;
+               }
+       } else {                                /* default-B */
+               otg_ctrl |= OTG_ID;
+               if (isp->phy.state == OTG_STATE_A_IDLE
+                       || isp->phy.state == OTG_STATE_UNDEFINED) {
+                       b_idle(isp, "init");
+                       return;
+               }
+       }
+       omap_writel(otg_ctrl, OTG_CTRL);
+}
+
+/* outputs from ISP1301_OTG_STATUS */
+static void update_otg2(struct isp1301 *isp, u8 otg_status)
+{
+       u32     otg_ctrl;
+
+       otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
+       otg_ctrl &= ~OTG_XCEIV_INPUTS;
+       otg_ctrl &= ~(OTG_BSESSVLD | OTG_BSESSEND);
+       if (otg_status & OTG_B_SESS_VLD)
+               otg_ctrl |= OTG_BSESSVLD;
+       else if (otg_status & OTG_B_SESS_END)
+               otg_ctrl |= OTG_BSESSEND;
+       omap_writel(otg_ctrl, OTG_CTRL);
+}
+
+/* inputs going to ISP1301 */
+static void otg_update_isp(struct isp1301 *isp)
+{
+       u32     otg_ctrl, otg_change;
+       u8      set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP;
+
+       otg_ctrl = omap_readl(OTG_CTRL);
+       otg_change = otg_ctrl ^ isp->last_otg_ctrl;
+       isp->last_otg_ctrl = otg_ctrl;
+       otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS;
+
+       switch (isp->phy.state) {
+       case OTG_STATE_B_IDLE:
+       case OTG_STATE_B_PERIPHERAL:
+       case OTG_STATE_B_SRP_INIT:
+               if (!(otg_ctrl & OTG_PULLUP)) {
+                       // if (otg_ctrl & OTG_B_HNPEN) {
+                       if (isp->phy.otg->gadget->b_hnp_enable) {
+                               isp->phy.state = OTG_STATE_B_WAIT_ACON;
+                               pr_debug("  --> b_wait_acon\n");
+                       }
+                       goto pulldown;
+               }
+pullup:
+               set |= OTG1_DP_PULLUP;
+               clr |= OTG1_DP_PULLDOWN;
+               break;
+       case OTG_STATE_A_SUSPEND:
+       case OTG_STATE_A_PERIPHERAL:
+               if (otg_ctrl & OTG_PULLUP)
+                       goto pullup;
+               /* FALLTHROUGH */
+       // case OTG_STATE_B_WAIT_ACON:
+       default:
+pulldown:
+               set |= OTG1_DP_PULLDOWN;
+               clr |= OTG1_DP_PULLUP;
+               break;
+       }
+
+#      define toggle(OTG,ISP) do { \
+               if (otg_ctrl & OTG) set |= ISP; \
+               else clr |= ISP; \
+               } while (0)
+
+       if (!(isp->phy.otg->host))
+               otg_ctrl &= ~OTG_DRV_VBUS;
+
+       switch (isp->phy.state) {
+       case OTG_STATE_A_SUSPEND:
+               if (otg_ctrl & OTG_DRV_VBUS) {
+                       set |= OTG1_VBUS_DRV;
+                       break;
+               }
+               /* HNP failed for some reason (A_AIDL_BDIS timeout) */
+               notresponding(isp);
+
+               /* FALLTHROUGH */
+       case OTG_STATE_A_VBUS_ERR:
+               isp->phy.state = OTG_STATE_A_WAIT_VFALL;
+               pr_debug("  --> a_wait_vfall\n");
+               /* FALLTHROUGH */
+       case OTG_STATE_A_WAIT_VFALL:
+               /* FIXME usbcore thinks port power is still on ... */
+               clr |= OTG1_VBUS_DRV;
+               break;
+       case OTG_STATE_A_IDLE:
+               if (otg_ctrl & OTG_DRV_VBUS) {
+                       isp->phy.state = OTG_STATE_A_WAIT_VRISE;
+                       pr_debug("  --> a_wait_vrise\n");
+               }
+               /* FALLTHROUGH */
+       default:
+               toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV);
+       }
+
+       toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG);
+       toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG);
+
+#      undef toggle
+
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set);
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr);
+
+       /* HNP switch to host or peripheral; and SRP */
+       if (otg_change & OTG_PULLUP) {
+               u32 l;
+
+               switch (isp->phy.state) {
+               case OTG_STATE_B_IDLE:
+                       if (clr & OTG1_DP_PULLUP)
+                               break;
+                       isp->phy.state = OTG_STATE_B_PERIPHERAL;
+                       pr_debug("  --> b_peripheral\n");
+                       break;
+               case OTG_STATE_A_SUSPEND:
+                       if (clr & OTG1_DP_PULLUP)
+                               break;
+                       isp->phy.state = OTG_STATE_A_PERIPHERAL;
+                       pr_debug("  --> a_peripheral\n");
+                       break;
+               default:
+                       break;
+               }
+               l = omap_readl(OTG_CTRL);
+               l |= OTG_PULLUP;
+               omap_writel(l, OTG_CTRL);
+       }
+
+       check_state(isp, __func__);
+       dump_regs(isp, "otg->isp1301");
+}
+
+static irqreturn_t omap_otg_irq(int irq, void *_isp)
+{
+       u16             otg_irq = omap_readw(OTG_IRQ_SRC);
+       u32             otg_ctrl;
+       int             ret = IRQ_NONE;
+       struct isp1301  *isp = _isp;
+       struct usb_otg  *otg = isp->phy.otg;
+
+       /* update ISP1301 transceiver from OTG controller */
+       if (otg_irq & OPRT_CHG) {
+               omap_writew(OPRT_CHG, OTG_IRQ_SRC);
+               isp1301_defer_work(isp, WORK_UPDATE_ISP);
+               ret = IRQ_HANDLED;
+
+       /* SRP to become b_peripheral failed */
+       } else if (otg_irq & B_SRP_TMROUT) {
+               pr_debug("otg: B_SRP_TIMEOUT, %06x\n", omap_readl(OTG_CTRL));
+               notresponding(isp);
+
+               /* gadget drivers that care should monitor all kinds of
+                * remote wakeup (SRP, normal) using their own timer
+                * to give "check cable and A-device" messages.
+                */
+               if (isp->phy.state == OTG_STATE_B_SRP_INIT)
+                       b_idle(isp, "srp_timeout");
+
+               omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
+               ret = IRQ_HANDLED;
+
+       /* HNP to become b_host failed */
+       } else if (otg_irq & B_HNP_FAIL) {
+               pr_debug("otg: %s B_HNP_FAIL, %06x\n",
+                               state_name(isp), omap_readl(OTG_CTRL));
+               notresponding(isp);
+
+               otg_ctrl = omap_readl(OTG_CTRL);
+               otg_ctrl |= OTG_BUSDROP;
+               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+               omap_writel(otg_ctrl, OTG_CTRL);
+
+               /* subset of b_peripheral()... */
+               isp->phy.state = OTG_STATE_B_PERIPHERAL;
+               pr_debug("  --> b_peripheral\n");
+
+               omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
+               ret = IRQ_HANDLED;
+
+       /* detect SRP from B-device ... */
+       } else if (otg_irq & A_SRP_DETECT) {
+               pr_debug("otg: %s SRP_DETECT, %06x\n",
+                               state_name(isp), omap_readl(OTG_CTRL));
+
+               isp1301_defer_work(isp, WORK_UPDATE_OTG);
+               switch (isp->phy.state) {
+               case OTG_STATE_A_IDLE:
+                       if (!otg->host)
+                               break;
+                       isp1301_defer_work(isp, WORK_HOST_RESUME);
+                       otg_ctrl = omap_readl(OTG_CTRL);
+                       otg_ctrl |= OTG_A_BUSREQ;
+                       otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)
+                                       & ~OTG_XCEIV_INPUTS
+                                       & OTG_CTRL_MASK;
+                       omap_writel(otg_ctrl, OTG_CTRL);
+                       break;
+               default:
+                       break;
+               }
+
+               omap_writew(A_SRP_DETECT, OTG_IRQ_SRC);
+               ret = IRQ_HANDLED;
+
+       /* timer expired:  T(a_wait_bcon) and maybe T(a_wait_vrise)
+        * we don't track them separately
+        */
+       } else if (otg_irq & A_REQ_TMROUT) {
+               otg_ctrl = omap_readl(OTG_CTRL);
+               pr_info("otg: BCON_TMOUT from %s, %06x\n",
+                               state_name(isp), otg_ctrl);
+               notresponding(isp);
+
+               otg_ctrl |= OTG_BUSDROP;
+               otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+               omap_writel(otg_ctrl, OTG_CTRL);
+               isp->phy.state = OTG_STATE_A_WAIT_VFALL;
+
+               omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
+               ret = IRQ_HANDLED;
+
+       /* A-supplied voltage fell too low; overcurrent */
+       } else if (otg_irq & A_VBUS_ERR) {
+               otg_ctrl = omap_readl(OTG_CTRL);
+               printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n",
+                       state_name(isp), otg_irq, otg_ctrl);
+
+               otg_ctrl |= OTG_BUSDROP;
+               otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+               omap_writel(otg_ctrl, OTG_CTRL);
+               isp->phy.state = OTG_STATE_A_VBUS_ERR;
+
+               omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
+               ret = IRQ_HANDLED;
+
+       /* switch driver; the transceiver code activates it,
+        * ungating the udc clock or resuming OHCI.
+        */
+       } else if (otg_irq & DRIVER_SWITCH) {
+               int     kick = 0;
+
+               otg_ctrl = omap_readl(OTG_CTRL);
+               printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n",
+                               state_name(isp),
+                               (otg_ctrl & OTG_DRIVER_SEL)
+                                       ? "gadget" : "host",
+                               otg_ctrl);
+               isp1301_defer_work(isp, WORK_UPDATE_ISP);
+
+               /* role is peripheral */
+               if (otg_ctrl & OTG_DRIVER_SEL) {
+                       switch (isp->phy.state) {
+                       case OTG_STATE_A_IDLE:
+                               b_idle(isp, __func__);
+                               break;
+                       default:
+                               break;
+                       }
+                       isp1301_defer_work(isp, WORK_UPDATE_ISP);
+
+               /* role is host */
+               } else {
+                       if (!(otg_ctrl & OTG_ID)) {
+                               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+                               omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL);
+                       }
+
+                       if (otg->host) {
+                               switch (isp->phy.state) {
+                               case OTG_STATE_B_WAIT_ACON:
+                                       isp->phy.state = OTG_STATE_B_HOST;
+                                       pr_debug("  --> b_host\n");
+                                       kick = 1;
+                                       break;
+                               case OTG_STATE_A_WAIT_BCON:
+                                       isp->phy.state = OTG_STATE_A_HOST;
+                                       pr_debug("  --> a_host\n");
+                                       break;
+                               case OTG_STATE_A_PERIPHERAL:
+                                       isp->phy.state = OTG_STATE_A_WAIT_BCON;
+                                       pr_debug("  --> a_wait_bcon\n");
+                                       break;
+                               default:
+                                       break;
+                               }
+                               isp1301_defer_work(isp, WORK_HOST_RESUME);
+                       }
+               }
+
+               omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC);
+               ret = IRQ_HANDLED;
+
+               if (kick)
+                       usb_bus_start_enum(otg->host, otg->host->otg_port);
+       }
+
+       check_state(isp, __func__);
+       return ret;
+}
+
+static struct platform_device *otg_dev;
+
+static int isp1301_otg_init(struct isp1301 *isp)
+{
+       u32 l;
+
+       if (!otg_dev)
+               return -ENODEV;
+
+       dump_regs(isp, __func__);
+       /* some of these values are board-specific... */
+       l = omap_readl(OTG_SYSCON_2);
+       l |= OTG_EN
+               /* for B-device: */
+               | SRP_GPDATA            /* 9msec Bdev D+ pulse */
+               | SRP_GPDVBUS           /* discharge after VBUS pulse */
+               // | (3 << 24)          /* 2msec VBUS pulse */
+               /* for A-device: */
+               | (0 << 20)             /* 200ms nominal A_WAIT_VRISE timer */
+               | SRP_DPW               /* detect 167+ns SRP pulses */
+               | SRP_DATA | SRP_VBUS   /* accept both kinds of SRP pulse */
+               ;
+       omap_writel(l, OTG_SYSCON_2);
+
+       update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
+       update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
+
+       check_state(isp, __func__);
+       pr_debug("otg: %s, %s %06x\n",
+                       state_name(isp), __func__, omap_readl(OTG_CTRL));
+
+       omap_writew(DRIVER_SWITCH | OPRT_CHG
+                       | B_SRP_TMROUT | B_HNP_FAIL
+                       | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT, OTG_IRQ_EN);
+
+       l = omap_readl(OTG_SYSCON_2);
+       l |= OTG_EN;
+       omap_writel(l, OTG_SYSCON_2);
+
+       return 0;
+}
+
+static int otg_probe(struct platform_device *dev)
+{
+       // struct omap_usb_config *config = dev->platform_data;
+
+       otg_dev = dev;
+       return 0;
+}
+
+static int otg_remove(struct platform_device *dev)
+{
+       otg_dev = NULL;
+       return 0;
+}
+
+static struct platform_driver omap_otg_driver = {
+       .probe          = otg_probe,
+       .remove         = otg_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "omap_otg",
+       },
+};
+
+static int otg_bind(struct isp1301 *isp)
+{
+       int     status;
+
+       if (otg_dev)
+               return -EBUSY;
+
+       status = platform_driver_register(&omap_otg_driver);
+       if (status < 0)
+               return status;
+
+       if (otg_dev)
+               status = request_irq(otg_dev->resource[1].start, omap_otg_irq,
+                               0, DRIVER_NAME, isp);
+       else
+               status = -ENODEV;
+
+       if (status < 0)
+               platform_driver_unregister(&omap_otg_driver);
+       return status;
+}
+
+static void otg_unbind(struct isp1301 *isp)
+{
+       if (!otg_dev)
+               return;
+       free_irq(otg_dev->resource[1].start, isp);
+}
+
+#else
+
+/* OTG controller isn't clocked */
+
+#endif /* CONFIG_USB_OTG */
+
+/*-------------------------------------------------------------------------*/
+
+static void b_peripheral(struct isp1301 *isp)
+{
+       u32 l;
+
+       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
+       omap_writel(l, OTG_CTRL);
+
+       usb_gadget_vbus_connect(isp->phy.otg->gadget);
+
+#ifdef CONFIG_USB_OTG
+       enable_vbus_draw(isp, 8);
+       otg_update_isp(isp);
+#else
+       enable_vbus_draw(isp, 100);
+       /* UDC driver just set OTG_BSESSVLD */
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP);
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN);
+       isp->phy.state = OTG_STATE_B_PERIPHERAL;
+       pr_debug("  --> b_peripheral\n");
+       dump_regs(isp, "2periph");
+#endif
+}
+
+static void isp_update_otg(struct isp1301 *isp, u8 stat)
+{
+       struct usb_otg          *otg = isp->phy.otg;
+       u8                      isp_stat, isp_bstat;
+       enum usb_otg_state      state = isp->phy.state;
+
+       if (stat & INTR_BDIS_ACON)
+               pr_debug("OTG:  BDIS_ACON, %s\n", state_name(isp));
+
+       /* start certain state transitions right away */
+       isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
+       if (isp_stat & INTR_ID_GND) {
+               if (otg->default_a) {
+                       switch (state) {
+                       case OTG_STATE_B_IDLE:
+                               a_idle(isp, "idle");
+                               /* FALLTHROUGH */
+                       case OTG_STATE_A_IDLE:
+                               enable_vbus_source(isp);
+                               /* FALLTHROUGH */
+                       case OTG_STATE_A_WAIT_VRISE:
+                               /* we skip over OTG_STATE_A_WAIT_BCON, since
+                                * the HC will transition to A_HOST (or
+                                * A_SUSPEND!) without our noticing except
+                                * when HNP is used.
+                                */
+                               if (isp_stat & INTR_VBUS_VLD)
+                                       isp->phy.state = OTG_STATE_A_HOST;
+                               break;
+                       case OTG_STATE_A_WAIT_VFALL:
+                               if (!(isp_stat & INTR_SESS_VLD))
+                                       a_idle(isp, "vfell");
+                               break;
+                       default:
+                               if (!(isp_stat & INTR_VBUS_VLD))
+                                       isp->phy.state = OTG_STATE_A_VBUS_ERR;
+                               break;
+                       }
+                       isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
+               } else {
+                       switch (state) {
+                       case OTG_STATE_B_PERIPHERAL:
+                       case OTG_STATE_B_HOST:
+                       case OTG_STATE_B_WAIT_ACON:
+                               usb_gadget_vbus_disconnect(otg->gadget);
+                               break;
+                       default:
+                               break;
+                       }
+                       if (state != OTG_STATE_A_IDLE)
+                               a_idle(isp, "id");
+                       if (otg->host && state == OTG_STATE_A_IDLE)
+                               isp1301_defer_work(isp, WORK_HOST_RESUME);
+                       isp_bstat = 0;
+               }
+       } else {
+               u32 l;
+
+               /* if user unplugged mini-A end of cable,
+                * don't bypass A_WAIT_VFALL.
+                */
+               if (otg->default_a) {
+                       switch (state) {
+                       default:
+                               isp->phy.state = OTG_STATE_A_WAIT_VFALL;
+                               break;
+                       case OTG_STATE_A_WAIT_VFALL:
+                               state = OTG_STATE_A_IDLE;
+                               /* khubd may take a while to notice and
+                                * handle this disconnect, so don't go
+                                * to B_IDLE quite yet.
+                                */
+                               break;
+                       case OTG_STATE_A_IDLE:
+                               host_suspend(isp);
+                               isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1,
+                                               MC1_BDIS_ACON_EN);
+                               isp->phy.state = OTG_STATE_B_IDLE;
+                               l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
+                               l &= ~OTG_CTRL_BITS;
+                               omap_writel(l, OTG_CTRL);
+                               break;
+                       case OTG_STATE_B_IDLE:
+                               break;
+                       }
+               }
+               isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
+
+               switch (isp->phy.state) {
+               case OTG_STATE_B_PERIPHERAL:
+               case OTG_STATE_B_WAIT_ACON:
+               case OTG_STATE_B_HOST:
+                       if (likely(isp_bstat & OTG_B_SESS_VLD))
+                               break;
+                       enable_vbus_draw(isp, 0);
+#ifndef        CONFIG_USB_OTG
+                       /* UDC driver will clear OTG_BSESSVLD */
+                       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
+                                               OTG1_DP_PULLDOWN);
+                       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
+                                               OTG1_DP_PULLUP);
+                       dump_regs(isp, __func__);
+#endif
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_SRP_INIT:
+                       b_idle(isp, __func__);
+                       l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
+                       omap_writel(l, OTG_CTRL);
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_IDLE:
+                       if (otg->gadget && (isp_bstat & OTG_B_SESS_VLD)) {
+#ifdef CONFIG_USB_OTG
+                               update_otg1(isp, isp_stat);
+                               update_otg2(isp, isp_bstat);
+#endif
+                               b_peripheral(isp);
+                       } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD)))
+                               isp_bstat |= OTG_B_SESS_END;
+                       break;
+               case OTG_STATE_A_WAIT_VFALL:
+                       break;
+               default:
+                       pr_debug("otg: unsupported b-device %s\n",
+                               state_name(isp));
+                       break;
+               }
+       }
+
+       if (state != isp->phy.state)
+               pr_debug("  isp, %s -> %s\n",
+                               usb_otg_state_string(state), state_name(isp));
+
+#ifdef CONFIG_USB_OTG
+       /* update the OTG controller state to match the isp1301; may
+        * trigger OPRT_CHG irqs for changes going to the isp1301.
+        */
+       update_otg1(isp, isp_stat);
+       update_otg2(isp, isp_bstat);
+       check_state(isp, __func__);
+#endif
+
+       dump_regs(isp, "isp1301->otg");
+}
+
+/*-------------------------------------------------------------------------*/
+
+static u8 isp1301_clear_latch(struct isp1301 *isp)
+{
+       u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch);
+       return latch;
+}
+
+static void
+isp1301_work(struct work_struct *work)
+{
+       struct isp1301  *isp = container_of(work, struct isp1301, work);
+       int             stop;
+
+       /* implicit lock:  we're the only task using this device */
+       isp->working = 1;
+       do {
+               stop = test_bit(WORK_STOP, &isp->todo);
+
+#ifdef CONFIG_USB_OTG
+               /* transfer state from otg engine to isp1301 */
+               if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
+                       otg_update_isp(isp);
+                       put_device(&isp->client->dev);
+               }
+#endif
+               /* transfer state from isp1301 to otg engine */
+               if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) {
+                       u8              stat = isp1301_clear_latch(isp);
+
+                       isp_update_otg(isp, stat);
+                       put_device(&isp->client->dev);
+               }
+
+               if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
+                       u32     otg_ctrl;
+
+                       /*
+                        * skip A_WAIT_VRISE; hc transitions invisibly
+                        * skip A_WAIT_BCON; same.
+                        */
+                       switch (isp->phy.state) {
+                       case OTG_STATE_A_WAIT_BCON:
+                       case OTG_STATE_A_WAIT_VRISE:
+                               isp->phy.state = OTG_STATE_A_HOST;
+                               pr_debug("  --> a_host\n");
+                               otg_ctrl = omap_readl(OTG_CTRL);
+                               otg_ctrl |= OTG_A_BUSREQ;
+                               otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)
+                                               & OTG_CTRL_MASK;
+                               omap_writel(otg_ctrl, OTG_CTRL);
+                               break;
+                       case OTG_STATE_B_WAIT_ACON:
+                               isp->phy.state = OTG_STATE_B_HOST;
+                               pr_debug("  --> b_host (acon)\n");
+                               break;
+                       case OTG_STATE_B_HOST:
+                       case OTG_STATE_B_IDLE:
+                       case OTG_STATE_A_IDLE:
+                               break;
+                       default:
+                               pr_debug("  host resume in %s\n",
+                                               state_name(isp));
+                       }
+                       host_resume(isp);
+                       // mdelay(10);
+                       put_device(&isp->client->dev);
+               }
+
+               if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
+#ifdef VERBOSE
+                       dump_regs(isp, "timer");
+                       if (!stop)
+                               mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
+#endif
+                       put_device(&isp->client->dev);
+               }
+
+               if (isp->todo)
+                       dev_vdbg(&isp->client->dev,
+                               "work done, todo = 0x%lx\n",
+                               isp->todo);
+               if (stop) {
+                       dev_dbg(&isp->client->dev, "stop\n");
+                       break;
+               }
+       } while (isp->todo);
+       isp->working = 0;
+}
+
+static irqreturn_t isp1301_irq(int irq, void *isp)
+{
+       isp1301_defer_work(isp, WORK_UPDATE_OTG);
+       return IRQ_HANDLED;
+}
+
+static void isp1301_timer(unsigned long _isp)
+{
+       isp1301_defer_work((void *)_isp, WORK_TIMER);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void isp1301_release(struct device *dev)
+{
+       struct isp1301  *isp;
+
+       isp = dev_get_drvdata(dev);
+
+       /* FIXME -- not with a "new style" driver, it doesn't!! */
+
+       /* ugly -- i2c hijacks our memory hook to wait_for_completion() */
+       if (isp->i2c_release)
+               isp->i2c_release(dev);
+       kfree(isp->phy.otg);
+       kfree (isp);
+}
+
+static struct isp1301 *the_transceiver;
+
+static int __exit isp1301_remove(struct i2c_client *i2c)
+{
+       struct isp1301  *isp;
+
+       isp = i2c_get_clientdata(i2c);
+
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+       free_irq(i2c->irq, isp);
+#ifdef CONFIG_USB_OTG
+       otg_unbind(isp);
+#endif
+       if (machine_is_omap_h2())
+               gpio_free(2);
+
+       isp->timer.data = 0;
+       set_bit(WORK_STOP, &isp->todo);
+       del_timer_sync(&isp->timer);
+       flush_work(&isp->work);
+
+       put_device(&i2c->dev);
+       the_transceiver = NULL;
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* NOTE:  three modes are possible here, only one of which
+ * will be standards-conformant on any given system:
+ *
+ *  - OTG mode (dual-role), required if there's a Mini-AB connector
+ *  - HOST mode, for when there's one or more A (host) connectors
+ *  - DEVICE mode, for when there's a B/Mini-B (device) connector
+ *
+ * As a rule, you won't have an isp1301 chip unless it's there to
+ * support the OTG mode.  Other modes help testing USB controllers
+ * in isolation from (full) OTG support, or maybe so later board
+ * revisions can help to support those feature.
+ */
+
+#ifdef CONFIG_USB_OTG
+
+static int isp1301_otg_enable(struct isp1301 *isp)
+{
+       power_up(isp);
+       isp1301_otg_init(isp);
+
+       /* NOTE:  since we don't change this, this provides
+        * a few more interrupts than are strictly needed.
+        */
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
+               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
+               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+
+       dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
+
+       return 0;
+}
+
+#endif
+
+/* add or disable the host device+driver */
+static int
+isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
+
+       if (!otg || isp != the_transceiver)
+               return -ENODEV;
+
+       if (!host) {
+               omap_writew(0, OTG_IRQ_EN);
+               power_down(isp);
+               otg->host = NULL;
+               return 0;
+       }
+
+#ifdef CONFIG_USB_OTG
+       otg->host = host;
+       dev_dbg(&isp->client->dev, "registered host\n");
+       host_suspend(isp);
+       if (otg->gadget)
+               return isp1301_otg_enable(isp);
+       return 0;
+
+#elif  !defined(CONFIG_USB_GADGET_OMAP)
+       // FIXME update its refcount
+       otg->host = host;
+
+       power_up(isp);
+
+       if (machine_is_omap_h2())
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+
+       dev_info(&isp->client->dev, "A-Host sessions ok\n");
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
+               INTR_ID_GND);
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
+               INTR_ID_GND);
+
+       /* If this has a Mini-AB connector, this mode is highly
+        * nonstandard ... but can be handy for testing, especially with
+        * the Mini-A end of an OTG cable.  (Or something nonstandard
+        * like MiniB-to-StandardB, maybe built with a gender mender.)
+        */
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV);
+
+       dump_regs(isp, __func__);
+
+       return 0;
+
+#else
+       dev_dbg(&isp->client->dev, "host sessions not allowed\n");
+       return -EINVAL;
+#endif
+
+}
+
+static int
+isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
+{
+       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
+
+       if (!otg || isp != the_transceiver)
+               return -ENODEV;
+
+       if (!gadget) {
+               omap_writew(0, OTG_IRQ_EN);
+               if (!otg->default_a)
+                       enable_vbus_draw(isp, 0);
+               usb_gadget_vbus_disconnect(otg->gadget);
+               otg->gadget = NULL;
+               power_down(isp);
+               return 0;
+       }
+
+#ifdef CONFIG_USB_OTG
+       otg->gadget = gadget;
+       dev_dbg(&isp->client->dev, "registered gadget\n");
+       /* gadget driver may be suspended until vbus_connect () */
+       if (otg->host)
+               return isp1301_otg_enable(isp);
+       return 0;
+
+#elif  !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE)
+       otg->gadget = gadget;
+       // FIXME update its refcount
+
+       {
+               u32 l;
+
+               l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
+               l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS);
+               l |= OTG_ID;
+               omap_writel(l, OTG_CTRL);
+       }
+
+       power_up(isp);
+       isp->phy.state = OTG_STATE_B_IDLE;
+
+       if (machine_is_omap_h2() || machine_is_omap_h3())
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
+               INTR_SESS_VLD);
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
+               INTR_VBUS_VLD);
+       dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
+       dump_regs(isp, __func__);
+
+       /* If this has a Mini-AB connector, this mode is highly
+        * nonstandard ... but can be handy for testing, so long
+        * as you don't plug a Mini-A cable into the jack.
+        */
+       if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD)
+               b_peripheral(isp);
+
+       return 0;
+
+#else
+       dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
+       return -EINVAL;
+#endif
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int
+isp1301_set_power(struct usb_phy *dev, unsigned mA)
+{
+       if (!the_transceiver)
+               return -ENODEV;
+       if (dev->state == OTG_STATE_B_PERIPHERAL)
+               enable_vbus_draw(the_transceiver, mA);
+       return 0;
+}
+
+static int
+isp1301_start_srp(struct usb_otg *otg)
+{
+       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
+       u32             otg_ctrl;
+
+       if (!otg || isp != the_transceiver
+                       || isp->phy.state != OTG_STATE_B_IDLE)
+               return -ENODEV;
+
+       otg_ctrl = omap_readl(OTG_CTRL);
+       if (!(otg_ctrl & OTG_BSESSEND))
+               return -EINVAL;
+
+       otg_ctrl |= OTG_B_BUSREQ;
+       otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK;
+       omap_writel(otg_ctrl, OTG_CTRL);
+       isp->phy.state = OTG_STATE_B_SRP_INIT;
+
+       pr_debug("otg: SRP, %s ... %06x\n", state_name(isp),
+                       omap_readl(OTG_CTRL));
+#ifdef CONFIG_USB_OTG
+       check_state(isp, __func__);
+#endif
+       return 0;
+}
+
+static int
+isp1301_start_hnp(struct usb_otg *otg)
+{
+#ifdef CONFIG_USB_OTG
+       struct isp1301  *isp = container_of(otg->phy, struct isp1301, phy);
+       u32 l;
+
+       if (!otg || isp != the_transceiver)
+               return -ENODEV;
+       if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable))
+               return -ENOTCONN;
+       if (!otg->default_a && (otg->gadget == NULL
+                       || !otg->gadget->b_hnp_enable))
+               return -ENOTCONN;
+
+       /* We want hardware to manage most HNP protocol timings.
+        * So do this part as early as possible...
+        */
+       switch (isp->phy.state) {
+       case OTG_STATE_B_HOST:
+               isp->phy.state = OTG_STATE_B_PERIPHERAL;
+               /* caller will suspend next */
+               break;
+       case OTG_STATE_A_HOST:
+#if 0
+               /* autoconnect mode avoids irq latency bugs */
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
+                               MC1_BDIS_ACON_EN);
+#endif
+               /* caller must suspend then clear A_BUSREQ */
+               usb_gadget_vbus_connect(otg->gadget);
+               l = omap_readl(OTG_CTRL);
+               l |= OTG_A_SETB_HNPEN;
+               omap_writel(l, OTG_CTRL);
+
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               /* initiated by B-Host suspend */
+               break;
+       default:
+               return -EILSEQ;
+       }
+       pr_debug("otg: HNP %s, %06x ...\n",
+               state_name(isp), omap_readl(OTG_CTRL));
+       check_state(isp, __func__);
+       return 0;
+#else
+       /* srp-only */
+       return -EINVAL;
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+       int                     status;
+       struct isp1301          *isp;
+
+       if (the_transceiver)
+               return 0;
+
+       isp = kzalloc(sizeof *isp, GFP_KERNEL);
+       if (!isp)
+               return 0;
+
+       isp->phy.otg = kzalloc(sizeof *isp->phy.otg, GFP_KERNEL);
+       if (!isp->phy.otg) {
+               kfree(isp);
+               return 0;
+       }
+
+       INIT_WORK(&isp->work, isp1301_work);
+       init_timer(&isp->timer);
+       isp->timer.function = isp1301_timer;
+       isp->timer.data = (unsigned long) isp;
+
+       i2c_set_clientdata(i2c, isp);
+       isp->client = i2c;
+
+       /* verify the chip (shouldn't be necessary) */
+       status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+       if (status != I2C_VENDOR_ID_PHILIPS) {
+               dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+               goto fail;
+       }
+       status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+       if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+               dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+               goto fail;
+       }
+       isp->i2c_release = i2c->dev.release;
+       i2c->dev.release = isp1301_release;
+
+       /* initial development used chiprev 2.00 */
+       status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE);
+       dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n",
+               status >> 8, status & 0xff);
+
+       /* make like power-on reset */
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK);
+
+       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI);
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI);
+
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
+                               OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
+                               ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+
+#ifdef CONFIG_USB_OTG
+       status = otg_bind(isp);
+       if (status < 0) {
+               dev_dbg(&i2c->dev, "can't bind OTG\n");
+               goto fail;
+       }
+#endif
+
+       if (machine_is_omap_h2()) {
+               /* full speed signaling by default */
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
+                       MC1_SPEED);
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
+                       MC2_SPD_SUSP_CTRL);
+
+               /* IRQ wired at M14 */
+               omap_cfg_reg(M14_1510_GPIO2);
+               if (gpio_request(2, "isp1301") == 0)
+                       gpio_direction_input(2);
+               isp->irq_type = IRQF_TRIGGER_FALLING;
+       }
+
+       status = request_irq(i2c->irq, isp1301_irq,
+                       isp->irq_type, DRIVER_NAME, isp);
+       if (status < 0) {
+               dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
+                               i2c->irq, status);
+               goto fail;
+       }
+
+       isp->phy.dev = &i2c->dev;
+       isp->phy.label = DRIVER_NAME;
+       isp->phy.set_power = isp1301_set_power,
+
+       isp->phy.otg->phy = &isp->phy;
+       isp->phy.otg->set_host = isp1301_set_host,
+       isp->phy.otg->set_peripheral = isp1301_set_peripheral,
+       isp->phy.otg->start_srp = isp1301_start_srp,
+       isp->phy.otg->start_hnp = isp1301_start_hnp,
+
+       enable_vbus_draw(isp, 0);
+       power_down(isp);
+       the_transceiver = isp;
+
+#ifdef CONFIG_USB_OTG
+       update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
+       update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
+#endif
+
+       dump_regs(isp, __func__);
+
+#ifdef VERBOSE
+       mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
+       dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
+#endif
+
+       status = usb_add_phy(&isp->phy, USB_PHY_TYPE_USB2);
+       if (status < 0)
+               dev_err(&i2c->dev, "can't register transceiver, %d\n",
+                       status);
+
+       return 0;
+
+fail:
+       kfree(isp->phy.otg);
+       kfree(isp);
+       return -ENODEV;
+}
+
+static const struct i2c_device_id isp1301_id[] = {
+       { "isp1301_omap", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
+
+static struct i2c_driver isp1301_driver = {
+       .driver = {
+               .name   = "isp1301_omap",
+       },
+       .probe          = isp1301_probe,
+       .remove         = __exit_p(isp1301_remove),
+       .id_table       = isp1301_id,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init isp_init(void)
+{
+       return i2c_add_driver(&isp1301_driver);
+}
+subsys_initcall(isp_init);
+
+static void __exit isp_exit(void)
+{
+       if (the_transceiver)
+               usb_remove_phy(&the_transceiver->phy);
+       i2c_del_driver(&isp1301_driver);
+}
+module_exit(isp_exit);
+
diff --git a/drivers/usb/phy/msm_otg.c b/drivers/usb/phy/msm_otg.c
new file mode 100644 (file)
index 0000000..749fbf4
--- /dev/null
@@ -0,0 +1,1762 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/clk.h>
+
+#define MSM_USB_BASE   (motg->regs)
+#define DRIVER_NAME    "msm_otg"
+
+#define ULPI_IO_TIMEOUT_USEC   (10 * 1000)
+
+#define USB_PHY_3P3_VOL_MIN    3050000 /* uV */
+#define USB_PHY_3P3_VOL_MAX    3300000 /* uV */
+#define USB_PHY_3P3_HPM_LOAD   50000   /* uA */
+#define USB_PHY_3P3_LPM_LOAD   4000    /* uA */
+
+#define USB_PHY_1P8_VOL_MIN    1800000 /* uV */
+#define USB_PHY_1P8_VOL_MAX    1800000 /* uV */
+#define USB_PHY_1P8_HPM_LOAD   50000   /* uA */
+#define USB_PHY_1P8_LPM_LOAD   4000    /* uA */
+
+#define USB_PHY_VDD_DIG_VOL_MIN        1000000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MAX        1320000 /* uV */
+
+static struct regulator *hsusb_3p3;
+static struct regulator *hsusb_1p8;
+static struct regulator *hsusb_vddcx;
+
+static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
+{
+       int ret = 0;
+
+       if (init) {
+               hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX");
+               if (IS_ERR(hsusb_vddcx)) {
+                       dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
+                       return PTR_ERR(hsusb_vddcx);
+               }
+
+               ret = regulator_set_voltage(hsusb_vddcx,
+                               USB_PHY_VDD_DIG_VOL_MIN,
+                               USB_PHY_VDD_DIG_VOL_MAX);
+               if (ret) {
+                       dev_err(motg->phy.dev, "unable to set the voltage "
+                                       "for hsusb vddcx\n");
+                       regulator_put(hsusb_vddcx);
+                       return ret;
+               }
+
+               ret = regulator_enable(hsusb_vddcx);
+               if (ret) {
+                       dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
+                       regulator_put(hsusb_vddcx);
+               }
+       } else {
+               ret = regulator_set_voltage(hsusb_vddcx, 0,
+                       USB_PHY_VDD_DIG_VOL_MAX);
+               if (ret)
+                       dev_err(motg->phy.dev, "unable to set the voltage "
+                                       "for hsusb vddcx\n");
+               ret = regulator_disable(hsusb_vddcx);
+               if (ret)
+                       dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
+
+               regulator_put(hsusb_vddcx);
+       }
+
+       return ret;
+}
+
+static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
+{
+       int rc = 0;
+
+       if (init) {
+               hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3");
+               if (IS_ERR(hsusb_3p3)) {
+                       dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
+                       return PTR_ERR(hsusb_3p3);
+               }
+
+               rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
+                               USB_PHY_3P3_VOL_MAX);
+               if (rc) {
+                       dev_err(motg->phy.dev, "unable to set voltage level "
+                                       "for hsusb 3p3\n");
+                       goto put_3p3;
+               }
+               rc = regulator_enable(hsusb_3p3);
+               if (rc) {
+                       dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
+                       goto put_3p3;
+               }
+               hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8");
+               if (IS_ERR(hsusb_1p8)) {
+                       dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
+                       rc = PTR_ERR(hsusb_1p8);
+                       goto disable_3p3;
+               }
+               rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
+                               USB_PHY_1P8_VOL_MAX);
+               if (rc) {
+                       dev_err(motg->phy.dev, "unable to set voltage level "
+                                       "for hsusb 1p8\n");
+                       goto put_1p8;
+               }
+               rc = regulator_enable(hsusb_1p8);
+               if (rc) {
+                       dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
+                       goto put_1p8;
+               }
+
+               return 0;
+       }
+
+       regulator_disable(hsusb_1p8);
+put_1p8:
+       regulator_put(hsusb_1p8);
+disable_3p3:
+       regulator_disable(hsusb_3p3);
+put_3p3:
+       regulator_put(hsusb_3p3);
+       return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+#define USB_PHY_SUSP_DIG_VOL  500000
+static int msm_hsusb_config_vddcx(int high)
+{
+       int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
+       int min_vol;
+       int ret;
+
+       if (high)
+               min_vol = USB_PHY_VDD_DIG_VOL_MIN;
+       else
+               min_vol = USB_PHY_SUSP_DIG_VOL;
+
+       ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
+       if (ret) {
+               pr_err("%s: unable to set the voltage for regulator "
+                       "HSUSB_VDDCX\n", __func__);
+               return ret;
+       }
+
+       pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
+
+       return ret;
+}
+#endif
+
+static int msm_hsusb_ldo_set_mode(int on)
+{
+       int ret = 0;
+
+       if (!hsusb_1p8 || IS_ERR(hsusb_1p8)) {
+               pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
+               return -ENODEV;
+       }
+
+       if (!hsusb_3p3 || IS_ERR(hsusb_3p3)) {
+               pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
+               return -ENODEV;
+       }
+
+       if (on) {
+               ret = regulator_set_optimum_mode(hsusb_1p8,
+                               USB_PHY_1P8_HPM_LOAD);
+               if (ret < 0) {
+                       pr_err("%s: Unable to set HPM of the regulator "
+                               "HSUSB_1p8\n", __func__);
+                       return ret;
+               }
+               ret = regulator_set_optimum_mode(hsusb_3p3,
+                               USB_PHY_3P3_HPM_LOAD);
+               if (ret < 0) {
+                       pr_err("%s: Unable to set HPM of the regulator "
+                               "HSUSB_3p3\n", __func__);
+                       regulator_set_optimum_mode(hsusb_1p8,
+                               USB_PHY_1P8_LPM_LOAD);
+                       return ret;
+               }
+       } else {
+               ret = regulator_set_optimum_mode(hsusb_1p8,
+                               USB_PHY_1P8_LPM_LOAD);
+               if (ret < 0)
+                       pr_err("%s: Unable to set LPM of the regulator "
+                               "HSUSB_1p8\n", __func__);
+               ret = regulator_set_optimum_mode(hsusb_3p3,
+                               USB_PHY_3P3_LPM_LOAD);
+               if (ret < 0)
+                       pr_err("%s: Unable to set LPM of the regulator "
+                               "HSUSB_3p3\n", __func__);
+       }
+
+       pr_debug("reg (%s)\n", on ? "HPM" : "LPM");
+       return ret < 0 ? ret : 0;
+}
+
+static int ulpi_read(struct usb_phy *phy, u32 reg)
+{
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+       int cnt = 0;
+
+       /* initiate read operation */
+       writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+              USB_ULPI_VIEWPORT);
+
+       /* wait for completion */
+       while (cnt < ULPI_IO_TIMEOUT_USEC) {
+               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
+                       break;
+               udelay(1);
+               cnt++;
+       }
+
+       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+               dev_err(phy->dev, "ulpi_read: timeout %08x\n",
+                       readl(USB_ULPI_VIEWPORT));
+               return -ETIMEDOUT;
+       }
+       return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
+}
+
+static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
+{
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+       int cnt = 0;
+
+       /* initiate write operation */
+       writel(ULPI_RUN | ULPI_WRITE |
+              ULPI_ADDR(reg) | ULPI_DATA(val),
+              USB_ULPI_VIEWPORT);
+
+       /* wait for completion */
+       while (cnt < ULPI_IO_TIMEOUT_USEC) {
+               if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN))
+                       break;
+               udelay(1);
+               cnt++;
+       }
+
+       if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+               dev_err(phy->dev, "ulpi_write: timeout\n");
+               return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static struct usb_phy_io_ops msm_otg_io_ops = {
+       .read = ulpi_read,
+       .write = ulpi_write,
+};
+
+static void ulpi_init(struct msm_otg *motg)
+{
+       struct msm_otg_platform_data *pdata = motg->pdata;
+       int *seq = pdata->phy_init_seq;
+
+       if (!seq)
+               return;
+
+       while (seq[0] >= 0) {
+               dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
+                               seq[0], seq[1]);
+               ulpi_write(&motg->phy, seq[0], seq[1]);
+               seq += 2;
+       }
+}
+
+static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
+{
+       int ret;
+
+       if (assert) {
+               ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
+               if (ret)
+                       dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
+       } else {
+               ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
+               if (ret)
+                       dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
+       }
+       return ret;
+}
+
+static int msm_otg_phy_clk_reset(struct msm_otg *motg)
+{
+       int ret;
+
+       ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
+       if (ret) {
+               dev_err(motg->phy.dev, "usb phy clk assert failed\n");
+               return ret;
+       }
+       usleep_range(10000, 12000);
+       ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
+       if (ret)
+               dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
+       return ret;
+}
+
+static int msm_otg_phy_reset(struct msm_otg *motg)
+{
+       u32 val;
+       int ret;
+       int retries;
+
+       ret = msm_otg_link_clk_reset(motg, 1);
+       if (ret)
+               return ret;
+       ret = msm_otg_phy_clk_reset(motg);
+       if (ret)
+               return ret;
+       ret = msm_otg_link_clk_reset(motg, 0);
+       if (ret)
+               return ret;
+
+       val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
+       writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+       for (retries = 3; retries > 0; retries--) {
+               ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
+                               ULPI_CLR(ULPI_FUNC_CTRL));
+               if (!ret)
+                       break;
+               ret = msm_otg_phy_clk_reset(motg);
+               if (ret)
+                       return ret;
+       }
+       if (!retries)
+               return -ETIMEDOUT;
+
+       /* This reset calibrates the phy, if the above write succeeded */
+       ret = msm_otg_phy_clk_reset(motg);
+       if (ret)
+               return ret;
+
+       for (retries = 3; retries > 0; retries--) {
+               ret = ulpi_read(&motg->phy, ULPI_DEBUG);
+               if (ret != -ETIMEDOUT)
+                       break;
+               ret = msm_otg_phy_clk_reset(motg);
+               if (ret)
+                       return ret;
+       }
+       if (!retries)
+               return -ETIMEDOUT;
+
+       dev_info(motg->phy.dev, "phy_reset: success\n");
+       return 0;
+}
+
+#define LINK_RESET_TIMEOUT_USEC                (250 * 1000)
+static int msm_otg_reset(struct usb_phy *phy)
+{
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+       struct msm_otg_platform_data *pdata = motg->pdata;
+       int cnt = 0;
+       int ret;
+       u32 val = 0;
+       u32 ulpi_val = 0;
+
+       ret = msm_otg_phy_reset(motg);
+       if (ret) {
+               dev_err(phy->dev, "phy_reset failed\n");
+               return ret;
+       }
+
+       ulpi_init(motg);
+
+       writel(USBCMD_RESET, USB_USBCMD);
+       while (cnt < LINK_RESET_TIMEOUT_USEC) {
+               if (!(readl(USB_USBCMD) & USBCMD_RESET))
+                       break;
+               udelay(1);
+               cnt++;
+       }
+       if (cnt >= LINK_RESET_TIMEOUT_USEC)
+               return -ETIMEDOUT;
+
+       /* select ULPI phy */
+       writel(0x80000000, USB_PORTSC);
+
+       msleep(100);
+
+       writel(0x0, USB_AHBBURST);
+       writel(0x00, USB_AHBMODE);
+
+       if (pdata->otg_control == OTG_PHY_CONTROL) {
+               val = readl(USB_OTGSC);
+               if (pdata->mode == USB_OTG) {
+                       ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
+                       val |= OTGSC_IDIE | OTGSC_BSVIE;
+               } else if (pdata->mode == USB_PERIPHERAL) {
+                       ulpi_val = ULPI_INT_SESS_VALID;
+                       val |= OTGSC_BSVIE;
+               }
+               writel(val, USB_OTGSC);
+               ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
+               ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
+       }
+
+       return 0;
+}
+
+#define PHY_SUSPEND_TIMEOUT_USEC       (500 * 1000)
+#define PHY_RESUME_TIMEOUT_USEC        (100 * 1000)
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_otg_suspend(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       struct usb_bus *bus = phy->otg->host;
+       struct msm_otg_platform_data *pdata = motg->pdata;
+       int cnt = 0;
+
+       if (atomic_read(&motg->in_lpm))
+               return 0;
+
+       disable_irq(motg->irq);
+       /*
+        * Chipidea 45-nm PHY suspend sequence:
+        *
+        * Interrupt Latch Register auto-clear feature is not present
+        * in all PHY versions. Latch register is clear on read type.
+        * Clear latch register to avoid spurious wakeup from
+        * low power mode (LPM).
+        *
+        * PHY comparators are disabled when PHY enters into low power
+        * mode (LPM). Keep PHY comparators ON in LPM only when we expect
+        * VBUS/Id notifications from USB PHY. Otherwise turn off USB
+        * PHY comparators. This save significant amount of power.
+        *
+        * PLL is not turned off when PHY enters into low power mode (LPM).
+        * Disable PLL for maximum power savings.
+        */
+
+       if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
+               ulpi_read(phy, 0x14);
+               if (pdata->otg_control == OTG_PHY_CONTROL)
+                       ulpi_write(phy, 0x01, 0x30);
+               ulpi_write(phy, 0x08, 0x09);
+       }
+
+       /*
+        * PHY may take some time or even fail to enter into low power
+        * mode (LPM). Hence poll for 500 msec and reset the PHY and link
+        * in failure case.
+        */
+       writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+       while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+               if (readl(USB_PORTSC) & PORTSC_PHCD)
+                       break;
+               udelay(1);
+               cnt++;
+       }
+
+       if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
+               dev_err(phy->dev, "Unable to suspend PHY\n");
+               msm_otg_reset(phy);
+               enable_irq(motg->irq);
+               return -ETIMEDOUT;
+       }
+
+       /*
+        * PHY has capability to generate interrupt asynchronously in low
+        * power mode (LPM). This interrupt is level triggered. So USB IRQ
+        * line must be disabled till async interrupt enable bit is cleared
+        * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+        * block data communication from PHY.
+        */
+       writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
+
+       if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
+                       motg->pdata->otg_control == OTG_PMIC_CONTROL)
+               writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL);
+
+       clk_disable(motg->pclk);
+       clk_disable(motg->clk);
+       if (motg->core_clk)
+               clk_disable(motg->core_clk);
+
+       if (!IS_ERR(motg->pclk_src))
+               clk_disable(motg->pclk_src);
+
+       if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
+                       motg->pdata->otg_control == OTG_PMIC_CONTROL) {
+               msm_hsusb_ldo_set_mode(0);
+               msm_hsusb_config_vddcx(0);
+       }
+
+       if (device_may_wakeup(phy->dev))
+               enable_irq_wake(motg->irq);
+       if (bus)
+               clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+       atomic_set(&motg->in_lpm, 1);
+       enable_irq(motg->irq);
+
+       dev_info(phy->dev, "USB in low power mode\n");
+
+       return 0;
+}
+
+static int msm_otg_resume(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       struct usb_bus *bus = phy->otg->host;
+       int cnt = 0;
+       unsigned temp;
+
+       if (!atomic_read(&motg->in_lpm))
+               return 0;
+
+       if (!IS_ERR(motg->pclk_src))
+               clk_enable(motg->pclk_src);
+
+       clk_enable(motg->pclk);
+       clk_enable(motg->clk);
+       if (motg->core_clk)
+               clk_enable(motg->core_clk);
+
+       if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
+                       motg->pdata->otg_control == OTG_PMIC_CONTROL) {
+               msm_hsusb_ldo_set_mode(1);
+               msm_hsusb_config_vddcx(1);
+               writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL);
+       }
+
+       temp = readl(USB_USBCMD);
+       temp &= ~ASYNC_INTR_CTRL;
+       temp &= ~ULPI_STP_CTRL;
+       writel(temp, USB_USBCMD);
+
+       /*
+        * PHY comes out of low power mode (LPM) in case of wakeup
+        * from asynchronous interrupt.
+        */
+       if (!(readl(USB_PORTSC) & PORTSC_PHCD))
+               goto skip_phy_resume;
+
+       writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
+       while (cnt < PHY_RESUME_TIMEOUT_USEC) {
+               if (!(readl(USB_PORTSC) & PORTSC_PHCD))
+                       break;
+               udelay(1);
+               cnt++;
+       }
+
+       if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
+               /*
+                * This is a fatal error. Reset the link and
+                * PHY. USB state can not be restored. Re-insertion
+                * of USB cable is the only way to get USB working.
+                */
+               dev_err(phy->dev, "Unable to resume USB."
+                               "Re-plugin the cable\n");
+               msm_otg_reset(phy);
+       }
+
+skip_phy_resume:
+       if (device_may_wakeup(phy->dev))
+               disable_irq_wake(motg->irq);
+       if (bus)
+               set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+       atomic_set(&motg->in_lpm, 0);
+
+       if (motg->async_int) {
+               motg->async_int = 0;
+               pm_runtime_put(phy->dev);
+               enable_irq(motg->irq);
+       }
+
+       dev_info(phy->dev, "USB exited from low power mode\n");
+
+       return 0;
+}
+#endif
+
+static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
+{
+       if (motg->cur_power == mA)
+               return;
+
+       /* TODO: Notify PMIC about available current */
+       dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
+       motg->cur_power = mA;
+}
+
+static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
+{
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+
+       /*
+        * Gadget driver uses set_power method to notify about the
+        * available current based on suspend/configured states.
+        *
+        * IDEV_CHG can be drawn irrespective of suspend/un-configured
+        * states when CDP/ACA is connected.
+        */
+       if (motg->chg_type == USB_SDP_CHARGER)
+               msm_otg_notify_charger(motg, mA);
+
+       return 0;
+}
+
+static void msm_otg_start_host(struct usb_phy *phy, int on)
+{
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+       struct msm_otg_platform_data *pdata = motg->pdata;
+       struct usb_hcd *hcd;
+
+       if (!phy->otg->host)
+               return;
+
+       hcd = bus_to_hcd(phy->otg->host);
+
+       if (on) {
+               dev_dbg(phy->dev, "host on\n");
+
+               if (pdata->vbus_power)
+                       pdata->vbus_power(1);
+               /*
+                * Some boards have a switch cotrolled by gpio
+                * to enable/disable internal HUB. Enable internal
+                * HUB before kicking the host.
+                */
+               if (pdata->setup_gpio)
+                       pdata->setup_gpio(OTG_STATE_A_HOST);
+#ifdef CONFIG_USB
+               usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+#endif
+       } else {
+               dev_dbg(phy->dev, "host off\n");
+
+#ifdef CONFIG_USB
+               usb_remove_hcd(hcd);
+#endif
+               if (pdata->setup_gpio)
+                       pdata->setup_gpio(OTG_STATE_UNDEFINED);
+               if (pdata->vbus_power)
+                       pdata->vbus_power(0);
+       }
+}
+
+static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
+       struct usb_hcd *hcd;
+
+       /*
+        * Fail host registration if this board can support
+        * only peripheral configuration.
+        */
+       if (motg->pdata->mode == USB_PERIPHERAL) {
+               dev_info(otg->phy->dev, "Host mode is not supported\n");
+               return -ENODEV;
+       }
+
+       if (!host) {
+               if (otg->phy->state == OTG_STATE_A_HOST) {
+                       pm_runtime_get_sync(otg->phy->dev);
+                       msm_otg_start_host(otg->phy, 0);
+                       otg->host = NULL;
+                       otg->phy->state = OTG_STATE_UNDEFINED;
+                       schedule_work(&motg->sm_work);
+               } else {
+                       otg->host = NULL;
+               }
+
+               return 0;
+       }
+
+       hcd = bus_to_hcd(host);
+       hcd->power_budget = motg->pdata->power_budget;
+
+       otg->host = host;
+       dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
+
+       /*
+        * Kick the state machine work, if peripheral is not supported
+        * or peripheral is already registered with us.
+        */
+       if (motg->pdata->mode == USB_HOST || otg->gadget) {
+               pm_runtime_get_sync(otg->phy->dev);
+               schedule_work(&motg->sm_work);
+       }
+
+       return 0;
+}
+
+static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
+{
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+       struct msm_otg_platform_data *pdata = motg->pdata;
+
+       if (!phy->otg->gadget)
+               return;
+
+       if (on) {
+               dev_dbg(phy->dev, "gadget on\n");
+               /*
+                * Some boards have a switch cotrolled by gpio
+                * to enable/disable internal HUB. Disable internal
+                * HUB before kicking the gadget.
+                */
+               if (pdata->setup_gpio)
+                       pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
+               usb_gadget_vbus_connect(phy->otg->gadget);
+       } else {
+               dev_dbg(phy->dev, "gadget off\n");
+               usb_gadget_vbus_disconnect(phy->otg->gadget);
+               if (pdata->setup_gpio)
+                       pdata->setup_gpio(OTG_STATE_UNDEFINED);
+       }
+
+}
+
+static int msm_otg_set_peripheral(struct usb_otg *otg,
+                                       struct usb_gadget *gadget)
+{
+       struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
+
+       /*
+        * Fail peripheral registration if this board can support
+        * only host configuration.
+        */
+       if (motg->pdata->mode == USB_HOST) {
+               dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
+               return -ENODEV;
+       }
+
+       if (!gadget) {
+               if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
+                       pm_runtime_get_sync(otg->phy->dev);
+                       msm_otg_start_peripheral(otg->phy, 0);
+                       otg->gadget = NULL;
+                       otg->phy->state = OTG_STATE_UNDEFINED;
+                       schedule_work(&motg->sm_work);
+               } else {
+                       otg->gadget = NULL;
+               }
+
+               return 0;
+       }
+       otg->gadget = gadget;
+       dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
+
+       /*
+        * Kick the state machine work, if host is not supported
+        * or host is already registered with us.
+        */
+       if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
+               pm_runtime_get_sync(otg->phy->dev);
+               schedule_work(&motg->sm_work);
+       }
+
+       return 0;
+}
+
+static bool msm_chg_check_secondary_det(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 chg_det;
+       bool ret = false;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               ret = chg_det & (1 << 4);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x87);
+               ret = chg_det & 1;
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+static void msm_chg_enable_secondary_det(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 chg_det;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               /* Turn off charger block */
+               chg_det |= ~(1 << 1);
+               ulpi_write(phy, chg_det, 0x34);
+               udelay(20);
+               /* control chg block via ULPI */
+               chg_det &= ~(1 << 3);
+               ulpi_write(phy, chg_det, 0x34);
+               /* put it in host mode for enabling D- source */
+               chg_det &= ~(1 << 2);
+               ulpi_write(phy, chg_det, 0x34);
+               /* Turn on chg detect block */
+               chg_det &= ~(1 << 1);
+               ulpi_write(phy, chg_det, 0x34);
+               udelay(20);
+               /* enable chg detection */
+               chg_det &= ~(1 << 0);
+               ulpi_write(phy, chg_det, 0x34);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               /*
+                * Configure DM as current source, DP as current sink
+                * and enable battery charging comparators.
+                */
+               ulpi_write(phy, 0x8, 0x85);
+               ulpi_write(phy, 0x2, 0x85);
+               ulpi_write(phy, 0x1, 0x85);
+               break;
+       default:
+               break;
+       }
+}
+
+static bool msm_chg_check_primary_det(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 chg_det;
+       bool ret = false;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               ret = chg_det & (1 << 4);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x87);
+               ret = chg_det & 1;
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+static void msm_chg_enable_primary_det(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 chg_det;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               /* enable chg detection */
+               chg_det &= ~(1 << 0);
+               ulpi_write(phy, chg_det, 0x34);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               /*
+                * Configure DP as current source, DM as current sink
+                * and enable battery charging comparators.
+                */
+               ulpi_write(phy, 0x2, 0x85);
+               ulpi_write(phy, 0x1, 0x85);
+               break;
+       default:
+               break;
+       }
+}
+
+static bool msm_chg_check_dcd(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 line_state;
+       bool ret = false;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               line_state = ulpi_read(phy, 0x15);
+               ret = !(line_state & 1);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               line_state = ulpi_read(phy, 0x87);
+               ret = line_state & 2;
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+static void msm_chg_disable_dcd(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 chg_det;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               chg_det &= ~(1 << 5);
+               ulpi_write(phy, chg_det, 0x34);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               ulpi_write(phy, 0x10, 0x86);
+               break;
+       default:
+               break;
+       }
+}
+
+static void msm_chg_enable_dcd(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 chg_det;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               /* Turn on D+ current source */
+               chg_det |= (1 << 5);
+               ulpi_write(phy, chg_det, 0x34);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               /* Data contact detection enable */
+               ulpi_write(phy, 0x10, 0x85);
+               break;
+       default:
+               break;
+       }
+}
+
+static void msm_chg_block_on(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 func_ctrl, chg_det;
+
+       /* put the controller in non-driving mode */
+       func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+       func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+       func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+       ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               /* control chg block via ULPI */
+               chg_det &= ~(1 << 3);
+               ulpi_write(phy, chg_det, 0x34);
+               /* Turn on chg detect block */
+               chg_det &= ~(1 << 1);
+               ulpi_write(phy, chg_det, 0x34);
+               udelay(20);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               /* Clear charger detecting control bits */
+               ulpi_write(phy, 0x3F, 0x86);
+               /* Clear alt interrupt latch and enable bits */
+               ulpi_write(phy, 0x1F, 0x92);
+               ulpi_write(phy, 0x1F, 0x95);
+               udelay(100);
+               break;
+       default:
+               break;
+       }
+}
+
+static void msm_chg_block_off(struct msm_otg *motg)
+{
+       struct usb_phy *phy = &motg->phy;
+       u32 func_ctrl, chg_det;
+
+       switch (motg->pdata->phy_type) {
+       case CI_45NM_INTEGRATED_PHY:
+               chg_det = ulpi_read(phy, 0x34);
+               /* Turn off charger block */
+               chg_det |= ~(1 << 1);
+               ulpi_write(phy, chg_det, 0x34);
+               break;
+       case SNPS_28NM_INTEGRATED_PHY:
+               /* Clear charger detecting control bits */
+               ulpi_write(phy, 0x3F, 0x86);
+               /* Clear alt interrupt latch and enable bits */
+               ulpi_write(phy, 0x1F, 0x92);
+               ulpi_write(phy, 0x1F, 0x95);
+               break;
+       default:
+               break;
+       }
+
+       /* put the controller in normal mode */
+       func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+       func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+       func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+       ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+}
+
+#define MSM_CHG_DCD_POLL_TIME          (100 * HZ/1000) /* 100 msec */
+#define MSM_CHG_DCD_MAX_RETRIES                6 /* Tdcd_tmout = 6 * 100 msec */
+#define MSM_CHG_PRIMARY_DET_TIME       (40 * HZ/1000) /* TVDPSRC_ON */
+#define MSM_CHG_SECONDARY_DET_TIME     (40 * HZ/1000) /* TVDMSRC_ON */
+static void msm_chg_detect_work(struct work_struct *w)
+{
+       struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
+       struct usb_phy *phy = &motg->phy;
+       bool is_dcd, tmout, vout;
+       unsigned long delay;
+
+       dev_dbg(phy->dev, "chg detection work\n");
+       switch (motg->chg_state) {
+       case USB_CHG_STATE_UNDEFINED:
+               pm_runtime_get_sync(phy->dev);
+               msm_chg_block_on(motg);
+               msm_chg_enable_dcd(motg);
+               motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
+               motg->dcd_retries = 0;
+               delay = MSM_CHG_DCD_POLL_TIME;
+               break;
+       case USB_CHG_STATE_WAIT_FOR_DCD:
+               is_dcd = msm_chg_check_dcd(motg);
+               tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
+               if (is_dcd || tmout) {
+                       msm_chg_disable_dcd(motg);
+                       msm_chg_enable_primary_det(motg);
+                       delay = MSM_CHG_PRIMARY_DET_TIME;
+                       motg->chg_state = USB_CHG_STATE_DCD_DONE;
+               } else {
+                       delay = MSM_CHG_DCD_POLL_TIME;
+               }
+               break;
+       case USB_CHG_STATE_DCD_DONE:
+               vout = msm_chg_check_primary_det(motg);
+               if (vout) {
+                       msm_chg_enable_secondary_det(motg);
+                       delay = MSM_CHG_SECONDARY_DET_TIME;
+                       motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
+               } else {
+                       motg->chg_type = USB_SDP_CHARGER;
+                       motg->chg_state = USB_CHG_STATE_DETECTED;
+                       delay = 0;
+               }
+               break;
+       case USB_CHG_STATE_PRIMARY_DONE:
+               vout = msm_chg_check_secondary_det(motg);
+               if (vout)
+                       motg->chg_type = USB_DCP_CHARGER;
+               else
+                       motg->chg_type = USB_CDP_CHARGER;
+               motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
+               /* fall through */
+       case USB_CHG_STATE_SECONDARY_DONE:
+               motg->chg_state = USB_CHG_STATE_DETECTED;
+       case USB_CHG_STATE_DETECTED:
+               msm_chg_block_off(motg);
+               dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
+               schedule_work(&motg->sm_work);
+               return;
+       default:
+               return;
+       }
+
+       schedule_delayed_work(&motg->chg_work, delay);
+}
+
+/*
+ * We support OTG, Peripheral only and Host only configurations. In case
+ * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
+ * via Id pin status or user request (debugfs). Id/BSV interrupts are not
+ * enabled when switch is controlled by user and default mode is supplied
+ * by board file, which can be changed by userspace later.
+ */
+static void msm_otg_init_sm(struct msm_otg *motg)
+{
+       struct msm_otg_platform_data *pdata = motg->pdata;
+       u32 otgsc = readl(USB_OTGSC);
+
+       switch (pdata->mode) {
+       case USB_OTG:
+               if (pdata->otg_control == OTG_PHY_CONTROL) {
+                       if (otgsc & OTGSC_ID)
+                               set_bit(ID, &motg->inputs);
+                       else
+                               clear_bit(ID, &motg->inputs);
+
+                       if (otgsc & OTGSC_BSV)
+                               set_bit(B_SESS_VLD, &motg->inputs);
+                       else
+                               clear_bit(B_SESS_VLD, &motg->inputs);
+               } else if (pdata->otg_control == OTG_USER_CONTROL) {
+                       if (pdata->default_mode == USB_HOST) {
+                               clear_bit(ID, &motg->inputs);
+                       } else if (pdata->default_mode == USB_PERIPHERAL) {
+                               set_bit(ID, &motg->inputs);
+                               set_bit(B_SESS_VLD, &motg->inputs);
+                       } else {
+                               set_bit(ID, &motg->inputs);
+                               clear_bit(B_SESS_VLD, &motg->inputs);
+                       }
+               }
+               break;
+       case USB_HOST:
+               clear_bit(ID, &motg->inputs);
+               break;
+       case USB_PERIPHERAL:
+               set_bit(ID, &motg->inputs);
+               if (otgsc & OTGSC_BSV)
+                       set_bit(B_SESS_VLD, &motg->inputs);
+               else
+                       clear_bit(B_SESS_VLD, &motg->inputs);
+               break;
+       default:
+               break;
+       }
+}
+
+static void msm_otg_sm_work(struct work_struct *w)
+{
+       struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
+       struct usb_otg *otg = motg->phy.otg;
+
+       switch (otg->phy->state) {
+       case OTG_STATE_UNDEFINED:
+               dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n");
+               msm_otg_reset(otg->phy);
+               msm_otg_init_sm(motg);
+               otg->phy->state = OTG_STATE_B_IDLE;
+               /* FALL THROUGH */
+       case OTG_STATE_B_IDLE:
+               dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n");
+               if (!test_bit(ID, &motg->inputs) && otg->host) {
+                       /* disable BSV bit */
+                       writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
+                       msm_otg_start_host(otg->phy, 1);
+                       otg->phy->state = OTG_STATE_A_HOST;
+               } else if (test_bit(B_SESS_VLD, &motg->inputs)) {
+                       switch (motg->chg_state) {
+                       case USB_CHG_STATE_UNDEFINED:
+                               msm_chg_detect_work(&motg->chg_work.work);
+                               break;
+                       case USB_CHG_STATE_DETECTED:
+                               switch (motg->chg_type) {
+                               case USB_DCP_CHARGER:
+                                       msm_otg_notify_charger(motg,
+                                                       IDEV_CHG_MAX);
+                                       break;
+                               case USB_CDP_CHARGER:
+                                       msm_otg_notify_charger(motg,
+                                                       IDEV_CHG_MAX);
+                                       msm_otg_start_peripheral(otg->phy, 1);
+                                       otg->phy->state
+                                               = OTG_STATE_B_PERIPHERAL;
+                                       break;
+                               case USB_SDP_CHARGER:
+                                       msm_otg_notify_charger(motg, IUNIT);
+                                       msm_otg_start_peripheral(otg->phy, 1);
+                                       otg->phy->state
+                                               = OTG_STATE_B_PERIPHERAL;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       /*
+                        * If charger detection work is pending, decrement
+                        * the pm usage counter to balance with the one that
+                        * is incremented in charger detection work.
+                        */
+                       if (cancel_delayed_work_sync(&motg->chg_work)) {
+                               pm_runtime_put_sync(otg->phy->dev);
+                               msm_otg_reset(otg->phy);
+                       }
+                       msm_otg_notify_charger(motg, 0);
+                       motg->chg_state = USB_CHG_STATE_UNDEFINED;
+                       motg->chg_type = USB_INVALID_CHARGER;
+               }
+               pm_runtime_put_sync(otg->phy->dev);
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
+               if (!test_bit(B_SESS_VLD, &motg->inputs) ||
+                               !test_bit(ID, &motg->inputs)) {
+                       msm_otg_notify_charger(motg, 0);
+                       msm_otg_start_peripheral(otg->phy, 0);
+                       motg->chg_state = USB_CHG_STATE_UNDEFINED;
+                       motg->chg_type = USB_INVALID_CHARGER;
+                       otg->phy->state = OTG_STATE_B_IDLE;
+                       msm_otg_reset(otg->phy);
+                       schedule_work(w);
+               }
+               break;
+       case OTG_STATE_A_HOST:
+               dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n");
+               if (test_bit(ID, &motg->inputs)) {
+                       msm_otg_start_host(otg->phy, 0);
+                       otg->phy->state = OTG_STATE_B_IDLE;
+                       msm_otg_reset(otg->phy);
+                       schedule_work(w);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static irqreturn_t msm_otg_irq(int irq, void *data)
+{
+       struct msm_otg *motg = data;
+       struct usb_phy *phy = &motg->phy;
+       u32 otgsc = 0;
+
+       if (atomic_read(&motg->in_lpm)) {
+               disable_irq_nosync(irq);
+               motg->async_int = 1;
+               pm_runtime_get(phy->dev);
+               return IRQ_HANDLED;
+       }
+
+       otgsc = readl(USB_OTGSC);
+       if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
+               return IRQ_NONE;
+
+       if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
+               if (otgsc & OTGSC_ID)
+                       set_bit(ID, &motg->inputs);
+               else
+                       clear_bit(ID, &motg->inputs);
+               dev_dbg(phy->dev, "ID set/clear\n");
+               pm_runtime_get_noresume(phy->dev);
+       } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
+               if (otgsc & OTGSC_BSV)
+                       set_bit(B_SESS_VLD, &motg->inputs);
+               else
+                       clear_bit(B_SESS_VLD, &motg->inputs);
+               dev_dbg(phy->dev, "BSV set/clear\n");
+               pm_runtime_get_noresume(phy->dev);
+       }
+
+       writel(otgsc, USB_OTGSC);
+       schedule_work(&motg->sm_work);
+       return IRQ_HANDLED;
+}
+
+static int msm_otg_mode_show(struct seq_file *s, void *unused)
+{
+       struct msm_otg *motg = s->private;
+       struct usb_otg *otg = motg->phy.otg;
+
+       switch (otg->phy->state) {
+       case OTG_STATE_A_HOST:
+               seq_printf(s, "host\n");
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               seq_printf(s, "peripheral\n");
+               break;
+       default:
+               seq_printf(s, "none\n");
+               break;
+       }
+
+       return 0;
+}
+
+static int msm_otg_mode_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, msm_otg_mode_show, inode->i_private);
+}
+
+static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
+                               size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct msm_otg *motg = s->private;
+       char buf[16];
+       struct usb_otg *otg = motg->phy.otg;
+       int status = count;
+       enum usb_mode_type req_mode;
+
+       memset(buf, 0x00, sizeof(buf));
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+               status = -EFAULT;
+               goto out;
+       }
+
+       if (!strncmp(buf, "host", 4)) {
+               req_mode = USB_HOST;
+       } else if (!strncmp(buf, "peripheral", 10)) {
+               req_mode = USB_PERIPHERAL;
+       } else if (!strncmp(buf, "none", 4)) {
+               req_mode = USB_NONE;
+       } else {
+               status = -EINVAL;
+               goto out;
+       }
+
+       switch (req_mode) {
+       case USB_NONE:
+               switch (otg->phy->state) {
+               case OTG_STATE_A_HOST:
+               case OTG_STATE_B_PERIPHERAL:
+                       set_bit(ID, &motg->inputs);
+                       clear_bit(B_SESS_VLD, &motg->inputs);
+                       break;
+               default:
+                       goto out;
+               }
+               break;
+       case USB_PERIPHERAL:
+               switch (otg->phy->state) {
+               case OTG_STATE_B_IDLE:
+               case OTG_STATE_A_HOST:
+                       set_bit(ID, &motg->inputs);
+                       set_bit(B_SESS_VLD, &motg->inputs);
+                       break;
+               default:
+                       goto out;
+               }
+               break;
+       case USB_HOST:
+               switch (otg->phy->state) {
+               case OTG_STATE_B_IDLE:
+               case OTG_STATE_B_PERIPHERAL:
+                       clear_bit(ID, &motg->inputs);
+                       break;
+               default:
+                       goto out;
+               }
+               break;
+       default:
+               goto out;
+       }
+
+       pm_runtime_get_sync(otg->phy->dev);
+       schedule_work(&motg->sm_work);
+out:
+       return status;
+}
+
+const struct file_operations msm_otg_mode_fops = {
+       .open = msm_otg_mode_open,
+       .read = seq_read,
+       .write = msm_otg_mode_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static struct dentry *msm_otg_dbg_root;
+static struct dentry *msm_otg_dbg_mode;
+
+static int msm_otg_debugfs_init(struct msm_otg *motg)
+{
+       msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
+
+       if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
+               return -ENODEV;
+
+       msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR,
+                               msm_otg_dbg_root, motg, &msm_otg_mode_fops);
+       if (!msm_otg_dbg_mode) {
+               debugfs_remove(msm_otg_dbg_root);
+               msm_otg_dbg_root = NULL;
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void msm_otg_debugfs_cleanup(void)
+{
+       debugfs_remove(msm_otg_dbg_mode);
+       debugfs_remove(msm_otg_dbg_root);
+}
+
+static int __init msm_otg_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct resource *res;
+       struct msm_otg *motg;
+       struct usb_phy *phy;
+
+       dev_info(&pdev->dev, "msm_otg probe\n");
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "No platform data given. Bailing out\n");
+               return -ENODEV;
+       }
+
+       motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
+       if (!motg) {
+               dev_err(&pdev->dev, "unable to allocate msm_otg\n");
+               return -ENOMEM;
+       }
+
+       motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+       if (!motg->phy.otg) {
+               dev_err(&pdev->dev, "unable to allocate msm_otg\n");
+               return -ENOMEM;
+       }
+
+       motg->pdata = pdev->dev.platform_data;
+       phy = &motg->phy;
+       phy->dev = &pdev->dev;
+
+       motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
+       if (IS_ERR(motg->phy_reset_clk)) {
+               dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
+               ret = PTR_ERR(motg->phy_reset_clk);
+               goto free_motg;
+       }
+
+       motg->clk = clk_get(&pdev->dev, "usb_hs_clk");
+       if (IS_ERR(motg->clk)) {
+               dev_err(&pdev->dev, "failed to get usb_hs_clk\n");
+               ret = PTR_ERR(motg->clk);
+               goto put_phy_reset_clk;
+       }
+       clk_set_rate(motg->clk, 60000000);
+
+       /*
+        * If USB Core is running its protocol engine based on CORE CLK,
+        * CORE CLK  must be running at >55Mhz for correct HSUSB
+        * operation and USB core cannot tolerate frequency changes on
+        * CORE CLK. For such USB cores, vote for maximum clk frequency
+        * on pclk source
+        */
+        if (motg->pdata->pclk_src_name) {
+               motg->pclk_src = clk_get(&pdev->dev,
+                       motg->pdata->pclk_src_name);
+               if (IS_ERR(motg->pclk_src))
+                       goto put_clk;
+               clk_set_rate(motg->pclk_src, INT_MAX);
+               clk_enable(motg->pclk_src);
+       } else
+               motg->pclk_src = ERR_PTR(-ENOENT);
+
+
+       motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk");
+       if (IS_ERR(motg->pclk)) {
+               dev_err(&pdev->dev, "failed to get usb_hs_pclk\n");
+               ret = PTR_ERR(motg->pclk);
+               goto put_pclk_src;
+       }
+
+       /*
+        * USB core clock is not present on all MSM chips. This
+        * clock is introduced to remove the dependency on AXI
+        * bus frequency.
+        */
+       motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk");
+       if (IS_ERR(motg->core_clk))
+               motg->core_clk = NULL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get platform resource mem\n");
+               ret = -ENODEV;
+               goto put_core_clk;
+       }
+
+       motg->regs = ioremap(res->start, resource_size(res));
+       if (!motg->regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto put_core_clk;
+       }
+       dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);
+
+       motg->irq = platform_get_irq(pdev, 0);
+       if (!motg->irq) {
+               dev_err(&pdev->dev, "platform_get_irq failed\n");
+               ret = -ENODEV;
+               goto free_regs;
+       }
+
+       clk_enable(motg->clk);
+       clk_enable(motg->pclk);
+
+       ret = msm_hsusb_init_vddcx(motg, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
+               goto free_regs;
+       }
+
+       ret = msm_hsusb_ldo_init(motg, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
+               goto vddcx_exit;
+       }
+       ret = msm_hsusb_ldo_set_mode(1);
+       if (ret) {
+               dev_err(&pdev->dev, "hsusb vreg enable failed\n");
+               goto ldo_exit;
+       }
+
+       if (motg->core_clk)
+               clk_enable(motg->core_clk);
+
+       writel(0, USB_USBINTR);
+       writel(0, USB_OTGSC);
+
+       INIT_WORK(&motg->sm_work, msm_otg_sm_work);
+       INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
+       ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
+                                       "msm_otg", motg);
+       if (ret) {
+               dev_err(&pdev->dev, "request irq failed\n");
+               goto disable_clks;
+       }
+
+       phy->init = msm_otg_reset;
+       phy->set_power = msm_otg_set_power;
+
+       phy->io_ops = &msm_otg_io_ops;
+
+       phy->otg->phy = &motg->phy;
+       phy->otg->set_host = msm_otg_set_host;
+       phy->otg->set_peripheral = msm_otg_set_peripheral;
+
+       ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
+       if (ret) {
+               dev_err(&pdev->dev, "usb_add_phy failed\n");
+               goto free_irq;
+       }
+
+       platform_set_drvdata(pdev, motg);
+       device_init_wakeup(&pdev->dev, 1);
+
+       if (motg->pdata->mode == USB_OTG &&
+                       motg->pdata->otg_control == OTG_USER_CONTROL) {
+               ret = msm_otg_debugfs_init(motg);
+               if (ret)
+                       dev_dbg(&pdev->dev, "mode debugfs file is"
+                                       "not available\n");
+       }
+
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       return 0;
+free_irq:
+       free_irq(motg->irq, motg);
+disable_clks:
+       clk_disable(motg->pclk);
+       clk_disable(motg->clk);
+ldo_exit:
+       msm_hsusb_ldo_init(motg, 0);
+vddcx_exit:
+       msm_hsusb_init_vddcx(motg, 0);
+free_regs:
+       iounmap(motg->regs);
+put_core_clk:
+       if (motg->core_clk)
+               clk_put(motg->core_clk);
+       clk_put(motg->pclk);
+put_pclk_src:
+       if (!IS_ERR(motg->pclk_src)) {
+               clk_disable(motg->pclk_src);
+               clk_put(motg->pclk_src);
+       }
+put_clk:
+       clk_put(motg->clk);
+put_phy_reset_clk:
+       clk_put(motg->phy_reset_clk);
+free_motg:
+       kfree(motg->phy.otg);
+       kfree(motg);
+       return ret;
+}
+
+static int msm_otg_remove(struct platform_device *pdev)
+{
+       struct msm_otg *motg = platform_get_drvdata(pdev);
+       struct usb_phy *phy = &motg->phy;
+       int cnt = 0;
+
+       if (phy->otg->host || phy->otg->gadget)
+               return -EBUSY;
+
+       msm_otg_debugfs_cleanup();
+       cancel_delayed_work_sync(&motg->chg_work);
+       cancel_work_sync(&motg->sm_work);
+
+       pm_runtime_resume(&pdev->dev);
+
+       device_init_wakeup(&pdev->dev, 0);
+       pm_runtime_disable(&pdev->dev);
+
+       usb_remove_phy(phy);
+       free_irq(motg->irq, motg);
+
+       /*
+        * Put PHY in low power mode.
+        */
+       ulpi_read(phy, 0x14);
+       ulpi_write(phy, 0x08, 0x09);
+
+       writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+       while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+               if (readl(USB_PORTSC) & PORTSC_PHCD)
+                       break;
+               udelay(1);
+               cnt++;
+       }
+       if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
+               dev_err(phy->dev, "Unable to suspend PHY\n");
+
+       clk_disable(motg->pclk);
+       clk_disable(motg->clk);
+       if (motg->core_clk)
+               clk_disable(motg->core_clk);
+       if (!IS_ERR(motg->pclk_src)) {
+               clk_disable(motg->pclk_src);
+               clk_put(motg->pclk_src);
+       }
+       msm_hsusb_ldo_init(motg, 0);
+
+       iounmap(motg->regs);
+       pm_runtime_set_suspended(&pdev->dev);
+
+       clk_put(motg->phy_reset_clk);
+       clk_put(motg->pclk);
+       clk_put(motg->clk);
+       if (motg->core_clk)
+               clk_put(motg->core_clk);
+
+       kfree(motg->phy.otg);
+       kfree(motg);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int msm_otg_runtime_idle(struct device *dev)
+{
+       struct msm_otg *motg = dev_get_drvdata(dev);
+       struct usb_otg *otg = motg->phy.otg;
+
+       dev_dbg(dev, "OTG runtime idle\n");
+
+       /*
+        * It is observed some times that a spurious interrupt
+        * comes when PHY is put into LPM immediately after PHY reset.
+        * This 1 sec delay also prevents entering into LPM immediately
+        * after asynchronous interrupt.
+        */
+       if (otg->phy->state != OTG_STATE_UNDEFINED)
+               pm_schedule_suspend(dev, 1000);
+
+       return -EAGAIN;
+}
+
+static int msm_otg_runtime_suspend(struct device *dev)
+{
+       struct msm_otg *motg = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "OTG runtime suspend\n");
+       return msm_otg_suspend(motg);
+}
+
+static int msm_otg_runtime_resume(struct device *dev)
+{
+       struct msm_otg *motg = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "OTG runtime resume\n");
+       return msm_otg_resume(motg);
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_otg_pm_suspend(struct device *dev)
+{
+       struct msm_otg *motg = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "OTG PM suspend\n");
+       return msm_otg_suspend(motg);
+}
+
+static int msm_otg_pm_resume(struct device *dev)
+{
+       struct msm_otg *motg = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(dev, "OTG PM resume\n");
+
+       ret = msm_otg_resume(motg);
+       if (ret)
+               return ret;
+
+       /*
+        * Runtime PM Documentation recommends bringing the
+        * device to full powered state upon resume.
+        */
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops msm_otg_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
+       SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
+                               msm_otg_runtime_idle)
+};
+#endif
+
+static struct platform_driver msm_otg_driver = {
+       .remove = msm_otg_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm = &msm_otg_dev_pm_ops,
+#endif
+       },
+};
+
+module_platform_driver_probe(msm_otg_driver, msm_otg_probe);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM USB transceiver driver");
diff --git a/drivers/usb/phy/mv_otg.c b/drivers/usb/phy/mv_otg.c
new file mode 100644 (file)
index 0000000..b6a9be3
--- /dev/null
@@ -0,0 +1,923 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Author: Chao Xie <chao.xie@marvell.com>
+ *        Neil Zhang <zhangwm@marvell.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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_data/mv_usb.h>
+
+#include "mv_otg.h"
+
+#define        DRIVER_DESC     "Marvell USB OTG transceiver driver"
+#define        DRIVER_VERSION  "Jan 20, 2010"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static const char driver_name[] = "mv-otg";
+
+static char *state_string[] = {
+       "undefined",
+       "b_idle",
+       "b_srp_init",
+       "b_peripheral",
+       "b_wait_acon",
+       "b_host",
+       "a_idle",
+       "a_wait_vrise",
+       "a_wait_bcon",
+       "a_host",
+       "a_suspend",
+       "a_peripheral",
+       "a_wait_vfall",
+       "a_vbus_err"
+};
+
+static int mv_otg_set_vbus(struct usb_otg *otg, bool on)
+{
+       struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy);
+       if (mvotg->pdata->set_vbus == NULL)
+               return -ENODEV;
+
+       return mvotg->pdata->set_vbus(on);
+}
+
+static int mv_otg_set_host(struct usb_otg *otg,
+                          struct usb_bus *host)
+{
+       otg->host = host;
+
+       return 0;
+}
+
+static int mv_otg_set_peripheral(struct usb_otg *otg,
+                                struct usb_gadget *gadget)
+{
+       otg->gadget = gadget;
+
+       return 0;
+}
+
+static void mv_otg_run_state_machine(struct mv_otg *mvotg,
+                                    unsigned long delay)
+{
+       dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n");
+       if (!mvotg->qwork)
+               return;
+
+       queue_delayed_work(mvotg->qwork, &mvotg->work, delay);
+}
+
+static void mv_otg_timer_await_bcon(unsigned long data)
+{
+       struct mv_otg *mvotg = (struct mv_otg *) data;
+
+       mvotg->otg_ctrl.a_wait_bcon_timeout = 1;
+
+       dev_info(&mvotg->pdev->dev, "B Device No Response!\n");
+
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 0);
+               spin_unlock(&mvotg->wq_lock);
+       }
+}
+
+static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id)
+{
+       struct timer_list *timer;
+
+       if (id >= OTG_TIMER_NUM)
+               return -EINVAL;
+
+       timer = &mvotg->otg_ctrl.timer[id];
+
+       if (timer_pending(timer))
+               del_timer(timer);
+
+       return 0;
+}
+
+static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id,
+                           unsigned long interval,
+                           void (*callback) (unsigned long))
+{
+       struct timer_list *timer;
+
+       if (id >= OTG_TIMER_NUM)
+               return -EINVAL;
+
+       timer = &mvotg->otg_ctrl.timer[id];
+       if (timer_pending(timer)) {
+               dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id);
+               return -EBUSY;
+       }
+
+       init_timer(timer);
+       timer->data = (unsigned long) mvotg;
+       timer->function = callback;
+       timer->expires = jiffies + interval;
+       add_timer(timer);
+
+       return 0;
+}
+
+static int mv_otg_reset(struct mv_otg *mvotg)
+{
+       unsigned int loops;
+       u32 tmp;
+
+       /* Stop the controller */
+       tmp = readl(&mvotg->op_regs->usbcmd);
+       tmp &= ~USBCMD_RUN_STOP;
+       writel(tmp, &mvotg->op_regs->usbcmd);
+
+       /* Reset the controller to get default values */
+       writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd);
+
+       loops = 500;
+       while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) {
+               if (loops == 0) {
+                       dev_err(&mvotg->pdev->dev,
+                               "Wait for RESET completed TIMEOUT\n");
+                       return -ETIMEDOUT;
+               }
+               loops--;
+               udelay(20);
+       }
+
+       writel(0x0, &mvotg->op_regs->usbintr);
+       tmp = readl(&mvotg->op_regs->usbsts);
+       writel(tmp, &mvotg->op_regs->usbsts);
+
+       return 0;
+}
+
+static void mv_otg_init_irq(struct mv_otg *mvotg)
+{
+       u32 otgsc;
+
+       mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID
+           | OTGSC_INTR_A_VBUS_VALID;
+       mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID
+           | OTGSC_INTSTS_A_VBUS_VALID;
+
+       if (mvotg->pdata->vbus == NULL) {
+               mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID
+                   | OTGSC_INTR_B_SESSION_END;
+               mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID
+                   | OTGSC_INTSTS_B_SESSION_END;
+       }
+
+       if (mvotg->pdata->id == NULL) {
+               mvotg->irq_en |= OTGSC_INTR_USB_ID;
+               mvotg->irq_status |= OTGSC_INTSTS_USB_ID;
+       }
+
+       otgsc = readl(&mvotg->op_regs->otgsc);
+       otgsc |= mvotg->irq_en;
+       writel(otgsc, &mvotg->op_regs->otgsc);
+}
+
+static void mv_otg_start_host(struct mv_otg *mvotg, int on)
+{
+#ifdef CONFIG_USB
+       struct usb_otg *otg = mvotg->phy.otg;
+       struct usb_hcd *hcd;
+
+       if (!otg->host)
+               return;
+
+       dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop");
+
+       hcd = bus_to_hcd(otg->host);
+
+       if (on)
+               usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+       else
+               usb_remove_hcd(hcd);
+#endif /* CONFIG_USB */
+}
+
+static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
+{
+       struct usb_otg *otg = mvotg->phy.otg;
+
+       if (!otg->gadget)
+               return;
+
+       dev_info(mvotg->phy.dev, "gadget %s\n", on ? "on" : "off");
+
+       if (on)
+               usb_gadget_vbus_connect(otg->gadget);
+       else
+               usb_gadget_vbus_disconnect(otg->gadget);
+}
+
+static void otg_clock_enable(struct mv_otg *mvotg)
+{
+       unsigned int i;
+
+       for (i = 0; i < mvotg->clknum; i++)
+               clk_prepare_enable(mvotg->clk[i]);
+}
+
+static void otg_clock_disable(struct mv_otg *mvotg)
+{
+       unsigned int i;
+
+       for (i = 0; i < mvotg->clknum; i++)
+               clk_disable_unprepare(mvotg->clk[i]);
+}
+
+static int mv_otg_enable_internal(struct mv_otg *mvotg)
+{
+       int retval = 0;
+
+       if (mvotg->active)
+               return 0;
+
+       dev_dbg(&mvotg->pdev->dev, "otg enabled\n");
+
+       otg_clock_enable(mvotg);
+       if (mvotg->pdata->phy_init) {
+               retval = mvotg->pdata->phy_init(mvotg->phy_regs);
+               if (retval) {
+                       dev_err(&mvotg->pdev->dev,
+                               "init phy error %d\n", retval);
+                       otg_clock_disable(mvotg);
+                       return retval;
+               }
+       }
+       mvotg->active = 1;
+
+       return 0;
+
+}
+
+static int mv_otg_enable(struct mv_otg *mvotg)
+{
+       if (mvotg->clock_gating)
+               return mv_otg_enable_internal(mvotg);
+
+       return 0;
+}
+
+static void mv_otg_disable_internal(struct mv_otg *mvotg)
+{
+       if (mvotg->active) {
+               dev_dbg(&mvotg->pdev->dev, "otg disabled\n");
+               if (mvotg->pdata->phy_deinit)
+                       mvotg->pdata->phy_deinit(mvotg->phy_regs);
+               otg_clock_disable(mvotg);
+               mvotg->active = 0;
+       }
+}
+
+static void mv_otg_disable(struct mv_otg *mvotg)
+{
+       if (mvotg->clock_gating)
+               mv_otg_disable_internal(mvotg);
+}
+
+static void mv_otg_update_inputs(struct mv_otg *mvotg)
+{
+       struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
+       u32 otgsc;
+
+       otgsc = readl(&mvotg->op_regs->otgsc);
+
+       if (mvotg->pdata->vbus) {
+               if (mvotg->pdata->vbus->poll() == VBUS_HIGH) {
+                       otg_ctrl->b_sess_vld = 1;
+                       otg_ctrl->b_sess_end = 0;
+               } else {
+                       otg_ctrl->b_sess_vld = 0;
+                       otg_ctrl->b_sess_end = 1;
+               }
+       } else {
+               otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID);
+               otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END);
+       }
+
+       if (mvotg->pdata->id)
+               otg_ctrl->id = !!mvotg->pdata->id->poll();
+       else
+               otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID);
+
+       if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id)
+               otg_ctrl->a_bus_req = 1;
+
+       otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID);
+       otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID);
+
+       dev_dbg(&mvotg->pdev->dev, "%s: ", __func__);
+       dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id);
+       dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld);
+       dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end);
+       dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld);
+       dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld);
+}
+
+static void mv_otg_update_state(struct mv_otg *mvotg)
+{
+       struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
+       struct usb_phy *phy = &mvotg->phy;
+       int old_state = phy->state;
+
+       switch (old_state) {
+       case OTG_STATE_UNDEFINED:
+               phy->state = OTG_STATE_B_IDLE;
+               /* FALL THROUGH */
+       case OTG_STATE_B_IDLE:
+               if (otg_ctrl->id == 0)
+                       phy->state = OTG_STATE_A_IDLE;
+               else if (otg_ctrl->b_sess_vld)
+                       phy->state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
+                       phy->state = OTG_STATE_B_IDLE;
+               break;
+       case OTG_STATE_A_IDLE:
+               if (otg_ctrl->id)
+                       phy->state = OTG_STATE_B_IDLE;
+               else if (!(otg_ctrl->a_bus_drop) &&
+                        (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
+                       phy->state = OTG_STATE_A_WAIT_VRISE;
+               break;
+       case OTG_STATE_A_WAIT_VRISE:
+               if (otg_ctrl->a_vbus_vld)
+                       phy->state = OTG_STATE_A_WAIT_BCON;
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               if (otg_ctrl->id || otg_ctrl->a_bus_drop
+                   || otg_ctrl->a_wait_bcon_timeout) {
+                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+                       phy->state = OTG_STATE_A_WAIT_VFALL;
+                       otg_ctrl->a_bus_req = 0;
+               } else if (!otg_ctrl->a_vbus_vld) {
+                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+                       phy->state = OTG_STATE_A_VBUS_ERR;
+               } else if (otg_ctrl->b_conn) {
+                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+                       phy->state = OTG_STATE_A_HOST;
+               }
+               break;
+       case OTG_STATE_A_HOST:
+               if (otg_ctrl->id || !otg_ctrl->b_conn
+                   || otg_ctrl->a_bus_drop)
+                       phy->state = OTG_STATE_A_WAIT_BCON;
+               else if (!otg_ctrl->a_vbus_vld)
+                       phy->state = OTG_STATE_A_VBUS_ERR;
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               if (otg_ctrl->id
+                   || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
+                   || otg_ctrl->a_bus_req)
+                       phy->state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_A_VBUS_ERR:
+               if (otg_ctrl->id || otg_ctrl->a_clr_err
+                   || otg_ctrl->a_bus_drop) {
+                       otg_ctrl->a_clr_err = 0;
+                       phy->state = OTG_STATE_A_WAIT_VFALL;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void mv_otg_work(struct work_struct *work)
+{
+       struct mv_otg *mvotg;
+       struct usb_phy *phy;
+       struct usb_otg *otg;
+       int old_state;
+
+       mvotg = container_of(to_delayed_work(work), struct mv_otg, work);
+
+run:
+       /* work queue is single thread, or we need spin_lock to protect */
+       phy = &mvotg->phy;
+       otg = phy->otg;
+       old_state = phy->state;
+
+       if (!mvotg->active)
+               return;
+
+       mv_otg_update_inputs(mvotg);
+       mv_otg_update_state(mvotg);
+
+       if (old_state != phy->state) {
+               dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
+                        state_string[old_state],
+                        state_string[phy->state]);
+
+               switch (phy->state) {
+               case OTG_STATE_B_IDLE:
+                       otg->default_a = 0;
+                       if (old_state == OTG_STATE_B_PERIPHERAL)
+                               mv_otg_start_periphrals(mvotg, 0);
+                       mv_otg_reset(mvotg);
+                       mv_otg_disable(mvotg);
+                       break;
+               case OTG_STATE_B_PERIPHERAL:
+                       mv_otg_enable(mvotg);
+                       mv_otg_start_periphrals(mvotg, 1);
+                       break;
+               case OTG_STATE_A_IDLE:
+                       otg->default_a = 1;
+                       mv_otg_enable(mvotg);
+                       if (old_state == OTG_STATE_A_WAIT_VFALL)
+                               mv_otg_start_host(mvotg, 0);
+                       mv_otg_reset(mvotg);
+                       break;
+               case OTG_STATE_A_WAIT_VRISE:
+                       mv_otg_set_vbus(otg, 1);
+                       break;
+               case OTG_STATE_A_WAIT_BCON:
+                       if (old_state != OTG_STATE_A_HOST)
+                               mv_otg_start_host(mvotg, 1);
+                       mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER,
+                                        T_A_WAIT_BCON,
+                                        mv_otg_timer_await_bcon);
+                       /*
+                        * Now, we directly enter A_HOST. So set b_conn = 1
+                        * here. In fact, it need host driver to notify us.
+                        */
+                       mvotg->otg_ctrl.b_conn = 1;
+                       break;
+               case OTG_STATE_A_HOST:
+                       break;
+               case OTG_STATE_A_WAIT_VFALL:
+                       /*
+                        * Now, we has exited A_HOST. So set b_conn = 0
+                        * here. In fact, it need host driver to notify us.
+                        */
+                       mvotg->otg_ctrl.b_conn = 0;
+                       mv_otg_set_vbus(otg, 0);
+                       break;
+               case OTG_STATE_A_VBUS_ERR:
+                       break;
+               default:
+                       break;
+               }
+               goto run;
+       }
+}
+
+static irqreturn_t mv_otg_irq(int irq, void *dev)
+{
+       struct mv_otg *mvotg = dev;
+       u32 otgsc;
+
+       otgsc = readl(&mvotg->op_regs->otgsc);
+       writel(otgsc, &mvotg->op_regs->otgsc);
+
+       /*
+        * if we have vbus, then the vbus detection for B-device
+        * will be done by mv_otg_inputs_irq().
+        */
+       if (mvotg->pdata->vbus)
+               if ((otgsc & OTGSC_STS_USB_ID) &&
+                   !(otgsc & OTGSC_INTSTS_USB_ID))
+                       return IRQ_NONE;
+
+       if ((otgsc & mvotg->irq_status) == 0)
+               return IRQ_NONE;
+
+       mv_otg_run_state_machine(mvotg, 0);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
+{
+       struct mv_otg *mvotg = dev;
+
+       /* The clock may disabled at this time */
+       if (!mvotg->active) {
+               mv_otg_enable(mvotg);
+               mv_otg_init_irq(mvotg);
+       }
+
+       mv_otg_run_state_machine(mvotg, 0);
+
+       return IRQ_HANDLED;
+}
+
+static ssize_t
+get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        mvotg->otg_ctrl.a_bus_req);
+}
+
+static ssize_t
+set_a_bus_req(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+
+       if (count > 2)
+               return -1;
+
+       /* We will use this interface to change to A device */
+       if (mvotg->phy.state != OTG_STATE_B_IDLE
+           && mvotg->phy.state != OTG_STATE_A_IDLE)
+               return -1;
+
+       /* The clock may disabled and we need to set irq for ID detected */
+       mv_otg_enable(mvotg);
+       mv_otg_init_irq(mvotg);
+
+       if (buf[0] == '1') {
+               mvotg->otg_ctrl.a_bus_req = 1;
+               mvotg->otg_ctrl.a_bus_drop = 0;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_bus_req = 1\n");
+
+               if (spin_trylock(&mvotg->wq_lock)) {
+                       mv_otg_run_state_machine(mvotg, 0);
+                       spin_unlock(&mvotg->wq_lock);
+               }
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req,
+                  set_a_bus_req);
+
+static ssize_t
+set_a_clr_err(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       if (!mvotg->phy.otg->default_a)
+               return -1;
+
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '1') {
+               mvotg->otg_ctrl.a_clr_err = 1;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_clr_err = 1\n");
+       }
+
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 0);
+               spin_unlock(&mvotg->wq_lock);
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
+
+static ssize_t
+get_a_bus_drop(struct device *dev, struct device_attribute *attr,
+              char *buf)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        mvotg->otg_ctrl.a_bus_drop);
+}
+
+static ssize_t
+set_a_bus_drop(struct device *dev, struct device_attribute *attr,
+              const char *buf, size_t count)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       if (!mvotg->phy.otg->default_a)
+               return -1;
+
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '0') {
+               mvotg->otg_ctrl.a_bus_drop = 0;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_bus_drop = 0\n");
+       } else if (buf[0] == '1') {
+               mvotg->otg_ctrl.a_bus_drop = 1;
+               mvotg->otg_ctrl.a_bus_req = 0;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_bus_drop = 1\n");
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: and a_bus_req = 0\n");
+       }
+
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 0);
+               spin_unlock(&mvotg->wq_lock);
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR,
+                  get_a_bus_drop, set_a_bus_drop);
+
+static struct attribute *inputs_attrs[] = {
+       &dev_attr_a_bus_req.attr,
+       &dev_attr_a_clr_err.attr,
+       &dev_attr_a_bus_drop.attr,
+       NULL,
+};
+
+static struct attribute_group inputs_attr_group = {
+       .name = "inputs",
+       .attrs = inputs_attrs,
+};
+
+int mv_otg_remove(struct platform_device *pdev)
+{
+       struct mv_otg *mvotg = platform_get_drvdata(pdev);
+
+       sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group);
+
+       if (mvotg->qwork) {
+               flush_workqueue(mvotg->qwork);
+               destroy_workqueue(mvotg->qwork);
+       }
+
+       mv_otg_disable(mvotg);
+
+       usb_remove_phy(&mvotg->phy);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static int mv_otg_probe(struct platform_device *pdev)
+{
+       struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct mv_otg *mvotg;
+       struct usb_otg *otg;
+       struct resource *r;
+       int retval = 0, clk_i, i;
+       size_t size;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "failed to get platform data\n");
+               return -ENODEV;
+       }
+
+       size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum;
+       mvotg = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!mvotg) {
+               dev_err(&pdev->dev, "failed to allocate memory!\n");
+               return -ENOMEM;
+       }
+
+       otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+       if (!otg)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, mvotg);
+
+       mvotg->pdev = pdev;
+       mvotg->pdata = pdata;
+
+       mvotg->clknum = pdata->clknum;
+       for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) {
+               mvotg->clk[clk_i] = devm_clk_get(&pdev->dev,
+                                               pdata->clkname[clk_i]);
+               if (IS_ERR(mvotg->clk[clk_i])) {
+                       retval = PTR_ERR(mvotg->clk[clk_i]);
+                       return retval;
+               }
+       }
+
+       mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
+       if (!mvotg->qwork) {
+               dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n");
+               return -ENOMEM;
+       }
+
+       INIT_DELAYED_WORK(&mvotg->work, mv_otg_work);
+
+       /* OTG common part */
+       mvotg->pdev = pdev;
+       mvotg->phy.dev = &pdev->dev;
+       mvotg->phy.otg = otg;
+       mvotg->phy.label = driver_name;
+       mvotg->phy.state = OTG_STATE_UNDEFINED;
+
+       otg->phy = &mvotg->phy;
+       otg->set_host = mv_otg_set_host;
+       otg->set_peripheral = mv_otg_set_peripheral;
+       otg->set_vbus = mv_otg_set_vbus;
+
+       for (i = 0; i < OTG_TIMER_NUM; i++)
+               init_timer(&mvotg->otg_ctrl.timer[i]);
+
+       r = platform_get_resource_byname(mvotg->pdev,
+                                        IORESOURCE_MEM, "phyregs");
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+               retval = -ENODEV;
+               goto err_destroy_workqueue;
+       }
+
+       mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+       if (mvotg->phy_regs == NULL) {
+               dev_err(&pdev->dev, "failed to map phy I/O memory\n");
+               retval = -EFAULT;
+               goto err_destroy_workqueue;
+       }
+
+       r = platform_get_resource_byname(mvotg->pdev,
+                                        IORESOURCE_MEM, "capregs");
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no I/O memory resource defined\n");
+               retval = -ENODEV;
+               goto err_destroy_workqueue;
+       }
+
+       mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+       if (mvotg->cap_regs == NULL) {
+               dev_err(&pdev->dev, "failed to map I/O memory\n");
+               retval = -EFAULT;
+               goto err_destroy_workqueue;
+       }
+
+       /* we will acces controller register, so enable the udc controller */
+       retval = mv_otg_enable_internal(mvotg);
+       if (retval) {
+               dev_err(&pdev->dev, "mv otg enable error %d\n", retval);
+               goto err_destroy_workqueue;
+       }
+
+       mvotg->op_regs =
+               (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs
+                       + (readl(mvotg->cap_regs) & CAPLENGTH_MASK));
+
+       if (pdata->id) {
+               retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq,
+                                               NULL, mv_otg_inputs_irq,
+                                               IRQF_ONESHOT, "id", mvotg);
+               if (retval) {
+                       dev_info(&pdev->dev,
+                                "Failed to request irq for ID\n");
+                       pdata->id = NULL;
+               }
+       }
+
+       if (pdata->vbus) {
+               mvotg->clock_gating = 1;
+               retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq,
+                                               NULL, mv_otg_inputs_irq,
+                                               IRQF_ONESHOT, "vbus", mvotg);
+               if (retval) {
+                       dev_info(&pdev->dev,
+                                "Failed to request irq for VBUS, "
+                                "disable clock gating\n");
+                       mvotg->clock_gating = 0;
+                       pdata->vbus = NULL;
+               }
+       }
+
+       if (pdata->disable_otg_clock_gating)
+               mvotg->clock_gating = 0;
+
+       mv_otg_reset(mvotg);
+       mv_otg_init_irq(mvotg);
+
+       r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0);
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no IRQ resource defined\n");
+               retval = -ENODEV;
+               goto err_disable_clk;
+       }
+
+       mvotg->irq = r->start;
+       if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED,
+                       driver_name, mvotg)) {
+               dev_err(&pdev->dev, "Request irq %d for OTG failed\n",
+                       mvotg->irq);
+               mvotg->irq = 0;
+               retval = -ENODEV;
+               goto err_disable_clk;
+       }
+
+       retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2);
+       if (retval < 0) {
+               dev_err(&pdev->dev, "can't register transceiver, %d\n",
+                       retval);
+               goto err_disable_clk;
+       }
+
+       retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group);
+       if (retval < 0) {
+               dev_dbg(&pdev->dev,
+                       "Can't register sysfs attr group: %d\n", retval);
+               goto err_remove_phy;
+       }
+
+       spin_lock_init(&mvotg->wq_lock);
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 2 * HZ);
+               spin_unlock(&mvotg->wq_lock);
+       }
+
+       dev_info(&pdev->dev,
+                "successful probe OTG device %s clock gating.\n",
+                mvotg->clock_gating ? "with" : "without");
+
+       return 0;
+
+err_remove_phy:
+       usb_remove_phy(&mvotg->phy);
+err_disable_clk:
+       mv_otg_disable_internal(mvotg);
+err_destroy_workqueue:
+       flush_workqueue(mvotg->qwork);
+       destroy_workqueue(mvotg->qwork);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return retval;
+}
+
+#ifdef CONFIG_PM
+static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct mv_otg *mvotg = platform_get_drvdata(pdev);
+
+       if (mvotg->phy.state != OTG_STATE_B_IDLE) {
+               dev_info(&pdev->dev,
+                        "OTG state is not B_IDLE, it is %d!\n",
+                        mvotg->phy.state);
+               return -EAGAIN;
+       }
+
+       if (!mvotg->clock_gating)
+               mv_otg_disable_internal(mvotg);
+
+       return 0;
+}
+
+static int mv_otg_resume(struct platform_device *pdev)
+{
+       struct mv_otg *mvotg = platform_get_drvdata(pdev);
+       u32 otgsc;
+
+       if (!mvotg->clock_gating) {
+               mv_otg_enable_internal(mvotg);
+
+               otgsc = readl(&mvotg->op_regs->otgsc);
+               otgsc |= mvotg->irq_en;
+               writel(otgsc, &mvotg->op_regs->otgsc);
+
+               if (spin_trylock(&mvotg->wq_lock)) {
+                       mv_otg_run_state_machine(mvotg, 0);
+                       spin_unlock(&mvotg->wq_lock);
+               }
+       }
+       return 0;
+}
+#endif
+
+static struct platform_driver mv_otg_driver = {
+       .probe = mv_otg_probe,
+       .remove = __exit_p(mv_otg_remove),
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = driver_name,
+                  },
+#ifdef CONFIG_PM
+       .suspend = mv_otg_suspend,
+       .resume = mv_otg_resume,
+#endif
+};
+module_platform_driver(mv_otg_driver);
diff --git a/drivers/usb/phy/mv_otg.h b/drivers/usb/phy/mv_otg.h
new file mode 100644 (file)
index 0000000..8a9e351
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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 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.
+ */
+
+#ifndef        __MV_USB_OTG_CONTROLLER__
+#define        __MV_USB_OTG_CONTROLLER__
+
+#include <linux/types.h>
+
+/* Command Register Bit Masks */
+#define USBCMD_RUN_STOP                        (0x00000001)
+#define USBCMD_CTRL_RESET              (0x00000002)
+
+/* otgsc Register Bit Masks */
+#define OTGSC_CTRL_VUSB_DISCHARGE              0x00000001
+#define OTGSC_CTRL_VUSB_CHARGE                 0x00000002
+#define OTGSC_CTRL_OTG_TERM                    0x00000008
+#define OTGSC_CTRL_DATA_PULSING                        0x00000010
+#define OTGSC_STS_USB_ID                       0x00000100
+#define OTGSC_STS_A_VBUS_VALID                 0x00000200
+#define OTGSC_STS_A_SESSION_VALID              0x00000400
+#define OTGSC_STS_B_SESSION_VALID              0x00000800
+#define OTGSC_STS_B_SESSION_END                        0x00001000
+#define OTGSC_STS_1MS_TOGGLE                   0x00002000
+#define OTGSC_STS_DATA_PULSING                 0x00004000
+#define OTGSC_INTSTS_USB_ID                    0x00010000
+#define OTGSC_INTSTS_A_VBUS_VALID              0x00020000
+#define OTGSC_INTSTS_A_SESSION_VALID           0x00040000
+#define OTGSC_INTSTS_B_SESSION_VALID           0x00080000
+#define OTGSC_INTSTS_B_SESSION_END             0x00100000
+#define OTGSC_INTSTS_1MS                       0x00200000
+#define OTGSC_INTSTS_DATA_PULSING              0x00400000
+#define OTGSC_INTR_USB_ID                      0x01000000
+#define OTGSC_INTR_A_VBUS_VALID                        0x02000000
+#define OTGSC_INTR_A_SESSION_VALID             0x04000000
+#define OTGSC_INTR_B_SESSION_VALID             0x08000000
+#define OTGSC_INTR_B_SESSION_END               0x10000000
+#define OTGSC_INTR_1MS_TIMER                   0x20000000
+#define OTGSC_INTR_DATA_PULSING                        0x40000000
+
+#define CAPLENGTH_MASK         (0xff)
+
+/* Timer's interval, unit 10ms */
+#define T_A_WAIT_VRISE         100
+#define T_A_WAIT_BCON          2000
+#define T_A_AIDL_BDIS          100
+#define T_A_BIDL_ADIS          20
+#define T_B_ASE0_BRST          400
+#define T_B_SE0_SRP            300
+#define T_B_SRP_FAIL           2000
+#define T_B_DATA_PLS           10
+#define T_B_SRP_INIT           100
+#define T_A_SRP_RSPNS          10
+#define T_A_DRV_RSM            5
+
+enum otg_function {
+       OTG_B_DEVICE = 0,
+       OTG_A_DEVICE
+};
+
+enum mv_otg_timer {
+       A_WAIT_BCON_TIMER = 0,
+       OTG_TIMER_NUM
+};
+
+/* PXA OTG state machine */
+struct mv_otg_ctrl {
+       /* internal variables */
+       u8 a_set_b_hnp_en;      /* A-Device set b_hnp_en */
+       u8 b_srp_done;
+       u8 b_hnp_en;
+
+       /* OTG inputs */
+       u8 a_bus_drop;
+       u8 a_bus_req;
+       u8 a_clr_err;
+       u8 a_bus_resume;
+       u8 a_bus_suspend;
+       u8 a_conn;
+       u8 a_sess_vld;
+       u8 a_srp_det;
+       u8 a_vbus_vld;
+       u8 b_bus_req;           /* B-Device Require Bus */
+       u8 b_bus_resume;
+       u8 b_bus_suspend;
+       u8 b_conn;
+       u8 b_se0_srp;
+       u8 b_sess_end;
+       u8 b_sess_vld;
+       u8 id;
+       u8 a_suspend_req;
+
+       /*Timer event */
+       u8 a_aidl_bdis_timeout;
+       u8 b_ase0_brst_timeout;
+       u8 a_bidl_adis_timeout;
+       u8 a_wait_bcon_timeout;
+
+       struct timer_list timer[OTG_TIMER_NUM];
+};
+
+#define VUSBHS_MAX_PORTS       8
+
+struct mv_otg_regs {
+       u32 usbcmd;             /* Command register */
+       u32 usbsts;             /* Status register */
+       u32 usbintr;            /* Interrupt enable */
+       u32 frindex;            /* Frame index */
+       u32 reserved1[1];
+       u32 deviceaddr;         /* Device Address */
+       u32 eplistaddr;         /* Endpoint List Address */
+       u32 ttctrl;             /* HOST TT status and control */
+       u32 burstsize;          /* Programmable Burst Size */
+       u32 txfilltuning;       /* Host Transmit Pre-Buffer Packet Tuning */
+       u32 reserved[4];
+       u32 epnak;              /* Endpoint NAK */
+       u32 epnaken;            /* Endpoint NAK Enable */
+       u32 configflag;         /* Configured Flag register */
+       u32 portsc[VUSBHS_MAX_PORTS];   /* Port Status/Control x, x = 1..8 */
+       u32 otgsc;
+       u32 usbmode;            /* USB Host/Device mode */
+       u32 epsetupstat;        /* Endpoint Setup Status */
+       u32 epprime;            /* Endpoint Initialize */
+       u32 epflush;            /* Endpoint De-initialize */
+       u32 epstatus;           /* Endpoint Status */
+       u32 epcomplete;         /* Endpoint Interrupt On Complete */
+       u32 epctrlx[16];        /* Endpoint Control, where x = 0.. 15 */
+       u32 mcr;                /* Mux Control */
+       u32 isr;                /* Interrupt Status */
+       u32 ier;                /* Interrupt Enable */
+};
+
+struct mv_otg {
+       struct usb_phy phy;
+       struct mv_otg_ctrl otg_ctrl;
+
+       /* base address */
+       void __iomem *phy_regs;
+       void __iomem *cap_regs;
+       struct mv_otg_regs __iomem *op_regs;
+
+       struct platform_device *pdev;
+       int irq;
+       u32 irq_status;
+       u32 irq_en;
+
+       struct delayed_work work;
+       struct workqueue_struct *qwork;
+
+       spinlock_t wq_lock;
+
+       struct mv_usb_platform_data *pdata;
+
+       unsigned int active;
+       unsigned int clock_gating;
+       unsigned int clknum;
+       struct clk *clk[0];
+};
+
+#endif
diff --git a/drivers/usb/phy/mxs-phy.c b/drivers/usb/phy/mxs-phy.c
new file mode 100644 (file)
index 0000000..9d4381e
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/usb/otg.h>
+#include <linux/stmp_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME "mxs_phy"
+
+#define HW_USBPHY_PWD                          0x00
+#define HW_USBPHY_CTRL                         0x30
+#define HW_USBPHY_CTRL_SET                     0x34
+#define HW_USBPHY_CTRL_CLR                     0x38
+
+#define BM_USBPHY_CTRL_SFTRST                  BIT(31)
+#define BM_USBPHY_CTRL_CLKGATE                 BIT(30)
+#define BM_USBPHY_CTRL_ENUTMILEVEL3            BIT(15)
+#define BM_USBPHY_CTRL_ENUTMILEVEL2            BIT(14)
+#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT      BIT(1)
+
+struct mxs_phy {
+       struct usb_phy phy;
+       struct clk *clk;
+};
+
+#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
+
+static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
+{
+       void __iomem *base = mxs_phy->phy.io_priv;
+
+       stmp_reset_block(base + HW_USBPHY_CTRL);
+
+       /* Power up the PHY */
+       writel(0, base + HW_USBPHY_PWD);
+
+       /* enable FS/LS device */
+       writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
+              BM_USBPHY_CTRL_ENUTMILEVEL3,
+              base + HW_USBPHY_CTRL_SET);
+}
+
+static int mxs_phy_init(struct usb_phy *phy)
+{
+       struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+
+       clk_prepare_enable(mxs_phy->clk);
+       mxs_phy_hw_init(mxs_phy);
+
+       return 0;
+}
+
+static void mxs_phy_shutdown(struct usb_phy *phy)
+{
+       struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+
+       writel(BM_USBPHY_CTRL_CLKGATE,
+              phy->io_priv + HW_USBPHY_CTRL_SET);
+
+       clk_disable_unprepare(mxs_phy->clk);
+}
+
+static int mxs_phy_suspend(struct usb_phy *x, int suspend)
+{
+       struct mxs_phy *mxs_phy = to_mxs_phy(x);
+
+       if (suspend) {
+               writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+               writel(BM_USBPHY_CTRL_CLKGATE,
+                      x->io_priv + HW_USBPHY_CTRL_SET);
+               clk_disable_unprepare(mxs_phy->clk);
+       } else {
+               clk_prepare_enable(mxs_phy->clk);
+               writel(BM_USBPHY_CTRL_CLKGATE,
+                      x->io_priv + HW_USBPHY_CTRL_CLR);
+               writel(0, x->io_priv + HW_USBPHY_PWD);
+       }
+
+       return 0;
+}
+
+static int mxs_phy_on_connect(struct usb_phy *phy,
+               enum usb_device_speed speed)
+{
+       dev_dbg(phy->dev, "%s speed device has connected\n",
+               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
+
+       if (speed == USB_SPEED_HIGH)
+               writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+                      phy->io_priv + HW_USBPHY_CTRL_SET);
+
+       return 0;
+}
+
+static int mxs_phy_on_disconnect(struct usb_phy *phy,
+               enum usb_device_speed speed)
+{
+       dev_dbg(phy->dev, "%s speed device has disconnected\n",
+               (speed == USB_SPEED_HIGH) ? "high" : "non-high");
+
+       if (speed == USB_SPEED_HIGH)
+               writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+                      phy->io_priv + HW_USBPHY_CTRL_CLR);
+
+       return 0;
+}
+
+static int mxs_phy_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       void __iomem *base;
+       struct clk *clk;
+       struct mxs_phy *mxs_phy;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't get device resources\n");
+               return -ENOENT;
+       }
+
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev,
+                       "can't get the clock, err=%ld", PTR_ERR(clk));
+               return PTR_ERR(clk);
+       }
+
+       mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
+       if (!mxs_phy) {
+               dev_err(&pdev->dev, "Failed to allocate USB PHY structure!\n");
+               return -ENOMEM;
+       }
+
+       mxs_phy->phy.io_priv            = base;
+       mxs_phy->phy.dev                = &pdev->dev;
+       mxs_phy->phy.label              = DRIVER_NAME;
+       mxs_phy->phy.init               = mxs_phy_init;
+       mxs_phy->phy.shutdown           = mxs_phy_shutdown;
+       mxs_phy->phy.set_suspend        = mxs_phy_suspend;
+       mxs_phy->phy.notify_connect     = mxs_phy_on_connect;
+       mxs_phy->phy.notify_disconnect  = mxs_phy_on_disconnect;
+
+       ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier);
+
+       mxs_phy->clk = clk;
+
+       platform_set_drvdata(pdev, &mxs_phy->phy);
+
+       ret = usb_add_phy_dev(&mxs_phy->phy);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int mxs_phy_remove(struct platform_device *pdev)
+{
+       struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&mxs_phy->phy);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id mxs_phy_dt_ids[] = {
+       { .compatible = "fsl,imx23-usbphy", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
+
+static struct platform_driver mxs_phy_driver = {
+       .probe = mxs_phy_probe,
+       .remove = mxs_phy_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = mxs_phy_dt_ids,
+        },
+};
+
+static int __init mxs_phy_module_init(void)
+{
+       return platform_driver_register(&mxs_phy_driver);
+}
+postcore_initcall(mxs_phy_module_init);
+
+static void __exit mxs_phy_module_exit(void)
+{
+       platform_driver_unregister(&mxs_phy_driver);
+}
+module_exit(mxs_phy_module_exit);
+
+MODULE_ALIAS("platform:mxs-usb-phy");
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
+MODULE_DESCRIPTION("Freescale MXS USB PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/nop-usb-xceiv.c b/drivers/usb/phy/nop-usb-xceiv.c
new file mode 100644 (file)
index 0000000..2b10cc9
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * drivers/usb/otg/nop-usb-xceiv.c
+ *
+ * NOP USB transceiver for all USB transceiver which are either built-in
+ * into USB IP or which are mostly autonomous.
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Ajay Kumar Gupta <ajay.gupta@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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Current status:
+ *     This provides a "nop" transceiver for PHYs which are
+ *     autonomous such as isp1504, isp1707, etc.
+ */
+
+#include <linux/module.h>
+#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>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+
+struct nop_usb_xceiv {
+       struct usb_phy phy;
+       struct device *dev;
+       struct clk *clk;
+       struct regulator *vcc;
+       struct regulator *reset;
+};
+
+static struct platform_device *pd;
+
+void usb_nop_xceiv_register(void)
+{
+       if (pd)
+               return;
+       pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
+       if (!pd) {
+               printk(KERN_ERR "Unable to register usb nop transceiver\n");
+               return;
+       }
+}
+EXPORT_SYMBOL(usb_nop_xceiv_register);
+
+void usb_nop_xceiv_unregister(void)
+{
+       platform_device_unregister(pd);
+       pd = NULL;
+}
+EXPORT_SYMBOL(usb_nop_xceiv_unregister);
+
+static int nop_set_suspend(struct usb_phy *x, int suspend)
+{
+       return 0;
+}
+
+static int nop_init(struct usb_phy *phy)
+{
+       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+       if (!IS_ERR(nop->vcc)) {
+               if (regulator_enable(nop->vcc))
+                       dev_err(phy->dev, "Failed to enable power\n");
+       }
+
+       if (!IS_ERR(nop->clk))
+               clk_enable(nop->clk);
+
+       if (!IS_ERR(nop->reset)) {
+               /* De-assert RESET */
+               if (regulator_enable(nop->reset))
+                       dev_err(phy->dev, "Failed to de-assert reset\n");
+       }
+
+       return 0;
+}
+
+static void nop_shutdown(struct usb_phy *phy)
+{
+       struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+       if (!IS_ERR(nop->reset)) {
+               /* Assert RESET */
+               if (regulator_disable(nop->reset))
+                       dev_err(phy->dev, "Failed to assert reset\n");
+       }
+
+       if (!IS_ERR(nop->clk))
+               clk_disable(nop->clk);
+
+       if (!IS_ERR(nop->vcc)) {
+               if (regulator_disable(nop->vcc))
+                       dev_err(phy->dev, "Failed to disable power\n");
+       }
+}
+
+static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
+{
+       if (!otg)
+               return -ENODEV;
+
+       if (!gadget) {
+               otg->gadget = NULL;
+               return -ENODEV;
+       }
+
+       otg->gadget = gadget;
+       otg->phy->state = OTG_STATE_B_IDLE;
+       return 0;
+}
+
+static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       if (!otg)
+               return -ENODEV;
+
+       if (!host) {
+               otg->host = NULL;
+               return -ENODEV;
+       }
+
+       otg->host = host;
+       return 0;
+}
+
+static int nop_usb_xceiv_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       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;
+       u32 clk_rate = 0;
+       bool needs_vcc = false;
+       bool needs_reset = false;
+
+       nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
+       if (!nop)
+               return -ENOMEM;
+
+       nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
+                                                       GFP_KERNEL);
+       if (!nop->phy.otg)
+               return -ENOMEM;
+
+       if (dev->of_node) {
+               struct device_node *node = dev->of_node;
+
+               if (of_property_read_u32(node, "clock-frequency", &clk_rate))
+                       clk_rate = 0;
+
+               needs_vcc = of_property_read_bool(node, "vcc-supply");
+               needs_reset = of_property_read_bool(node, "reset-supply");
+
+       } else if (pdata) {
+               type = pdata->type;
+               clk_rate = pdata->clk_rate;
+               needs_vcc = pdata->needs_vcc;
+               needs_reset = pdata->needs_reset;
+       }
+
+       nop->clk = devm_clk_get(&pdev->dev, "main_clk");
+       if (IS_ERR(nop->clk)) {
+               dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
+                                       PTR_ERR(nop->clk));
+       }
+
+       if (!IS_ERR(nop->clk) && clk_rate) {
+               err = clk_set_rate(nop->clk, clk_rate);
+               if (err) {
+                       dev_err(&pdev->dev, "Error setting clock rate\n");
+                       return err;
+               }
+       }
+
+       if (!IS_ERR(nop->clk)) {
+               err = clk_prepare(nop->clk);
+               if (err) {
+                       dev_err(&pdev->dev, "Error preparing clock\n");
+                       return err;
+               }
+       }
+
+       nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
+       if (IS_ERR(nop->vcc)) {
+               dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
+                                       PTR_ERR(nop->vcc));
+               if (needs_vcc)
+                       return -EPROBE_DEFER;
+       }
+
+       nop->reset = devm_regulator_get(&pdev->dev, "reset");
+       if (IS_ERR(nop->reset)) {
+               dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
+                                       PTR_ERR(nop->reset));
+               if (needs_reset)
+                       return -EPROBE_DEFER;
+       }
+
+       nop->dev                = &pdev->dev;
+       nop->phy.dev            = nop->dev;
+       nop->phy.label          = "nop-xceiv";
+       nop->phy.set_suspend    = nop_set_suspend;
+       nop->phy.init           = nop_init;
+       nop->phy.shutdown       = nop_shutdown;
+       nop->phy.state          = OTG_STATE_UNDEFINED;
+       nop->phy.type           = type;
+
+       nop->phy.otg->phy               = &nop->phy;
+       nop->phy.otg->set_host          = nop_set_host;
+       nop->phy.otg->set_peripheral    = nop_set_peripheral;
+
+       err = usb_add_phy_dev(&nop->phy);
+       if (err) {
+               dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
+                       err);
+               goto err_add;
+       }
+
+       platform_set_drvdata(pdev, nop);
+
+       ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
+
+       return 0;
+
+err_add:
+       if (!IS_ERR(nop->clk))
+               clk_unprepare(nop->clk);
+       return err;
+}
+
+static int nop_usb_xceiv_remove(struct platform_device *pdev)
+{
+       struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
+
+       if (!IS_ERR(nop->clk))
+               clk_unprepare(nop->clk);
+
+       usb_remove_phy(&nop->phy);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id nop_xceiv_dt_ids[] = {
+       { .compatible = "usb-nop-xceiv" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
+
+static struct platform_driver nop_usb_xceiv_driver = {
+       .probe          = nop_usb_xceiv_probe,
+       .remove         = nop_usb_xceiv_remove,
+       .driver         = {
+               .name   = "nop_usb_xceiv",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(nop_xceiv_dt_ids),
+       },
+};
+
+static int __init nop_usb_xceiv_init(void)
+{
+       return platform_driver_register(&nop_usb_xceiv_driver);
+}
+subsys_initcall(nop_usb_xceiv_init);
+
+static void __exit nop_usb_xceiv_exit(void)
+{
+       platform_driver_unregister(&nop_usb_xceiv_driver);
+}
+module_exit(nop_usb_xceiv_exit);
+
+MODULE_ALIAS("platform:nop_usb_xceiv");
+MODULE_AUTHOR("Texas Instruments Inc");
+MODULE_DESCRIPTION("NOP USB Transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/otg_fsm.c b/drivers/usb/phy/otg_fsm.c
new file mode 100644 (file)
index 0000000..1f729a1
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * OTG Finite State Machine from OTG spec
+ *
+ * Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
+ *
+ * Author:     Li Yang <LeoLi@freescale.com>
+ *             Jerry Huang <Chang-Ming.Huang@freescale.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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+
+#include "otg_fsm.h"
+
+/* Change USB protocol when there is a protocol change */
+static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
+{
+       int ret = 0;
+
+       if (fsm->protocol != protocol) {
+               VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
+                       fsm->protocol, protocol);
+               /* stop old protocol */
+               if (fsm->protocol == PROTO_HOST)
+                       ret = fsm->ops->start_host(fsm, 0);
+               else if (fsm->protocol == PROTO_GADGET)
+                       ret = fsm->ops->start_gadget(fsm, 0);
+               if (ret)
+                       return ret;
+
+               /* start new protocol */
+               if (protocol == PROTO_HOST)
+                       ret = fsm->ops->start_host(fsm, 1);
+               else if (protocol == PROTO_GADGET)
+                       ret = fsm->ops->start_gadget(fsm, 1);
+               if (ret)
+                       return ret;
+
+               fsm->protocol = protocol;
+               return 0;
+       }
+
+       return 0;
+}
+
+static int state_changed;
+
+/* Called when leaving a state.  Do state clean up jobs here */
+void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
+{
+       switch (old_state) {
+       case OTG_STATE_B_IDLE:
+               otg_del_timer(fsm, b_se0_srp_tmr);
+               fsm->b_se0_srp = 0;
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               fsm->b_srp_done = 0;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+               otg_del_timer(fsm, b_ase0_brst_tmr);
+               fsm->b_ase0_brst_tmout = 0;
+               break;
+       case OTG_STATE_B_HOST:
+               break;
+       case OTG_STATE_A_IDLE:
+               break;
+       case OTG_STATE_A_WAIT_VRISE:
+               otg_del_timer(fsm, a_wait_vrise_tmr);
+               fsm->a_wait_vrise_tmout = 0;
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               otg_del_timer(fsm, a_wait_bcon_tmr);
+               fsm->a_wait_bcon_tmout = 0;
+               break;
+       case OTG_STATE_A_HOST:
+               otg_del_timer(fsm, a_wait_enum_tmr);
+               break;
+       case OTG_STATE_A_SUSPEND:
+               otg_del_timer(fsm, a_aidl_bdis_tmr);
+               fsm->a_aidl_bdis_tmout = 0;
+               fsm->a_suspend_req = 0;
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               otg_del_timer(fsm, a_wait_vrise_tmr);
+               break;
+       case OTG_STATE_A_VBUS_ERR:
+               break;
+       default:
+               break;
+       }
+}
+
+/* Called when entering a state */
+int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
+{
+       state_changed = 1;
+       if (fsm->otg->phy->state == new_state)
+               return 0;
+       VDBG("Set state: %s\n", usb_otg_state_string(new_state));
+       otg_leave_state(fsm, fsm->otg->phy->state);
+       switch (new_state) {
+       case OTG_STATE_B_IDLE:
+               otg_drv_vbus(fsm, 0);
+               otg_chrg_vbus(fsm, 0);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_UNDEF);
+               otg_add_timer(fsm, b_se0_srp_tmr);
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               otg_start_pulse(fsm);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_UNDEF);
+               otg_add_timer(fsm, b_srp_fail_tmr);
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               otg_chrg_vbus(fsm, 0);
+               otg_loc_conn(fsm, 1);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_GADGET);
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+               otg_chrg_vbus(fsm, 0);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_HOST);
+               otg_add_timer(fsm, b_ase0_brst_tmr);
+               fsm->a_bus_suspend = 0;
+               break;
+       case OTG_STATE_B_HOST:
+               otg_chrg_vbus(fsm, 0);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 1);
+               otg_set_protocol(fsm, PROTO_HOST);
+               usb_bus_start_enum(fsm->otg->host,
+                               fsm->otg->host->otg_port);
+               break;
+       case OTG_STATE_A_IDLE:
+               otg_drv_vbus(fsm, 0);
+               otg_chrg_vbus(fsm, 0);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_HOST);
+               break;
+       case OTG_STATE_A_WAIT_VRISE:
+               otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_HOST);
+               otg_add_timer(fsm, a_wait_vrise_tmr);
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_HOST);
+               otg_add_timer(fsm, a_wait_bcon_tmr);
+               break;
+       case OTG_STATE_A_HOST:
+               otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 1);
+               otg_set_protocol(fsm, PROTO_HOST);
+               /*
+                * When HNP is triggered while a_bus_req = 0, a_host will
+                * suspend too fast to complete a_set_b_hnp_en
+                */
+               if (!fsm->a_bus_req || fsm->a_suspend_req)
+                       otg_add_timer(fsm, a_wait_enum_tmr);
+               break;
+       case OTG_STATE_A_SUSPEND:
+               otg_drv_vbus(fsm, 1);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_HOST);
+               otg_add_timer(fsm, a_aidl_bdis_tmr);
+
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               otg_loc_conn(fsm, 1);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_GADGET);
+               otg_drv_vbus(fsm, 1);
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               otg_drv_vbus(fsm, 0);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_HOST);
+               break;
+       case OTG_STATE_A_VBUS_ERR:
+               otg_drv_vbus(fsm, 0);
+               otg_loc_conn(fsm, 0);
+               otg_loc_sof(fsm, 0);
+               otg_set_protocol(fsm, PROTO_UNDEF);
+               break;
+       default:
+               break;
+       }
+
+       fsm->otg->phy->state = new_state;
+       return 0;
+}
+
+/* State change judgement */
+int otg_statemachine(struct otg_fsm *fsm)
+{
+       enum usb_otg_state state;
+       unsigned long flags;
+
+       spin_lock_irqsave(&fsm->lock, flags);
+
+       state = fsm->otg->phy->state;
+       state_changed = 0;
+       /* State machine state change judgement */
+
+       switch (state) {
+       case OTG_STATE_UNDEFINED:
+               VDBG("fsm->id = %d\n", fsm->id);
+               if (fsm->id)
+                       otg_set_state(fsm, OTG_STATE_B_IDLE);
+               else
+                       otg_set_state(fsm, OTG_STATE_A_IDLE);
+               break;
+       case OTG_STATE_B_IDLE:
+               if (!fsm->id)
+                       otg_set_state(fsm, OTG_STATE_A_IDLE);
+               else if (fsm->b_sess_vld && fsm->otg->gadget)
+                       otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+               else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp)
+                       otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               if (!fsm->id || fsm->b_srp_done)
+                       otg_set_state(fsm, OTG_STATE_B_IDLE);
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (!fsm->id || !fsm->b_sess_vld)
+                       otg_set_state(fsm, OTG_STATE_B_IDLE);
+               else if (fsm->b_bus_req && fsm->otg->
+                               gadget->b_hnp_enable && fsm->a_bus_suspend)
+                       otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+               if (fsm->a_conn)
+                       otg_set_state(fsm, OTG_STATE_B_HOST);
+               else if (!fsm->id || !fsm->b_sess_vld)
+                       otg_set_state(fsm, OTG_STATE_B_IDLE);
+               else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) {
+                       fsm->b_ase0_brst_tmout = 0;
+                       otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+               }
+               break;
+       case OTG_STATE_B_HOST:
+               if (!fsm->id || !fsm->b_sess_vld)
+                       otg_set_state(fsm, OTG_STATE_B_IDLE);
+               else if (!fsm->b_bus_req || !fsm->a_conn)
+                       otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
+               break;
+       case OTG_STATE_A_IDLE:
+               if (fsm->id)
+                       otg_set_state(fsm, OTG_STATE_B_IDLE);
+               else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det))
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);
+               break;
+       case OTG_STATE_A_WAIT_VRISE:
+               if (fsm->id || fsm->a_bus_drop || fsm->a_vbus_vld ||
+                               fsm->a_wait_vrise_tmout) {
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
+               }
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               if (!fsm->a_vbus_vld)
+                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
+               else if (fsm->b_conn)
+                       otg_set_state(fsm, OTG_STATE_A_HOST);
+               else if (fsm->id | fsm->a_bus_drop | fsm->a_wait_bcon_tmout)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
+               break;
+       case OTG_STATE_A_HOST:
+               if ((!fsm->a_bus_req || fsm->a_suspend_req) &&
+                               fsm->otg->host->b_hnp_enable)
+                       otg_set_state(fsm, OTG_STATE_A_SUSPEND);
+               else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
+               else if (!fsm->a_vbus_vld)
+                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
+               break;
+       case OTG_STATE_A_SUSPEND:
+               if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
+                       otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
+               else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
+               else if (fsm->a_bus_req || fsm->b_bus_resume)
+                       otg_set_state(fsm, OTG_STATE_A_HOST);
+               else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
+               else if (!fsm->a_vbus_vld)
+                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               if (fsm->id || fsm->a_bus_drop)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
+               else if (fsm->b_bus_suspend)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
+               else if (!fsm->a_vbus_vld)
+                       otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld &&
+                                       !fsm->b_conn))
+                       otg_set_state(fsm, OTG_STATE_A_IDLE);
+               break;
+       case OTG_STATE_A_VBUS_ERR:
+               if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err)
+                       otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&fsm->lock, flags);
+
+       VDBG("quit statemachine, changed = %d\n", state_changed);
+       return state_changed;
+}
diff --git a/drivers/usb/phy/otg_fsm.h b/drivers/usb/phy/otg_fsm.h
new file mode 100644 (file)
index 0000000..c30a2e1
--- /dev/null
@@ -0,0 +1,154 @@
+/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+#undef VERBOSE
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_DEBUG "[%s]  " fmt , \
+                                __func__, ## args)
+#else
+#define DBG(fmt, args...)      do {} while (0)
+#endif
+
+#ifdef VERBOSE
+#define VDBG           DBG
+#else
+#define VDBG(stuff...) do {} while (0)
+#endif
+
+#ifdef VERBOSE
+#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__)
+#else
+#define MPC_LOC do {} while (0)
+#endif
+
+#define PROTO_UNDEF    (0)
+#define PROTO_HOST     (1)
+#define PROTO_GADGET   (2)
+
+/* OTG state machine according to the OTG spec */
+struct otg_fsm {
+       /* Input */
+       int a_bus_resume;
+       int a_bus_suspend;
+       int a_conn;
+       int a_sess_vld;
+       int a_srp_det;
+       int a_vbus_vld;
+       int b_bus_resume;
+       int b_bus_suspend;
+       int b_conn;
+       int b_se0_srp;
+       int b_sess_end;
+       int b_sess_vld;
+       int id;
+
+       /* Internal variables */
+       int a_set_b_hnp_en;
+       int b_srp_done;
+       int b_hnp_enable;
+
+       /* Timeout indicator for timers */
+       int a_wait_vrise_tmout;
+       int a_wait_bcon_tmout;
+       int a_aidl_bdis_tmout;
+       int b_ase0_brst_tmout;
+
+       /* Informative variables */
+       int a_bus_drop;
+       int a_bus_req;
+       int a_clr_err;
+       int a_suspend_req;
+       int b_bus_req;
+
+       /* Output */
+       int drv_vbus;
+       int loc_conn;
+       int loc_sof;
+
+       struct otg_fsm_ops *ops;
+       struct usb_otg *otg;
+
+       /* Current usb protocol used: 0:undefine; 1:host; 2:client */
+       int protocol;
+       spinlock_t lock;
+};
+
+struct otg_fsm_ops {
+       void    (*chrg_vbus)(int on);
+       void    (*drv_vbus)(int on);
+       void    (*loc_conn)(int on);
+       void    (*loc_sof)(int on);
+       void    (*start_pulse)(void);
+       void    (*add_timer)(void *timer);
+       void    (*del_timer)(void *timer);
+       int     (*start_host)(struct otg_fsm *fsm, int on);
+       int     (*start_gadget)(struct otg_fsm *fsm, int on);
+};
+
+
+static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on)
+{
+       fsm->ops->chrg_vbus(on);
+}
+
+static inline void otg_drv_vbus(struct otg_fsm *fsm, int on)
+{
+       if (fsm->drv_vbus != on) {
+               fsm->drv_vbus = on;
+               fsm->ops->drv_vbus(on);
+       }
+}
+
+static inline void otg_loc_conn(struct otg_fsm *fsm, int on)
+{
+       if (fsm->loc_conn != on) {
+               fsm->loc_conn = on;
+               fsm->ops->loc_conn(on);
+       }
+}
+
+static inline void otg_loc_sof(struct otg_fsm *fsm, int on)
+{
+       if (fsm->loc_sof != on) {
+               fsm->loc_sof = on;
+               fsm->ops->loc_sof(on);
+       }
+}
+
+static inline void otg_start_pulse(struct otg_fsm *fsm)
+{
+       fsm->ops->start_pulse();
+}
+
+static inline void otg_add_timer(struct otg_fsm *fsm, void *timer)
+{
+       fsm->ops->add_timer(timer);
+}
+
+static inline void otg_del_timer(struct otg_fsm *fsm, void *timer)
+{
+       fsm->ops->del_timer(timer);
+}
+
+int otg_statemachine(struct otg_fsm *fsm);
+
+/* Defined by device specific driver, for different timer implementation */
+extern struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr,
+       *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_fail_tmr,
+       *a_wait_enum_tmr;
diff --git a/drivers/usb/phy/twl4030-usb.c b/drivers/usb/phy/twl4030-usb.c
new file mode 100644 (file)
index 0000000..a994715
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller
+ *
+ * Copyright (C) 2004-2007 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Current status:
+ *     - HS USB ULPI mode works.
+ *     - 3-pin mode support may be added in future.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/musb-omap.h>
+#include <linux/usb/ulpi.h>
+#include <linux/i2c/twl.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+/* Register defines */
+
+#define MCPC_CTRL                      0x30
+#define MCPC_CTRL_RTSOL                        (1 << 7)
+#define MCPC_CTRL_EXTSWR               (1 << 6)
+#define MCPC_CTRL_EXTSWC               (1 << 5)
+#define MCPC_CTRL_VOICESW              (1 << 4)
+#define MCPC_CTRL_OUT64K               (1 << 3)
+#define MCPC_CTRL_RTSCTSSW             (1 << 2)
+#define MCPC_CTRL_HS_UART              (1 << 0)
+
+#define MCPC_IO_CTRL                   0x33
+#define MCPC_IO_CTRL_MICBIASEN         (1 << 5)
+#define MCPC_IO_CTRL_CTS_NPU           (1 << 4)
+#define MCPC_IO_CTRL_RXD_PU            (1 << 3)
+#define MCPC_IO_CTRL_TXDTYP            (1 << 2)
+#define MCPC_IO_CTRL_CTSTYP            (1 << 1)
+#define MCPC_IO_CTRL_RTSTYP            (1 << 0)
+
+#define MCPC_CTRL2                     0x36
+#define MCPC_CTRL2_MCPC_CK_EN          (1 << 0)
+
+#define OTHER_FUNC_CTRL                        0x80
+#define OTHER_FUNC_CTRL_BDIS_ACON_EN   (1 << 4)
+#define OTHER_FUNC_CTRL_FIVEWIRE_MODE  (1 << 2)
+
+#define OTHER_IFC_CTRL                 0x83
+#define OTHER_IFC_CTRL_OE_INT_EN       (1 << 6)
+#define OTHER_IFC_CTRL_CEA2011_MODE    (1 << 5)
+#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN     (1 << 4)
+#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT      (1 << 3)
+#define OTHER_IFC_CTRL_HIZ_ULPI                (1 << 2)
+#define OTHER_IFC_CTRL_ALT_INT_REROUTE (1 << 0)
+
+#define OTHER_INT_EN_RISE              0x86
+#define OTHER_INT_EN_FALL              0x89
+#define OTHER_INT_STS                  0x8C
+#define OTHER_INT_LATCH                        0x8D
+#define OTHER_INT_VB_SESS_VLD          (1 << 7)
+#define OTHER_INT_DM_HI                        (1 << 6) /* not valid for "latch" reg */
+#define OTHER_INT_DP_HI                        (1 << 5) /* not valid for "latch" reg */
+#define OTHER_INT_BDIS_ACON            (1 << 3) /* not valid for "fall" regs */
+#define OTHER_INT_MANU                 (1 << 1)
+#define OTHER_INT_ABNORMAL_STRESS      (1 << 0)
+
+#define ID_STATUS                      0x96
+#define ID_RES_FLOAT                   (1 << 4)
+#define ID_RES_440K                    (1 << 3)
+#define ID_RES_200K                    (1 << 2)
+#define ID_RES_102K                    (1 << 1)
+#define ID_RES_GND                     (1 << 0)
+
+#define POWER_CTRL                     0xAC
+#define POWER_CTRL_OTG_ENAB            (1 << 5)
+
+#define OTHER_IFC_CTRL2                        0xAF
+#define OTHER_IFC_CTRL2_ULPI_STP_LOW   (1 << 4)
+#define OTHER_IFC_CTRL2_ULPI_TXEN_POL  (1 << 3)
+#define OTHER_IFC_CTRL2_ULPI_4PIN_2430 (1 << 2)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK    (3 << 0) /* bits 0 and 1 */
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N   (0 << 0)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N   (1 << 0)
+
+#define REG_CTRL_EN                    0xB2
+#define REG_CTRL_ERROR                 0xB5
+#define ULPI_I2C_CONFLICT_INTEN                (1 << 0)
+
+#define OTHER_FUNC_CTRL2               0xB8
+#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN (1 << 0)
+
+/* following registers do not have separate _clr and _set registers */
+#define VBUS_DEBOUNCE                  0xC0
+#define ID_DEBOUNCE                    0xC1
+#define VBAT_TIMER                     0xD3
+#define PHY_PWR_CTRL                   0xFD
+#define PHY_PWR_PHYPWD                 (1 << 0)
+#define PHY_CLK_CTRL                   0xFE
+#define PHY_CLK_CTRL_CLOCKGATING_EN    (1 << 2)
+#define PHY_CLK_CTRL_CLK32K_EN         (1 << 1)
+#define REQ_PHY_DPLL_CLK               (1 << 0)
+#define PHY_CLK_CTRL_STS               0xFF
+#define PHY_DPLL_CLK                   (1 << 0)
+
+/* In module TWL_MODULE_PM_MASTER */
+#define STS_HW_CONDITIONS              0x0F
+
+/* In module TWL_MODULE_PM_RECEIVER */
+#define VUSB_DEDICATED1                        0x7D
+#define VUSB_DEDICATED2                        0x7E
+#define VUSB1V5_DEV_GRP                        0x71
+#define VUSB1V5_TYPE                   0x72
+#define VUSB1V5_REMAP                  0x73
+#define VUSB1V8_DEV_GRP                        0x74
+#define VUSB1V8_TYPE                   0x75
+#define VUSB1V8_REMAP                  0x76
+#define VUSB3V1_DEV_GRP                        0x77
+#define VUSB3V1_TYPE                   0x78
+#define VUSB3V1_REMAP                  0x79
+
+/* In module TWL4030_MODULE_INTBR */
+#define PMBR1                          0x0D
+#define GPIO_USB_4PIN_ULPI_2430C       (3 << 0)
+
+struct twl4030_usb {
+       struct usb_phy          phy;
+       struct device           *dev;
+
+       /* TWL4030 internal USB regulator supplies */
+       struct regulator        *usb1v5;
+       struct regulator        *usb1v8;
+       struct regulator        *usb3v1;
+
+       /* for vbus reporting with irqs disabled */
+       spinlock_t              lock;
+
+       /* pin configuration */
+       enum twl4030_usb_mode   usb_mode;
+
+       int                     irq;
+       enum omap_musb_vbus_id_status linkstat;
+       bool                    vbus_supplied;
+       u8                      asleep;
+       bool                    irq_enabled;
+};
+
+/* internal define on top of container_of */
+#define phy_to_twl(x)          container_of((x), struct twl4030_usb, phy)
+
+/*-------------------------------------------------------------------------*/
+
+static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl,
+               u8 module, u8 data, u8 address)
+{
+       u8 check;
+
+       if ((twl_i2c_write_u8(module, data, address) >= 0) &&
+           (twl_i2c_read_u8(module, &check, address) >= 0) &&
+                                               (check == data))
+               return 0;
+       dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
+                       1, module, address, check, data);
+
+       /* Failed once: Try again */
+       if ((twl_i2c_write_u8(module, data, address) >= 0) &&
+           (twl_i2c_read_u8(module, &check, address) >= 0) &&
+                                               (check == data))
+               return 0;
+       dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
+                       2, module, address, check, data);
+
+       /* Failed again: Return error */
+       return -EBUSY;
+}
+
+#define twl4030_usb_write_verify(twl, address, data)   \
+       twl4030_i2c_write_u8_verify(twl, TWL_MODULE_USB, (data), (address))
+
+static inline int twl4030_usb_write(struct twl4030_usb *twl,
+               u8 address, u8 data)
+{
+       int ret = 0;
+
+       ret = twl_i2c_write_u8(TWL_MODULE_USB, data, address);
+       if (ret < 0)
+               dev_dbg(twl->dev,
+                       "TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
+       return ret;
+}
+
+static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address)
+{
+       u8 data;
+       int ret = 0;
+
+       ret = twl_i2c_read_u8(module, &data, address);
+       if (ret >= 0)
+               ret = data;
+       else
+               dev_dbg(twl->dev,
+                       "TWL4030:readb[0x%x,0x%x] Error %d\n",
+                                       module, address, ret);
+
+       return ret;
+}
+
+static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address)
+{
+       return twl4030_readb(twl, TWL_MODULE_USB, address);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+       return twl4030_usb_write(twl, ULPI_SET(reg), bits);
+}
+
+static inline int
+twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+       return twl4030_usb_write(twl, ULPI_CLR(reg), bits);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static enum omap_musb_vbus_id_status
+       twl4030_usb_linkstat(struct twl4030_usb *twl)
+{
+       int     status;
+       enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN;
+
+       twl->vbus_supplied = false;
+
+       /*
+        * For ID/VBUS sensing, see manual section 15.4.8 ...
+        * except when using only battery backup power, two
+        * comparators produce VBUS_PRES and ID_PRES signals,
+        * which don't match docs elsewhere.  But ... BIT(7)
+        * and BIT(2) of STS_HW_CONDITIONS, respectively, do
+        * seem to match up.  If either is true the USB_PRES
+        * signal is active, the OTG module is activated, and
+        * its interrupt may be raised (may wake the system).
+        */
+       status = twl4030_readb(twl, TWL_MODULE_PM_MASTER, STS_HW_CONDITIONS);
+       if (status < 0)
+               dev_err(twl->dev, "USB link status err %d\n", status);
+       else if (status & (BIT(7) | BIT(2))) {
+               if (status & (BIT(7)))
+                        twl->vbus_supplied = true;
+
+               if (status & BIT(2))
+                       linkstat = OMAP_MUSB_ID_GROUND;
+               else
+                       linkstat = OMAP_MUSB_VBUS_VALID;
+       } else {
+               if (twl->linkstat != OMAP_MUSB_UNKNOWN)
+                       linkstat = OMAP_MUSB_VBUS_OFF;
+       }
+
+       dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
+                       status, status, linkstat);
+
+       /* REVISIT this assumes host and peripheral controllers
+        * are registered, and that both are active...
+        */
+
+       spin_lock_irq(&twl->lock);
+       twl->linkstat = linkstat;
+       spin_unlock_irq(&twl->lock);
+
+       return linkstat;
+}
+
+static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
+{
+       twl->usb_mode = mode;
+
+       switch (mode) {
+       case T2_USB_MODE_ULPI:
+               twl4030_usb_clear_bits(twl, ULPI_IFC_CTRL,
+                                       ULPI_IFC_CTRL_CARKITMODE);
+               twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+               twl4030_usb_clear_bits(twl, ULPI_FUNC_CTRL,
+                                       ULPI_FUNC_CTRL_XCVRSEL_MASK |
+                                       ULPI_FUNC_CTRL_OPMODE_MASK);
+               break;
+       case -1:
+               /* FIXME: power on defaults */
+               break;
+       default:
+               dev_err(twl->dev, "unsupported T2 transceiver mode %d\n",
+                               mode);
+               break;
+       };
+}
+
+static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
+{
+       unsigned long timeout;
+       int val = twl4030_usb_read(twl, PHY_CLK_CTRL);
+
+       if (val >= 0) {
+               if (on) {
+                       /* enable DPLL to access PHY registers over I2C */
+                       val |= REQ_PHY_DPLL_CLK;
+                       WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+                                               (u8)val) < 0);
+
+                       timeout = jiffies + HZ;
+                       while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
+                                                       PHY_DPLL_CLK)
+                               && time_before(jiffies, timeout))
+                                       udelay(10);
+                       if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
+                                                       PHY_DPLL_CLK))
+                               dev_err(twl->dev, "Timeout setting T2 HSUSB "
+                                               "PHY DPLL clock\n");
+               } else {
+                       /* let ULPI control the DPLL clock */
+                       val &= ~REQ_PHY_DPLL_CLK;
+                       WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+                                               (u8)val) < 0);
+               }
+       }
+}
+
+static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
+{
+       u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
+
+       if (on)
+               pwr &= ~PHY_PWR_PHYPWD;
+       else
+               pwr |= PHY_PWR_PHYPWD;
+
+       WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+}
+
+static void twl4030_phy_power(struct twl4030_usb *twl, int on)
+{
+       if (on) {
+               regulator_enable(twl->usb3v1);
+               regulator_enable(twl->usb1v8);
+               /*
+                * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
+                * in twl4030) resets the VUSB_DEDICATED2 register. This reset
+                * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to
+                * SLEEP. We work around this by clearing the bit after usv3v1
+                * is re-activated. This ensures that VUSB3V1 is really active.
+                */
+               twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
+               regulator_enable(twl->usb1v5);
+               __twl4030_phy_power(twl, 1);
+               twl4030_usb_write(twl, PHY_CLK_CTRL,
+                                 twl4030_usb_read(twl, PHY_CLK_CTRL) |
+                                       (PHY_CLK_CTRL_CLOCKGATING_EN |
+                                               PHY_CLK_CTRL_CLK32K_EN));
+       } else {
+               __twl4030_phy_power(twl, 0);
+               regulator_disable(twl->usb1v5);
+               regulator_disable(twl->usb1v8);
+               regulator_disable(twl->usb3v1);
+       }
+}
+
+static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off)
+{
+       if (twl->asleep)
+               return;
+
+       twl4030_phy_power(twl, 0);
+       twl->asleep = 1;
+       dev_dbg(twl->dev, "%s\n", __func__);
+}
+
+static void __twl4030_phy_resume(struct twl4030_usb *twl)
+{
+       twl4030_phy_power(twl, 1);
+       twl4030_i2c_access(twl, 1);
+       twl4030_usb_set_mode(twl, twl->usb_mode);
+       if (twl->usb_mode == T2_USB_MODE_ULPI)
+               twl4030_i2c_access(twl, 0);
+}
+
+static void twl4030_phy_resume(struct twl4030_usb *twl)
+{
+       if (!twl->asleep)
+               return;
+       __twl4030_phy_resume(twl);
+       twl->asleep = 0;
+       dev_dbg(twl->dev, "%s\n", __func__);
+}
+
+static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
+{
+       /* Enable writing to power configuration registers */
+       twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
+                        TWL4030_PM_MASTER_PROTECT_KEY);
+
+       twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
+                        TWL4030_PM_MASTER_PROTECT_KEY);
+
+       /* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/
+       /*twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/
+
+       /* input to VUSB3V1 LDO is from VBAT, not VBUS */
+       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
+
+       /* Initialize 3.1V regulator */
+       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
+
+       twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
+       if (IS_ERR(twl->usb3v1))
+               return -ENODEV;
+
+       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
+
+       /* Initialize 1.5V regulator */
+       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
+
+       twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
+       if (IS_ERR(twl->usb1v5))
+               goto fail1;
+
+       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
+
+       /* Initialize 1.8V regulator */
+       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
+
+       twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
+       if (IS_ERR(twl->usb1v8))
+               goto fail2;
+
+       twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
+
+       /* disable access to power configuration registers */
+       twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
+                        TWL4030_PM_MASTER_PROTECT_KEY);
+
+       return 0;
+
+fail2:
+       regulator_put(twl->usb1v5);
+       twl->usb1v5 = NULL;
+fail1:
+       regulator_put(twl->usb3v1);
+       twl->usb3v1 = NULL;
+       return -ENODEV;
+}
+
+static ssize_t twl4030_usb_vbus_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct twl4030_usb *twl = dev_get_drvdata(dev);
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&twl->lock, flags);
+       ret = sprintf(buf, "%s\n",
+                       twl->vbus_supplied ? "on" : "off");
+       spin_unlock_irqrestore(&twl->lock, flags);
+
+       return ret;
+}
+static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
+
+static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
+{
+       struct twl4030_usb *twl = _twl;
+       enum omap_musb_vbus_id_status status;
+
+       status = twl4030_usb_linkstat(twl);
+       if (status > 0) {
+               /* FIXME add a set_power() method so that B-devices can
+                * configure the charger appropriately.  It's not always
+                * correct to consume VBUS power, and how much current to
+                * consume is a function of the USB configuration chosen
+                * by the host.
+                *
+                * REVISIT usb_gadget_vbus_connect(...) as needed, ditto
+                * its disconnect() sibling, when changing to/from the
+                * USB_LINK_VBUS state.  musb_hdrc won't care until it
+                * starts to handle softconnect right.
+                */
+               if (status == OMAP_MUSB_VBUS_OFF ||
+                               status == OMAP_MUSB_ID_FLOAT)
+                       twl4030_phy_suspend(twl, 0);
+               else
+                       twl4030_phy_resume(twl);
+
+               omap_musb_mailbox(twl->linkstat);
+       }
+       sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+
+       return IRQ_HANDLED;
+}
+
+static void twl4030_usb_phy_init(struct twl4030_usb *twl)
+{
+       enum omap_musb_vbus_id_status status;
+
+       status = twl4030_usb_linkstat(twl);
+       if (status > 0) {
+               if (status == OMAP_MUSB_VBUS_OFF ||
+                               status == OMAP_MUSB_ID_FLOAT) {
+                       __twl4030_phy_power(twl, 0);
+                       twl->asleep = 1;
+               } else {
+                       __twl4030_phy_resume(twl);
+                       twl->asleep = 0;
+               }
+
+               omap_musb_mailbox(twl->linkstat);
+       }
+       sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+}
+
+static int twl4030_set_suspend(struct usb_phy *x, int suspend)
+{
+       struct twl4030_usb *twl = phy_to_twl(x);
+
+       if (suspend)
+               twl4030_phy_suspend(twl, 1);
+       else
+               twl4030_phy_resume(twl);
+
+       return 0;
+}
+
+static int twl4030_set_peripheral(struct usb_otg *otg,
+                                       struct usb_gadget *gadget)
+{
+       if (!otg)
+               return -ENODEV;
+
+       otg->gadget = gadget;
+       if (!gadget)
+               otg->phy->state = OTG_STATE_UNDEFINED;
+
+       return 0;
+}
+
+static int twl4030_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 twl4030_usb_probe(struct platform_device *pdev)
+{
+       struct twl4030_usb_data *pdata = pdev->dev.platform_data;
+       struct twl4030_usb      *twl;
+       int                     status, err;
+       struct usb_otg          *otg;
+       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->vbus_supplied      = false;
+       twl->asleep             = 1;
+       twl->linkstat           = OMAP_MUSB_UNKNOWN;
+
+       twl->phy.dev            = twl->dev;
+       twl->phy.label          = "twl4030";
+       twl->phy.otg            = otg;
+       twl->phy.type           = USB_PHY_TYPE_USB2;
+       twl->phy.set_suspend    = twl4030_set_suspend;
+
+       otg->phy                = &twl->phy;
+       otg->set_host           = twl4030_set_host;
+       otg->set_peripheral     = twl4030_set_peripheral;
+
+       /* init spinlock for workqueue */
+       spin_lock_init(&twl->lock);
+
+       err = twl4030_usb_ldo_init(twl);
+       if (err) {
+               dev_err(&pdev->dev, "ldo init failed\n");
+               return err;
+       }
+       usb_add_phy_dev(&twl->phy);
+
+       platform_set_drvdata(pdev, twl);
+       if (device_create_file(&pdev->dev, &dev_attr_vbus))
+               dev_warn(&pdev->dev, "could not create sysfs file\n");
+
+       /* Our job is to use irqs and status from the power module
+        * to keep the transceiver disabled when nothing's connected.
+        *
+        * FIXME we actually shouldn't start enabling it until the
+        * USB controller drivers have said they're ready, by calling
+        * set_host() and/or set_peripheral() ... OTG_capable boards
+        * need both handles, otherwise just one suffices.
+        */
+       twl->irq_enabled = true;
+       status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
+                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+                       IRQF_ONESHOT, "twl4030_usb", twl);
+       if (status < 0) {
+               dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
+                       twl->irq, status);
+               return status;
+       }
+
+       /* Power down phy or make it work according to
+        * current link state.
+        */
+       twl4030_usb_phy_init(twl);
+
+       dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
+       return 0;
+}
+
+static int __exit twl4030_usb_remove(struct platform_device *pdev)
+{
+       struct twl4030_usb *twl = platform_get_drvdata(pdev);
+       int val;
+
+       free_irq(twl->irq, twl);
+       device_remove_file(twl->dev, &dev_attr_vbus);
+
+       /* set transceiver mode to power on defaults */
+       twl4030_usb_set_mode(twl, -1);
+
+       /* autogate 60MHz ULPI clock,
+        * clear dpll clock request for i2c access,
+        * disable 32KHz
+        */
+       val = twl4030_usb_read(twl, PHY_CLK_CTRL);
+       if (val >= 0) {
+               val |= PHY_CLK_CTRL_CLOCKGATING_EN;
+               val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK);
+               twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val);
+       }
+
+       /* disable complete OTG block */
+       twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+
+       if (!twl->asleep)
+               twl4030_phy_power(twl, 0);
+       regulator_put(twl->usb1v5);
+       regulator_put(twl->usb1v8);
+       regulator_put(twl->usb3v1);
+
+       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),
+       },
+};
+
+static int __init twl4030_usb_init(void)
+{
+       return platform_driver_register(&twl4030_usb_driver);
+}
+subsys_initcall(twl4030_usb_init);
+
+static void __exit twl4030_usb_exit(void)
+{
+       platform_driver_unregister(&twl4030_usb_driver);
+}
+module_exit(twl4030_usb_exit);
+
+MODULE_ALIAS("platform:twl4030_usb");
+MODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation");
+MODULE_DESCRIPTION("TWL4030 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/twl6030-usb.c b/drivers/usb/phy/twl6030-usb.c
new file mode 100644 (file)
index 0000000..8cd6cf4
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver.
+ *
+ * Copyright (C) 2010 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: Hema HK <hemahk@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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.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>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+/* usb register definitions */
+#define USB_VENDOR_ID_LSB              0x00
+#define USB_VENDOR_ID_MSB              0x01
+#define USB_PRODUCT_ID_LSB             0x02
+#define USB_PRODUCT_ID_MSB             0x03
+#define USB_VBUS_CTRL_SET              0x04
+#define USB_VBUS_CTRL_CLR              0x05
+#define USB_ID_CTRL_SET                        0x06
+#define USB_ID_CTRL_CLR                        0x07
+#define USB_VBUS_INT_SRC               0x08
+#define USB_VBUS_INT_LATCH_SET         0x09
+#define USB_VBUS_INT_LATCH_CLR         0x0A
+#define USB_VBUS_INT_EN_LO_SET         0x0B
+#define USB_VBUS_INT_EN_LO_CLR         0x0C
+#define USB_VBUS_INT_EN_HI_SET         0x0D
+#define USB_VBUS_INT_EN_HI_CLR         0x0E
+#define USB_ID_INT_SRC                 0x0F
+#define USB_ID_INT_LATCH_SET           0x10
+#define USB_ID_INT_LATCH_CLR           0x11
+
+#define USB_ID_INT_EN_LO_SET           0x12
+#define USB_ID_INT_EN_LO_CLR           0x13
+#define USB_ID_INT_EN_HI_SET           0x14
+#define USB_ID_INT_EN_HI_CLR           0x15
+#define USB_OTG_ADP_CTRL               0x16
+#define USB_OTG_ADP_HIGH               0x17
+#define USB_OTG_ADP_LOW                        0x18
+#define USB_OTG_ADP_RISE               0x19
+#define USB_OTG_REVISION               0x1A
+
+/* to be moved to LDO */
+#define TWL6030_MISC2                  0xE5
+#define TWL6030_CFG_LDO_PD2            0xF5
+#define TWL6030_BACKUP_REG             0xFA
+
+#define STS_HW_CONDITIONS              0x21
+
+/* In module TWL6030_MODULE_PM_MASTER */
+#define STS_HW_CONDITIONS              0x21
+#define STS_USB_ID                     BIT(2)
+
+/* In module TWL6030_MODULE_PM_RECEIVER */
+#define VUSB_CFG_TRANS                 0x71
+#define VUSB_CFG_STATE                 0x72
+#define VUSB_CFG_VOLTAGE               0x73
+
+/* in module TWL6030_MODULE_MAIN_CHARGE */
+
+#define CHARGERUSB_CTRL1               0x8
+
+#define CONTROLLER_STAT1               0x03
+#define        VBUS_DET                        BIT(2)
+
+struct twl6030_usb {
+       struct phy_companion    comparator;
+       struct device           *dev;
+
+       /* for vbus reporting with irqs disabled */
+       spinlock_t              lock;
+
+       struct regulator                *usb3v3;
+
+       /* used to set vbus, in atomic path */
+       struct work_struct      set_vbus_work;
+
+       int                     irq1;
+       int                     irq2;
+       enum omap_musb_vbus_id_status linkstat;
+       u8                      asleep;
+       bool                    irq_enabled;
+       bool                    vbus_enable;
+       const char              *regulator;
+};
+
+#define        comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
+
+/*-------------------------------------------------------------------------*/
+
+static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,
+                                               u8 data, u8 address)
+{
+       int ret = 0;
+
+       ret = twl_i2c_write_u8(module, data, address);
+       if (ret < 0)
+               dev_err(twl->dev,
+                       "Write[0x%x] Error %d\n", address, ret);
+       return ret;
+}
+
+static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
+{
+       u8 data, ret = 0;
+
+       ret = twl_i2c_read_u8(module, &data, address);
+       if (ret >= 0)
+               ret = data;
+       else
+               dev_err(twl->dev,
+                       "readb[0x%x,0x%x] Error %d\n",
+                                       module, address, ret);
+       return ret;
+}
+
+static int twl6030_start_srp(struct phy_companion *comparator)
+{
+       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);
+
+       mdelay(100);
+       twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR);
+
+       return 0;
+}
+
+static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
+{
+       /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
+       twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
+
+       /* Program CFG_LDO_PD2 register and set VUSB bit */
+       twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2);
+
+       /* Program MISC2 register and set bit VUSB_IN_VBAT */
+       twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
+
+       twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
+       if (IS_ERR(twl->usb3v3))
+               return -ENODEV;
+
+       /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
+       twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);
+
+       /*
+        * Program the USB_ID_CTRL_SET register to enable GND drive
+        * and the ID comparators
+        */
+       twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);
+
+       return 0;
+}
+
+static ssize_t twl6030_usb_vbus_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct twl6030_usb *twl = dev_get_drvdata(dev);
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&twl->lock, flags);
+
+       switch (twl->linkstat) {
+       case OMAP_MUSB_VBUS_VALID:
+              ret = snprintf(buf, PAGE_SIZE, "vbus\n");
+              break;
+       case OMAP_MUSB_ID_GROUND:
+              ret = snprintf(buf, PAGE_SIZE, "id\n");
+              break;
+       case OMAP_MUSB_VBUS_OFF:
+              ret = snprintf(buf, PAGE_SIZE, "none\n");
+              break;
+       default:
+              ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+       }
+       spin_unlock_irqrestore(&twl->lock, flags);
+
+       return ret;
+}
+static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
+
+static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
+{
+       struct twl6030_usb *twl = _twl;
+       enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
+       u8 vbus_state, hw_state;
+
+       hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
+
+       vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
+                                               CONTROLLER_STAT1);
+       if (!(hw_state & STS_USB_ID)) {
+               if (vbus_state & VBUS_DET) {
+                       regulator_enable(twl->usb3v3);
+                       twl->asleep = 1;
+                       status = OMAP_MUSB_VBUS_VALID;
+                       twl->linkstat = status;
+                       omap_musb_mailbox(status);
+               } else {
+                       if (twl->linkstat != OMAP_MUSB_UNKNOWN) {
+                               status = OMAP_MUSB_VBUS_OFF;
+                               twl->linkstat = status;
+                               omap_musb_mailbox(status);
+                               if (twl->asleep) {
+                                       regulator_disable(twl->usb3v3);
+                                       twl->asleep = 0;
+                               }
+                       }
+               }
+       }
+       sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
+{
+       struct twl6030_usb *twl = _twl;
+       enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
+       u8 hw_state;
+
+       hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
+
+       if (hw_state & STS_USB_ID) {
+
+               regulator_enable(twl->usb3v3);
+               twl->asleep = 1;
+               twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
+               twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
+               status = OMAP_MUSB_ID_GROUND;
+               twl->linkstat = status;
+               omap_musb_mailbox(status);
+       } else  {
+               twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
+               twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
+       }
+       twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
+
+       return IRQ_HANDLED;
+}
+
+static int twl6030_enable_irq(struct twl6030_usb *twl)
+{
+       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);
+
+       twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
+                               REG_INT_MSK_LINE_C);
+       twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
+                               REG_INT_MSK_STS_C);
+       twl6030_usb_irq(twl->irq2, twl);
+       twl6030_usbotg_irq(twl->irq1, twl);
+
+       return 0;
+}
+
+static void otg_set_vbus_work(struct work_struct *data)
+{
+       struct twl6030_usb *twl = container_of(data, struct twl6030_usb,
+                                                               set_vbus_work);
+
+       /*
+        * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
+        * register. This enables boost mode.
+        */
+
+       if (twl->vbus_enable)
+               twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
+                                                       CHARGERUSB_CTRL1);
+       else
+               twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
+                                                       CHARGERUSB_CTRL1);
+}
+
+static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
+{
+       struct twl6030_usb *twl = comparator_to_twl(comparator);
+
+       twl->vbus_enable = enabled;
+       schedule_work(&twl->set_vbus_work);
+
+       return 0;
+}
+
+static int twl6030_usb_probe(struct platform_device *pdev)
+{
+       u32 ret;
+       struct twl6030_usb      *twl;
+       int                     status, err;
+       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;
+
+       twl->dev                = &pdev->dev;
+       twl->irq1               = platform_get_irq(pdev, 0);
+       twl->irq2               = platform_get_irq(pdev, 1);
+       twl->linkstat           = OMAP_MUSB_UNKNOWN;
+
+       twl->comparator.set_vbus        = twl6030_set_vbus;
+       twl->comparator.start_srp       = twl6030_start_srp;
+
+       ret = omap_usb2_set_comparator(&twl->comparator);
+       if (ret == -ENODEV) {
+               dev_info(&pdev->dev, "phy not ready, deferring probe");
+               return -EPROBE_DEFER;
+       }
+
+       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);
+
+       err = twl6030_usb_ldo_init(twl);
+       if (err) {
+               dev_err(&pdev->dev, "ldo init failed\n");
+               return err;
+       }
+
+       platform_set_drvdata(pdev, twl);
+       if (device_create_file(&pdev->dev, &dev_attr_vbus))
+               dev_warn(&pdev->dev, "could not create sysfs file\n");
+
+       INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
+
+       twl->irq_enabled = true;
+       status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
+                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                       "twl6030_usb", twl);
+       if (status < 0) {
+               dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+                       twl->irq1, status);
+               device_remove_file(twl->dev, &dev_attr_vbus);
+               return status;
+       }
+
+       status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
+                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                       "twl6030_usb", twl);
+       if (status < 0) {
+               dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+                       twl->irq2, status);
+               free_irq(twl->irq1, twl);
+               device_remove_file(twl->dev, &dev_attr_vbus);
+               return status;
+       }
+
+       twl->asleep = 0;
+       twl6030_enable_irq(twl);
+       dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
+
+       return 0;
+}
+
+static int __exit twl6030_usb_remove(struct platform_device *pdev)
+{
+       struct twl6030_usb *twl = platform_get_drvdata(pdev);
+
+       twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
+               REG_INT_MSK_LINE_C);
+       twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
+                       REG_INT_MSK_STS_C);
+       free_irq(twl->irq1, twl);
+       free_irq(twl->irq2, twl);
+       regulator_put(twl->usb3v3);
+       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),
+       },
+};
+
+static int __init twl6030_usb_init(void)
+{
+       return platform_driver_register(&twl6030_usb_driver);
+}
+subsys_initcall(twl6030_usb_init);
+
+static void __exit twl6030_usb_exit(void)
+{
+       platform_driver_unregister(&twl6030_usb_driver);
+}
+module_exit(twl6030_usb_exit);
+
+MODULE_ALIAS("platform:twl6030_usb");
+MODULE_AUTHOR("Hema HK <hemahk@ti.com>");
+MODULE_DESCRIPTION("TWL6030 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/ulpi.c b/drivers/usb/phy/ulpi.c
new file mode 100644 (file)
index 0000000..217339d
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Generic ULPI USB transceiver support
+ *
+ * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * Based on sources from
+ *
+ *   Sascha Hauer <s.hauer@pengutronix.de>
+ *   Freescale Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+
+
+struct ulpi_info {
+       unsigned int    id;
+       char            *name;
+};
+
+#define ULPI_ID(vendor, product) (((vendor) << 16) | (product))
+#define ULPI_INFO(_id, _name)          \
+       {                               \
+               .id     = (_id),        \
+               .name   = (_name),      \
+       }
+
+/* ULPI hardcoded IDs, used for probing */
+static struct ulpi_info ulpi_ids[] = {
+       ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
+       ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
+};
+
+static int ulpi_set_otg_flags(struct usb_phy *phy)
+{
+       unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
+                            ULPI_OTG_CTRL_DM_PULLDOWN;
+
+       if (phy->flags & ULPI_OTG_ID_PULLUP)
+               flags |= ULPI_OTG_CTRL_ID_PULLUP;
+
+       /*
+        * ULPI Specification rev.1.1 default
+        * for Dp/DmPulldown is enabled.
+        */
+       if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS)
+               flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN;
+
+       if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS)
+               flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN;
+
+       if (phy->flags & ULPI_OTG_EXTVBUSIND)
+               flags |= ULPI_OTG_CTRL_EXTVBUSIND;
+
+       return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
+}
+
+static int ulpi_set_fc_flags(struct usb_phy *phy)
+{
+       unsigned int flags = 0;
+
+       /*
+        * ULPI Specification rev.1.1 default
+        * for XcvrSelect is Full Speed.
+        */
+       if (phy->flags & ULPI_FC_HS)
+               flags |= ULPI_FUNC_CTRL_HIGH_SPEED;
+       else if (phy->flags & ULPI_FC_LS)
+               flags |= ULPI_FUNC_CTRL_LOW_SPEED;
+       else if (phy->flags & ULPI_FC_FS4LS)
+               flags |= ULPI_FUNC_CTRL_FS4LS;
+       else
+               flags |= ULPI_FUNC_CTRL_FULL_SPEED;
+
+       if (phy->flags & ULPI_FC_TERMSEL)
+               flags |= ULPI_FUNC_CTRL_TERMSELECT;
+
+       /*
+        * ULPI Specification rev.1.1 default
+        * for OpMode is Normal Operation.
+        */
+       if (phy->flags & ULPI_FC_OP_NODRV)
+               flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+       else if (phy->flags & ULPI_FC_OP_DIS_NRZI)
+               flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI;
+       else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP)
+               flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP;
+       else
+               flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+
+       /*
+        * ULPI Specification rev.1.1 default
+        * for SuspendM is Powered.
+        */
+       flags |= ULPI_FUNC_CTRL_SUSPENDM;
+
+       return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL);
+}
+
+static int ulpi_set_ic_flags(struct usb_phy *phy)
+{
+       unsigned int flags = 0;
+
+       if (phy->flags & ULPI_IC_AUTORESUME)
+               flags |= ULPI_IFC_CTRL_AUTORESUME;
+
+       if (phy->flags & ULPI_IC_EXTVBUS_INDINV)
+               flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS;
+
+       if (phy->flags & ULPI_IC_IND_PASSTHRU)
+               flags |= ULPI_IFC_CTRL_PASSTHRU;
+
+       if (phy->flags & ULPI_IC_PROTECT_DIS)
+               flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE;
+
+       return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
+}
+
+static int ulpi_set_flags(struct usb_phy *phy)
+{
+       int ret;
+
+       ret = ulpi_set_otg_flags(phy);
+       if (ret)
+               return ret;
+
+       ret = ulpi_set_ic_flags(phy);
+       if (ret)
+               return ret;
+
+       return ulpi_set_fc_flags(phy);
+}
+
+static int ulpi_check_integrity(struct usb_phy *phy)
+{
+       int ret, i;
+       unsigned int val = 0x55;
+
+       for (i = 0; i < 2; i++) {
+               ret = usb_phy_io_write(phy, val, ULPI_SCRATCH);
+               if (ret < 0)
+                       return ret;
+
+               ret = usb_phy_io_read(phy, ULPI_SCRATCH);
+               if (ret < 0)
+                       return ret;
+
+               if (ret != val) {
+                       pr_err("ULPI integrity check: failed!");
+                       return -ENODEV;
+               }
+               val = val << 1;
+       }
+
+       pr_info("ULPI integrity check: passed.\n");
+
+       return 0;
+}
+
+static int ulpi_init(struct usb_phy *phy)
+{
+       int i, vid, pid, ret;
+       u32 ulpi_id = 0;
+
+       for (i = 0; i < 4; i++) {
+               ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i);
+               if (ret < 0)
+                       return ret;
+               ulpi_id = (ulpi_id << 8) | ret;
+       }
+       vid = ulpi_id & 0xffff;
+       pid = ulpi_id >> 16;
+
+       pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);
+
+       for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) {
+               if (ulpi_ids[i].id == ULPI_ID(vid, pid)) {
+                       pr_info("Found %s ULPI transceiver.\n",
+                               ulpi_ids[i].name);
+                       break;
+               }
+       }
+
+       ret = ulpi_check_integrity(phy);
+       if (ret)
+               return ret;
+
+       return ulpi_set_flags(phy);
+}
+
+static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct usb_phy *phy = otg->phy;
+       unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);
+
+       if (!host) {
+               otg->host = NULL;
+               return 0;
+       }
+
+       otg->host = host;
+
+       flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE |
+                  ULPI_IFC_CTRL_3_PIN_SERIAL_MODE |
+                  ULPI_IFC_CTRL_CARKITMODE);
+
+       if (phy->flags & ULPI_IC_6PIN_SERIAL)
+               flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE;
+       else if (phy->flags & ULPI_IC_3PIN_SERIAL)
+               flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE;
+       else if (phy->flags & ULPI_IC_CARKIT)
+               flags |= ULPI_IFC_CTRL_CARKITMODE;
+
+       return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
+}
+
+static int ulpi_set_vbus(struct usb_otg *otg, bool on)
+{
+       struct usb_phy *phy = otg->phy;
+       unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
+
+       flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
+
+       if (on) {
+               if (phy->flags & ULPI_OTG_DRVVBUS)
+                       flags |= ULPI_OTG_CTRL_DRVVBUS;
+
+               if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
+                       flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
+       }
+
+       return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
+}
+
+struct usb_phy *
+otg_ulpi_create(struct usb_phy_io_ops *ops,
+               unsigned int flags)
+{
+       struct usb_phy *phy;
+       struct usb_otg *otg;
+
+       phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+       if (!phy)
+               return NULL;
+
+       otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+       if (!otg) {
+               kfree(phy);
+               return NULL;
+       }
+
+       phy->label      = "ULPI";
+       phy->flags      = flags;
+       phy->io_ops     = ops;
+       phy->otg        = otg;
+       phy->init       = ulpi_init;
+
+       otg->phy        = phy;
+       otg->set_host   = ulpi_set_host;
+       otg->set_vbus   = ulpi_set_vbus;
+
+       return phy;
+}
+EXPORT_SYMBOL_GPL(otg_ulpi_create);
+
diff --git a/drivers/usb/phy/ulpi_viewport.c b/drivers/usb/phy/ulpi_viewport.c
new file mode 100644 (file)
index 0000000..c5ba7e5
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/kernel.h>
+#include <linux/usb.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+
+#define ULPI_VIEW_WAKEUP       (1 << 31)
+#define ULPI_VIEW_RUN          (1 << 30)
+#define ULPI_VIEW_WRITE                (1 << 29)
+#define ULPI_VIEW_READ         (0 << 29)
+#define ULPI_VIEW_ADDR(x)      (((x) & 0xff) << 16)
+#define ULPI_VIEW_DATA_READ(x) (((x) >> 8) & 0xff)
+#define ULPI_VIEW_DATA_WRITE(x)        ((x) & 0xff)
+
+static int ulpi_viewport_wait(void __iomem *view, u32 mask)
+{
+       unsigned long usec = 2000;
+
+       while (usec--) {
+               if (!(readl(view) & mask))
+                       return 0;
+
+               udelay(1);
+       };
+
+       return -ETIMEDOUT;
+}
+
+static int ulpi_viewport_read(struct usb_phy *otg, u32 reg)
+{
+       int ret;
+       void __iomem *view = otg->io_priv;
+
+       writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view);
+       ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP);
+       if (ret)
+               return ret;
+
+       writel(ULPI_VIEW_RUN | ULPI_VIEW_READ | ULPI_VIEW_ADDR(reg), view);
+       ret = ulpi_viewport_wait(view, ULPI_VIEW_RUN);
+       if (ret)
+               return ret;
+
+       return ULPI_VIEW_DATA_READ(readl(view));
+}
+
+static int ulpi_viewport_write(struct usb_phy *otg, u32 val, u32 reg)
+{
+       int ret;
+       void __iomem *view = otg->io_priv;
+
+       writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view);
+       ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP);
+       if (ret)
+               return ret;
+
+       writel(ULPI_VIEW_RUN | ULPI_VIEW_WRITE | ULPI_VIEW_DATA_WRITE(val) |
+                                                ULPI_VIEW_ADDR(reg), view);
+
+       return ulpi_viewport_wait(view, ULPI_VIEW_RUN);
+}
+
+struct usb_phy_io_ops ulpi_viewport_access_ops = {
+       .read   = ulpi_viewport_read,
+       .write  = ulpi_viewport_write,
+};