usb: musb: add ulpi access operations
authorHeikki Krogerus <ext-heikki.krogerus@nokia.com>
Thu, 25 Mar 2010 11:25:28 +0000 (13:25 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 20 May 2010 20:21:36 +0000 (13:21 -0700)
This adds helper functions for ULPI access, and implements
otg_io_access_ops for musb.

Signed-off-by: Heikki Krogerus <ext-heikki.krogerus@nokia.com>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_regs.h

index 27aaaa023a1e70dfafff6e279804ff09d194abfb..fad70bc835558a501e0f06a615237e07be4197e0 100644 (file)
@@ -149,6 +149,87 @@ static inline struct musb *dev_to_musb(struct device *dev)
 
 /*-------------------------------------------------------------------------*/
 
+#ifndef CONFIG_BLACKFIN
+static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
+{
+       void __iomem *addr = otg->io_priv;
+       int     i = 0;
+       u8      r;
+       u8      power;
+
+       /* Make sure the transceiver is not in low power mode */
+       power = musb_readb(addr, MUSB_POWER);
+       power &= ~MUSB_POWER_SUSPENDM;
+       musb_writeb(addr, MUSB_POWER, power);
+
+       /* REVISIT: musbhdrc_ulpi_an.pdf recommends setting the
+        * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM.
+        */
+
+       musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+       musb_writeb(addr, MUSB_ULPI_REG_CONTROL,
+                       MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR);
+
+       while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
+                               & MUSB_ULPI_REG_CMPLT)) {
+               i++;
+               if (i == 10000) {
+                       DBG(3, "ULPI read timed out\n");
+                       return -ETIMEDOUT;
+               }
+
+       }
+       r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
+       r &= ~MUSB_ULPI_REG_CMPLT;
+       musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
+
+       return musb_readb(addr, MUSB_ULPI_REG_DATA);
+}
+
+static int musb_ulpi_write(struct otg_transceiver *otg,
+               u32 offset, u32 data)
+{
+       void __iomem *addr = otg->io_priv;
+       int     i = 0;
+       u8      r = 0;
+       u8      power;
+
+       /* Make sure the transceiver is not in low power mode */
+       power = musb_readb(addr, MUSB_POWER);
+       power &= ~MUSB_POWER_SUSPENDM;
+       musb_writeb(addr, MUSB_POWER, power);
+
+       musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+       musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data);
+       musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ);
+
+       while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
+                               & MUSB_ULPI_REG_CMPLT)) {
+               i++;
+               if (i == 10000) {
+                       DBG(3, "ULPI write timed out\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
+       r &= ~MUSB_ULPI_REG_CMPLT;
+       musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
+
+       return 0;
+}
+#else
+#define musb_ulpi_read(a, b)           NULL
+#define musb_ulpi_write(a, b, c)       NULL
+#endif
+
+static struct otg_io_access_ops musb_ulpi_access = {
+       .read = musb_ulpi_read,
+       .write = musb_ulpi_write,
+};
+
+/*-------------------------------------------------------------------------*/
+
 #if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
 
 /*
@@ -1954,6 +2035,11 @@ bad_config:
                goto fail3;
        }
 
+       if (!musb->xceiv->io_ops) {
+               musb->xceiv->io_priv = musb->mregs;
+               musb->xceiv->io_ops = &musb_ulpi_access;
+       }
+
 #ifndef CONFIG_MUSB_PIO_ONLY
        if (use_dma && dev->dma_mask) {
                struct dma_controller   *c;
index fa55aacc385d3541b6fa162e4ee00000c96cd7a2..244267527a60b1421ea7c70a814388dde6951f7f 100644 (file)
 /* MUSB ULPI VBUSCONTROL */
 #define MUSB_ULPI_USE_EXTVBUS  0x01
 #define MUSB_ULPI_USE_EXTVBUSIND 0x02
+/* ULPI_REG_CONTROL */
+#define MUSB_ULPI_REG_REQ      (1 << 0)
+#define MUSB_ULPI_REG_CMPLT    (1 << 1)
+#define MUSB_ULPI_RDN_WR       (1 << 2)
 
 /* TESTMODE */
 #define MUSB_TEST_FORCE_HOST   0x80
 /* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
 #define MUSB_HWVERS            0x6C    /* 8 bit */
 #define MUSB_ULPI_BUSCONTROL   0x70    /* 8 bit */
+#define MUSB_ULPI_INT_MASK     0x72    /* 8 bit */
+#define MUSB_ULPI_INT_SRC      0x73    /* 8 bit */
+#define MUSB_ULPI_REG_DATA     0x74    /* 8 bit */
+#define MUSB_ULPI_REG_ADDR     0x75    /* 8 bit */
+#define MUSB_ULPI_REG_CONTROL  0x76    /* 8 bit */
+#define MUSB_ULPI_RAW_DATA     0x77    /* 8 bit */
 
 #define MUSB_EPINFO            0x78    /* 8 bit */
 #define MUSB_RAMINFO           0x79    /* 8 bit */