15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 29ecb8875SAjay Kumar Gupta /* 39ecb8875SAjay Kumar Gupta * Texas Instruments DSPS platforms "glue layer" 49ecb8875SAjay Kumar Gupta * 59ecb8875SAjay Kumar Gupta * Copyright (C) 2012, by Texas Instruments 69ecb8875SAjay Kumar Gupta * 79ecb8875SAjay Kumar Gupta * Based on the am35x "glue layer" code. 89ecb8875SAjay Kumar Gupta * 99ecb8875SAjay Kumar Gupta * This file is part of the Inventra Controller Driver for Linux. 109ecb8875SAjay Kumar Gupta * 119ecb8875SAjay Kumar Gupta * musb_dsps.c will be a common file for all the TI DSPS platforms 129ecb8875SAjay Kumar Gupta * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x. 139ecb8875SAjay Kumar Gupta * For now only ti81x is using this and in future davinci.c, am35x.c 149ecb8875SAjay Kumar Gupta * da8xx.c would be merged to this file after testing. 159ecb8875SAjay Kumar Gupta */ 169ecb8875SAjay Kumar Gupta 179ecb8875SAjay Kumar Gupta #include <linux/io.h> 18ded017eeSKishon Vijay Abraham I #include <linux/err.h> 199ecb8875SAjay Kumar Gupta #include <linux/platform_device.h> 209ecb8875SAjay Kumar Gupta #include <linux/dma-mapping.h> 219ecb8875SAjay Kumar Gupta #include <linux/pm_runtime.h> 229ecb8875SAjay Kumar Gupta #include <linux/module.h> 23d7078df6SFelipe Balbi #include <linux/usb/usb_phy_generic.h> 24e8c4a7acSFelipe Balbi #include <linux/platform_data/usb-omap.h> 250f53e481SFelipe Balbi #include <linux/sizes.h> 269ecb8875SAjay Kumar Gupta 279ecb8875SAjay Kumar Gupta #include <linux/of.h> 289ecb8875SAjay Kumar Gupta #include <linux/of_device.h> 299ecb8875SAjay Kumar Gupta #include <linux/of_address.h> 3097238b35SSebastian Andrzej Siewior #include <linux/of_irq.h> 31c031a7d4SSebastian Andrzej Siewior #include <linux/usb/of.h> 329ecb8875SAjay Kumar Gupta 3340f099e3SMarkus Pargmann #include <linux/debugfs.h> 3440f099e3SMarkus Pargmann 359ecb8875SAjay Kumar Gupta #include "musb_core.h" 369ecb8875SAjay Kumar Gupta 3765145677SAjay Kumar Gupta static const struct of_device_id musb_dsps_of_match[]; 3865145677SAjay Kumar Gupta 3909e03a89SLee Jones /* 409ecb8875SAjay Kumar Gupta * DSPS musb wrapper register offset. 419ecb8875SAjay Kumar Gupta * FIXME: This should be expanded to have all the wrapper registers from TI DSPS 429ecb8875SAjay Kumar Gupta * musb ips. 439ecb8875SAjay Kumar Gupta */ 449ecb8875SAjay Kumar Gupta struct dsps_musb_wrapper { 459ecb8875SAjay Kumar Gupta u16 revision; 469ecb8875SAjay Kumar Gupta u16 control; 479ecb8875SAjay Kumar Gupta u16 status; 489ecb8875SAjay Kumar Gupta u16 epintr_set; 499ecb8875SAjay Kumar Gupta u16 epintr_clear; 509ecb8875SAjay Kumar Gupta u16 epintr_status; 519ecb8875SAjay Kumar Gupta u16 coreintr_set; 529ecb8875SAjay Kumar Gupta u16 coreintr_clear; 539ecb8875SAjay Kumar Gupta u16 coreintr_status; 549ecb8875SAjay Kumar Gupta u16 phy_utmi; 559ecb8875SAjay Kumar Gupta u16 mode; 56b991f9b7SDaniel Mack u16 tx_mode; 57b991f9b7SDaniel Mack u16 rx_mode; 589ecb8875SAjay Kumar Gupta 599ecb8875SAjay Kumar Gupta /* bit positions for control */ 609ecb8875SAjay Kumar Gupta unsigned reset:5; 619ecb8875SAjay Kumar Gupta 629ecb8875SAjay Kumar Gupta /* bit positions for interrupt */ 639ecb8875SAjay Kumar Gupta unsigned usb_shift:5; 649ecb8875SAjay Kumar Gupta u32 usb_mask; 659ecb8875SAjay Kumar Gupta u32 usb_bitmap; 669ecb8875SAjay Kumar Gupta unsigned drvvbus:5; 679ecb8875SAjay Kumar Gupta 689ecb8875SAjay Kumar Gupta unsigned txep_shift:5; 699ecb8875SAjay Kumar Gupta u32 txep_mask; 709ecb8875SAjay Kumar Gupta u32 txep_bitmap; 719ecb8875SAjay Kumar Gupta 729ecb8875SAjay Kumar Gupta unsigned rxep_shift:5; 739ecb8875SAjay Kumar Gupta u32 rxep_mask; 749ecb8875SAjay Kumar Gupta u32 rxep_bitmap; 759ecb8875SAjay Kumar Gupta 769ecb8875SAjay Kumar Gupta /* bit positions for phy_utmi */ 779ecb8875SAjay Kumar Gupta unsigned otg_disable:5; 789ecb8875SAjay Kumar Gupta 799ecb8875SAjay Kumar Gupta /* bit positions for mode */ 809ecb8875SAjay Kumar Gupta unsigned iddig:5; 81943c1397SFelipe Balbi unsigned iddig_mux:5; 829ecb8875SAjay Kumar Gupta /* miscellaneous stuff */ 839e204d88SFelipe Balbi unsigned poll_timeout; 849ecb8875SAjay Kumar Gupta }; 859ecb8875SAjay Kumar Gupta 86869c5978SDaniel Mack /* 87869c5978SDaniel Mack * register shadow for suspend 88869c5978SDaniel Mack */ 89869c5978SDaniel Mack struct dsps_context { 90869c5978SDaniel Mack u32 control; 91869c5978SDaniel Mack u32 epintr; 92869c5978SDaniel Mack u32 coreintr; 93869c5978SDaniel Mack u32 phy_utmi; 94869c5978SDaniel Mack u32 mode; 95869c5978SDaniel Mack u32 tx_mode; 96869c5978SDaniel Mack u32 rx_mode; 97869c5978SDaniel Mack }; 98869c5978SDaniel Mack 9909e03a89SLee Jones /* 1009ecb8875SAjay Kumar Gupta * DSPS glue structure. 1019ecb8875SAjay Kumar Gupta */ 1029ecb8875SAjay Kumar Gupta struct dsps_glue { 1039ecb8875SAjay Kumar Gupta struct device *dev; 10497238b35SSebastian Andrzej Siewior struct platform_device *musb; /* child musb pdev */ 1059ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ 106369469a9STony Lindgren int vbus_irq; /* optional vbus irq */ 10797238b35SSebastian Andrzej Siewior unsigned long last_timer; /* last timer data for each instance */ 108371254ceSGeorge Cherian bool sw_babble_enabled; 10925534828SAlexandre Bailon void __iomem *usbss_base; 110869c5978SDaniel Mack 111869c5978SDaniel Mack struct dsps_context context; 11240f099e3SMarkus Pargmann struct debugfs_regset32 regset; 11340f099e3SMarkus Pargmann struct dentry *dbgfs_root; 11440f099e3SMarkus Pargmann }; 11540f099e3SMarkus Pargmann 11640f099e3SMarkus Pargmann static const struct debugfs_reg32 dsps_musb_regs[] = { 11740f099e3SMarkus Pargmann { "revision", 0x00 }, 11840f099e3SMarkus Pargmann { "control", 0x14 }, 11940f099e3SMarkus Pargmann { "status", 0x18 }, 12040f099e3SMarkus Pargmann { "eoi", 0x24 }, 12140f099e3SMarkus Pargmann { "intr0_stat", 0x30 }, 12240f099e3SMarkus Pargmann { "intr1_stat", 0x34 }, 12340f099e3SMarkus Pargmann { "intr0_set", 0x38 }, 12440f099e3SMarkus Pargmann { "intr1_set", 0x3c }, 12540f099e3SMarkus Pargmann { "txmode", 0x70 }, 12640f099e3SMarkus Pargmann { "rxmode", 0x74 }, 12740f099e3SMarkus Pargmann { "autoreq", 0xd0 }, 12840f099e3SMarkus Pargmann { "srpfixtime", 0xd4 }, 12940f099e3SMarkus Pargmann { "tdown", 0xd8 }, 13040f099e3SMarkus Pargmann { "phy_utmi", 0xe0 }, 13140f099e3SMarkus Pargmann { "mode", 0xe8 }, 1329ecb8875SAjay Kumar Gupta }; 1339ecb8875SAjay Kumar Gupta 134369469a9STony Lindgren static void dsps_mod_timer(struct dsps_glue *glue, int wait_ms) 135369469a9STony Lindgren { 136b82162bcSBin Liu struct musb *musb = platform_get_drvdata(glue->musb); 137369469a9STony Lindgren int wait; 138369469a9STony Lindgren 139369469a9STony Lindgren if (wait_ms < 0) 140369469a9STony Lindgren wait = msecs_to_jiffies(glue->wrp->poll_timeout); 141369469a9STony Lindgren else 142369469a9STony Lindgren wait = msecs_to_jiffies(wait_ms); 143369469a9STony Lindgren 144b82162bcSBin Liu mod_timer(&musb->dev_timer, jiffies + wait); 145369469a9STony Lindgren } 146369469a9STony Lindgren 147369469a9STony Lindgren /* 148369469a9STony Lindgren * If no vbus irq from the PMIC is configured, we need to poll VBUS status. 149369469a9STony Lindgren */ 150369469a9STony Lindgren static void dsps_mod_timer_optional(struct dsps_glue *glue) 151369469a9STony Lindgren { 152369469a9STony Lindgren if (glue->vbus_irq) 153369469a9STony Lindgren return; 154369469a9STony Lindgren 155369469a9STony Lindgren dsps_mod_timer(glue, -1); 156369469a9STony Lindgren } 157369469a9STony Lindgren 15825534828SAlexandre Bailon /* USBSS / USB AM335x */ 15925534828SAlexandre Bailon #define USBSS_IRQ_STATUS 0x28 16025534828SAlexandre Bailon #define USBSS_IRQ_ENABLER 0x2c 16125534828SAlexandre Bailon #define USBSS_IRQ_CLEARR 0x30 16225534828SAlexandre Bailon 16325534828SAlexandre Bailon #define USBSS_IRQ_PD_COMP (1 << 2) 16425534828SAlexandre Bailon 16509e03a89SLee Jones /* 1669ecb8875SAjay Kumar Gupta * dsps_musb_enable - enable interrupts 1679ecb8875SAjay Kumar Gupta */ 1689ecb8875SAjay Kumar Gupta static void dsps_musb_enable(struct musb *musb) 1699ecb8875SAjay Kumar Gupta { 1709ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 171e823d948SKefeng Wang struct dsps_glue *glue = dev_get_drvdata(dev->parent); 1729ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 1739ecb8875SAjay Kumar Gupta void __iomem *reg_base = musb->ctrl_base; 1749ecb8875SAjay Kumar Gupta u32 epmask, coremask; 1759ecb8875SAjay Kumar Gupta 1769ecb8875SAjay Kumar Gupta /* Workaround: setup IRQs through both register sets. */ 1779ecb8875SAjay Kumar Gupta epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) | 1789ecb8875SAjay Kumar Gupta ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift); 1799ecb8875SAjay Kumar Gupta coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF); 1809ecb8875SAjay Kumar Gupta 181086b2882SBin Liu musb_writel(reg_base, wrp->epintr_set, epmask); 182086b2882SBin Liu musb_writel(reg_base, wrp->coreintr_set, coremask); 18354578ee8SBin Liu /* 18454578ee8SBin Liu * start polling for runtime PM active and idle, 18554578ee8SBin Liu * and for ID change in dual-role idle mode. 18654578ee8SBin Liu */ 18754578ee8SBin Liu if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) 188369469a9STony Lindgren dsps_mod_timer(glue, -1); 1899ecb8875SAjay Kumar Gupta } 1909ecb8875SAjay Kumar Gupta 19109e03a89SLee Jones /* 1929ecb8875SAjay Kumar Gupta * dsps_musb_disable - disable HDRC and flush interrupts 1939ecb8875SAjay Kumar Gupta */ 1949ecb8875SAjay Kumar Gupta static void dsps_musb_disable(struct musb *musb) 1959ecb8875SAjay Kumar Gupta { 1969ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 197e823d948SKefeng Wang struct dsps_glue *glue = dev_get_drvdata(dev->parent); 1989ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 1999ecb8875SAjay Kumar Gupta void __iomem *reg_base = musb->ctrl_base; 2009ecb8875SAjay Kumar Gupta 201086b2882SBin Liu musb_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); 202086b2882SBin Liu musb_writel(reg_base, wrp->epintr_clear, 2039ecb8875SAjay Kumar Gupta wrp->txep_bitmap | wrp->rxep_bitmap); 204b82162bcSBin Liu del_timer_sync(&musb->dev_timer); 2059ecb8875SAjay Kumar Gupta } 2069ecb8875SAjay Kumar Gupta 207ea2f35c0STony Lindgren /* Caller must take musb->lock */ 208ea2f35c0STony Lindgren static int dsps_check_status(struct musb *musb, void *unused) 2099ecb8875SAjay Kumar Gupta { 2109ecb8875SAjay Kumar Gupta void __iomem *mregs = musb->mregs; 2119ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 212db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 2139ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 2149ecb8875SAjay Kumar Gupta u8 devctl; 2150f901c98SSebastian Andrzej Siewior int skip_session = 0; 2169ecb8875SAjay Kumar Gupta 217369469a9STony Lindgren if (glue->vbus_irq) 218b82162bcSBin Liu del_timer(&musb->dev_timer); 219369469a9STony Lindgren 2209ecb8875SAjay Kumar Gupta /* 2219ecb8875SAjay Kumar Gupta * We poll because DSPS IP's won't expose several OTG-critical 2229ecb8875SAjay Kumar Gupta * status change events (from the transceiver) otherwise. 2239ecb8875SAjay Kumar Gupta */ 224086b2882SBin Liu devctl = musb_readb(mregs, MUSB_DEVCTL); 2259ecb8875SAjay Kumar Gupta dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, 226e47d9254SAntoine Tenart usb_otg_state_string(musb->xceiv->otg->state)); 2279ecb8875SAjay Kumar Gupta 228e47d9254SAntoine Tenart switch (musb->xceiv->otg->state) { 2292f3fd2c5STony Lindgren case OTG_STATE_A_WAIT_VRISE: 2306010abf2SBin Liu if (musb->port_mode == MUSB_HOST) { 2316010abf2SBin Liu musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; 232369469a9STony Lindgren dsps_mod_timer_optional(glue); 2332f3fd2c5STony Lindgren break; 2346010abf2SBin Liu } 235df561f66SGustavo A. R. Silva fallthrough; 2366010abf2SBin Liu 2379ecb8875SAjay Kumar Gupta case OTG_STATE_A_WAIT_BCON: 238b3addcf0SBin Liu /* keep VBUS on for host-only mode */ 2397ad76955SBin Liu if (musb->port_mode == MUSB_HOST) { 240b3addcf0SBin Liu dsps_mod_timer_optional(glue); 241b3addcf0SBin Liu break; 242b3addcf0SBin Liu } 243086b2882SBin Liu musb_writeb(musb->mregs, MUSB_DEVCTL, 0); 2440f901c98SSebastian Andrzej Siewior skip_session = 1; 245df561f66SGustavo A. R. Silva fallthrough; 2469ecb8875SAjay Kumar Gupta 2470f901c98SSebastian Andrzej Siewior case OTG_STATE_A_IDLE: 2480f901c98SSebastian Andrzej Siewior case OTG_STATE_B_IDLE: 249369469a9STony Lindgren if (!glue->vbus_irq) { 2509ecb8875SAjay Kumar Gupta if (devctl & MUSB_DEVCTL_BDEVICE) { 251e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_B_IDLE; 2529ecb8875SAjay Kumar Gupta MUSB_DEV_MODE(musb); 2539ecb8875SAjay Kumar Gupta } else { 254e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_IDLE; 2559ecb8875SAjay Kumar Gupta MUSB_HST_MODE(musb); 2569ecb8875SAjay Kumar Gupta } 25754578ee8SBin Liu 25854578ee8SBin Liu if (musb->port_mode == MUSB_PERIPHERAL) 25954578ee8SBin Liu skip_session = 1; 26054578ee8SBin Liu 2610f901c98SSebastian Andrzej Siewior if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) 262369469a9STony Lindgren musb_writeb(mregs, MUSB_DEVCTL, 263369469a9STony Lindgren MUSB_DEVCTL_SESSION); 264369469a9STony Lindgren } 265369469a9STony Lindgren dsps_mod_timer_optional(glue); 2669ecb8875SAjay Kumar Gupta break; 2679ecb8875SAjay Kumar Gupta case OTG_STATE_A_WAIT_VFALL: 268e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; 269086b2882SBin Liu musb_writel(musb->ctrl_base, wrp->coreintr_set, 2709ecb8875SAjay Kumar Gupta MUSB_INTR_VBUSERROR << wrp->usb_shift); 2719ecb8875SAjay Kumar Gupta break; 2729ecb8875SAjay Kumar Gupta default: 2739ecb8875SAjay Kumar Gupta break; 2749ecb8875SAjay Kumar Gupta } 27565b3f50eSTony Lindgren 276ea2f35c0STony Lindgren return 0; 277ea2f35c0STony Lindgren } 278ea2f35c0STony Lindgren 27905678497SKees Cook static void otg_timer(struct timer_list *t) 280ea2f35c0STony Lindgren { 281b82162bcSBin Liu struct musb *musb = from_timer(musb, t, dev_timer); 282ea2f35c0STony Lindgren struct device *dev = musb->controller; 283ea2f35c0STony Lindgren unsigned long flags; 284ea2f35c0STony Lindgren int err; 285ea2f35c0STony Lindgren 286ea2f35c0STony Lindgren err = pm_runtime_get(dev); 287ea2f35c0STony Lindgren if ((err != -EINPROGRESS) && err < 0) { 288ea2f35c0STony Lindgren dev_err(dev, "Poll could not pm_runtime_get: %i\n", err); 289ea2f35c0STony Lindgren pm_runtime_put_noidle(dev); 290ea2f35c0STony Lindgren 291ea2f35c0STony Lindgren return; 292ea2f35c0STony Lindgren } 293ea2f35c0STony Lindgren 294ea2f35c0STony Lindgren spin_lock_irqsave(&musb->lock, flags); 295ea2f35c0STony Lindgren err = musb_queue_resume_work(musb, dsps_check_status, NULL); 296ea2f35c0STony Lindgren if (err < 0) 297ea2f35c0STony Lindgren dev_err(dev, "%s resume work: %i\n", __func__, err); 298ea2f35c0STony Lindgren spin_unlock_irqrestore(&musb->lock, flags); 29965b3f50eSTony Lindgren pm_runtime_mark_last_busy(dev); 30065b3f50eSTony Lindgren pm_runtime_put_autosuspend(dev); 3019ecb8875SAjay Kumar Gupta } 3029ecb8875SAjay Kumar Gupta 3034ab53a69SWei Yongjun static void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) 304c48400baSBin Liu { 305c48400baSBin Liu u32 epintr; 306c48400baSBin Liu struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 307c48400baSBin Liu const struct dsps_musb_wrapper *wrp = glue->wrp; 308c48400baSBin Liu 309c48400baSBin Liu /* musb->lock might already been held */ 310c48400baSBin Liu epintr = (1 << epnum) << wrp->rxep_shift; 311c48400baSBin Liu musb_writel(musb->ctrl_base, wrp->epintr_status, epintr); 312c48400baSBin Liu } 313c48400baSBin Liu 3149ecb8875SAjay Kumar Gupta static irqreturn_t dsps_interrupt(int irq, void *hci) 3159ecb8875SAjay Kumar Gupta { 3169ecb8875SAjay Kumar Gupta struct musb *musb = hci; 3179ecb8875SAjay Kumar Gupta void __iomem *reg_base = musb->ctrl_base; 3189ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 319db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 3209ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 3219ecb8875SAjay Kumar Gupta unsigned long flags; 3229ecb8875SAjay Kumar Gupta irqreturn_t ret = IRQ_NONE; 3239ecb8875SAjay Kumar Gupta u32 epintr, usbintr; 3249ecb8875SAjay Kumar Gupta 3259ecb8875SAjay Kumar Gupta spin_lock_irqsave(&musb->lock, flags); 3269ecb8875SAjay Kumar Gupta 3279ecb8875SAjay Kumar Gupta /* Get endpoint interrupts */ 328086b2882SBin Liu epintr = musb_readl(reg_base, wrp->epintr_status); 3299ecb8875SAjay Kumar Gupta musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; 3309ecb8875SAjay Kumar Gupta musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; 3319ecb8875SAjay Kumar Gupta 3329ecb8875SAjay Kumar Gupta if (epintr) 333086b2882SBin Liu musb_writel(reg_base, wrp->epintr_status, epintr); 3349ecb8875SAjay Kumar Gupta 3359ecb8875SAjay Kumar Gupta /* Get usb core interrupts */ 336086b2882SBin Liu usbintr = musb_readl(reg_base, wrp->coreintr_status); 3379ecb8875SAjay Kumar Gupta if (!usbintr && !epintr) 3389be73baeSSebastian Andrzej Siewior goto out; 3399ecb8875SAjay Kumar Gupta 3409ecb8875SAjay Kumar Gupta musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; 3419ecb8875SAjay Kumar Gupta if (usbintr) 342086b2882SBin Liu musb_writel(reg_base, wrp->coreintr_status, usbintr); 3439ecb8875SAjay Kumar Gupta 3449ecb8875SAjay Kumar Gupta dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", 3459ecb8875SAjay Kumar Gupta usbintr, epintr); 3461d57de30SDaniel Mack 3479ecb8875SAjay Kumar Gupta if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { 348086b2882SBin Liu int drvvbus = musb_readl(reg_base, wrp->status); 3499ecb8875SAjay Kumar Gupta void __iomem *mregs = musb->mregs; 350086b2882SBin Liu u8 devctl = musb_readb(mregs, MUSB_DEVCTL); 3519ecb8875SAjay Kumar Gupta int err; 3529ecb8875SAjay Kumar Gupta 353032ec49fSFelipe Balbi err = musb->int_usb & MUSB_INTR_VBUSERROR; 3549ecb8875SAjay Kumar Gupta if (err) { 3559ecb8875SAjay Kumar Gupta /* 3569ecb8875SAjay Kumar Gupta * The Mentor core doesn't debounce VBUS as needed 3579ecb8875SAjay Kumar Gupta * to cope with device connect current spikes. This 3589ecb8875SAjay Kumar Gupta * means it's not uncommon for bus-powered devices 3599ecb8875SAjay Kumar Gupta * to get VBUS errors during enumeration. 3609ecb8875SAjay Kumar Gupta * 3619ecb8875SAjay Kumar Gupta * This is a workaround, but newer RTL from Mentor 3629ecb8875SAjay Kumar Gupta * seems to allow a better one: "re"-starting sessions 3639ecb8875SAjay Kumar Gupta * without waiting for VBUS to stop registering in 3649ecb8875SAjay Kumar Gupta * devctl. 3659ecb8875SAjay Kumar Gupta */ 3669ecb8875SAjay Kumar Gupta musb->int_usb &= ~MUSB_INTR_VBUSERROR; 367e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; 368369469a9STony Lindgren dsps_mod_timer_optional(glue); 3699ecb8875SAjay Kumar Gupta WARNING("VBUS error workaround (delay coming)\n"); 370032ec49fSFelipe Balbi } else if (drvvbus) { 3719ecb8875SAjay Kumar Gupta MUSB_HST_MODE(musb); 372e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; 373369469a9STony Lindgren dsps_mod_timer_optional(glue); 3749ecb8875SAjay Kumar Gupta } else { 3759ecb8875SAjay Kumar Gupta musb->is_active = 0; 3769ecb8875SAjay Kumar Gupta MUSB_DEV_MODE(musb); 377e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_B_IDLE; 3789ecb8875SAjay Kumar Gupta } 3799ecb8875SAjay Kumar Gupta 3809ecb8875SAjay Kumar Gupta /* NOTE: this must complete power-on within 100 ms. */ 3819ecb8875SAjay Kumar Gupta dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", 3829ecb8875SAjay Kumar Gupta drvvbus ? "on" : "off", 383e47d9254SAntoine Tenart usb_otg_state_string(musb->xceiv->otg->state), 3849ecb8875SAjay Kumar Gupta err ? " ERROR" : "", 3859ecb8875SAjay Kumar Gupta devctl); 3869ecb8875SAjay Kumar Gupta ret = IRQ_HANDLED; 3879ecb8875SAjay Kumar Gupta } 3889ecb8875SAjay Kumar Gupta 3899ecb8875SAjay Kumar Gupta if (musb->int_tx || musb->int_rx || musb->int_usb) 3909ecb8875SAjay Kumar Gupta ret |= musb_interrupt(musb); 3919ecb8875SAjay Kumar Gupta 3922f3fd2c5STony Lindgren /* Poll for ID change and connect */ 3932f3fd2c5STony Lindgren switch (musb->xceiv->otg->state) { 3942f3fd2c5STony Lindgren case OTG_STATE_B_IDLE: 3952f3fd2c5STony Lindgren case OTG_STATE_A_WAIT_BCON: 396369469a9STony Lindgren dsps_mod_timer_optional(glue); 3972f3fd2c5STony Lindgren break; 3982f3fd2c5STony Lindgren default: 3992f3fd2c5STony Lindgren break; 4002f3fd2c5STony Lindgren } 4012f3fd2c5STony Lindgren 4029be73baeSSebastian Andrzej Siewior out: 4039ecb8875SAjay Kumar Gupta spin_unlock_irqrestore(&musb->lock, flags); 4049ecb8875SAjay Kumar Gupta 4059ecb8875SAjay Kumar Gupta return ret; 4069ecb8875SAjay Kumar Gupta } 4079ecb8875SAjay Kumar Gupta 40840f099e3SMarkus Pargmann static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) 40940f099e3SMarkus Pargmann { 41040f099e3SMarkus Pargmann struct dentry *root; 41140f099e3SMarkus Pargmann char buf[128]; 41240f099e3SMarkus Pargmann 41340f099e3SMarkus Pargmann sprintf(buf, "%s.dsps", dev_name(musb->controller)); 414b3c69ec8SChunfeng Yun root = debugfs_create_dir(buf, usb_debug_root); 41540f099e3SMarkus Pargmann glue->dbgfs_root = root; 41640f099e3SMarkus Pargmann 41740f099e3SMarkus Pargmann glue->regset.regs = dsps_musb_regs; 41840f099e3SMarkus Pargmann glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs); 41940f099e3SMarkus Pargmann glue->regset.base = musb->ctrl_base; 42040f099e3SMarkus Pargmann 4218a1ef171SGreg Kroah-Hartman debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset); 42240f099e3SMarkus Pargmann return 0; 42340f099e3SMarkus Pargmann } 42440f099e3SMarkus Pargmann 4259ecb8875SAjay Kumar Gupta static int dsps_musb_init(struct musb *musb) 4269ecb8875SAjay Kumar Gupta { 4279ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 428db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 42997238b35SSebastian Andrzej Siewior struct platform_device *parent = to_platform_device(dev->parent); 4309ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 43197238b35SSebastian Andrzej Siewior void __iomem *reg_base; 432ffa13d2dSGeert Uytterhoeven struct resource *r; 4339ecb8875SAjay Kumar Gupta u32 rev, val; 43440f099e3SMarkus Pargmann int ret; 4359ecb8875SAjay Kumar Gupta 436ffa13d2dSGeert Uytterhoeven r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); 437ffa13d2dSGeert Uytterhoeven reg_base = devm_ioremap_resource(dev, r); 43851ef74f6SJulia Lawall if (IS_ERR(reg_base)) 43951ef74f6SJulia Lawall return PTR_ERR(reg_base); 44097238b35SSebastian Andrzej Siewior musb->ctrl_base = reg_base; 4419ecb8875SAjay Kumar Gupta 442d7554226SAfzal Mohammed /* NOP driver needs change if supporting dual instance */ 443983f3cabSFelipe Balbi musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "phys", 0); 44497238b35SSebastian Andrzej Siewior if (IS_ERR(musb->xceiv)) 44597238b35SSebastian Andrzej Siewior return PTR_ERR(musb->xceiv); 4469ecb8875SAjay Kumar Gupta 447bb90600dSTony Lindgren musb->phy = devm_phy_get(dev->parent, "usb2-phy"); 448bb90600dSTony Lindgren 4499ecb8875SAjay Kumar Gupta /* Returns zero if e.g. not clocked */ 450086b2882SBin Liu rev = musb_readl(reg_base, wrp->revision); 45197238b35SSebastian Andrzej Siewior if (!rev) 45297238b35SSebastian Andrzej Siewior return -ENODEV; 4539ecb8875SAjay Kumar Gupta 454bb90600dSTony Lindgren if (IS_ERR(musb->phy)) { 455bb90600dSTony Lindgren musb->phy = NULL; 456bb90600dSTony Lindgren } else { 457bb90600dSTony Lindgren ret = phy_init(musb->phy); 458bb90600dSTony Lindgren if (ret < 0) 459bb90600dSTony Lindgren return ret; 460bb90600dSTony Lindgren ret = phy_power_on(musb->phy); 461bb90600dSTony Lindgren if (ret) { 462bb90600dSTony Lindgren phy_exit(musb->phy); 463bb90600dSTony Lindgren return ret; 464bb90600dSTony Lindgren } 465bb90600dSTony Lindgren } 466bb90600dSTony Lindgren 467b82162bcSBin Liu timer_setup(&musb->dev_timer, otg_timer, 0); 4689ecb8875SAjay Kumar Gupta 4699ecb8875SAjay Kumar Gupta /* Reset the musb */ 470086b2882SBin Liu musb_writel(reg_base, wrp->control, (1 << wrp->reset)); 4719ecb8875SAjay Kumar Gupta 4729ecb8875SAjay Kumar Gupta musb->isr = dsps_interrupt; 4739ecb8875SAjay Kumar Gupta 4749ecb8875SAjay Kumar Gupta /* reset the otgdisable bit, needed for host mode to work */ 475086b2882SBin Liu val = musb_readl(reg_base, wrp->phy_utmi); 4769ecb8875SAjay Kumar Gupta val &= ~(1 << wrp->otg_disable); 477086b2882SBin Liu musb_writel(musb->ctrl_base, wrp->phy_utmi, val); 4789ecb8875SAjay Kumar Gupta 479371254ceSGeorge Cherian /* 480371254ceSGeorge Cherian * Check whether the dsps version has babble control enabled. 481371254ceSGeorge Cherian * In latest silicon revision the babble control logic is enabled. 482371254ceSGeorge Cherian * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control 483371254ceSGeorge Cherian * logic enabled. 484371254ceSGeorge Cherian */ 485086b2882SBin Liu val = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 486f860f0b1SFelipe Balbi if (val & MUSB_BABBLE_RCV_DISABLE) { 487371254ceSGeorge Cherian glue->sw_babble_enabled = true; 488371254ceSGeorge Cherian val |= MUSB_BABBLE_SW_SESSION_CTRL; 489086b2882SBin Liu musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); 490371254ceSGeorge Cherian } 491371254ceSGeorge Cherian 492369469a9STony Lindgren dsps_mod_timer(glue, -1); 4932f3fd2c5STony Lindgren 494e94a7369SSaurabh Karajgaonkar return dsps_musb_dbg_init(musb, glue); 4959ecb8875SAjay Kumar Gupta } 4969ecb8875SAjay Kumar Gupta 4979ecb8875SAjay Kumar Gupta static int dsps_musb_exit(struct musb *musb) 4989ecb8875SAjay Kumar Gupta { 4999ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 500db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 5019ecb8875SAjay Kumar Gupta 502b82162bcSBin Liu del_timer_sync(&musb->dev_timer); 503bb90600dSTony Lindgren phy_power_off(musb->phy); 504bb90600dSTony Lindgren phy_exit(musb->phy); 5050fca91b8SDaniel Mack debugfs_remove_recursive(glue->dbgfs_root); 5060fca91b8SDaniel Mack 5079ecb8875SAjay Kumar Gupta return 0; 5089ecb8875SAjay Kumar Gupta } 5099ecb8875SAjay Kumar Gupta 510943c1397SFelipe Balbi static int dsps_musb_set_mode(struct musb *musb, u8 mode) 511943c1397SFelipe Balbi { 512943c1397SFelipe Balbi struct device *dev = musb->controller; 513943c1397SFelipe Balbi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 514943c1397SFelipe Balbi const struct dsps_musb_wrapper *wrp = glue->wrp; 515943c1397SFelipe Balbi void __iomem *ctrl_base = musb->ctrl_base; 516943c1397SFelipe Balbi u32 reg; 517943c1397SFelipe Balbi 518086b2882SBin Liu reg = musb_readl(ctrl_base, wrp->mode); 519943c1397SFelipe Balbi 520943c1397SFelipe Balbi switch (mode) { 521943c1397SFelipe Balbi case MUSB_HOST: 522943c1397SFelipe Balbi reg &= ~(1 << wrp->iddig); 523943c1397SFelipe Balbi 524943c1397SFelipe Balbi /* 525943c1397SFelipe Balbi * if we're setting mode to host-only or device-only, we're 526943c1397SFelipe Balbi * going to ignore whatever the PHY sends us and just force 527943c1397SFelipe Balbi * ID pin status by SW 528943c1397SFelipe Balbi */ 529943c1397SFelipe Balbi reg |= (1 << wrp->iddig_mux); 530943c1397SFelipe Balbi 531086b2882SBin Liu musb_writel(ctrl_base, wrp->mode, reg); 532086b2882SBin Liu musb_writel(ctrl_base, wrp->phy_utmi, 0x02); 533943c1397SFelipe Balbi break; 534943c1397SFelipe Balbi case MUSB_PERIPHERAL: 535943c1397SFelipe Balbi reg |= (1 << wrp->iddig); 536943c1397SFelipe Balbi 537943c1397SFelipe Balbi /* 538943c1397SFelipe Balbi * if we're setting mode to host-only or device-only, we're 539943c1397SFelipe Balbi * going to ignore whatever the PHY sends us and just force 540943c1397SFelipe Balbi * ID pin status by SW 541943c1397SFelipe Balbi */ 542943c1397SFelipe Balbi reg |= (1 << wrp->iddig_mux); 543943c1397SFelipe Balbi 544086b2882SBin Liu musb_writel(ctrl_base, wrp->mode, reg); 545943c1397SFelipe Balbi break; 546943c1397SFelipe Balbi case MUSB_OTG: 547086b2882SBin Liu musb_writel(ctrl_base, wrp->phy_utmi, 0x02); 548943c1397SFelipe Balbi break; 549943c1397SFelipe Balbi default: 550943c1397SFelipe Balbi dev_err(glue->dev, "unsupported mode %d\n", mode); 551943c1397SFelipe Balbi return -EINVAL; 552943c1397SFelipe Balbi } 553943c1397SFelipe Balbi 554943c1397SFelipe Balbi return 0; 555943c1397SFelipe Balbi } 556943c1397SFelipe Balbi 5573709ffcaSFelipe Balbi static bool dsps_sw_babble_control(struct musb *musb) 558371254ceSGeorge Cherian { 559371254ceSGeorge Cherian u8 babble_ctl; 560371254ceSGeorge Cherian bool session_restart = false; 561371254ceSGeorge Cherian 562086b2882SBin Liu babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 563371254ceSGeorge Cherian dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", 564371254ceSGeorge Cherian babble_ctl); 565371254ceSGeorge Cherian /* 566371254ceSGeorge Cherian * check line monitor flag to check whether babble is 567371254ceSGeorge Cherian * due to noise 568371254ceSGeorge Cherian */ 569371254ceSGeorge Cherian dev_dbg(musb->controller, "STUCK_J is %s\n", 570371254ceSGeorge Cherian babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset"); 571371254ceSGeorge Cherian 572371254ceSGeorge Cherian if (babble_ctl & MUSB_BABBLE_STUCK_J) { 573371254ceSGeorge Cherian int timeout = 10; 574371254ceSGeorge Cherian 575371254ceSGeorge Cherian /* 576371254ceSGeorge Cherian * babble is due to noise, then set transmit idle (d7 bit) 577371254ceSGeorge Cherian * to resume normal operation 578371254ceSGeorge Cherian */ 579086b2882SBin Liu babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 580371254ceSGeorge Cherian babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; 581086b2882SBin Liu musb_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); 582371254ceSGeorge Cherian 583371254ceSGeorge Cherian /* wait till line monitor flag cleared */ 584371254ceSGeorge Cherian dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); 585371254ceSGeorge Cherian do { 586086b2882SBin Liu babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 587371254ceSGeorge Cherian udelay(1); 588371254ceSGeorge Cherian } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); 589371254ceSGeorge Cherian 590371254ceSGeorge Cherian /* check whether stuck_at_j bit cleared */ 591371254ceSGeorge Cherian if (babble_ctl & MUSB_BABBLE_STUCK_J) { 592371254ceSGeorge Cherian /* 593371254ceSGeorge Cherian * real babble condition has occurred 594371254ceSGeorge Cherian * restart the controller to start the 595371254ceSGeorge Cherian * session again 596371254ceSGeorge Cherian */ 597371254ceSGeorge Cherian dev_dbg(musb->controller, "J not cleared, misc (%x)\n", 598371254ceSGeorge Cherian babble_ctl); 599371254ceSGeorge Cherian session_restart = true; 600371254ceSGeorge Cherian } 601371254ceSGeorge Cherian } else { 602371254ceSGeorge Cherian session_restart = true; 603371254ceSGeorge Cherian } 604371254ceSGeorge Cherian 605371254ceSGeorge Cherian return session_restart; 606371254ceSGeorge Cherian } 607371254ceSGeorge Cherian 608b28a6432SFelipe Balbi static int dsps_musb_recover(struct musb *musb) 6091d57de30SDaniel Mack { 6101d57de30SDaniel Mack struct device *dev = musb->controller; 6111d57de30SDaniel Mack struct dsps_glue *glue = dev_get_drvdata(dev->parent); 612011d0dd5SFelipe Balbi int session_restart = 0; 6131d57de30SDaniel Mack 614371254ceSGeorge Cherian if (glue->sw_babble_enabled) 6153709ffcaSFelipe Balbi session_restart = dsps_sw_babble_control(musb); 616011d0dd5SFelipe Balbi else 617371254ceSGeorge Cherian session_restart = 1; 61856700178SGeorge Cherian 619d0cddae7SFelipe Balbi return session_restart ? 0 : -EPIPE; 6201d57de30SDaniel Mack } 6211d57de30SDaniel Mack 6223e457371STony Lindgren /* Similar to am35x, dm81xx support only 32-bit read operation */ 6233e457371STony Lindgren static void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) 6243e457371STony Lindgren { 6253e457371STony Lindgren void __iomem *fifo = hw_ep->fifo; 6263e457371STony Lindgren 6273e457371STony Lindgren if (len >= 4) { 628d30323f8STony Lindgren ioread32_rep(fifo, dst, len >> 2); 6293e457371STony Lindgren dst += len & ~0x03; 6303e457371STony Lindgren len &= 0x03; 6313e457371STony Lindgren } 6323e457371STony Lindgren 6333e457371STony Lindgren /* Read any remaining 1 to 3 bytes */ 6343e457371STony Lindgren if (len > 0) { 6353e457371STony Lindgren u32 val = musb_readl(fifo, 0); 6363e457371STony Lindgren memcpy(dst, &val, len); 6373e457371STony Lindgren } 6383e457371STony Lindgren } 6393e457371STony Lindgren 64025534828SAlexandre Bailon #ifdef CONFIG_USB_TI_CPPI41_DMA 64125534828SAlexandre Bailon static void dsps_dma_controller_callback(struct dma_controller *c) 64225534828SAlexandre Bailon { 64325534828SAlexandre Bailon struct musb *musb = c->musb; 64425534828SAlexandre Bailon struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 64525534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 64625534828SAlexandre Bailon u32 status; 64725534828SAlexandre Bailon 64825534828SAlexandre Bailon status = musb_readl(usbss_base, USBSS_IRQ_STATUS); 64925534828SAlexandre Bailon if (status & USBSS_IRQ_PD_COMP) 65025534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_STATUS, USBSS_IRQ_PD_COMP); 65125534828SAlexandre Bailon } 65225534828SAlexandre Bailon 65325534828SAlexandre Bailon static struct dma_controller * 65425534828SAlexandre Bailon dsps_dma_controller_create(struct musb *musb, void __iomem *base) 65525534828SAlexandre Bailon { 65625534828SAlexandre Bailon struct dma_controller *controller; 65725534828SAlexandre Bailon struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 65825534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 65925534828SAlexandre Bailon 66025534828SAlexandre Bailon controller = cppi41_dma_controller_create(musb, base); 66125534828SAlexandre Bailon if (IS_ERR_OR_NULL(controller)) 66225534828SAlexandre Bailon return controller; 66325534828SAlexandre Bailon 66425534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); 66525534828SAlexandre Bailon controller->dma_callback = dsps_dma_controller_callback; 66625534828SAlexandre Bailon 66725534828SAlexandre Bailon return controller; 66825534828SAlexandre Bailon } 66925534828SAlexandre Bailon 67025534828SAlexandre Bailon #ifdef CONFIG_PM_SLEEP 67125534828SAlexandre Bailon static void dsps_dma_controller_suspend(struct dsps_glue *glue) 67225534828SAlexandre Bailon { 67325534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 67425534828SAlexandre Bailon 67525534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); 67625534828SAlexandre Bailon } 67725534828SAlexandre Bailon 67825534828SAlexandre Bailon static void dsps_dma_controller_resume(struct dsps_glue *glue) 67925534828SAlexandre Bailon { 68025534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 68125534828SAlexandre Bailon 68225534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); 68325534828SAlexandre Bailon } 68425534828SAlexandre Bailon #endif 68525534828SAlexandre Bailon #else /* CONFIG_USB_TI_CPPI41_DMA */ 68625534828SAlexandre Bailon #ifdef CONFIG_PM_SLEEP 68725534828SAlexandre Bailon static void dsps_dma_controller_suspend(struct dsps_glue *glue) {} 68825534828SAlexandre Bailon static void dsps_dma_controller_resume(struct dsps_glue *glue) {} 68925534828SAlexandre Bailon #endif 69025534828SAlexandre Bailon #endif /* CONFIG_USB_TI_CPPI41_DMA */ 69125534828SAlexandre Bailon 6929ecb8875SAjay Kumar Gupta static struct musb_platform_ops dsps_ops = { 693f8e9f34fSTony Lindgren .quirks = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP, 6949ecb8875SAjay Kumar Gupta .init = dsps_musb_init, 6959ecb8875SAjay Kumar Gupta .exit = dsps_musb_exit, 6969ecb8875SAjay Kumar Gupta 6977f6283edSTony Lindgren #ifdef CONFIG_USB_TI_CPPI41_DMA 69825534828SAlexandre Bailon .dma_init = dsps_dma_controller_create, 699783f3b4eSBin Liu .dma_exit = cppi41_dma_controller_destroy, 7007f6283edSTony Lindgren #endif 7019ecb8875SAjay Kumar Gupta .enable = dsps_musb_enable, 7029ecb8875SAjay Kumar Gupta .disable = dsps_musb_disable, 7039ecb8875SAjay Kumar Gupta 704943c1397SFelipe Balbi .set_mode = dsps_musb_set_mode, 705b28a6432SFelipe Balbi .recover = dsps_musb_recover, 706c48400baSBin Liu .clear_ep_rxintr = dsps_musb_clear_ep_rxintr, 7079ecb8875SAjay Kumar Gupta }; 7089ecb8875SAjay Kumar Gupta 7099ecb8875SAjay Kumar Gupta static u64 musb_dmamask = DMA_BIT_MASK(32); 7109ecb8875SAjay Kumar Gupta 71197238b35SSebastian Andrzej Siewior static int get_int_prop(struct device_node *dn, const char *s) 7129ecb8875SAjay Kumar Gupta { 71397238b35SSebastian Andrzej Siewior int ret; 71497238b35SSebastian Andrzej Siewior u32 val; 71597238b35SSebastian Andrzej Siewior 71697238b35SSebastian Andrzej Siewior ret = of_property_read_u32(dn, s, &val); 71797238b35SSebastian Andrzej Siewior if (ret) 71897238b35SSebastian Andrzej Siewior return 0; 71997238b35SSebastian Andrzej Siewior return val; 72097238b35SSebastian Andrzej Siewior } 72197238b35SSebastian Andrzej Siewior 72297238b35SSebastian Andrzej Siewior static int dsps_create_musb_pdev(struct dsps_glue *glue, 72397238b35SSebastian Andrzej Siewior struct platform_device *parent) 72497238b35SSebastian Andrzej Siewior { 72597238b35SSebastian Andrzej Siewior struct musb_hdrc_platform_data pdata; 72697238b35SSebastian Andrzej Siewior struct resource resources[2]; 727c031a7d4SSebastian Andrzej Siewior struct resource *res; 72897238b35SSebastian Andrzej Siewior struct device *dev = &parent->dev; 72965145677SAjay Kumar Gupta struct musb_hdrc_config *config; 7309ecb8875SAjay Kumar Gupta struct platform_device *musb; 73197238b35SSebastian Andrzej Siewior struct device_node *dn = parent->dev.of_node; 732606bf4d5STony Lindgren int ret, val; 7339ecb8875SAjay Kumar Gupta 73497238b35SSebastian Andrzej Siewior memset(resources, 0, sizeof(resources)); 735c031a7d4SSebastian Andrzej Siewior res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc"); 736c031a7d4SSebastian Andrzej Siewior if (!res) { 73797238b35SSebastian Andrzej Siewior dev_err(dev, "failed to get memory.\n"); 738c031a7d4SSebastian Andrzej Siewior return -EINVAL; 7399ecb8875SAjay Kumar Gupta } 740c031a7d4SSebastian Andrzej Siewior resources[0] = *res; 74197238b35SSebastian Andrzej Siewior 742c031a7d4SSebastian Andrzej Siewior res = platform_get_resource_byname(parent, IORESOURCE_IRQ, "mc"); 743c031a7d4SSebastian Andrzej Siewior if (!res) { 74497238b35SSebastian Andrzej Siewior dev_err(dev, "failed to get irq.\n"); 745c031a7d4SSebastian Andrzej Siewior return -EINVAL; 74697238b35SSebastian Andrzej Siewior } 747c031a7d4SSebastian Andrzej Siewior resources[1] = *res; 7489ecb8875SAjay Kumar Gupta 74965b3d52dSB, Ravi /* allocate the child platform device */ 75045abfa68SBin Liu musb = platform_device_alloc("musb-hdrc", 75145abfa68SBin Liu (resources[0].start & 0xFFF) == 0x400 ? 0 : 1); 75265b3d52dSB, Ravi if (!musb) { 75365b3d52dSB, Ravi dev_err(dev, "failed to allocate musb device\n"); 75497238b35SSebastian Andrzej Siewior return -ENOMEM; 75565b3d52dSB, Ravi } 7569ecb8875SAjay Kumar Gupta 7579ecb8875SAjay Kumar Gupta musb->dev.parent = dev; 7589ecb8875SAjay Kumar Gupta musb->dev.dma_mask = &musb_dmamask; 7599ecb8875SAjay Kumar Gupta musb->dev.coherent_dma_mask = musb_dmamask; 76049484abdSJohan Hovold device_set_of_node_from_dev(&musb->dev, &parent->dev); 7619ecb8875SAjay Kumar Gupta 76297238b35SSebastian Andrzej Siewior glue->musb = musb; 7639ecb8875SAjay Kumar Gupta 76497238b35SSebastian Andrzej Siewior ret = platform_device_add_resources(musb, resources, 76597238b35SSebastian Andrzej Siewior ARRAY_SIZE(resources)); 7669ecb8875SAjay Kumar Gupta if (ret) { 7679ecb8875SAjay Kumar Gupta dev_err(dev, "failed to add resources\n"); 76897238b35SSebastian Andrzej Siewior goto err; 7699ecb8875SAjay Kumar Gupta } 7709ecb8875SAjay Kumar Gupta 77197238b35SSebastian Andrzej Siewior config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); 77265145677SAjay Kumar Gupta if (!config) { 773b25e5f1cSWei Yongjun ret = -ENOMEM; 77497238b35SSebastian Andrzej Siewior goto err; 77565145677SAjay Kumar Gupta } 77697238b35SSebastian Andrzej Siewior pdata.config = config; 77797238b35SSebastian Andrzej Siewior pdata.platform_ops = &dsps_ops; 77865145677SAjay Kumar Gupta 779c031a7d4SSebastian Andrzej Siewior config->num_eps = get_int_prop(dn, "mentor,num-eps"); 780c031a7d4SSebastian Andrzej Siewior config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); 781869c5978SDaniel Mack config->host_port_deassert_reset_at_resume = 1; 78255479956SBin Liu pdata.mode = musb_get_mode(dev); 783c031a7d4SSebastian Andrzej Siewior /* DT keeps this entry in mA, musb expects it as per USB spec */ 784c031a7d4SSebastian Andrzej Siewior pdata.power = get_int_prop(dn, "mentor,power") / 2; 785606bf4d5STony Lindgren 786606bf4d5STony Lindgren ret = of_property_read_u32(dn, "mentor,multipoint", &val); 787606bf4d5STony Lindgren if (!ret && val) 788606bf4d5STony Lindgren config->multipoint = true; 78965145677SAjay Kumar Gupta 79063863b98SHeikki Krogerus config->maximum_speed = usb_get_maximum_speed(&parent->dev); 79141932b9bSBin Liu switch (config->maximum_speed) { 79241932b9bSBin Liu case USB_SPEED_LOW: 79341932b9bSBin Liu case USB_SPEED_FULL: 79441932b9bSBin Liu break; 79541932b9bSBin Liu case USB_SPEED_SUPER: 79641932b9bSBin Liu dev_warn(dev, "ignore incorrect maximum_speed " 79741932b9bSBin Liu "(super-speed) setting in dts"); 798df561f66SGustavo A. R. Silva fallthrough; 79941932b9bSBin Liu default: 80041932b9bSBin Liu config->maximum_speed = USB_SPEED_HIGH; 80141932b9bSBin Liu } 80241932b9bSBin Liu 80397238b35SSebastian Andrzej Siewior ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); 8049ecb8875SAjay Kumar Gupta if (ret) { 8059ecb8875SAjay Kumar Gupta dev_err(dev, "failed to add platform_data\n"); 80697238b35SSebastian Andrzej Siewior goto err; 8079ecb8875SAjay Kumar Gupta } 8089ecb8875SAjay Kumar Gupta 8099ecb8875SAjay Kumar Gupta ret = platform_device_add(musb); 8109ecb8875SAjay Kumar Gupta if (ret) { 8119ecb8875SAjay Kumar Gupta dev_err(dev, "failed to register musb device\n"); 81297238b35SSebastian Andrzej Siewior goto err; 8139ecb8875SAjay Kumar Gupta } 8149ecb8875SAjay Kumar Gupta return 0; 8159ecb8875SAjay Kumar Gupta 81697238b35SSebastian Andrzej Siewior err: 8179ecb8875SAjay Kumar Gupta platform_device_put(musb); 8189ecb8875SAjay Kumar Gupta return ret; 8199ecb8875SAjay Kumar Gupta } 8209ecb8875SAjay Kumar Gupta 821369469a9STony Lindgren static irqreturn_t dsps_vbus_threaded_irq(int irq, void *priv) 822369469a9STony Lindgren { 823369469a9STony Lindgren struct dsps_glue *glue = priv; 824369469a9STony Lindgren struct musb *musb = platform_get_drvdata(glue->musb); 825369469a9STony Lindgren 826369469a9STony Lindgren if (!musb) 827369469a9STony Lindgren return IRQ_NONE; 828369469a9STony Lindgren 829369469a9STony Lindgren dev_dbg(glue->dev, "VBUS interrupt\n"); 830369469a9STony Lindgren dsps_mod_timer(glue, 0); 831369469a9STony Lindgren 832369469a9STony Lindgren return IRQ_HANDLED; 833369469a9STony Lindgren } 834369469a9STony Lindgren 835369469a9STony Lindgren static int dsps_setup_optional_vbus_irq(struct platform_device *pdev, 836369469a9STony Lindgren struct dsps_glue *glue) 837369469a9STony Lindgren { 838369469a9STony Lindgren int error; 839369469a9STony Lindgren 840369469a9STony Lindgren glue->vbus_irq = platform_get_irq_byname(pdev, "vbus"); 841369469a9STony Lindgren if (glue->vbus_irq == -EPROBE_DEFER) 842369469a9STony Lindgren return -EPROBE_DEFER; 843369469a9STony Lindgren 844369469a9STony Lindgren if (glue->vbus_irq <= 0) { 845369469a9STony Lindgren glue->vbus_irq = 0; 846369469a9STony Lindgren return 0; 847369469a9STony Lindgren } 848369469a9STony Lindgren 849369469a9STony Lindgren error = devm_request_threaded_irq(glue->dev, glue->vbus_irq, 850369469a9STony Lindgren NULL, dsps_vbus_threaded_irq, 851369469a9STony Lindgren IRQF_ONESHOT, 852369469a9STony Lindgren "vbus", glue); 853369469a9STony Lindgren if (error) { 854369469a9STony Lindgren glue->vbus_irq = 0; 855369469a9STony Lindgren return error; 856369469a9STony Lindgren } 857369469a9STony Lindgren dev_dbg(glue->dev, "VBUS irq %i configured\n", glue->vbus_irq); 858369469a9STony Lindgren 859369469a9STony Lindgren return 0; 860369469a9STony Lindgren } 861369469a9STony Lindgren 86241ac7b3aSBill Pemberton static int dsps_probe(struct platform_device *pdev) 8639ecb8875SAjay Kumar Gupta { 86465145677SAjay Kumar Gupta const struct of_device_id *match; 86565145677SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp; 8669ecb8875SAjay Kumar Gupta struct dsps_glue *glue; 86797238b35SSebastian Andrzej Siewior int ret; 8689ecb8875SAjay Kumar Gupta 8694fc4b274SSebastian Andrzej Siewior if (!strcmp(pdev->name, "musb-hdrc")) 8704fc4b274SSebastian Andrzej Siewior return -ENODEV; 8714fc4b274SSebastian Andrzej Siewior 872cc506036SFelipe Balbi match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); 87365145677SAjay Kumar Gupta if (!match) { 87465145677SAjay Kumar Gupta dev_err(&pdev->dev, "fail to get matching of_match struct\n"); 87597238b35SSebastian Andrzej Siewior return -EINVAL; 87665145677SAjay Kumar Gupta } 87765145677SAjay Kumar Gupta wrp = match->data; 8789ecb8875SAjay Kumar Gupta 8793e457371STony Lindgren if (of_device_is_compatible(pdev->dev.of_node, "ti,musb-dm816")) 8803e457371STony Lindgren dsps_ops.read_fifo = dsps_read_fifo32; 8813e457371STony Lindgren 8829ecb8875SAjay Kumar Gupta /* allocate glue */ 883de9db572SMarkus Pargmann glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); 8840816ea2fSPeter Chen if (!glue) 88597238b35SSebastian Andrzej Siewior return -ENOMEM; 8869ecb8875SAjay Kumar Gupta 8879ecb8875SAjay Kumar Gupta glue->dev = &pdev->dev; 88897238b35SSebastian Andrzej Siewior glue->wrp = wrp; 88925534828SAlexandre Bailon glue->usbss_base = of_iomap(pdev->dev.parent->of_node, 0); 89025534828SAlexandre Bailon if (!glue->usbss_base) 89125534828SAlexandre Bailon return -ENXIO; 8929ecb8875SAjay Kumar Gupta 8939ecb8875SAjay Kumar Gupta platform_set_drvdata(pdev, glue); 8949ecb8875SAjay Kumar Gupta pm_runtime_enable(&pdev->dev); 89597238b35SSebastian Andrzej Siewior ret = dsps_create_musb_pdev(glue, pdev); 89697238b35SSebastian Andrzej Siewior if (ret) 89724752917STony Lindgren goto err; 89865b3f50eSTony Lindgren 8997c75bde3SNadezda Lutovinova if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) { 9007c75bde3SNadezda Lutovinova ret = dsps_setup_optional_vbus_irq(pdev, glue); 9017c75bde3SNadezda Lutovinova if (ret) 902*c2115b2bSMiquel Raynal goto unregister_pdev; 9037c75bde3SNadezda Lutovinova } 9047c75bde3SNadezda Lutovinova 9059ecb8875SAjay Kumar Gupta return 0; 9069ecb8875SAjay Kumar Gupta 907*c2115b2bSMiquel Raynal unregister_pdev: 908*c2115b2bSMiquel Raynal platform_device_unregister(glue->musb); 90924752917STony Lindgren err: 9100e38c4edSAjay Kumar Gupta pm_runtime_disable(&pdev->dev); 9116b7ad496SBin Liu iounmap(glue->usbss_base); 9129ecb8875SAjay Kumar Gupta return ret; 9139ecb8875SAjay Kumar Gupta } 91497238b35SSebastian Andrzej Siewior 915fb4e98abSBill Pemberton static int dsps_remove(struct platform_device *pdev) 9169ecb8875SAjay Kumar Gupta { 9179ecb8875SAjay Kumar Gupta struct dsps_glue *glue = platform_get_drvdata(pdev); 9189ecb8875SAjay Kumar Gupta 91997238b35SSebastian Andrzej Siewior platform_device_unregister(glue->musb); 9209ecb8875SAjay Kumar Gupta 9219ecb8875SAjay Kumar Gupta pm_runtime_disable(&pdev->dev); 9226b7ad496SBin Liu iounmap(glue->usbss_base); 92340f099e3SMarkus Pargmann 9249ecb8875SAjay Kumar Gupta return 0; 9259ecb8875SAjay Kumar Gupta } 9269ecb8875SAjay Kumar Gupta 927fa7b4ca5SSebastian Andrzej Siewior static const struct dsps_musb_wrapper am33xx_driver_data = { 9289ecb8875SAjay Kumar Gupta .revision = 0x00, 9299ecb8875SAjay Kumar Gupta .control = 0x14, 9309ecb8875SAjay Kumar Gupta .status = 0x18, 9319ecb8875SAjay Kumar Gupta .epintr_set = 0x38, 9329ecb8875SAjay Kumar Gupta .epintr_clear = 0x40, 9339ecb8875SAjay Kumar Gupta .epintr_status = 0x30, 9349ecb8875SAjay Kumar Gupta .coreintr_set = 0x3c, 9359ecb8875SAjay Kumar Gupta .coreintr_clear = 0x44, 9369ecb8875SAjay Kumar Gupta .coreintr_status = 0x34, 9379ecb8875SAjay Kumar Gupta .phy_utmi = 0xe0, 9389ecb8875SAjay Kumar Gupta .mode = 0xe8, 939b991f9b7SDaniel Mack .tx_mode = 0x70, 940b991f9b7SDaniel Mack .rx_mode = 0x74, 9419ecb8875SAjay Kumar Gupta .reset = 0, 9429ecb8875SAjay Kumar Gupta .otg_disable = 21, 9439ecb8875SAjay Kumar Gupta .iddig = 8, 944943c1397SFelipe Balbi .iddig_mux = 7, 9459ecb8875SAjay Kumar Gupta .usb_shift = 0, 9469ecb8875SAjay Kumar Gupta .usb_mask = 0x1ff, 9479ecb8875SAjay Kumar Gupta .usb_bitmap = (0x1ff << 0), 9489ecb8875SAjay Kumar Gupta .drvvbus = 8, 9499ecb8875SAjay Kumar Gupta .txep_shift = 0, 9509ecb8875SAjay Kumar Gupta .txep_mask = 0xffff, 9519ecb8875SAjay Kumar Gupta .txep_bitmap = (0xffff << 0), 9529ecb8875SAjay Kumar Gupta .rxep_shift = 16, 9539ecb8875SAjay Kumar Gupta .rxep_mask = 0xfffe, 9549ecb8875SAjay Kumar Gupta .rxep_bitmap = (0xfffe << 16), 9559e204d88SFelipe Balbi .poll_timeout = 2000, /* ms */ 9569ecb8875SAjay Kumar Gupta }; 9579ecb8875SAjay Kumar Gupta 9582f82686eSBill Pemberton static const struct of_device_id musb_dsps_of_match[] = { 95965145677SAjay Kumar Gupta { .compatible = "ti,musb-am33xx", 9603e457371STony Lindgren .data = &am33xx_driver_data, }, 9613e457371STony Lindgren { .compatible = "ti,musb-dm816", 9623e457371STony Lindgren .data = &am33xx_driver_data, }, 9639ecb8875SAjay Kumar Gupta { }, 9649ecb8875SAjay Kumar Gupta }; 9659ecb8875SAjay Kumar Gupta MODULE_DEVICE_TABLE(of, musb_dsps_of_match); 9669ecb8875SAjay Kumar Gupta 9675b783983SWolfram Sang #ifdef CONFIG_PM_SLEEP 968869c5978SDaniel Mack static int dsps_suspend(struct device *dev) 969869c5978SDaniel Mack { 970869c5978SDaniel Mack struct dsps_glue *glue = dev_get_drvdata(dev); 971869c5978SDaniel Mack const struct dsps_musb_wrapper *wrp = glue->wrp; 972869c5978SDaniel Mack struct musb *musb = platform_get_drvdata(glue->musb); 973f042e9cbSSebastian Andrzej Siewior void __iomem *mbase; 974706d61b2SJohan Hovold int ret; 975f042e9cbSSebastian Andrzej Siewior 976f042e9cbSSebastian Andrzej Siewior if (!musb) 977f042e9cbSSebastian Andrzej Siewior /* This can happen if the musb device is in -EPROBE_DEFER */ 978f042e9cbSSebastian Andrzej Siewior return 0; 979f042e9cbSSebastian Andrzej Siewior 980706d61b2SJohan Hovold ret = pm_runtime_get_sync(dev); 981706d61b2SJohan Hovold if (ret < 0) { 982706d61b2SJohan Hovold pm_runtime_put_noidle(dev); 983706d61b2SJohan Hovold return ret; 984706d61b2SJohan Hovold } 985706d61b2SJohan Hovold 986b82162bcSBin Liu del_timer_sync(&musb->dev_timer); 987706d61b2SJohan Hovold 988f042e9cbSSebastian Andrzej Siewior mbase = musb->ctrl_base; 989086b2882SBin Liu glue->context.control = musb_readl(mbase, wrp->control); 990086b2882SBin Liu glue->context.epintr = musb_readl(mbase, wrp->epintr_set); 991086b2882SBin Liu glue->context.coreintr = musb_readl(mbase, wrp->coreintr_set); 992086b2882SBin Liu glue->context.phy_utmi = musb_readl(mbase, wrp->phy_utmi); 993086b2882SBin Liu glue->context.mode = musb_readl(mbase, wrp->mode); 994086b2882SBin Liu glue->context.tx_mode = musb_readl(mbase, wrp->tx_mode); 995086b2882SBin Liu glue->context.rx_mode = musb_readl(mbase, wrp->rx_mode); 996869c5978SDaniel Mack 99725534828SAlexandre Bailon dsps_dma_controller_suspend(glue); 99825534828SAlexandre Bailon 999869c5978SDaniel Mack return 0; 1000869c5978SDaniel Mack } 1001869c5978SDaniel Mack 1002869c5978SDaniel Mack static int dsps_resume(struct device *dev) 1003869c5978SDaniel Mack { 1004869c5978SDaniel Mack struct dsps_glue *glue = dev_get_drvdata(dev); 1005869c5978SDaniel Mack const struct dsps_musb_wrapper *wrp = glue->wrp; 1006869c5978SDaniel Mack struct musb *musb = platform_get_drvdata(glue->musb); 1007f042e9cbSSebastian Andrzej Siewior void __iomem *mbase; 1008869c5978SDaniel Mack 1009f042e9cbSSebastian Andrzej Siewior if (!musb) 1010f042e9cbSSebastian Andrzej Siewior return 0; 1011f042e9cbSSebastian Andrzej Siewior 101225534828SAlexandre Bailon dsps_dma_controller_resume(glue); 101325534828SAlexandre Bailon 1014f042e9cbSSebastian Andrzej Siewior mbase = musb->ctrl_base; 1015086b2882SBin Liu musb_writel(mbase, wrp->control, glue->context.control); 1016086b2882SBin Liu musb_writel(mbase, wrp->epintr_set, glue->context.epintr); 1017086b2882SBin Liu musb_writel(mbase, wrp->coreintr_set, glue->context.coreintr); 1018086b2882SBin Liu musb_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); 1019086b2882SBin Liu musb_writel(mbase, wrp->mode, glue->context.mode); 1020086b2882SBin Liu musb_writel(mbase, wrp->tx_mode, glue->context.tx_mode); 1021086b2882SBin Liu musb_writel(mbase, wrp->rx_mode, glue->context.rx_mode); 1022e47d9254SAntoine Tenart if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && 10237ad76955SBin Liu musb->port_mode == MUSB_OTG) 1024369469a9STony Lindgren dsps_mod_timer(glue, -1); 1025869c5978SDaniel Mack 1026706d61b2SJohan Hovold pm_runtime_put(dev); 1027706d61b2SJohan Hovold 1028869c5978SDaniel Mack return 0; 1029869c5978SDaniel Mack } 1030869c5978SDaniel Mack #endif 1031869c5978SDaniel Mack 1032869c5978SDaniel Mack static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); 1033869c5978SDaniel Mack 10349ecb8875SAjay Kumar Gupta static struct platform_driver dsps_usbss_driver = { 10359ecb8875SAjay Kumar Gupta .probe = dsps_probe, 10367690417dSBill Pemberton .remove = dsps_remove, 10379ecb8875SAjay Kumar Gupta .driver = { 10389ecb8875SAjay Kumar Gupta .name = "musb-dsps", 1039869c5978SDaniel Mack .pm = &dsps_pm_ops, 1040b432cb83SSachin Kamat .of_match_table = musb_dsps_of_match, 10419ecb8875SAjay Kumar Gupta }, 10429ecb8875SAjay Kumar Gupta }; 10439ecb8875SAjay Kumar Gupta 10449ecb8875SAjay Kumar Gupta MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); 10459ecb8875SAjay Kumar Gupta MODULE_AUTHOR("Ravi B <ravibabu@ti.com>"); 10469ecb8875SAjay Kumar Gupta MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); 10479ecb8875SAjay Kumar Gupta MODULE_LICENSE("GPL v2"); 10489ecb8875SAjay Kumar Gupta 104997238b35SSebastian Andrzej Siewior module_platform_driver(dsps_usbss_driver); 1050