From: Ravi B <[email protected]>

This patch implments the support for USB VBUS, PHY control, DM646x
USB memory map, IRQ, USB Mode. It initializes for a single instance
of MUSB controller.

Signed-off-by: Ravi B <[email protected]>
---
 arch/arm/mach-davinci/board-dm646x-evm.c         |   72 +++++++++++++++++
 arch/arm/mach-davinci/dm646x.c                   |   91 ++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/dm646x.h      |    3 +
 arch/arm/mach-davinci/include/mach/usb_davinci.h |    4 +-
 4 files changed, 169 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c 
b/arch/arm/mach-davinci/board-dm646x-evm.c
index 24e0e13..49103a6 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -33,6 +33,7 @@
 #include <linux/i2c/at24.h>
 #include <linux/i2c/pcf857x.h>
 #include <linux/etherdevice.h>
+#include <linux/usb/musb.h>
 
 #include <media/tvp514x.h>
 
@@ -60,6 +61,7 @@
 /* CPLD Register 0 bits to control ATA */
 #define DM646X_EVM_ATA_RST             BIT(0)
 #define DM646X_EVM_ATA_PWD             BIT(1)
+#define DM646X_EVM_USB_VBUS            BIT(7)
 
 #define DM646X_EVM_PHY_MASK            (0x2)
 #define DM646X_EVM_MDIO_FREQUENCY      (2200000) /* PHY bus frequency */
@@ -88,14 +90,33 @@ static void __iomem *vpif_vsclkdis_reg;
 /* spin lock for updating above registers */
 static spinlock_t vpif_reg_lock;
 
+static int dm646x_evm_set_vbus(struct device *dev, int is_on);
+static struct musb_hdrc_platform_data usb_evm_data[] = {
+       {
+#if defined(CONFIG_USB_MUSB_OTG)
+               .mode = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+               .mode =  MUSB_PERIPHERAL,
+#elif defined(CONFIG_USB_MUSB_HOST)
+               .mode = MUSB_HOST,
+#endif
+               .power = 255,
+               .potpgt = 8,
+               .set_vbus = dm646x_evm_set_vbus,
+       }
+};
+
 static struct davinci_uart_config uart_config __initdata = {
        .enabled_uarts = (1 << 0),
 };
 
+struct i2c_client *cpld_reg0_client;
 /* CPLD Register 0 Client: used for I/O Control */
 static int cpld_reg0_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
+       cpld_reg0_client = client;
+
        if (HAS_ATA) {
                u8 data;
                struct i2c_msg msg[2] = {
@@ -652,6 +673,8 @@ static __init void evm_init(void)
 
        soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
        soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
+
+       dm646x_usb_configure(usb_evm_data, ARRAY_SIZE(usb_evm_data));
 }
 
 static __init void davinci_dm646x_evm_irq_init(void)
@@ -659,6 +682,55 @@ static __init void davinci_dm646x_evm_irq_init(void)
        davinci_irq_init();
 }
 
+/* Initiate the I2C command to the expander to turn on/off the VBUS line */
+static int vbus_state = -1;
+static void evm_deferred_drvvbus(struct work_struct *ignored)
+{
+       u8 data;
+
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = cpld_reg0_client->addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = &data,
+               },
+               {
+                       .addr = cpld_reg0_client->addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &data,
+               },
+       };
+
+       i2c_transfer(cpld_reg0_client->adapter, msg, 1);
+       if (vbus_state)
+               data |= DM646X_EVM_USB_VBUS;
+       else
+               data &= ~DM646X_EVM_USB_VBUS;
+
+       i2c_transfer(cpld_reg0_client->adapter, msg + 1, 1);
+       vbus_state = !vbus_state;
+}
+
+/*
+ * DM644x EVM USB VBUS handler.  On TI DM644x EVM USB VBUS is controller
+ * through I2C expander (0x3A) lines.  Tthis function schedules a
+ * work thread to handle the actual VBUS on/off operations.
+ */
+static int dm646x_evm_set_vbus(struct device *dev, int is_on)
+{
+       static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
+
+       is_on = is_on ? 1 : 0;
+       if (vbus_state == is_on)
+               return 0;
+
+       vbus_state = !is_on;
+       schedule_work(&evm_vbus_work);
+       return 0;
+}
+
 MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
        .phys_io      = IO_PHYS,
        .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 36e4fb4..2276c6a 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -28,6 +28,8 @@
 #include <mach/serial.h>
 #include <mach/common.h>
 #include <mach/asp.h>
+#include <mach/usb_davinci.h>
+#include <mach/usb_musb.h>
 
 #include "clock.h"
 #include "mux.h"
@@ -315,6 +317,12 @@ static struct clk vpif1_clk = {
        .flags = ALWAYS_ENABLED,
 };
 
+static struct clk usb_clk = {
+       .name = "usb",
+       .parent = &pll1_sysclk3,
+       .lpsc = DAVINCI_LPSC_USB,
+};
+
 struct davinci_clk dm646x_clks[] = {
        CLK(NULL, "ref", &ref_clk),
        CLK(NULL, "aux", &aux_clkin),
@@ -355,6 +363,7 @@ struct davinci_clk dm646x_clks[] = {
        CLK("palm_bk3710", NULL, &ide_clk),
        CLK(NULL, "vpif0", &vpif0_clk),
        CLK(NULL, "vpif1", &vpif1_clk),
+       CLK(NULL, "usb", &usb_clk),
        CLK(NULL, NULL, NULL),
 };
 
@@ -930,6 +939,87 @@ void __init dm646x_init(void)
        davinci_common_init(&davinci_soc_info_dm646x);
 }
 
