#include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 #include <linux/i2c/twl4030.h>
+#include <asm/arch/usb.h>
 
 /* Register defines */
 
 #define REG_PWR_SIH_CTRL               0x07
 #define COR                            (1 << 2)
 
+/* internal define on top of container_of */
+#define xceiv_to_twl(x)                container_of((x), struct twl4030_usb, otg);
+
+/* bits in OTG_CTRL_REG */
+
+#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)
+
+
 /*-------------------------------------------------------------------------*/
 
 struct twl4030_usb {
+       struct otg_transceiver  otg;
        int                     irq;
        u8                      usb_mode;       /* pin configuration */
 #define T2_USB_MODE_ULPI               1
 twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 {
        return twl4030_usb_write(reg + 2, bits);
+
 }
 
 /*-------------------------------------------------------------------------*/
        return;
 }
 
-void twl4030_phy_suspend(int controller_off);
-void twl4030_phy_resume(void);
+static void twl4030_phy_suspend(int controller_off);
+static void twl4030_phy_resume(void);
 
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
        twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, PROTECT_KEY);
 }
 
-void twl4030_phy_suspend(int controller_off)
+static void twl4030_phy_suspend(int controller_off)
 {
        struct twl4030_usb *twl = the_transceiver;
 
        twl->asleep = 1;
        return;
 }
-EXPORT_SYMBOL(twl4030_phy_suspend);
 
-
-void twl4030_phy_resume(void)
+static void twl4030_phy_resume(void)
 {
        struct twl4030_usb *twl = the_transceiver;
 
        twl->asleep = 0;
        return;
 }
-EXPORT_SYMBOL(twl4030_phy_resume);
 
+static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
+{
+       if (suspend)
+               twl4030_phy_suspend(1);
+       else
+               twl4030_phy_resume();
+
+       return 0;
+}
+
+static int twl4030_set_peripheral(struct otg_transceiver *xceiv, struct usb_gadget *gadget)
+{
+       struct twl4030_usb *twl = xceiv_to_twl(xceiv);
+
+       if (!xceiv)
+               return -ENODEV;
+
+       if (!gadget) {
+               OTG_IRQ_EN_REG = 0;
+               twl4030_phy_suspend(1);
+               twl->otg.gadget = NULL;
+
+               return -ENODEV;
+       }
+
+       twl->otg.gadget = gadget;
+       twl4030_phy_resume();
+
+       OTG_CTRL_REG = (OTG_CTRL_REG & OTG_CTRL_MASK
+                       & ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS))
+                       | OTG_ID;
+
+       twl->otg.state = OTG_STATE_B_IDLE;
+
+       twl4030_usb_set_bits(twl, USB_INT_EN_RISE,
+                       USB_INT_SESSVALID | USB_INT_VBUSVALID);
+       twl4030_usb_set_bits(twl, USB_INT_EN_FALL,
+                       USB_INT_SESSVALID | USB_INT_VBUSVALID);
+
+       return 0;
+}
+
+static int twl4030_set_host(struct otg_transceiver *xceiv, struct usb_bus *host)
+{
+       struct twl4030_usb *twl = xceiv_to_twl(xceiv);
+
+       if (!xceiv)
+               return -ENODEV;
+
+       if (!host) {
+               OTG_IRQ_EN_REG = 0;
+               twl4030_phy_suspend(1);
+               twl->otg.host = NULL;
+
+               return -ENODEV;
+       }
+
+       twl->otg.host = host;
+       twl4030_phy_resume();
+
+       twl4030_usb_set_bits(twl, OTG_CTRL,
+                       OTG_CTRL_DMPULLDOWN | OTG_CTRL_DPPULLDOWN);
+       twl4030_usb_set_bits(twl, USB_INT_EN_RISE, USB_INT_IDGND);
+       twl4030_usb_set_bits(twl, USB_INT_EN_FALL, USB_INT_IDGND);
+       twl4030_usb_set_bits(twl, FUNC_CTRL, FUNC_CTRL_SUSPENDM);
+       twl4030_usb_set_bits(twl, OTG_CTRL, OTG_CTRL_DRVVBUS);
+
+       return 0;
+}
 
 static int __init twl4030_usb_init(void)
 {
 
        the_transceiver = twl;
 
-       twl->irq = TWL4030_MODIRQ_PWR;
+       twl->irq                = TWL4030_MODIRQ_PWR;
+       twl->otg.set_host       = twl4030_set_host;
+       twl->otg.set_peripheral = twl4030_set_peripheral;
+       twl->otg.set_suspend    = twl4030_set_suspend;
 
        usb_irq_disable();
        status = request_irq(twl->irq, twl4030_usb_irq,
        if (twl->usb_mode == T2_USB_MODE_ULPI)
                twl4030_phy_suspend(1);
 
+       otg_set_transceiver(&twl->otg);
+
        printk(KERN_INFO "Initialized TWL4030 USB module");
 
        return 0;
 
        return 0;
 }
 
-static int omap_set_suspend(struct otg_transceiver *x, int suspend)
+int musb_platform_resume(struct musb *musb);
+
+void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
 {
-       if (suspend)
-               twl4030_phy_suspend(1);
-       else
-               twl4030_phy_resume();
-       return 0;
-}
+       u8      devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 
-int musb_platform_resume(struct musb *musb);
+       devctl |= MUSB_DEVCTL_SESSION;
+       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+       switch (musb_mode) {
+       case MUSB_HOST:
+               otg_set_host(&musb->xceiv, musb->xceiv.host);
+               break;
+       case MUSB_PERIPHERAL:
+               otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
+               break;
+       case MUSB_OTG:
+               break;
+       }
+}
 
 int __init musb_platform_init(struct musb *musb)
 {
+       struct otg_transceiver *xceiv = otg_get_transceiver();
+
 #if defined(CONFIG_ARCH_OMAP2430)
        omap_cfg_reg(AE5_2430_USB0HS_STP);
        /* get the clock */
        if(IS_ERR(musb->clock))
                return PTR_ERR(musb->clock);
 
-       musb->xceiv.set_suspend = omap_set_suspend;
+       musb->xceiv = *xceiv;
        musb_platform_resume(musb);
 
        OTG_INTERFSEL_REG |= ULPI_12PIN;