diff mbox

[Ver,1.0,3/7] Subscribes for USB resources for TI-DM646x EVM

Message ID 1255621580-24379-4-git-send-email-swami.iyer@ti.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Subbrathnam, Swaminathan Oct. 15, 2009, 3:46 p.m. UTC
None
diff mbox

Patch

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..bede7fe 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.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.h b/arch/arm/mach-davinci/include/mach/usb.h
index 96a60b1..6fb9620 100644
--- a/arch/arm/mach-davinci/include/mach/usb.h
+++ b/arch/arm/mach-davinci/include/mach/usb.h
@@ -40,6 +40,9 @@ 
 #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 */