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> 18ce1d37cbSLad Prabhakar #include <linux/irq.h> 19ded017eeSKishon Vijay Abraham I #include <linux/err.h> 209ecb8875SAjay Kumar Gupta #include <linux/platform_device.h> 219ecb8875SAjay Kumar Gupta #include <linux/dma-mapping.h> 229ecb8875SAjay Kumar Gupta #include <linux/pm_runtime.h> 239ecb8875SAjay Kumar Gupta #include <linux/module.h> 24d7078df6SFelipe Balbi #include <linux/usb/usb_phy_generic.h> 25e8c4a7acSFelipe Balbi #include <linux/platform_data/usb-omap.h> 260f53e481SFelipe Balbi #include <linux/sizes.h> 279ecb8875SAjay Kumar Gupta 289ecb8875SAjay Kumar Gupta #include <linux/of.h> 299ecb8875SAjay Kumar Gupta #include <linux/of_device.h> 309ecb8875SAjay Kumar Gupta #include <linux/of_address.h> 3197238b35SSebastian Andrzej Siewior #include <linux/of_irq.h> 32c031a7d4SSebastian Andrzej Siewior #include <linux/usb/of.h> 339ecb8875SAjay Kumar Gupta 3440f099e3SMarkus Pargmann #include <linux/debugfs.h> 3540f099e3SMarkus Pargmann 369ecb8875SAjay Kumar Gupta #include "musb_core.h" 379ecb8875SAjay Kumar Gupta 3865145677SAjay Kumar Gupta static const struct of_device_id musb_dsps_of_match[]; 3965145677SAjay Kumar Gupta 4009e03a89SLee Jones /* 419ecb8875SAjay Kumar Gupta * DSPS musb wrapper register offset. 429ecb8875SAjay Kumar Gupta * FIXME: This should be expanded to have all the wrapper registers from TI DSPS 439ecb8875SAjay Kumar Gupta * musb ips. 449ecb8875SAjay Kumar Gupta */ 459ecb8875SAjay Kumar Gupta struct dsps_musb_wrapper { 469ecb8875SAjay Kumar Gupta u16 revision; 479ecb8875SAjay Kumar Gupta u16 control; 489ecb8875SAjay Kumar Gupta u16 status; 499ecb8875SAjay Kumar Gupta u16 epintr_set; 509ecb8875SAjay Kumar Gupta u16 epintr_clear; 519ecb8875SAjay Kumar Gupta u16 epintr_status; 529ecb8875SAjay Kumar Gupta u16 coreintr_set; 539ecb8875SAjay Kumar Gupta u16 coreintr_clear; 549ecb8875SAjay Kumar Gupta u16 coreintr_status; 559ecb8875SAjay Kumar Gupta u16 phy_utmi; 569ecb8875SAjay Kumar Gupta u16 mode; 57b991f9b7SDaniel Mack u16 tx_mode; 58b991f9b7SDaniel Mack u16 rx_mode; 599ecb8875SAjay Kumar Gupta 609ecb8875SAjay Kumar Gupta /* bit positions for control */ 619ecb8875SAjay Kumar Gupta unsigned reset:5; 629ecb8875SAjay Kumar Gupta 639ecb8875SAjay Kumar Gupta /* bit positions for interrupt */ 649ecb8875SAjay Kumar Gupta unsigned usb_shift:5; 659ecb8875SAjay Kumar Gupta u32 usb_mask; 669ecb8875SAjay Kumar Gupta u32 usb_bitmap; 679ecb8875SAjay Kumar Gupta unsigned drvvbus:5; 689ecb8875SAjay Kumar Gupta 699ecb8875SAjay Kumar Gupta unsigned txep_shift:5; 709ecb8875SAjay Kumar Gupta u32 txep_mask; 719ecb8875SAjay Kumar Gupta u32 txep_bitmap; 729ecb8875SAjay Kumar Gupta 739ecb8875SAjay Kumar Gupta unsigned rxep_shift:5; 749ecb8875SAjay Kumar Gupta u32 rxep_mask; 759ecb8875SAjay Kumar Gupta u32 rxep_bitmap; 769ecb8875SAjay Kumar Gupta 779ecb8875SAjay Kumar Gupta /* bit positions for phy_utmi */ 789ecb8875SAjay Kumar Gupta unsigned otg_disable:5; 799ecb8875SAjay Kumar Gupta 809ecb8875SAjay Kumar Gupta /* bit positions for mode */ 819ecb8875SAjay Kumar Gupta unsigned iddig:5; 82943c1397SFelipe Balbi unsigned iddig_mux:5; 839ecb8875SAjay Kumar Gupta /* miscellaneous stuff */ 849e204d88SFelipe Balbi unsigned poll_timeout; 859ecb8875SAjay Kumar Gupta }; 869ecb8875SAjay Kumar Gupta 87869c5978SDaniel Mack /* 88869c5978SDaniel Mack * register shadow for suspend 89869c5978SDaniel Mack */ 90869c5978SDaniel Mack struct dsps_context { 91869c5978SDaniel Mack u32 control; 92869c5978SDaniel Mack u32 epintr; 93869c5978SDaniel Mack u32 coreintr; 94869c5978SDaniel Mack u32 phy_utmi; 95869c5978SDaniel Mack u32 mode; 96869c5978SDaniel Mack u32 tx_mode; 97869c5978SDaniel Mack u32 rx_mode; 98869c5978SDaniel Mack }; 99869c5978SDaniel Mack 10009e03a89SLee Jones /* 1019ecb8875SAjay Kumar Gupta * DSPS glue structure. 1029ecb8875SAjay Kumar Gupta */ 1039ecb8875SAjay Kumar Gupta struct dsps_glue { 1049ecb8875SAjay Kumar Gupta struct device *dev; 10597238b35SSebastian Andrzej Siewior struct platform_device *musb; /* child musb pdev */ 1069ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ 107369469a9STony Lindgren int vbus_irq; /* optional vbus irq */ 10897238b35SSebastian Andrzej Siewior unsigned long last_timer; /* last timer data for each instance */ 109371254ceSGeorge Cherian bool sw_babble_enabled; 11025534828SAlexandre Bailon void __iomem *usbss_base; 111869c5978SDaniel Mack 112869c5978SDaniel Mack struct dsps_context context; 11340f099e3SMarkus Pargmann struct debugfs_regset32 regset; 11440f099e3SMarkus Pargmann struct dentry *dbgfs_root; 11540f099e3SMarkus Pargmann }; 11640f099e3SMarkus Pargmann 11740f099e3SMarkus Pargmann static const struct debugfs_reg32 dsps_musb_regs[] = { 11840f099e3SMarkus Pargmann { "revision", 0x00 }, 11940f099e3SMarkus Pargmann { "control", 0x14 }, 12040f099e3SMarkus Pargmann { "status", 0x18 }, 12140f099e3SMarkus Pargmann { "eoi", 0x24 }, 12240f099e3SMarkus Pargmann { "intr0_stat", 0x30 }, 12340f099e3SMarkus Pargmann { "intr1_stat", 0x34 }, 12440f099e3SMarkus Pargmann { "intr0_set", 0x38 }, 12540f099e3SMarkus Pargmann { "intr1_set", 0x3c }, 12640f099e3SMarkus Pargmann { "txmode", 0x70 }, 12740f099e3SMarkus Pargmann { "rxmode", 0x74 }, 12840f099e3SMarkus Pargmann { "autoreq", 0xd0 }, 12940f099e3SMarkus Pargmann { "srpfixtime", 0xd4 }, 13040f099e3SMarkus Pargmann { "tdown", 0xd8 }, 13140f099e3SMarkus Pargmann { "phy_utmi", 0xe0 }, 13240f099e3SMarkus Pargmann { "mode", 0xe8 }, 1339ecb8875SAjay Kumar Gupta }; 1349ecb8875SAjay Kumar Gupta 135369469a9STony Lindgren static void dsps_mod_timer(struct dsps_glue *glue, int wait_ms) 136369469a9STony Lindgren { 137b82162bcSBin Liu struct musb *musb = platform_get_drvdata(glue->musb); 138369469a9STony Lindgren int wait; 139369469a9STony Lindgren 140369469a9STony Lindgren if (wait_ms < 0) 141369469a9STony Lindgren wait = msecs_to_jiffies(glue->wrp->poll_timeout); 142369469a9STony Lindgren else 143369469a9STony Lindgren wait = msecs_to_jiffies(wait_ms); 144369469a9STony Lindgren 145b82162bcSBin Liu mod_timer(&musb->dev_timer, jiffies + wait); 146369469a9STony Lindgren } 147369469a9STony Lindgren 148369469a9STony Lindgren /* 149369469a9STony Lindgren * If no vbus irq from the PMIC is configured, we need to poll VBUS status. 150369469a9STony Lindgren */ 151369469a9STony Lindgren static void dsps_mod_timer_optional(struct dsps_glue *glue) 152369469a9STony Lindgren { 153369469a9STony Lindgren if (glue->vbus_irq) 154369469a9STony Lindgren return; 155369469a9STony Lindgren 156369469a9STony Lindgren dsps_mod_timer(glue, -1); 157369469a9STony Lindgren } 158369469a9STony Lindgren 15925534828SAlexandre Bailon /* USBSS / USB AM335x */ 16025534828SAlexandre Bailon #define USBSS_IRQ_STATUS 0x28 16125534828SAlexandre Bailon #define USBSS_IRQ_ENABLER 0x2c 16225534828SAlexandre Bailon #define USBSS_IRQ_CLEARR 0x30 16325534828SAlexandre Bailon 16425534828SAlexandre Bailon #define USBSS_IRQ_PD_COMP (1 << 2) 16525534828SAlexandre Bailon 16609e03a89SLee Jones /* 1679ecb8875SAjay Kumar Gupta * dsps_musb_enable - enable interrupts 1689ecb8875SAjay Kumar Gupta */ 1699ecb8875SAjay Kumar Gupta static void dsps_musb_enable(struct musb *musb) 1709ecb8875SAjay Kumar Gupta { 1719ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 172e823d948SKefeng Wang struct dsps_glue *glue = dev_get_drvdata(dev->parent); 1739ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 1749ecb8875SAjay Kumar Gupta void __iomem *reg_base = musb->ctrl_base; 1759ecb8875SAjay Kumar Gupta u32 epmask, coremask; 1769ecb8875SAjay Kumar Gupta 1779ecb8875SAjay Kumar Gupta /* Workaround: setup IRQs through both register sets. */ 1789ecb8875SAjay Kumar Gupta epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) | 1799ecb8875SAjay Kumar Gupta ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift); 1809ecb8875SAjay Kumar Gupta coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF); 1819ecb8875SAjay Kumar Gupta 182086b2882SBin Liu musb_writel(reg_base, wrp->epintr_set, epmask); 183086b2882SBin Liu musb_writel(reg_base, wrp->coreintr_set, coremask); 18454578ee8SBin Liu /* 18554578ee8SBin Liu * start polling for runtime PM active and idle, 18654578ee8SBin Liu * and for ID change in dual-role idle mode. 18754578ee8SBin Liu */ 18854578ee8SBin Liu if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) 189369469a9STony Lindgren dsps_mod_timer(glue, -1); 1909ecb8875SAjay Kumar Gupta } 1919ecb8875SAjay Kumar Gupta 19209e03a89SLee Jones /* 1939ecb8875SAjay Kumar Gupta * dsps_musb_disable - disable HDRC and flush interrupts 1949ecb8875SAjay Kumar Gupta */ 1959ecb8875SAjay Kumar Gupta static void dsps_musb_disable(struct musb *musb) 1969ecb8875SAjay Kumar Gupta { 1979ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 198e823d948SKefeng Wang struct dsps_glue *glue = dev_get_drvdata(dev->parent); 1999ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 2009ecb8875SAjay Kumar Gupta void __iomem *reg_base = musb->ctrl_base; 2019ecb8875SAjay Kumar Gupta 202086b2882SBin Liu musb_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); 203086b2882SBin Liu musb_writel(reg_base, wrp->epintr_clear, 2049ecb8875SAjay Kumar Gupta wrp->txep_bitmap | wrp->rxep_bitmap); 205b82162bcSBin Liu del_timer_sync(&musb->dev_timer); 2069ecb8875SAjay Kumar Gupta } 2079ecb8875SAjay Kumar Gupta 208ea2f35c0STony Lindgren /* Caller must take musb->lock */ 209ea2f35c0STony Lindgren static int dsps_check_status(struct musb *musb, void *unused) 2109ecb8875SAjay Kumar Gupta { 2119ecb8875SAjay Kumar Gupta void __iomem *mregs = musb->mregs; 2129ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 213db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 2149ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 2159ecb8875SAjay Kumar Gupta u8 devctl; 2160f901c98SSebastian Andrzej Siewior int skip_session = 0; 2179ecb8875SAjay Kumar Gupta 218369469a9STony Lindgren if (glue->vbus_irq) 219b82162bcSBin Liu del_timer(&musb->dev_timer); 220369469a9STony Lindgren 2219ecb8875SAjay Kumar Gupta /* 2229ecb8875SAjay Kumar Gupta * We poll because DSPS IP's won't expose several OTG-critical 2239ecb8875SAjay Kumar Gupta * status change events (from the transceiver) otherwise. 2249ecb8875SAjay Kumar Gupta */ 225086b2882SBin Liu devctl = musb_readb(mregs, MUSB_DEVCTL); 2269ecb8875SAjay Kumar Gupta dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, 227e47d9254SAntoine Tenart usb_otg_state_string(musb->xceiv->otg->state)); 2289ecb8875SAjay Kumar Gupta 229e47d9254SAntoine Tenart switch (musb->xceiv->otg->state) { 2302f3fd2c5STony Lindgren case OTG_STATE_A_WAIT_VRISE: 2316010abf2SBin Liu if (musb->port_mode == MUSB_HOST) { 2326010abf2SBin Liu musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; 233369469a9STony Lindgren dsps_mod_timer_optional(glue); 2342f3fd2c5STony Lindgren break; 2356010abf2SBin Liu } 236df561f66SGustavo A. R. Silva fallthrough; 2376010abf2SBin Liu 2389ecb8875SAjay Kumar Gupta case OTG_STATE_A_WAIT_BCON: 239b3addcf0SBin Liu /* keep VBUS on for host-only mode */ 2407ad76955SBin Liu if (musb->port_mode == MUSB_HOST) { 241b3addcf0SBin Liu dsps_mod_timer_optional(glue); 242b3addcf0SBin Liu break; 243b3addcf0SBin Liu } 244086b2882SBin Liu musb_writeb(musb->mregs, MUSB_DEVCTL, 0); 2450f901c98SSebastian Andrzej Siewior skip_session = 1; 246df561f66SGustavo A. R. Silva fallthrough; 2479ecb8875SAjay Kumar Gupta 2480f901c98SSebastian Andrzej Siewior case OTG_STATE_A_IDLE: 2490f901c98SSebastian Andrzej Siewior case OTG_STATE_B_IDLE: 250369469a9STony Lindgren if (!glue->vbus_irq) { 2519ecb8875SAjay Kumar Gupta if (devctl & MUSB_DEVCTL_BDEVICE) { 252e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_B_IDLE; 2539ecb8875SAjay Kumar Gupta MUSB_DEV_MODE(musb); 2549ecb8875SAjay Kumar Gupta } else { 255e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_IDLE; 2569ecb8875SAjay Kumar Gupta MUSB_HST_MODE(musb); 2579ecb8875SAjay Kumar Gupta } 25854578ee8SBin Liu 25954578ee8SBin Liu if (musb->port_mode == MUSB_PERIPHERAL) 26054578ee8SBin Liu skip_session = 1; 26154578ee8SBin Liu 2620f901c98SSebastian Andrzej Siewior if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) 263369469a9STony Lindgren musb_writeb(mregs, MUSB_DEVCTL, 264369469a9STony Lindgren MUSB_DEVCTL_SESSION); 265369469a9STony Lindgren } 266369469a9STony Lindgren dsps_mod_timer_optional(glue); 2679ecb8875SAjay Kumar Gupta break; 2689ecb8875SAjay Kumar Gupta case OTG_STATE_A_WAIT_VFALL: 269e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; 270086b2882SBin Liu musb_writel(musb->ctrl_base, wrp->coreintr_set, 2719ecb8875SAjay Kumar Gupta MUSB_INTR_VBUSERROR << wrp->usb_shift); 2729ecb8875SAjay Kumar Gupta break; 2739ecb8875SAjay Kumar Gupta default: 2749ecb8875SAjay Kumar Gupta break; 2759ecb8875SAjay Kumar Gupta } 27665b3f50eSTony Lindgren 277ea2f35c0STony Lindgren return 0; 278ea2f35c0STony Lindgren } 279ea2f35c0STony Lindgren 28005678497SKees Cook static void otg_timer(struct timer_list *t) 281ea2f35c0STony Lindgren { 282b82162bcSBin Liu struct musb *musb = from_timer(musb, t, dev_timer); 283ea2f35c0STony Lindgren struct device *dev = musb->controller; 284ea2f35c0STony Lindgren unsigned long flags; 285ea2f35c0STony Lindgren int err; 286ea2f35c0STony Lindgren 287ea2f35c0STony Lindgren err = pm_runtime_get(dev); 288ea2f35c0STony Lindgren if ((err != -EINPROGRESS) && err < 0) { 289ea2f35c0STony Lindgren dev_err(dev, "Poll could not pm_runtime_get: %i\n", err); 290ea2f35c0STony Lindgren pm_runtime_put_noidle(dev); 291ea2f35c0STony Lindgren 292ea2f35c0STony Lindgren return; 293ea2f35c0STony Lindgren } 294ea2f35c0STony Lindgren 295ea2f35c0STony Lindgren spin_lock_irqsave(&musb->lock, flags); 296ea2f35c0STony Lindgren err = musb_queue_resume_work(musb, dsps_check_status, NULL); 297ea2f35c0STony Lindgren if (err < 0) 298ea2f35c0STony Lindgren dev_err(dev, "%s resume work: %i\n", __func__, err); 299ea2f35c0STony Lindgren spin_unlock_irqrestore(&musb->lock, flags); 30065b3f50eSTony Lindgren pm_runtime_mark_last_busy(dev); 30165b3f50eSTony Lindgren pm_runtime_put_autosuspend(dev); 3029ecb8875SAjay Kumar Gupta } 3039ecb8875SAjay Kumar Gupta 3044ab53a69SWei Yongjun static void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) 305c48400baSBin Liu { 306c48400baSBin Liu u32 epintr; 307c48400baSBin Liu struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 308c48400baSBin Liu const struct dsps_musb_wrapper *wrp = glue->wrp; 309c48400baSBin Liu 310c48400baSBin Liu /* musb->lock might already been held */ 311c48400baSBin Liu epintr = (1 << epnum) << wrp->rxep_shift; 312c48400baSBin Liu musb_writel(musb->ctrl_base, wrp->epintr_status, epintr); 313c48400baSBin Liu } 314c48400baSBin Liu 3159ecb8875SAjay Kumar Gupta static irqreturn_t dsps_interrupt(int irq, void *hci) 3169ecb8875SAjay Kumar Gupta { 3179ecb8875SAjay Kumar Gupta struct musb *musb = hci; 3189ecb8875SAjay Kumar Gupta void __iomem *reg_base = musb->ctrl_base; 3199ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 320db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 3219ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 3229ecb8875SAjay Kumar Gupta unsigned long flags; 3239ecb8875SAjay Kumar Gupta irqreturn_t ret = IRQ_NONE; 3249ecb8875SAjay Kumar Gupta u32 epintr, usbintr; 3259ecb8875SAjay Kumar Gupta 3269ecb8875SAjay Kumar Gupta spin_lock_irqsave(&musb->lock, flags); 3279ecb8875SAjay Kumar Gupta 3289ecb8875SAjay Kumar Gupta /* Get endpoint interrupts */ 329086b2882SBin Liu epintr = musb_readl(reg_base, wrp->epintr_status); 3309ecb8875SAjay Kumar Gupta musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; 3319ecb8875SAjay Kumar Gupta musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; 3329ecb8875SAjay Kumar Gupta 3339ecb8875SAjay Kumar Gupta if (epintr) 334086b2882SBin Liu musb_writel(reg_base, wrp->epintr_status, epintr); 3359ecb8875SAjay Kumar Gupta 3369ecb8875SAjay Kumar Gupta /* Get usb core interrupts */ 337086b2882SBin Liu usbintr = musb_readl(reg_base, wrp->coreintr_status); 3389ecb8875SAjay Kumar Gupta if (!usbintr && !epintr) 3399be73baeSSebastian Andrzej Siewior goto out; 3409ecb8875SAjay Kumar Gupta 3419ecb8875SAjay Kumar Gupta musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; 3429ecb8875SAjay Kumar Gupta if (usbintr) 343086b2882SBin Liu musb_writel(reg_base, wrp->coreintr_status, usbintr); 3449ecb8875SAjay Kumar Gupta 3459ecb8875SAjay Kumar Gupta dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", 3469ecb8875SAjay Kumar Gupta usbintr, epintr); 3471d57de30SDaniel Mack 3489ecb8875SAjay Kumar Gupta if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { 349086b2882SBin Liu int drvvbus = musb_readl(reg_base, wrp->status); 3509ecb8875SAjay Kumar Gupta void __iomem *mregs = musb->mregs; 351086b2882SBin Liu u8 devctl = musb_readb(mregs, MUSB_DEVCTL); 3529ecb8875SAjay Kumar Gupta int err; 3539ecb8875SAjay Kumar Gupta 354032ec49fSFelipe Balbi err = musb->int_usb & MUSB_INTR_VBUSERROR; 3559ecb8875SAjay Kumar Gupta if (err) { 3569ecb8875SAjay Kumar Gupta /* 3579ecb8875SAjay Kumar Gupta * The Mentor core doesn't debounce VBUS as needed 3589ecb8875SAjay Kumar Gupta * to cope with device connect current spikes. This 3599ecb8875SAjay Kumar Gupta * means it's not uncommon for bus-powered devices 3609ecb8875SAjay Kumar Gupta * to get VBUS errors during enumeration. 3619ecb8875SAjay Kumar Gupta * 3629ecb8875SAjay Kumar Gupta * This is a workaround, but newer RTL from Mentor 3639ecb8875SAjay Kumar Gupta * seems to allow a better one: "re"-starting sessions 3649ecb8875SAjay Kumar Gupta * without waiting for VBUS to stop registering in 3659ecb8875SAjay Kumar Gupta * devctl. 3669ecb8875SAjay Kumar Gupta */ 3679ecb8875SAjay Kumar Gupta musb->int_usb &= ~MUSB_INTR_VBUSERROR; 368e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; 369369469a9STony Lindgren dsps_mod_timer_optional(glue); 3709ecb8875SAjay Kumar Gupta WARNING("VBUS error workaround (delay coming)\n"); 371032ec49fSFelipe Balbi } else if (drvvbus) { 3729ecb8875SAjay Kumar Gupta MUSB_HST_MODE(musb); 373e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; 374369469a9STony Lindgren dsps_mod_timer_optional(glue); 3759ecb8875SAjay Kumar Gupta } else { 3769ecb8875SAjay Kumar Gupta musb->is_active = 0; 3779ecb8875SAjay Kumar Gupta MUSB_DEV_MODE(musb); 378e47d9254SAntoine Tenart musb->xceiv->otg->state = OTG_STATE_B_IDLE; 3799ecb8875SAjay Kumar Gupta } 3809ecb8875SAjay Kumar Gupta 3819ecb8875SAjay Kumar Gupta /* NOTE: this must complete power-on within 100 ms. */ 3829ecb8875SAjay Kumar Gupta dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", 3839ecb8875SAjay Kumar Gupta drvvbus ? "on" : "off", 384e47d9254SAntoine Tenart usb_otg_state_string(musb->xceiv->otg->state), 3859ecb8875SAjay Kumar Gupta err ? " ERROR" : "", 3869ecb8875SAjay Kumar Gupta devctl); 3879ecb8875SAjay Kumar Gupta ret = IRQ_HANDLED; 3889ecb8875SAjay Kumar Gupta } 3899ecb8875SAjay Kumar Gupta 3909ecb8875SAjay Kumar Gupta if (musb->int_tx || musb->int_rx || musb->int_usb) 3919ecb8875SAjay Kumar Gupta ret |= musb_interrupt(musb); 3929ecb8875SAjay Kumar Gupta 3932f3fd2c5STony Lindgren /* Poll for ID change and connect */ 3942f3fd2c5STony Lindgren switch (musb->xceiv->otg->state) { 3952f3fd2c5STony Lindgren case OTG_STATE_B_IDLE: 3962f3fd2c5STony Lindgren case OTG_STATE_A_WAIT_BCON: 397369469a9STony Lindgren dsps_mod_timer_optional(glue); 3982f3fd2c5STony Lindgren break; 3992f3fd2c5STony Lindgren default: 4002f3fd2c5STony Lindgren break; 4012f3fd2c5STony Lindgren } 4022f3fd2c5STony Lindgren 4039be73baeSSebastian Andrzej Siewior out: 4049ecb8875SAjay Kumar Gupta spin_unlock_irqrestore(&musb->lock, flags); 4059ecb8875SAjay Kumar Gupta 4069ecb8875SAjay Kumar Gupta return ret; 4079ecb8875SAjay Kumar Gupta } 4089ecb8875SAjay Kumar Gupta 40940f099e3SMarkus Pargmann static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) 41040f099e3SMarkus Pargmann { 41140f099e3SMarkus Pargmann struct dentry *root; 41240f099e3SMarkus Pargmann char buf[128]; 41340f099e3SMarkus Pargmann 41440f099e3SMarkus Pargmann sprintf(buf, "%s.dsps", dev_name(musb->controller)); 415b3c69ec8SChunfeng Yun root = debugfs_create_dir(buf, usb_debug_root); 41640f099e3SMarkus Pargmann glue->dbgfs_root = root; 41740f099e3SMarkus Pargmann 41840f099e3SMarkus Pargmann glue->regset.regs = dsps_musb_regs; 41940f099e3SMarkus Pargmann glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs); 42040f099e3SMarkus Pargmann glue->regset.base = musb->ctrl_base; 42140f099e3SMarkus Pargmann 4228a1ef171SGreg Kroah-Hartman debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset); 42340f099e3SMarkus Pargmann return 0; 42440f099e3SMarkus Pargmann } 42540f099e3SMarkus Pargmann 4269ecb8875SAjay Kumar Gupta static int dsps_musb_init(struct musb *musb) 4279ecb8875SAjay Kumar Gupta { 4289ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 429db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 43097238b35SSebastian Andrzej Siewior struct platform_device *parent = to_platform_device(dev->parent); 4319ecb8875SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp = glue->wrp; 43297238b35SSebastian Andrzej Siewior void __iomem *reg_base; 433ffa13d2dSGeert Uytterhoeven struct resource *r; 4349ecb8875SAjay Kumar Gupta u32 rev, val; 43540f099e3SMarkus Pargmann int ret; 4369ecb8875SAjay Kumar Gupta 437ffa13d2dSGeert Uytterhoeven r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); 438ffa13d2dSGeert Uytterhoeven reg_base = devm_ioremap_resource(dev, r); 43951ef74f6SJulia Lawall if (IS_ERR(reg_base)) 44051ef74f6SJulia Lawall return PTR_ERR(reg_base); 44197238b35SSebastian Andrzej Siewior musb->ctrl_base = reg_base; 4429ecb8875SAjay Kumar Gupta 443d7554226SAfzal Mohammed /* NOP driver needs change if supporting dual instance */ 444983f3cabSFelipe Balbi musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "phys", 0); 44597238b35SSebastian Andrzej Siewior if (IS_ERR(musb->xceiv)) 44697238b35SSebastian Andrzej Siewior return PTR_ERR(musb->xceiv); 4479ecb8875SAjay Kumar Gupta 448bb90600dSTony Lindgren musb->phy = devm_phy_get(dev->parent, "usb2-phy"); 449bb90600dSTony Lindgren 4509ecb8875SAjay Kumar Gupta /* Returns zero if e.g. not clocked */ 451086b2882SBin Liu rev = musb_readl(reg_base, wrp->revision); 45297238b35SSebastian Andrzej Siewior if (!rev) 45397238b35SSebastian Andrzej Siewior return -ENODEV; 4549ecb8875SAjay Kumar Gupta 455bb90600dSTony Lindgren if (IS_ERR(musb->phy)) { 456bb90600dSTony Lindgren musb->phy = NULL; 457bb90600dSTony Lindgren } else { 458bb90600dSTony Lindgren ret = phy_init(musb->phy); 459bb90600dSTony Lindgren if (ret < 0) 460bb90600dSTony Lindgren return ret; 461bb90600dSTony Lindgren ret = phy_power_on(musb->phy); 462bb90600dSTony Lindgren if (ret) { 463bb90600dSTony Lindgren phy_exit(musb->phy); 464bb90600dSTony Lindgren return ret; 465bb90600dSTony Lindgren } 466bb90600dSTony Lindgren } 467bb90600dSTony Lindgren 468b82162bcSBin Liu timer_setup(&musb->dev_timer, otg_timer, 0); 4699ecb8875SAjay Kumar Gupta 4709ecb8875SAjay Kumar Gupta /* Reset the musb */ 471086b2882SBin Liu musb_writel(reg_base, wrp->control, (1 << wrp->reset)); 4729ecb8875SAjay Kumar Gupta 4739ecb8875SAjay Kumar Gupta musb->isr = dsps_interrupt; 4749ecb8875SAjay Kumar Gupta 4759ecb8875SAjay Kumar Gupta /* reset the otgdisable bit, needed for host mode to work */ 476086b2882SBin Liu val = musb_readl(reg_base, wrp->phy_utmi); 4779ecb8875SAjay Kumar Gupta val &= ~(1 << wrp->otg_disable); 478086b2882SBin Liu musb_writel(musb->ctrl_base, wrp->phy_utmi, val); 4799ecb8875SAjay Kumar Gupta 480371254ceSGeorge Cherian /* 481371254ceSGeorge Cherian * Check whether the dsps version has babble control enabled. 482371254ceSGeorge Cherian * In latest silicon revision the babble control logic is enabled. 483371254ceSGeorge Cherian * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control 484371254ceSGeorge Cherian * logic enabled. 485371254ceSGeorge Cherian */ 486086b2882SBin Liu val = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 487f860f0b1SFelipe Balbi if (val & MUSB_BABBLE_RCV_DISABLE) { 488371254ceSGeorge Cherian glue->sw_babble_enabled = true; 489371254ceSGeorge Cherian val |= MUSB_BABBLE_SW_SESSION_CTRL; 490086b2882SBin Liu musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); 491371254ceSGeorge Cherian } 492371254ceSGeorge Cherian 493369469a9STony Lindgren dsps_mod_timer(glue, -1); 4942f3fd2c5STony Lindgren 495e94a7369SSaurabh Karajgaonkar return dsps_musb_dbg_init(musb, glue); 4969ecb8875SAjay Kumar Gupta } 4979ecb8875SAjay Kumar Gupta 4989ecb8875SAjay Kumar Gupta static int dsps_musb_exit(struct musb *musb) 4999ecb8875SAjay Kumar Gupta { 5009ecb8875SAjay Kumar Gupta struct device *dev = musb->controller; 501db4a9320SB, Ravi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 5029ecb8875SAjay Kumar Gupta 503b82162bcSBin Liu del_timer_sync(&musb->dev_timer); 504bb90600dSTony Lindgren phy_power_off(musb->phy); 505bb90600dSTony Lindgren phy_exit(musb->phy); 5060fca91b8SDaniel Mack debugfs_remove_recursive(glue->dbgfs_root); 5070fca91b8SDaniel Mack 5089ecb8875SAjay Kumar Gupta return 0; 5099ecb8875SAjay Kumar Gupta } 5109ecb8875SAjay Kumar Gupta 511943c1397SFelipe Balbi static int dsps_musb_set_mode(struct musb *musb, u8 mode) 512943c1397SFelipe Balbi { 513943c1397SFelipe Balbi struct device *dev = musb->controller; 514943c1397SFelipe Balbi struct dsps_glue *glue = dev_get_drvdata(dev->parent); 515943c1397SFelipe Balbi const struct dsps_musb_wrapper *wrp = glue->wrp; 516943c1397SFelipe Balbi void __iomem *ctrl_base = musb->ctrl_base; 517943c1397SFelipe Balbi u32 reg; 518943c1397SFelipe Balbi 519086b2882SBin Liu reg = musb_readl(ctrl_base, wrp->mode); 520943c1397SFelipe Balbi 521943c1397SFelipe Balbi switch (mode) { 522943c1397SFelipe Balbi case MUSB_HOST: 523943c1397SFelipe Balbi reg &= ~(1 << wrp->iddig); 524943c1397SFelipe Balbi 525943c1397SFelipe Balbi /* 526943c1397SFelipe Balbi * if we're setting mode to host-only or device-only, we're 527943c1397SFelipe Balbi * going to ignore whatever the PHY sends us and just force 528943c1397SFelipe Balbi * ID pin status by SW 529943c1397SFelipe Balbi */ 530943c1397SFelipe Balbi reg |= (1 << wrp->iddig_mux); 531943c1397SFelipe Balbi 532086b2882SBin Liu musb_writel(ctrl_base, wrp->mode, reg); 533086b2882SBin Liu musb_writel(ctrl_base, wrp->phy_utmi, 0x02); 534943c1397SFelipe Balbi break; 535943c1397SFelipe Balbi case MUSB_PERIPHERAL: 536943c1397SFelipe Balbi reg |= (1 << wrp->iddig); 537943c1397SFelipe Balbi 538943c1397SFelipe Balbi /* 539943c1397SFelipe Balbi * if we're setting mode to host-only or device-only, we're 540943c1397SFelipe Balbi * going to ignore whatever the PHY sends us and just force 541943c1397SFelipe Balbi * ID pin status by SW 542943c1397SFelipe Balbi */ 543943c1397SFelipe Balbi reg |= (1 << wrp->iddig_mux); 544943c1397SFelipe Balbi 545086b2882SBin Liu musb_writel(ctrl_base, wrp->mode, reg); 546943c1397SFelipe Balbi break; 547943c1397SFelipe Balbi case MUSB_OTG: 548086b2882SBin Liu musb_writel(ctrl_base, wrp->phy_utmi, 0x02); 549943c1397SFelipe Balbi break; 550943c1397SFelipe Balbi default: 551943c1397SFelipe Balbi dev_err(glue->dev, "unsupported mode %d\n", mode); 552943c1397SFelipe Balbi return -EINVAL; 553943c1397SFelipe Balbi } 554943c1397SFelipe Balbi 555943c1397SFelipe Balbi return 0; 556943c1397SFelipe Balbi } 557943c1397SFelipe Balbi 5583709ffcaSFelipe Balbi static bool dsps_sw_babble_control(struct musb *musb) 559371254ceSGeorge Cherian { 560371254ceSGeorge Cherian u8 babble_ctl; 561371254ceSGeorge Cherian bool session_restart = false; 562371254ceSGeorge Cherian 563086b2882SBin Liu babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 564371254ceSGeorge Cherian dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", 565371254ceSGeorge Cherian babble_ctl); 566371254ceSGeorge Cherian /* 567371254ceSGeorge Cherian * check line monitor flag to check whether babble is 568371254ceSGeorge Cherian * due to noise 569371254ceSGeorge Cherian */ 570371254ceSGeorge Cherian dev_dbg(musb->controller, "STUCK_J is %s\n", 571371254ceSGeorge Cherian babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset"); 572371254ceSGeorge Cherian 573371254ceSGeorge Cherian if (babble_ctl & MUSB_BABBLE_STUCK_J) { 574371254ceSGeorge Cherian int timeout = 10; 575371254ceSGeorge Cherian 576371254ceSGeorge Cherian /* 577371254ceSGeorge Cherian * babble is due to noise, then set transmit idle (d7 bit) 578371254ceSGeorge Cherian * to resume normal operation 579371254ceSGeorge Cherian */ 580086b2882SBin Liu babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 581371254ceSGeorge Cherian babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; 582086b2882SBin Liu musb_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); 583371254ceSGeorge Cherian 584371254ceSGeorge Cherian /* wait till line monitor flag cleared */ 585371254ceSGeorge Cherian dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); 586371254ceSGeorge Cherian do { 587086b2882SBin Liu babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 588371254ceSGeorge Cherian udelay(1); 589371254ceSGeorge Cherian } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); 590371254ceSGeorge Cherian 591371254ceSGeorge Cherian /* check whether stuck_at_j bit cleared */ 592371254ceSGeorge Cherian if (babble_ctl & MUSB_BABBLE_STUCK_J) { 593371254ceSGeorge Cherian /* 594371254ceSGeorge Cherian * real babble condition has occurred 595371254ceSGeorge Cherian * restart the controller to start the 596371254ceSGeorge Cherian * session again 597371254ceSGeorge Cherian */ 598371254ceSGeorge Cherian dev_dbg(musb->controller, "J not cleared, misc (%x)\n", 599371254ceSGeorge Cherian babble_ctl); 600371254ceSGeorge Cherian session_restart = true; 601371254ceSGeorge Cherian } 602371254ceSGeorge Cherian } else { 603371254ceSGeorge Cherian session_restart = true; 604371254ceSGeorge Cherian } 605371254ceSGeorge Cherian 606371254ceSGeorge Cherian return session_restart; 607371254ceSGeorge Cherian } 608371254ceSGeorge Cherian 609b28a6432SFelipe Balbi static int dsps_musb_recover(struct musb *musb) 6101d57de30SDaniel Mack { 6111d57de30SDaniel Mack struct device *dev = musb->controller; 6121d57de30SDaniel Mack struct dsps_glue *glue = dev_get_drvdata(dev->parent); 613011d0dd5SFelipe Balbi int session_restart = 0; 6141d57de30SDaniel Mack 615371254ceSGeorge Cherian if (glue->sw_babble_enabled) 6163709ffcaSFelipe Balbi session_restart = dsps_sw_babble_control(musb); 617011d0dd5SFelipe Balbi else 618371254ceSGeorge Cherian session_restart = 1; 61956700178SGeorge Cherian 620d0cddae7SFelipe Balbi return session_restart ? 0 : -EPIPE; 6211d57de30SDaniel Mack } 6221d57de30SDaniel Mack 6233e457371STony Lindgren /* Similar to am35x, dm81xx support only 32-bit read operation */ 6243e457371STony Lindgren static void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) 6253e457371STony Lindgren { 6263e457371STony Lindgren void __iomem *fifo = hw_ep->fifo; 6273e457371STony Lindgren 6283e457371STony Lindgren if (len >= 4) { 629d30323f8STony Lindgren ioread32_rep(fifo, dst, len >> 2); 6303e457371STony Lindgren dst += len & ~0x03; 6313e457371STony Lindgren len &= 0x03; 6323e457371STony Lindgren } 6333e457371STony Lindgren 6343e457371STony Lindgren /* Read any remaining 1 to 3 bytes */ 6353e457371STony Lindgren if (len > 0) { 6363e457371STony Lindgren u32 val = musb_readl(fifo, 0); 6373e457371STony Lindgren memcpy(dst, &val, len); 6383e457371STony Lindgren } 6393e457371STony Lindgren } 6403e457371STony Lindgren 64125534828SAlexandre Bailon #ifdef CONFIG_USB_TI_CPPI41_DMA 64225534828SAlexandre Bailon static void dsps_dma_controller_callback(struct dma_controller *c) 64325534828SAlexandre Bailon { 64425534828SAlexandre Bailon struct musb *musb = c->musb; 64525534828SAlexandre Bailon struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 64625534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 64725534828SAlexandre Bailon u32 status; 64825534828SAlexandre Bailon 64925534828SAlexandre Bailon status = musb_readl(usbss_base, USBSS_IRQ_STATUS); 65025534828SAlexandre Bailon if (status & USBSS_IRQ_PD_COMP) 65125534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_STATUS, USBSS_IRQ_PD_COMP); 65225534828SAlexandre Bailon } 65325534828SAlexandre Bailon 65425534828SAlexandre Bailon static struct dma_controller * 65525534828SAlexandre Bailon dsps_dma_controller_create(struct musb *musb, void __iomem *base) 65625534828SAlexandre Bailon { 65725534828SAlexandre Bailon struct dma_controller *controller; 65825534828SAlexandre Bailon struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 65925534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 66025534828SAlexandre Bailon 66125534828SAlexandre Bailon controller = cppi41_dma_controller_create(musb, base); 66225534828SAlexandre Bailon if (IS_ERR_OR_NULL(controller)) 66325534828SAlexandre Bailon return controller; 66425534828SAlexandre Bailon 66525534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); 66625534828SAlexandre Bailon controller->dma_callback = dsps_dma_controller_callback; 66725534828SAlexandre Bailon 66825534828SAlexandre Bailon return controller; 66925534828SAlexandre Bailon } 67025534828SAlexandre Bailon 67125534828SAlexandre Bailon #ifdef CONFIG_PM_SLEEP 67225534828SAlexandre Bailon static void dsps_dma_controller_suspend(struct dsps_glue *glue) 67325534828SAlexandre Bailon { 67425534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 67525534828SAlexandre Bailon 67625534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); 67725534828SAlexandre Bailon } 67825534828SAlexandre Bailon 67925534828SAlexandre Bailon static void dsps_dma_controller_resume(struct dsps_glue *glue) 68025534828SAlexandre Bailon { 68125534828SAlexandre Bailon void __iomem *usbss_base = glue->usbss_base; 68225534828SAlexandre Bailon 68325534828SAlexandre Bailon musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); 68425534828SAlexandre Bailon } 68525534828SAlexandre Bailon #endif 68625534828SAlexandre Bailon #else /* CONFIG_USB_TI_CPPI41_DMA */ 68725534828SAlexandre Bailon #ifdef CONFIG_PM_SLEEP 68825534828SAlexandre Bailon static void dsps_dma_controller_suspend(struct dsps_glue *glue) {} 68925534828SAlexandre Bailon static void dsps_dma_controller_resume(struct dsps_glue *glue) {} 69025534828SAlexandre Bailon #endif 69125534828SAlexandre Bailon #endif /* CONFIG_USB_TI_CPPI41_DMA */ 69225534828SAlexandre Bailon 6939ecb8875SAjay Kumar Gupta static struct musb_platform_ops dsps_ops = { 694f8e9f34fSTony Lindgren .quirks = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP, 6959ecb8875SAjay Kumar Gupta .init = dsps_musb_init, 6969ecb8875SAjay Kumar Gupta .exit = dsps_musb_exit, 6979ecb8875SAjay Kumar Gupta 6987f6283edSTony Lindgren #ifdef CONFIG_USB_TI_CPPI41_DMA 69925534828SAlexandre Bailon .dma_init = dsps_dma_controller_create, 700783f3b4eSBin Liu .dma_exit = cppi41_dma_controller_destroy, 7017f6283edSTony Lindgren #endif 7029ecb8875SAjay Kumar Gupta .enable = dsps_musb_enable, 7039ecb8875SAjay Kumar Gupta .disable = dsps_musb_disable, 7049ecb8875SAjay Kumar Gupta 705943c1397SFelipe Balbi .set_mode = dsps_musb_set_mode, 706b28a6432SFelipe Balbi .recover = dsps_musb_recover, 707c48400baSBin Liu .clear_ep_rxintr = dsps_musb_clear_ep_rxintr, 7089ecb8875SAjay Kumar Gupta }; 7099ecb8875SAjay Kumar Gupta 7109ecb8875SAjay Kumar Gupta static u64 musb_dmamask = DMA_BIT_MASK(32); 7119ecb8875SAjay Kumar Gupta 71297238b35SSebastian Andrzej Siewior static int get_int_prop(struct device_node *dn, const char *s) 7139ecb8875SAjay Kumar Gupta { 71497238b35SSebastian Andrzej Siewior int ret; 71597238b35SSebastian Andrzej Siewior u32 val; 71697238b35SSebastian Andrzej Siewior 71797238b35SSebastian Andrzej Siewior ret = of_property_read_u32(dn, s, &val); 71897238b35SSebastian Andrzej Siewior if (ret) 71997238b35SSebastian Andrzej Siewior return 0; 72097238b35SSebastian Andrzej Siewior return val; 72197238b35SSebastian Andrzej Siewior } 72297238b35SSebastian Andrzej Siewior 72397238b35SSebastian Andrzej Siewior static int dsps_create_musb_pdev(struct dsps_glue *glue, 72497238b35SSebastian Andrzej Siewior struct platform_device *parent) 72597238b35SSebastian Andrzej Siewior { 72697238b35SSebastian Andrzej Siewior struct musb_hdrc_platform_data pdata; 72797238b35SSebastian Andrzej Siewior struct resource resources[2]; 728c031a7d4SSebastian Andrzej Siewior struct resource *res; 72997238b35SSebastian Andrzej Siewior struct device *dev = &parent->dev; 73065145677SAjay Kumar Gupta struct musb_hdrc_config *config; 7319ecb8875SAjay Kumar Gupta struct platform_device *musb; 73297238b35SSebastian Andrzej Siewior struct device_node *dn = parent->dev.of_node; 733606bf4d5STony Lindgren int ret, val; 7349ecb8875SAjay Kumar Gupta 73597238b35SSebastian Andrzej Siewior memset(resources, 0, sizeof(resources)); 736c031a7d4SSebastian Andrzej Siewior res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc"); 737c031a7d4SSebastian Andrzej Siewior if (!res) { 73897238b35SSebastian Andrzej Siewior dev_err(dev, "failed to get memory.\n"); 739c031a7d4SSebastian Andrzej Siewior return -EINVAL; 7409ecb8875SAjay Kumar Gupta } 741c031a7d4SSebastian Andrzej Siewior resources[0] = *res; 74297238b35SSebastian Andrzej Siewior 743ce1d37cbSLad Prabhakar ret = platform_get_irq_byname(parent, "mc"); 744ce1d37cbSLad Prabhakar if (ret < 0) 745ce1d37cbSLad Prabhakar return ret; 746ce1d37cbSLad Prabhakar 747ce1d37cbSLad Prabhakar resources[1].start = ret; 748ce1d37cbSLad Prabhakar resources[1].end = ret; 749ce1d37cbSLad Prabhakar resources[1].flags = IORESOURCE_IRQ | irq_get_trigger_type(ret); 750ce1d37cbSLad Prabhakar resources[1].name = "mc"; 7519ecb8875SAjay Kumar Gupta 75265b3d52dSB, Ravi /* allocate the child platform device */ 75345abfa68SBin Liu musb = platform_device_alloc("musb-hdrc", 75445abfa68SBin Liu (resources[0].start & 0xFFF) == 0x400 ? 0 : 1); 75565b3d52dSB, Ravi if (!musb) { 75665b3d52dSB, Ravi dev_err(dev, "failed to allocate musb device\n"); 75797238b35SSebastian Andrzej Siewior return -ENOMEM; 75865b3d52dSB, Ravi } 7599ecb8875SAjay Kumar Gupta 7609ecb8875SAjay Kumar Gupta musb->dev.parent = dev; 7619ecb8875SAjay Kumar Gupta musb->dev.dma_mask = &musb_dmamask; 7629ecb8875SAjay Kumar Gupta musb->dev.coherent_dma_mask = musb_dmamask; 76349484abdSJohan Hovold device_set_of_node_from_dev(&musb->dev, &parent->dev); 7649ecb8875SAjay Kumar Gupta 76597238b35SSebastian Andrzej Siewior glue->musb = musb; 7669ecb8875SAjay Kumar Gupta 76797238b35SSebastian Andrzej Siewior ret = platform_device_add_resources(musb, resources, 76897238b35SSebastian Andrzej Siewior ARRAY_SIZE(resources)); 7699ecb8875SAjay Kumar Gupta if (ret) { 7709ecb8875SAjay Kumar Gupta dev_err(dev, "failed to add resources\n"); 77197238b35SSebastian Andrzej Siewior goto err; 7729ecb8875SAjay Kumar Gupta } 7739ecb8875SAjay Kumar Gupta 77497238b35SSebastian Andrzej Siewior config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); 77565145677SAjay Kumar Gupta if (!config) { 776b25e5f1cSWei Yongjun ret = -ENOMEM; 77797238b35SSebastian Andrzej Siewior goto err; 77865145677SAjay Kumar Gupta } 77997238b35SSebastian Andrzej Siewior pdata.config = config; 78097238b35SSebastian Andrzej Siewior pdata.platform_ops = &dsps_ops; 78165145677SAjay Kumar Gupta 782c031a7d4SSebastian Andrzej Siewior config->num_eps = get_int_prop(dn, "mentor,num-eps"); 783c031a7d4SSebastian Andrzej Siewior config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); 784869c5978SDaniel Mack config->host_port_deassert_reset_at_resume = 1; 78555479956SBin Liu pdata.mode = musb_get_mode(dev); 786c031a7d4SSebastian Andrzej Siewior /* DT keeps this entry in mA, musb expects it as per USB spec */ 787c031a7d4SSebastian Andrzej Siewior pdata.power = get_int_prop(dn, "mentor,power") / 2; 788606bf4d5STony Lindgren 789606bf4d5STony Lindgren ret = of_property_read_u32(dn, "mentor,multipoint", &val); 790606bf4d5STony Lindgren if (!ret && val) 791606bf4d5STony Lindgren config->multipoint = true; 79265145677SAjay Kumar Gupta 79363863b98SHeikki Krogerus config->maximum_speed = usb_get_maximum_speed(&parent->dev); 79441932b9bSBin Liu switch (config->maximum_speed) { 79541932b9bSBin Liu case USB_SPEED_LOW: 79641932b9bSBin Liu case USB_SPEED_FULL: 79741932b9bSBin Liu break; 79841932b9bSBin Liu case USB_SPEED_SUPER: 79941932b9bSBin Liu dev_warn(dev, "ignore incorrect maximum_speed " 80041932b9bSBin Liu "(super-speed) setting in dts"); 801df561f66SGustavo A. R. Silva fallthrough; 80241932b9bSBin Liu default: 80341932b9bSBin Liu config->maximum_speed = USB_SPEED_HIGH; 80441932b9bSBin Liu } 80541932b9bSBin Liu 80697238b35SSebastian Andrzej Siewior ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); 8079ecb8875SAjay Kumar Gupta if (ret) { 8089ecb8875SAjay Kumar Gupta dev_err(dev, "failed to add platform_data\n"); 80997238b35SSebastian Andrzej Siewior goto err; 8109ecb8875SAjay Kumar Gupta } 8119ecb8875SAjay Kumar Gupta 8129ecb8875SAjay Kumar Gupta ret = platform_device_add(musb); 8139ecb8875SAjay Kumar Gupta if (ret) { 8149ecb8875SAjay Kumar Gupta dev_err(dev, "failed to register musb device\n"); 81597238b35SSebastian Andrzej Siewior goto err; 8169ecb8875SAjay Kumar Gupta } 8179ecb8875SAjay Kumar Gupta return 0; 8189ecb8875SAjay Kumar Gupta 81997238b35SSebastian Andrzej Siewior err: 8209ecb8875SAjay Kumar Gupta platform_device_put(musb); 8219ecb8875SAjay Kumar Gupta return ret; 8229ecb8875SAjay Kumar Gupta } 8239ecb8875SAjay Kumar Gupta 824369469a9STony Lindgren static irqreturn_t dsps_vbus_threaded_irq(int irq, void *priv) 825369469a9STony Lindgren { 826369469a9STony Lindgren struct dsps_glue *glue = priv; 827369469a9STony Lindgren struct musb *musb = platform_get_drvdata(glue->musb); 828369469a9STony Lindgren 829369469a9STony Lindgren if (!musb) 830369469a9STony Lindgren return IRQ_NONE; 831369469a9STony Lindgren 832369469a9STony Lindgren dev_dbg(glue->dev, "VBUS interrupt\n"); 833369469a9STony Lindgren dsps_mod_timer(glue, 0); 834369469a9STony Lindgren 835369469a9STony Lindgren return IRQ_HANDLED; 836369469a9STony Lindgren } 837369469a9STony Lindgren 838369469a9STony Lindgren static int dsps_setup_optional_vbus_irq(struct platform_device *pdev, 839369469a9STony Lindgren struct dsps_glue *glue) 840369469a9STony Lindgren { 841369469a9STony Lindgren int error; 842369469a9STony Lindgren 843369469a9STony Lindgren glue->vbus_irq = platform_get_irq_byname(pdev, "vbus"); 844369469a9STony Lindgren if (glue->vbus_irq == -EPROBE_DEFER) 845369469a9STony Lindgren return -EPROBE_DEFER; 846369469a9STony Lindgren 847369469a9STony Lindgren if (glue->vbus_irq <= 0) { 848369469a9STony Lindgren glue->vbus_irq = 0; 849369469a9STony Lindgren return 0; 850369469a9STony Lindgren } 851369469a9STony Lindgren 852369469a9STony Lindgren error = devm_request_threaded_irq(glue->dev, glue->vbus_irq, 853369469a9STony Lindgren NULL, dsps_vbus_threaded_irq, 854369469a9STony Lindgren IRQF_ONESHOT, 855369469a9STony Lindgren "vbus", glue); 856369469a9STony Lindgren if (error) { 857369469a9STony Lindgren glue->vbus_irq = 0; 858369469a9STony Lindgren return error; 859369469a9STony Lindgren } 860369469a9STony Lindgren dev_dbg(glue->dev, "VBUS irq %i configured\n", glue->vbus_irq); 861369469a9STony Lindgren 862369469a9STony Lindgren return 0; 863369469a9STony Lindgren } 864369469a9STony Lindgren 86541ac7b3aSBill Pemberton static int dsps_probe(struct platform_device *pdev) 8669ecb8875SAjay Kumar Gupta { 86765145677SAjay Kumar Gupta const struct of_device_id *match; 86865145677SAjay Kumar Gupta const struct dsps_musb_wrapper *wrp; 8699ecb8875SAjay Kumar Gupta struct dsps_glue *glue; 87097238b35SSebastian Andrzej Siewior int ret; 8719ecb8875SAjay Kumar Gupta 8724fc4b274SSebastian Andrzej Siewior if (!strcmp(pdev->name, "musb-hdrc")) 8734fc4b274SSebastian Andrzej Siewior return -ENODEV; 8744fc4b274SSebastian Andrzej Siewior 875cc506036SFelipe Balbi match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); 87665145677SAjay Kumar Gupta if (!match) { 87765145677SAjay Kumar Gupta dev_err(&pdev->dev, "fail to get matching of_match struct\n"); 87897238b35SSebastian Andrzej Siewior return -EINVAL; 87965145677SAjay Kumar Gupta } 88065145677SAjay Kumar Gupta wrp = match->data; 8819ecb8875SAjay Kumar Gupta 8823e457371STony Lindgren if (of_device_is_compatible(pdev->dev.of_node, "ti,musb-dm816")) 8833e457371STony Lindgren dsps_ops.read_fifo = dsps_read_fifo32; 8843e457371STony Lindgren 8859ecb8875SAjay Kumar Gupta /* allocate glue */ 886de9db572SMarkus Pargmann glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); 8870816ea2fSPeter Chen if (!glue) 88897238b35SSebastian Andrzej Siewior return -ENOMEM; 8899ecb8875SAjay Kumar Gupta 8909ecb8875SAjay Kumar Gupta glue->dev = &pdev->dev; 89197238b35SSebastian Andrzej Siewior glue->wrp = wrp; 89225534828SAlexandre Bailon glue->usbss_base = of_iomap(pdev->dev.parent->of_node, 0); 89325534828SAlexandre Bailon if (!glue->usbss_base) 89425534828SAlexandre Bailon return -ENXIO; 8959ecb8875SAjay Kumar Gupta 8969ecb8875SAjay Kumar Gupta platform_set_drvdata(pdev, glue); 8979ecb8875SAjay Kumar Gupta pm_runtime_enable(&pdev->dev); 89897238b35SSebastian Andrzej Siewior ret = dsps_create_musb_pdev(glue, pdev); 89997238b35SSebastian Andrzej Siewior if (ret) 90024752917STony Lindgren goto err; 90165b3f50eSTony Lindgren 9027c75bde3SNadezda Lutovinova if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) { 9037c75bde3SNadezda Lutovinova ret = dsps_setup_optional_vbus_irq(pdev, glue); 9047c75bde3SNadezda Lutovinova if (ret) 905c2115b2bSMiquel Raynal goto unregister_pdev; 9067c75bde3SNadezda Lutovinova } 9077c75bde3SNadezda Lutovinova 9089ecb8875SAjay Kumar Gupta return 0; 9099ecb8875SAjay Kumar Gupta 910c2115b2bSMiquel Raynal unregister_pdev: 911c2115b2bSMiquel Raynal platform_device_unregister(glue->musb); 91224752917STony Lindgren err: 9130e38c4edSAjay Kumar Gupta pm_runtime_disable(&pdev->dev); 9146b7ad496SBin Liu iounmap(glue->usbss_base); 9159ecb8875SAjay Kumar Gupta return ret; 9169ecb8875SAjay Kumar Gupta } 91797238b35SSebastian Andrzej Siewior 918*e6547b5eSUwe Kleine-König static void dsps_remove(struct platform_device *pdev) 9199ecb8875SAjay Kumar Gupta { 9209ecb8875SAjay Kumar Gupta struct dsps_glue *glue = platform_get_drvdata(pdev); 9219ecb8875SAjay Kumar Gupta 92297238b35SSebastian Andrzej Siewior platform_device_unregister(glue->musb); 9239ecb8875SAjay Kumar Gupta 9249ecb8875SAjay Kumar Gupta pm_runtime_disable(&pdev->dev); 9256b7ad496SBin Liu iounmap(glue->usbss_base); 9269ecb8875SAjay Kumar Gupta } 9279ecb8875SAjay Kumar Gupta 928fa7b4ca5SSebastian Andrzej Siewior static const struct dsps_musb_wrapper am33xx_driver_data = { 9299ecb8875SAjay Kumar Gupta .revision = 0x00, 9309ecb8875SAjay Kumar Gupta .control = 0x14, 9319ecb8875SAjay Kumar Gupta .status = 0x18, 9329ecb8875SAjay Kumar Gupta .epintr_set = 0x38, 9339ecb8875SAjay Kumar Gupta .epintr_clear = 0x40, 9349ecb8875SAjay Kumar Gupta .epintr_status = 0x30, 9359ecb8875SAjay Kumar Gupta .coreintr_set = 0x3c, 9369ecb8875SAjay Kumar Gupta .coreintr_clear = 0x44, 9379ecb8875SAjay Kumar Gupta .coreintr_status = 0x34, 9389ecb8875SAjay Kumar Gupta .phy_utmi = 0xe0, 9399ecb8875SAjay Kumar Gupta .mode = 0xe8, 940b991f9b7SDaniel Mack .tx_mode = 0x70, 941b991f9b7SDaniel Mack .rx_mode = 0x74, 9429ecb8875SAjay Kumar Gupta .reset = 0, 9439ecb8875SAjay Kumar Gupta .otg_disable = 21, 9449ecb8875SAjay Kumar Gupta .iddig = 8, 945943c1397SFelipe Balbi .iddig_mux = 7, 9469ecb8875SAjay Kumar Gupta .usb_shift = 0, 9479ecb8875SAjay Kumar Gupta .usb_mask = 0x1ff, 9489ecb8875SAjay Kumar Gupta .usb_bitmap = (0x1ff << 0), 9499ecb8875SAjay Kumar Gupta .drvvbus = 8, 9509ecb8875SAjay Kumar Gupta .txep_shift = 0, 9519ecb8875SAjay Kumar Gupta .txep_mask = 0xffff, 9529ecb8875SAjay Kumar Gupta .txep_bitmap = (0xffff << 0), 9539ecb8875SAjay Kumar Gupta .rxep_shift = 16, 9549ecb8875SAjay Kumar Gupta .rxep_mask = 0xfffe, 9559ecb8875SAjay Kumar Gupta .rxep_bitmap = (0xfffe << 16), 9569e204d88SFelipe Balbi .poll_timeout = 2000, /* ms */ 9579ecb8875SAjay Kumar Gupta }; 9589ecb8875SAjay Kumar Gupta 9592f82686eSBill Pemberton static const struct of_device_id musb_dsps_of_match[] = { 96065145677SAjay Kumar Gupta { .compatible = "ti,musb-am33xx", 9613e457371STony Lindgren .data = &am33xx_driver_data, }, 9623e457371STony Lindgren { .compatible = "ti,musb-dm816", 9633e457371STony Lindgren .data = &am33xx_driver_data, }, 9649ecb8875SAjay Kumar Gupta { }, 9659ecb8875SAjay Kumar Gupta }; 9669ecb8875SAjay Kumar Gupta MODULE_DEVICE_TABLE(of, musb_dsps_of_match); 9679ecb8875SAjay Kumar Gupta 9685b783983SWolfram Sang #ifdef CONFIG_PM_SLEEP 969869c5978SDaniel Mack static int dsps_suspend(struct device *dev) 970869c5978SDaniel Mack { 971869c5978SDaniel Mack struct dsps_glue *glue = dev_get_drvdata(dev); 972869c5978SDaniel Mack const struct dsps_musb_wrapper *wrp = glue->wrp; 973869c5978SDaniel Mack struct musb *musb = platform_get_drvdata(glue->musb); 974f042e9cbSSebastian Andrzej Siewior void __iomem *mbase; 975706d61b2SJohan Hovold int ret; 976f042e9cbSSebastian Andrzej Siewior 977f042e9cbSSebastian Andrzej Siewior if (!musb) 978f042e9cbSSebastian Andrzej Siewior /* This can happen if the musb device is in -EPROBE_DEFER */ 979f042e9cbSSebastian Andrzej Siewior return 0; 980f042e9cbSSebastian Andrzej Siewior 981706d61b2SJohan Hovold ret = pm_runtime_get_sync(dev); 982706d61b2SJohan Hovold if (ret < 0) { 983706d61b2SJohan Hovold pm_runtime_put_noidle(dev); 984706d61b2SJohan Hovold return ret; 985706d61b2SJohan Hovold } 986706d61b2SJohan Hovold 987b82162bcSBin Liu del_timer_sync(&musb->dev_timer); 988706d61b2SJohan Hovold 989f042e9cbSSebastian Andrzej Siewior mbase = musb->ctrl_base; 990086b2882SBin Liu glue->context.control = musb_readl(mbase, wrp->control); 991086b2882SBin Liu glue->context.epintr = musb_readl(mbase, wrp->epintr_set); 992086b2882SBin Liu glue->context.coreintr = musb_readl(mbase, wrp->coreintr_set); 993086b2882SBin Liu glue->context.phy_utmi = musb_readl(mbase, wrp->phy_utmi); 994086b2882SBin Liu glue->context.mode = musb_readl(mbase, wrp->mode); 995086b2882SBin Liu glue->context.tx_mode = musb_readl(mbase, wrp->tx_mode); 996086b2882SBin Liu glue->context.rx_mode = musb_readl(mbase, wrp->rx_mode); 997869c5978SDaniel Mack 99825534828SAlexandre Bailon dsps_dma_controller_suspend(glue); 99925534828SAlexandre Bailon 1000869c5978SDaniel Mack return 0; 1001869c5978SDaniel Mack } 1002869c5978SDaniel Mack 1003869c5978SDaniel Mack static int dsps_resume(struct device *dev) 1004869c5978SDaniel Mack { 1005869c5978SDaniel Mack struct dsps_glue *glue = dev_get_drvdata(dev); 1006869c5978SDaniel Mack const struct dsps_musb_wrapper *wrp = glue->wrp; 1007869c5978SDaniel Mack struct musb *musb = platform_get_drvdata(glue->musb); 1008f042e9cbSSebastian Andrzej Siewior void __iomem *mbase; 1009869c5978SDaniel Mack 1010f042e9cbSSebastian Andrzej Siewior if (!musb) 1011f042e9cbSSebastian Andrzej Siewior return 0; 1012f042e9cbSSebastian Andrzej Siewior 101325534828SAlexandre Bailon dsps_dma_controller_resume(glue); 101425534828SAlexandre Bailon 1015f042e9cbSSebastian Andrzej Siewior mbase = musb->ctrl_base; 1016086b2882SBin Liu musb_writel(mbase, wrp->control, glue->context.control); 1017086b2882SBin Liu musb_writel(mbase, wrp->epintr_set, glue->context.epintr); 1018086b2882SBin Liu musb_writel(mbase, wrp->coreintr_set, glue->context.coreintr); 1019086b2882SBin Liu musb_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); 1020086b2882SBin Liu musb_writel(mbase, wrp->mode, glue->context.mode); 1021086b2882SBin Liu musb_writel(mbase, wrp->tx_mode, glue->context.tx_mode); 1022086b2882SBin Liu musb_writel(mbase, wrp->rx_mode, glue->context.rx_mode); 1023e47d9254SAntoine Tenart if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && 10247ad76955SBin Liu musb->port_mode == MUSB_OTG) 1025369469a9STony Lindgren dsps_mod_timer(glue, -1); 1026869c5978SDaniel Mack 1027706d61b2SJohan Hovold pm_runtime_put(dev); 1028706d61b2SJohan Hovold 1029869c5978SDaniel Mack return 0; 1030869c5978SDaniel Mack } 1031869c5978SDaniel Mack #endif 1032869c5978SDaniel Mack 1033869c5978SDaniel Mack static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); 1034869c5978SDaniel Mack 10359ecb8875SAjay Kumar Gupta static struct platform_driver dsps_usbss_driver = { 10369ecb8875SAjay Kumar Gupta .probe = dsps_probe, 1037*e6547b5eSUwe Kleine-König .remove_new = dsps_remove, 10389ecb8875SAjay Kumar Gupta .driver = { 10399ecb8875SAjay Kumar Gupta .name = "musb-dsps", 1040869c5978SDaniel Mack .pm = &dsps_pm_ops, 1041b432cb83SSachin Kamat .of_match_table = musb_dsps_of_match, 10429ecb8875SAjay Kumar Gupta }, 10439ecb8875SAjay Kumar Gupta }; 10449ecb8875SAjay Kumar Gupta 10459ecb8875SAjay Kumar Gupta MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); 10469ecb8875SAjay Kumar Gupta MODULE_AUTHOR("Ravi B <ravibabu@ti.com>"); 10479ecb8875SAjay Kumar Gupta MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); 10489ecb8875SAjay Kumar Gupta MODULE_LICENSE("GPL v2"); 10499ecb8875SAjay Kumar Gupta 105097238b35SSebastian Andrzej Siewior module_platform_driver(dsps_usbss_driver); 1051