summaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb
diff options
context:
space:
mode:
authorSanthapuri, Damodar <damodar.santhapuri@ti.com>2012-11-02 22:02:53 +0530
committerFelipe Balbi <balbi@ti.com>2012-11-06 15:03:02 +0200
commitc68bb4c679e68b2814bc5de812665fbd37f8a9b1 (patch)
tree4e024c8efe2affb784f0803e6d06252b2338d668 /drivers/usb/musb
parent3e594b18f1871a758812aa5e705873012cabf0e8 (diff)
downloadlinux-c68bb4c679e68b2814bc5de812665fbd37f8a9b1.tar.bz2
usb: musb: dsps: control module handling (quirk)
am335x uses nop transceiver driver and need to enable builtin phy by writing into usb_ctrl register available in system control module register space. This is being added at musb glue driver layer until a separate system control module driver is available. Proper solution is to make use of control module driver, but it is not expected to be ready soon. Other options available are providing control module register space as memory resource via DT or using omap hwmod. DT approach has been rejected by Rob Herring, while resources are being moved from hwmod to DT. And both of the above approaches require that control module registers be configured in wrapper itself requring a quirk in driver as well as DT or hwmod. Here another option is used, providing driver with control module register physical address. Even though this a hack, there is no other option left till control module driver is ready. As of now only am335x is using dsps wrapper, and so driver is made aware of am335x control module physical address. Please note that this is a temporary arrangment till omap control module driver is available. [afzal@ti.com: limit quirk to dsps wrapper] Signed-off-by: Santhapuri, Damodar <damodar.santhapuri@ti.com> Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> Signed-off-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: Afzal Mohammed <afzal@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/musb_dsps.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index b159fc92f846..6053af1f57c1 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -124,8 +124,44 @@ struct dsps_glue {
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
struct timer_list timer[2]; /* otg_workaround timer */
unsigned long last_timer[2]; /* last timer data for each instance */
+ u32 __iomem *usb_ctrl[2];
};
+#define DSPS_AM33XX_CONTROL_MODULE_PHYS_0 0x44e10620
+#define DSPS_AM33XX_CONTROL_MODULE_PHYS_1 0x44e10628
+
+static const resource_size_t dsps_control_module_phys[] = {
+ DSPS_AM33XX_CONTROL_MODULE_PHYS_0,
+ DSPS_AM33XX_CONTROL_MODULE_PHYS_1,
+};
+
+/**
+ * musb_dsps_phy_control - phy on/off
+ * @glue: struct dsps_glue *
+ * @id: musb instance
+ * @on: flag for phy to be switched on or off
+ *
+ * This is to enable the PHY using usb_ctrl register in system control
+ * module space.
+ *
+ * XXX: This function will be removed once we have a seperate driver for
+ * control module
+ */
+static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on)
+{
+ u32 usbphycfg;
+
+ usbphycfg = readl(glue->usb_ctrl[id]);
+
+ if (on) {
+ usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+ usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+ } else {
+ usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
+ }
+
+ writel(usbphycfg, glue->usb_ctrl[id]);
+}
/**
* dsps_musb_enable - enable interrupts
*/
@@ -392,6 +428,9 @@ static int dsps_musb_init(struct musb *musb)
/* Reset the musb */
dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
+ /* Start the on-chip PHY and its PLL. */
+ musb_dsps_phy_control(glue, pdev->id, 1);
+
musb->isr = dsps_interrupt;
/* reset the otgdisable bit, needed for host mode to work */
@@ -417,6 +456,9 @@ static int dsps_musb_exit(struct musb *musb)
del_timer_sync(&glue->timer[pdev->id]);
+ /* Shutdown the on-chip PHY and its PLL. */
+ musb_dsps_phy_control(glue, pdev->id, 0);
+
/* NOP driver needs change if supporting dual instance */
usb_put_phy(musb->xceiv);
usb_nop_xceiv_unregister();
@@ -449,6 +491,17 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
char res_name[10];
int ret;
+ resources[0].start = dsps_control_module_phys[id];
+ resources[0].end = resources[0].start + SZ_4 - 1;
+ resources[0].flags = IORESOURCE_MEM;
+
+ glue->usb_ctrl[id] = devm_request_and_ioremap(&pdev->dev, resources);
+ if (glue->usb_ctrl[id] == NULL) {
+ dev_err(dev, "Failed to obtain usb_ctrl%d memory\n", id);
+ ret = -ENODEV;
+ goto err0;
+ }
+
/* first resource is for usbss, so start index from 1 */
res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
if (!res) {
@@ -635,11 +688,27 @@ static int __devexit dsps_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int dsps_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ int i;
+
+ for (i = 0; i < wrp->instances; i++)
+ musb_dsps_phy_control(glue, i, 0);
+
return 0;
}
static int dsps_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ int i;
+
+ for (i = 0; i < wrp->instances; i++)
+ musb_dsps_phy_control(glue, i, 1);
+
return 0;
}
#endif