@@ -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,
@@ -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);
+
@@ -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);
@@ -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 */