+/*
+ * Configure the USB PHY for DM644x platforms.
+ */
+static int dm646x_usb_phy_config(struct device *dev, u8 mode, int is_on)
+{
+       u32     phy_ctrl = __raw_readl(USB_PHY_CTRL);
+
+       if (is_on) {
+               /* power everything up; start the on-chip PHY and its PLL */
+               phy_ctrl &= ~(USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN);
+               phy_ctrl |= USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON;
+               phy_ctrl |= USBPHY_NDATAPOL | USBPHY_SESSION_VBUS;
+               switch (mode) {
+               case MUSB_PERIPHERAL:
+                       phy_ctrl |= USBPHY_PERI_USBID;
+                       break;
+               case MUSB_HOST:
+                       phy_ctrl &= ~USBPHY_VBDTCTEN;
+                       break;
+               }
+
+       } else {
+               /* powerdown the on-chip PHY, its PLL, and the OTG block */
+               phy_ctrl &= ~(USBPHY_SESNDEN | USBPHY_VBDTCTEN |
+                               USBPHY_PHYPLLON);
+               phy_ctrl |= USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN;
+       }
+
+       __raw_writel(phy_ctrl, USB_PHY_CTRL);
+
+       if (is_on) {
+               /* wait for PLL to lock before proceeding */
+               while ((__raw_readl(USB_PHY_CTRL) & USBPHY_PHYCLKGD) == 0)
+                       cpu_relax();
+       }
+
+       return 0;
+}
+
+static struct resource usb_resources[] = {
+       {
+               .start  = DAVINCI_USB_OTG_BASE,
+               .end    = DAVINCI_USB_OTG_BASE + 0x5ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_DM646X_USBINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = IRQ_DM646X_USBDMAINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct plat_res_data dm646x_usb_res;
+static struct usb_plat_data dm646x_usb_plat_data;
+/*
+ * Initialize DM644x related USB information such as Memory maps, IRQ etc.
+ * Since DM644x supprot a single MUSB controller initialize the instance
+ * value to 1.
+ */
+void dm646x_usb_configure(struct musb_hdrc_platform_data *pdata, u8 num_inst)
+{
+       pdata->phy_config = dm646x_usb_phy_config;
+
+       dm646x_usb_res.plat_data = pdata;
+       dm646x_usb_res.res_data = usb_resources;
+       dm646x_usb_res.num_res = ARRAY_SIZE(usb_resources);
+
+       dm646x_usb_plat_data.prdata = &dm646x_usb_res;
+       dm646x_usb_plat_data.num_inst = num_inst;
+
+       /* Call the generic platform register function.  The USB
+        * configuration w.r.t no. of ep's, capabalities etc. are common
+        * across DaVinci platforms and hence allow the generic handler
+        * to populate the information.
+        */
+       setup_usb(&dm646x_usb_plat_data);
+}
+
 static int __init dm646x_init_devices(void)
 {
        if (!cpu_is_davinci_dm646x())
@@ -940,3 +1030,4 @@ static int __init dm646x_init_devices(void)
        return 0;
 }
 postcore_initcall(dm646x_init_devices);
+
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h 
b/arch/arm/mach-davinci/include/mach/dm646x.h
index 8cec746..3c49bfa 100644
--- a/arch/arm/mach-davinci/include/mach/dm646x.h
+++ b/arch/arm/mach-davinci/include/mach/dm646x.h
@@ -16,6 +16,7 @@
 #include <mach/asp.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
+#include <linux/usb/musb.h>
 
 #define DM646X_EMAC_BASE               (0x01C80000)
 #define DM646X_EMAC_CNTRL_OFFSET       (0x0000)
@@ -30,6 +31,8 @@ void __init dm646x_init(void);
 void __init dm646x_init_ide(void);
 void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
 void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
+extern void dm646x_usb_configure(struct musb_hdrc_platform_data *pdata,
+                                       u8 num_inst);
 
 void dm646x_video_init(void);
 
diff --git a/arch/arm/mach-davinci/include/mach/usb_davinci.h 
b/arch/arm/mach-davinci/include/mach/usb_davinci.h
index 02f8af7..eaa84f1 100644
--- a/arch/arm/mach-davinci/include/mach/usb_davinci.h
+++ b/arch/arm/mach-davinci/include/mach/usb_davinci.h
@@ -27,7 +27,9 @@
 /* Integrated highspeed/otg PHY */
 #define USBPHY_CTL_PADDR        (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
 #define USB_PHY_CTRL           IO_ADDRESS(USBPHY_CTL_PADDR)
-
+#define USBPHY_NDATAPOL         BIT(18)
+#define USBPHY_SESSION_VBUS     BIT(17)
+#define USBPHY_PERI_USBID       BIT(16)
 #define USBPHY_PHYCLKGD         BIT(8)
 #define USBPHY_SESNDEN          BIT(7)  /* v(sess_end) comparator */
 #define USBPHY_VBDTCTEN         BIT(6)  /* v(bus) comparator */
-- 
1.6.0.rc1.64.g61192

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to