18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Texas Instruments DSPS platforms "glue layer" 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012, by Texas Instruments 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on the am35x "glue layer" code. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is part of the Inventra Controller Driver for Linux. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * musb_dsps.c will be a common file for all the TI DSPS platforms 128c2ecf20Sopenharmony_ci * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x. 138c2ecf20Sopenharmony_ci * For now only ti81x is using this and in future davinci.c, am35x.c 148c2ecf20Sopenharmony_ci * da8xx.c would be merged to this file after testing. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/err.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 218c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/usb/usb_phy_generic.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_data/usb-omap.h> 258c2ecf20Sopenharmony_ci#include <linux/sizes.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/of.h> 288c2ecf20Sopenharmony_ci#include <linux/of_device.h> 298c2ecf20Sopenharmony_ci#include <linux/of_address.h> 308c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 318c2ecf20Sopenharmony_ci#include <linux/usb/of.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "musb_core.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const struct of_device_id musb_dsps_of_match[]; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * DSPS musb wrapper register offset. 418c2ecf20Sopenharmony_ci * FIXME: This should be expanded to have all the wrapper registers from TI DSPS 428c2ecf20Sopenharmony_ci * musb ips. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_cistruct dsps_musb_wrapper { 458c2ecf20Sopenharmony_ci u16 revision; 468c2ecf20Sopenharmony_ci u16 control; 478c2ecf20Sopenharmony_ci u16 status; 488c2ecf20Sopenharmony_ci u16 epintr_set; 498c2ecf20Sopenharmony_ci u16 epintr_clear; 508c2ecf20Sopenharmony_ci u16 epintr_status; 518c2ecf20Sopenharmony_ci u16 coreintr_set; 528c2ecf20Sopenharmony_ci u16 coreintr_clear; 538c2ecf20Sopenharmony_ci u16 coreintr_status; 548c2ecf20Sopenharmony_ci u16 phy_utmi; 558c2ecf20Sopenharmony_ci u16 mode; 568c2ecf20Sopenharmony_ci u16 tx_mode; 578c2ecf20Sopenharmony_ci u16 rx_mode; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* bit positions for control */ 608c2ecf20Sopenharmony_ci unsigned reset:5; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* bit positions for interrupt */ 638c2ecf20Sopenharmony_ci unsigned usb_shift:5; 648c2ecf20Sopenharmony_ci u32 usb_mask; 658c2ecf20Sopenharmony_ci u32 usb_bitmap; 668c2ecf20Sopenharmony_ci unsigned drvvbus:5; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci unsigned txep_shift:5; 698c2ecf20Sopenharmony_ci u32 txep_mask; 708c2ecf20Sopenharmony_ci u32 txep_bitmap; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci unsigned rxep_shift:5; 738c2ecf20Sopenharmony_ci u32 rxep_mask; 748c2ecf20Sopenharmony_ci u32 rxep_bitmap; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* bit positions for phy_utmi */ 778c2ecf20Sopenharmony_ci unsigned otg_disable:5; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* bit positions for mode */ 808c2ecf20Sopenharmony_ci unsigned iddig:5; 818c2ecf20Sopenharmony_ci unsigned iddig_mux:5; 828c2ecf20Sopenharmony_ci /* miscellaneous stuff */ 838c2ecf20Sopenharmony_ci unsigned poll_timeout; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* 878c2ecf20Sopenharmony_ci * register shadow for suspend 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_cistruct dsps_context { 908c2ecf20Sopenharmony_ci u32 control; 918c2ecf20Sopenharmony_ci u32 epintr; 928c2ecf20Sopenharmony_ci u32 coreintr; 938c2ecf20Sopenharmony_ci u32 phy_utmi; 948c2ecf20Sopenharmony_ci u32 mode; 958c2ecf20Sopenharmony_ci u32 tx_mode; 968c2ecf20Sopenharmony_ci u32 rx_mode; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * DSPS glue structure. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistruct dsps_glue { 1038c2ecf20Sopenharmony_ci struct device *dev; 1048c2ecf20Sopenharmony_ci struct platform_device *musb; /* child musb pdev */ 1058c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ 1068c2ecf20Sopenharmony_ci int vbus_irq; /* optional vbus irq */ 1078c2ecf20Sopenharmony_ci unsigned long last_timer; /* last timer data for each instance */ 1088c2ecf20Sopenharmony_ci bool sw_babble_enabled; 1098c2ecf20Sopenharmony_ci void __iomem *usbss_base; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci struct dsps_context context; 1128c2ecf20Sopenharmony_ci struct debugfs_regset32 regset; 1138c2ecf20Sopenharmony_ci struct dentry *dbgfs_root; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic const struct debugfs_reg32 dsps_musb_regs[] = { 1178c2ecf20Sopenharmony_ci { "revision", 0x00 }, 1188c2ecf20Sopenharmony_ci { "control", 0x14 }, 1198c2ecf20Sopenharmony_ci { "status", 0x18 }, 1208c2ecf20Sopenharmony_ci { "eoi", 0x24 }, 1218c2ecf20Sopenharmony_ci { "intr0_stat", 0x30 }, 1228c2ecf20Sopenharmony_ci { "intr1_stat", 0x34 }, 1238c2ecf20Sopenharmony_ci { "intr0_set", 0x38 }, 1248c2ecf20Sopenharmony_ci { "intr1_set", 0x3c }, 1258c2ecf20Sopenharmony_ci { "txmode", 0x70 }, 1268c2ecf20Sopenharmony_ci { "rxmode", 0x74 }, 1278c2ecf20Sopenharmony_ci { "autoreq", 0xd0 }, 1288c2ecf20Sopenharmony_ci { "srpfixtime", 0xd4 }, 1298c2ecf20Sopenharmony_ci { "tdown", 0xd8 }, 1308c2ecf20Sopenharmony_ci { "phy_utmi", 0xe0 }, 1318c2ecf20Sopenharmony_ci { "mode", 0xe8 }, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void dsps_mod_timer(struct dsps_glue *glue, int wait_ms) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct musb *musb = platform_get_drvdata(glue->musb); 1378c2ecf20Sopenharmony_ci int wait; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (wait_ms < 0) 1408c2ecf20Sopenharmony_ci wait = msecs_to_jiffies(glue->wrp->poll_timeout); 1418c2ecf20Sopenharmony_ci else 1428c2ecf20Sopenharmony_ci wait = msecs_to_jiffies(wait_ms); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci mod_timer(&musb->dev_timer, jiffies + wait); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* 1488c2ecf20Sopenharmony_ci * If no vbus irq from the PMIC is configured, we need to poll VBUS status. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic void dsps_mod_timer_optional(struct dsps_glue *glue) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci if (glue->vbus_irq) 1538c2ecf20Sopenharmony_ci return; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci dsps_mod_timer(glue, -1); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* USBSS / USB AM335x */ 1598c2ecf20Sopenharmony_ci#define USBSS_IRQ_STATUS 0x28 1608c2ecf20Sopenharmony_ci#define USBSS_IRQ_ENABLER 0x2c 1618c2ecf20Sopenharmony_ci#define USBSS_IRQ_CLEARR 0x30 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#define USBSS_IRQ_PD_COMP (1 << 2) 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * dsps_musb_enable - enable interrupts 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistatic void dsps_musb_enable(struct musb *musb) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 1718c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 1728c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 1738c2ecf20Sopenharmony_ci void __iomem *reg_base = musb->ctrl_base; 1748c2ecf20Sopenharmony_ci u32 epmask, coremask; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* Workaround: setup IRQs through both register sets. */ 1778c2ecf20Sopenharmony_ci epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) | 1788c2ecf20Sopenharmony_ci ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift); 1798c2ecf20Sopenharmony_ci coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci musb_writel(reg_base, wrp->epintr_set, epmask); 1828c2ecf20Sopenharmony_ci musb_writel(reg_base, wrp->coreintr_set, coremask); 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * start polling for runtime PM active and idle, 1858c2ecf20Sopenharmony_ci * and for ID change in dual-role idle mode. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) 1888c2ecf20Sopenharmony_ci dsps_mod_timer(glue, -1); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* 1928c2ecf20Sopenharmony_ci * dsps_musb_disable - disable HDRC and flush interrupts 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_cistatic void dsps_musb_disable(struct musb *musb) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 1978c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 1988c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 1998c2ecf20Sopenharmony_ci void __iomem *reg_base = musb->ctrl_base; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci musb_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); 2028c2ecf20Sopenharmony_ci musb_writel(reg_base, wrp->epintr_clear, 2038c2ecf20Sopenharmony_ci wrp->txep_bitmap | wrp->rxep_bitmap); 2048c2ecf20Sopenharmony_ci del_timer_sync(&musb->dev_timer); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* Caller must take musb->lock */ 2088c2ecf20Sopenharmony_cistatic int dsps_check_status(struct musb *musb, void *unused) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci void __iomem *mregs = musb->mregs; 2118c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 2128c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 2138c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 2148c2ecf20Sopenharmony_ci u8 devctl; 2158c2ecf20Sopenharmony_ci int skip_session = 0; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (glue->vbus_irq) 2188c2ecf20Sopenharmony_ci del_timer(&musb->dev_timer); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * We poll because DSPS IP's won't expose several OTG-critical 2228c2ecf20Sopenharmony_ci * status change events (from the transceiver) otherwise. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci devctl = musb_readb(mregs, MUSB_DEVCTL); 2258c2ecf20Sopenharmony_ci dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, 2268c2ecf20Sopenharmony_ci usb_otg_state_string(musb->xceiv->otg->state)); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci switch (musb->xceiv->otg->state) { 2298c2ecf20Sopenharmony_ci case OTG_STATE_A_WAIT_VRISE: 2308c2ecf20Sopenharmony_ci if (musb->port_mode == MUSB_HOST) { 2318c2ecf20Sopenharmony_ci musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; 2328c2ecf20Sopenharmony_ci dsps_mod_timer_optional(glue); 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci fallthrough; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci case OTG_STATE_A_WAIT_BCON: 2388c2ecf20Sopenharmony_ci /* keep VBUS on for host-only mode */ 2398c2ecf20Sopenharmony_ci if (musb->port_mode == MUSB_HOST) { 2408c2ecf20Sopenharmony_ci dsps_mod_timer_optional(glue); 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci musb_writeb(musb->mregs, MUSB_DEVCTL, 0); 2448c2ecf20Sopenharmony_ci skip_session = 1; 2458c2ecf20Sopenharmony_ci fallthrough; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci case OTG_STATE_A_IDLE: 2488c2ecf20Sopenharmony_ci case OTG_STATE_B_IDLE: 2498c2ecf20Sopenharmony_ci if (!glue->vbus_irq) { 2508c2ecf20Sopenharmony_ci if (devctl & MUSB_DEVCTL_BDEVICE) { 2518c2ecf20Sopenharmony_ci musb->xceiv->otg->state = OTG_STATE_B_IDLE; 2528c2ecf20Sopenharmony_ci MUSB_DEV_MODE(musb); 2538c2ecf20Sopenharmony_ci } else { 2548c2ecf20Sopenharmony_ci musb->xceiv->otg->state = OTG_STATE_A_IDLE; 2558c2ecf20Sopenharmony_ci MUSB_HST_MODE(musb); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (musb->port_mode == MUSB_PERIPHERAL) 2598c2ecf20Sopenharmony_ci skip_session = 1; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) 2628c2ecf20Sopenharmony_ci musb_writeb(mregs, MUSB_DEVCTL, 2638c2ecf20Sopenharmony_ci MUSB_DEVCTL_SESSION); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci dsps_mod_timer_optional(glue); 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci case OTG_STATE_A_WAIT_VFALL: 2688c2ecf20Sopenharmony_ci musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; 2698c2ecf20Sopenharmony_ci musb_writel(musb->ctrl_base, wrp->coreintr_set, 2708c2ecf20Sopenharmony_ci MUSB_INTR_VBUSERROR << wrp->usb_shift); 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci default: 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void otg_timer(struct timer_list *t) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct musb *musb = from_timer(musb, t, dev_timer); 2828c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 2838c2ecf20Sopenharmony_ci unsigned long flags; 2848c2ecf20Sopenharmony_ci int err; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci err = pm_runtime_get(dev); 2878c2ecf20Sopenharmony_ci if ((err != -EINPROGRESS) && err < 0) { 2888c2ecf20Sopenharmony_ci dev_err(dev, "Poll could not pm_runtime_get: %i\n", err); 2898c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci spin_lock_irqsave(&musb->lock, flags); 2958c2ecf20Sopenharmony_ci err = musb_queue_resume_work(musb, dsps_check_status, NULL); 2968c2ecf20Sopenharmony_ci if (err < 0) 2978c2ecf20Sopenharmony_ci dev_err(dev, "%s resume work: %i\n", __func__, err); 2988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&musb->lock, flags); 2998c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 3008c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci u32 epintr; 3068c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 3078c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* musb->lock might already been held */ 3108c2ecf20Sopenharmony_ci epintr = (1 << epnum) << wrp->rxep_shift; 3118c2ecf20Sopenharmony_ci musb_writel(musb->ctrl_base, wrp->epintr_status, epintr); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic irqreturn_t dsps_interrupt(int irq, void *hci) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct musb *musb = hci; 3178c2ecf20Sopenharmony_ci void __iomem *reg_base = musb->ctrl_base; 3188c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 3198c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 3208c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 3218c2ecf20Sopenharmony_ci unsigned long flags; 3228c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 3238c2ecf20Sopenharmony_ci u32 epintr, usbintr; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci spin_lock_irqsave(&musb->lock, flags); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Get endpoint interrupts */ 3288c2ecf20Sopenharmony_ci epintr = musb_readl(reg_base, wrp->epintr_status); 3298c2ecf20Sopenharmony_ci musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; 3308c2ecf20Sopenharmony_ci musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (epintr) 3338c2ecf20Sopenharmony_ci musb_writel(reg_base, wrp->epintr_status, epintr); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Get usb core interrupts */ 3368c2ecf20Sopenharmony_ci usbintr = musb_readl(reg_base, wrp->coreintr_status); 3378c2ecf20Sopenharmony_ci if (!usbintr && !epintr) 3388c2ecf20Sopenharmony_ci goto out; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; 3418c2ecf20Sopenharmony_ci if (usbintr) 3428c2ecf20Sopenharmony_ci musb_writel(reg_base, wrp->coreintr_status, usbintr); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", 3458c2ecf20Sopenharmony_ci usbintr, epintr); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { 3488c2ecf20Sopenharmony_ci int drvvbus = musb_readl(reg_base, wrp->status); 3498c2ecf20Sopenharmony_ci void __iomem *mregs = musb->mregs; 3508c2ecf20Sopenharmony_ci u8 devctl = musb_readb(mregs, MUSB_DEVCTL); 3518c2ecf20Sopenharmony_ci int err; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci err = musb->int_usb & MUSB_INTR_VBUSERROR; 3548c2ecf20Sopenharmony_ci if (err) { 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci * The Mentor core doesn't debounce VBUS as needed 3578c2ecf20Sopenharmony_ci * to cope with device connect current spikes. This 3588c2ecf20Sopenharmony_ci * means it's not uncommon for bus-powered devices 3598c2ecf20Sopenharmony_ci * to get VBUS errors during enumeration. 3608c2ecf20Sopenharmony_ci * 3618c2ecf20Sopenharmony_ci * This is a workaround, but newer RTL from Mentor 3628c2ecf20Sopenharmony_ci * seems to allow a better one: "re"-starting sessions 3638c2ecf20Sopenharmony_ci * without waiting for VBUS to stop registering in 3648c2ecf20Sopenharmony_ci * devctl. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci musb->int_usb &= ~MUSB_INTR_VBUSERROR; 3678c2ecf20Sopenharmony_ci musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; 3688c2ecf20Sopenharmony_ci dsps_mod_timer_optional(glue); 3698c2ecf20Sopenharmony_ci WARNING("VBUS error workaround (delay coming)\n"); 3708c2ecf20Sopenharmony_ci } else if (drvvbus) { 3718c2ecf20Sopenharmony_ci MUSB_HST_MODE(musb); 3728c2ecf20Sopenharmony_ci musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; 3738c2ecf20Sopenharmony_ci dsps_mod_timer_optional(glue); 3748c2ecf20Sopenharmony_ci } else { 3758c2ecf20Sopenharmony_ci musb->is_active = 0; 3768c2ecf20Sopenharmony_ci MUSB_DEV_MODE(musb); 3778c2ecf20Sopenharmony_ci musb->xceiv->otg->state = OTG_STATE_B_IDLE; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* NOTE: this must complete power-on within 100 ms. */ 3818c2ecf20Sopenharmony_ci dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", 3828c2ecf20Sopenharmony_ci drvvbus ? "on" : "off", 3838c2ecf20Sopenharmony_ci usb_otg_state_string(musb->xceiv->otg->state), 3848c2ecf20Sopenharmony_ci err ? " ERROR" : "", 3858c2ecf20Sopenharmony_ci devctl); 3868c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (musb->int_tx || musb->int_rx || musb->int_usb) 3908c2ecf20Sopenharmony_ci ret |= musb_interrupt(musb); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* Poll for ID change and connect */ 3938c2ecf20Sopenharmony_ci switch (musb->xceiv->otg->state) { 3948c2ecf20Sopenharmony_ci case OTG_STATE_B_IDLE: 3958c2ecf20Sopenharmony_ci case OTG_STATE_A_WAIT_BCON: 3968c2ecf20Sopenharmony_ci dsps_mod_timer_optional(glue); 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ciout: 4038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&musb->lock, flags); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return ret; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct dentry *root; 4118c2ecf20Sopenharmony_ci char buf[128]; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci sprintf(buf, "%s.dsps", dev_name(musb->controller)); 4148c2ecf20Sopenharmony_ci root = debugfs_create_dir(buf, usb_debug_root); 4158c2ecf20Sopenharmony_ci glue->dbgfs_root = root; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci glue->regset.regs = dsps_musb_regs; 4188c2ecf20Sopenharmony_ci glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs); 4198c2ecf20Sopenharmony_ci glue->regset.base = musb->ctrl_base; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset); 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int dsps_musb_init(struct musb *musb) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 4288c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 4298c2ecf20Sopenharmony_ci struct platform_device *parent = to_platform_device(dev->parent); 4308c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 4318c2ecf20Sopenharmony_ci void __iomem *reg_base; 4328c2ecf20Sopenharmony_ci struct resource *r; 4338c2ecf20Sopenharmony_ci u32 rev, val; 4348c2ecf20Sopenharmony_ci int ret; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); 4378c2ecf20Sopenharmony_ci reg_base = devm_ioremap_resource(dev, r); 4388c2ecf20Sopenharmony_ci if (IS_ERR(reg_base)) 4398c2ecf20Sopenharmony_ci return PTR_ERR(reg_base); 4408c2ecf20Sopenharmony_ci musb->ctrl_base = reg_base; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* NOP driver needs change if supporting dual instance */ 4438c2ecf20Sopenharmony_ci musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "phys", 0); 4448c2ecf20Sopenharmony_ci if (IS_ERR(musb->xceiv)) 4458c2ecf20Sopenharmony_ci return PTR_ERR(musb->xceiv); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci musb->phy = devm_phy_get(dev->parent, "usb2-phy"); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* Returns zero if e.g. not clocked */ 4508c2ecf20Sopenharmony_ci rev = musb_readl(reg_base, wrp->revision); 4518c2ecf20Sopenharmony_ci if (!rev) 4528c2ecf20Sopenharmony_ci return -ENODEV; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (IS_ERR(musb->phy)) { 4558c2ecf20Sopenharmony_ci musb->phy = NULL; 4568c2ecf20Sopenharmony_ci } else { 4578c2ecf20Sopenharmony_ci ret = phy_init(musb->phy); 4588c2ecf20Sopenharmony_ci if (ret < 0) 4598c2ecf20Sopenharmony_ci return ret; 4608c2ecf20Sopenharmony_ci ret = phy_power_on(musb->phy); 4618c2ecf20Sopenharmony_ci if (ret) { 4628c2ecf20Sopenharmony_ci phy_exit(musb->phy); 4638c2ecf20Sopenharmony_ci return ret; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci timer_setup(&musb->dev_timer, otg_timer, 0); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Reset the musb */ 4708c2ecf20Sopenharmony_ci musb_writel(reg_base, wrp->control, (1 << wrp->reset)); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci musb->isr = dsps_interrupt; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* reset the otgdisable bit, needed for host mode to work */ 4758c2ecf20Sopenharmony_ci val = musb_readl(reg_base, wrp->phy_utmi); 4768c2ecf20Sopenharmony_ci val &= ~(1 << wrp->otg_disable); 4778c2ecf20Sopenharmony_ci musb_writel(musb->ctrl_base, wrp->phy_utmi, val); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* 4808c2ecf20Sopenharmony_ci * Check whether the dsps version has babble control enabled. 4818c2ecf20Sopenharmony_ci * In latest silicon revision the babble control logic is enabled. 4828c2ecf20Sopenharmony_ci * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control 4838c2ecf20Sopenharmony_ci * logic enabled. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci val = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 4868c2ecf20Sopenharmony_ci if (val & MUSB_BABBLE_RCV_DISABLE) { 4878c2ecf20Sopenharmony_ci glue->sw_babble_enabled = true; 4888c2ecf20Sopenharmony_ci val |= MUSB_BABBLE_SW_SESSION_CTRL; 4898c2ecf20Sopenharmony_ci musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci dsps_mod_timer(glue, -1); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return dsps_musb_dbg_init(musb, glue); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int dsps_musb_exit(struct musb *musb) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 5008c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci del_timer_sync(&musb->dev_timer); 5038c2ecf20Sopenharmony_ci phy_power_off(musb->phy); 5048c2ecf20Sopenharmony_ci phy_exit(musb->phy); 5058c2ecf20Sopenharmony_ci debugfs_remove_recursive(glue->dbgfs_root); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return 0; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int dsps_musb_set_mode(struct musb *musb, u8 mode) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 5138c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 5148c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 5158c2ecf20Sopenharmony_ci void __iomem *ctrl_base = musb->ctrl_base; 5168c2ecf20Sopenharmony_ci u32 reg; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci reg = musb_readl(ctrl_base, wrp->mode); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci switch (mode) { 5218c2ecf20Sopenharmony_ci case MUSB_HOST: 5228c2ecf20Sopenharmony_ci reg &= ~(1 << wrp->iddig); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* 5258c2ecf20Sopenharmony_ci * if we're setting mode to host-only or device-only, we're 5268c2ecf20Sopenharmony_ci * going to ignore whatever the PHY sends us and just force 5278c2ecf20Sopenharmony_ci * ID pin status by SW 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_ci reg |= (1 << wrp->iddig_mux); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci musb_writel(ctrl_base, wrp->mode, reg); 5328c2ecf20Sopenharmony_ci musb_writel(ctrl_base, wrp->phy_utmi, 0x02); 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci case MUSB_PERIPHERAL: 5358c2ecf20Sopenharmony_ci reg |= (1 << wrp->iddig); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * if we're setting mode to host-only or device-only, we're 5398c2ecf20Sopenharmony_ci * going to ignore whatever the PHY sends us and just force 5408c2ecf20Sopenharmony_ci * ID pin status by SW 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci reg |= (1 << wrp->iddig_mux); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci musb_writel(ctrl_base, wrp->mode, reg); 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci case MUSB_OTG: 5478c2ecf20Sopenharmony_ci musb_writel(ctrl_base, wrp->phy_utmi, 0x02); 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci default: 5508c2ecf20Sopenharmony_ci dev_err(glue->dev, "unsupported mode %d\n", mode); 5518c2ecf20Sopenharmony_ci return -EINVAL; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic bool dsps_sw_babble_control(struct musb *musb) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci u8 babble_ctl; 5608c2ecf20Sopenharmony_ci bool session_restart = false; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 5638c2ecf20Sopenharmony_ci dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", 5648c2ecf20Sopenharmony_ci babble_ctl); 5658c2ecf20Sopenharmony_ci /* 5668c2ecf20Sopenharmony_ci * check line monitor flag to check whether babble is 5678c2ecf20Sopenharmony_ci * due to noise 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci dev_dbg(musb->controller, "STUCK_J is %s\n", 5708c2ecf20Sopenharmony_ci babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset"); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (babble_ctl & MUSB_BABBLE_STUCK_J) { 5738c2ecf20Sopenharmony_ci int timeout = 10; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * babble is due to noise, then set transmit idle (d7 bit) 5778c2ecf20Sopenharmony_ci * to resume normal operation 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 5808c2ecf20Sopenharmony_ci babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; 5818c2ecf20Sopenharmony_ci musb_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* wait till line monitor flag cleared */ 5848c2ecf20Sopenharmony_ci dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); 5858c2ecf20Sopenharmony_ci do { 5868c2ecf20Sopenharmony_ci babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); 5878c2ecf20Sopenharmony_ci udelay(1); 5888c2ecf20Sopenharmony_ci } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* check whether stuck_at_j bit cleared */ 5918c2ecf20Sopenharmony_ci if (babble_ctl & MUSB_BABBLE_STUCK_J) { 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * real babble condition has occurred 5948c2ecf20Sopenharmony_ci * restart the controller to start the 5958c2ecf20Sopenharmony_ci * session again 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_ci dev_dbg(musb->controller, "J not cleared, misc (%x)\n", 5988c2ecf20Sopenharmony_ci babble_ctl); 5998c2ecf20Sopenharmony_ci session_restart = true; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci } else { 6028c2ecf20Sopenharmony_ci session_restart = true; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return session_restart; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int dsps_musb_recover(struct musb *musb) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct device *dev = musb->controller; 6118c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev->parent); 6128c2ecf20Sopenharmony_ci int session_restart = 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (glue->sw_babble_enabled) 6158c2ecf20Sopenharmony_ci session_restart = dsps_sw_babble_control(musb); 6168c2ecf20Sopenharmony_ci else 6178c2ecf20Sopenharmony_ci session_restart = 1; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return session_restart ? 0 : -EPIPE; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci/* Similar to am35x, dm81xx support only 32-bit read operation */ 6238c2ecf20Sopenharmony_cistatic void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci void __iomem *fifo = hw_ep->fifo; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (len >= 4) { 6288c2ecf20Sopenharmony_ci ioread32_rep(fifo, dst, len >> 2); 6298c2ecf20Sopenharmony_ci dst += len & ~0x03; 6308c2ecf20Sopenharmony_ci len &= 0x03; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Read any remaining 1 to 3 bytes */ 6348c2ecf20Sopenharmony_ci if (len > 0) { 6358c2ecf20Sopenharmony_ci u32 val = musb_readl(fifo, 0); 6368c2ecf20Sopenharmony_ci memcpy(dst, &val, len); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_TI_CPPI41_DMA 6418c2ecf20Sopenharmony_cistatic void dsps_dma_controller_callback(struct dma_controller *c) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct musb *musb = c->musb; 6448c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 6458c2ecf20Sopenharmony_ci void __iomem *usbss_base = glue->usbss_base; 6468c2ecf20Sopenharmony_ci u32 status; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci status = musb_readl(usbss_base, USBSS_IRQ_STATUS); 6498c2ecf20Sopenharmony_ci if (status & USBSS_IRQ_PD_COMP) 6508c2ecf20Sopenharmony_ci musb_writel(usbss_base, USBSS_IRQ_STATUS, USBSS_IRQ_PD_COMP); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic struct dma_controller * 6548c2ecf20Sopenharmony_cidsps_dma_controller_create(struct musb *musb, void __iomem *base) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct dma_controller *controller; 6578c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); 6588c2ecf20Sopenharmony_ci void __iomem *usbss_base = glue->usbss_base; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci controller = cppi41_dma_controller_create(musb, base); 6618c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(controller)) 6628c2ecf20Sopenharmony_ci return controller; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); 6658c2ecf20Sopenharmony_ci controller->dma_callback = dsps_dma_controller_callback; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return controller; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 6718c2ecf20Sopenharmony_cistatic void dsps_dma_controller_suspend(struct dsps_glue *glue) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci void __iomem *usbss_base = glue->usbss_base; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic void dsps_dma_controller_resume(struct dsps_glue *glue) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci void __iomem *usbss_base = glue->usbss_base; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci#endif 6858c2ecf20Sopenharmony_ci#else /* CONFIG_USB_TI_CPPI41_DMA */ 6868c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 6878c2ecf20Sopenharmony_cistatic void dsps_dma_controller_suspend(struct dsps_glue *glue) {} 6888c2ecf20Sopenharmony_cistatic void dsps_dma_controller_resume(struct dsps_glue *glue) {} 6898c2ecf20Sopenharmony_ci#endif 6908c2ecf20Sopenharmony_ci#endif /* CONFIG_USB_TI_CPPI41_DMA */ 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic struct musb_platform_ops dsps_ops = { 6938c2ecf20Sopenharmony_ci .quirks = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP, 6948c2ecf20Sopenharmony_ci .init = dsps_musb_init, 6958c2ecf20Sopenharmony_ci .exit = dsps_musb_exit, 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_TI_CPPI41_DMA 6988c2ecf20Sopenharmony_ci .dma_init = dsps_dma_controller_create, 6998c2ecf20Sopenharmony_ci .dma_exit = cppi41_dma_controller_destroy, 7008c2ecf20Sopenharmony_ci#endif 7018c2ecf20Sopenharmony_ci .enable = dsps_musb_enable, 7028c2ecf20Sopenharmony_ci .disable = dsps_musb_disable, 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci .set_mode = dsps_musb_set_mode, 7058c2ecf20Sopenharmony_ci .recover = dsps_musb_recover, 7068c2ecf20Sopenharmony_ci .clear_ep_rxintr = dsps_musb_clear_ep_rxintr, 7078c2ecf20Sopenharmony_ci}; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic u64 musb_dmamask = DMA_BIT_MASK(32); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic int get_int_prop(struct device_node *dn, const char *s) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci int ret; 7148c2ecf20Sopenharmony_ci u32 val; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci ret = of_property_read_u32(dn, s, &val); 7178c2ecf20Sopenharmony_ci if (ret) 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci return val; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int dsps_create_musb_pdev(struct dsps_glue *glue, 7238c2ecf20Sopenharmony_ci struct platform_device *parent) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct musb_hdrc_platform_data pdata; 7268c2ecf20Sopenharmony_ci struct resource resources[2]; 7278c2ecf20Sopenharmony_ci struct resource *res; 7288c2ecf20Sopenharmony_ci struct device *dev = &parent->dev; 7298c2ecf20Sopenharmony_ci struct musb_hdrc_config *config; 7308c2ecf20Sopenharmony_ci struct platform_device *musb; 7318c2ecf20Sopenharmony_ci struct device_node *dn = parent->dev.of_node; 7328c2ecf20Sopenharmony_ci int ret, val; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci memset(resources, 0, sizeof(resources)); 7358c2ecf20Sopenharmony_ci res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc"); 7368c2ecf20Sopenharmony_ci if (!res) { 7378c2ecf20Sopenharmony_ci dev_err(dev, "failed to get memory.\n"); 7388c2ecf20Sopenharmony_ci return -EINVAL; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci resources[0] = *res; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci res = platform_get_resource_byname(parent, IORESOURCE_IRQ, "mc"); 7438c2ecf20Sopenharmony_ci if (!res) { 7448c2ecf20Sopenharmony_ci dev_err(dev, "failed to get irq.\n"); 7458c2ecf20Sopenharmony_ci return -EINVAL; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci resources[1] = *res; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* allocate the child platform device */ 7508c2ecf20Sopenharmony_ci musb = platform_device_alloc("musb-hdrc", 7518c2ecf20Sopenharmony_ci (resources[0].start & 0xFFF) == 0x400 ? 0 : 1); 7528c2ecf20Sopenharmony_ci if (!musb) { 7538c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate musb device\n"); 7548c2ecf20Sopenharmony_ci return -ENOMEM; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci musb->dev.parent = dev; 7588c2ecf20Sopenharmony_ci musb->dev.dma_mask = &musb_dmamask; 7598c2ecf20Sopenharmony_ci musb->dev.coherent_dma_mask = musb_dmamask; 7608c2ecf20Sopenharmony_ci device_set_of_node_from_dev(&musb->dev, &parent->dev); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci glue->musb = musb; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci ret = platform_device_add_resources(musb, resources, 7658c2ecf20Sopenharmony_ci ARRAY_SIZE(resources)); 7668c2ecf20Sopenharmony_ci if (ret) { 7678c2ecf20Sopenharmony_ci dev_err(dev, "failed to add resources\n"); 7688c2ecf20Sopenharmony_ci goto err; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); 7728c2ecf20Sopenharmony_ci if (!config) { 7738c2ecf20Sopenharmony_ci ret = -ENOMEM; 7748c2ecf20Sopenharmony_ci goto err; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci pdata.config = config; 7778c2ecf20Sopenharmony_ci pdata.platform_ops = &dsps_ops; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci config->num_eps = get_int_prop(dn, "mentor,num-eps"); 7808c2ecf20Sopenharmony_ci config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); 7818c2ecf20Sopenharmony_ci config->host_port_deassert_reset_at_resume = 1; 7828c2ecf20Sopenharmony_ci pdata.mode = musb_get_mode(dev); 7838c2ecf20Sopenharmony_ci /* DT keeps this entry in mA, musb expects it as per USB spec */ 7848c2ecf20Sopenharmony_ci pdata.power = get_int_prop(dn, "mentor,power") / 2; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci ret = of_property_read_u32(dn, "mentor,multipoint", &val); 7878c2ecf20Sopenharmony_ci if (!ret && val) 7888c2ecf20Sopenharmony_ci config->multipoint = true; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci config->maximum_speed = usb_get_maximum_speed(&parent->dev); 7918c2ecf20Sopenharmony_ci switch (config->maximum_speed) { 7928c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 7938c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci case USB_SPEED_SUPER: 7968c2ecf20Sopenharmony_ci dev_warn(dev, "ignore incorrect maximum_speed " 7978c2ecf20Sopenharmony_ci "(super-speed) setting in dts"); 7988c2ecf20Sopenharmony_ci fallthrough; 7998c2ecf20Sopenharmony_ci default: 8008c2ecf20Sopenharmony_ci config->maximum_speed = USB_SPEED_HIGH; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); 8048c2ecf20Sopenharmony_ci if (ret) { 8058c2ecf20Sopenharmony_ci dev_err(dev, "failed to add platform_data\n"); 8068c2ecf20Sopenharmony_ci goto err; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci ret = platform_device_add(musb); 8108c2ecf20Sopenharmony_ci if (ret) { 8118c2ecf20Sopenharmony_ci dev_err(dev, "failed to register musb device\n"); 8128c2ecf20Sopenharmony_ci goto err; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci return 0; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cierr: 8178c2ecf20Sopenharmony_ci platform_device_put(musb); 8188c2ecf20Sopenharmony_ci return ret; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic irqreturn_t dsps_vbus_threaded_irq(int irq, void *priv) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct dsps_glue *glue = priv; 8248c2ecf20Sopenharmony_ci struct musb *musb = platform_get_drvdata(glue->musb); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (!musb) 8278c2ecf20Sopenharmony_ci return IRQ_NONE; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci dev_dbg(glue->dev, "VBUS interrupt\n"); 8308c2ecf20Sopenharmony_ci dsps_mod_timer(glue, 0); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int dsps_setup_optional_vbus_irq(struct platform_device *pdev, 8368c2ecf20Sopenharmony_ci struct dsps_glue *glue) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int error; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci glue->vbus_irq = platform_get_irq_byname(pdev, "vbus"); 8418c2ecf20Sopenharmony_ci if (glue->vbus_irq == -EPROBE_DEFER) 8428c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (glue->vbus_irq <= 0) { 8458c2ecf20Sopenharmony_ci glue->vbus_irq = 0; 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(glue->dev, glue->vbus_irq, 8508c2ecf20Sopenharmony_ci NULL, dsps_vbus_threaded_irq, 8518c2ecf20Sopenharmony_ci IRQF_ONESHOT, 8528c2ecf20Sopenharmony_ci "vbus", glue); 8538c2ecf20Sopenharmony_ci if (error) { 8548c2ecf20Sopenharmony_ci glue->vbus_irq = 0; 8558c2ecf20Sopenharmony_ci return error; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci dev_dbg(glue->dev, "VBUS irq %i configured\n", glue->vbus_irq); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci return 0; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic int dsps_probe(struct platform_device *pdev) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci const struct of_device_id *match; 8658c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp; 8668c2ecf20Sopenharmony_ci struct dsps_glue *glue; 8678c2ecf20Sopenharmony_ci int ret; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (!strcmp(pdev->name, "musb-hdrc")) 8708c2ecf20Sopenharmony_ci return -ENODEV; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); 8738c2ecf20Sopenharmony_ci if (!match) { 8748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "fail to get matching of_match struct\n"); 8758c2ecf20Sopenharmony_ci return -EINVAL; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci wrp = match->data; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (of_device_is_compatible(pdev->dev.of_node, "ti,musb-dm816")) 8808c2ecf20Sopenharmony_ci dsps_ops.read_fifo = dsps_read_fifo32; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* allocate glue */ 8838c2ecf20Sopenharmony_ci glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); 8848c2ecf20Sopenharmony_ci if (!glue) 8858c2ecf20Sopenharmony_ci return -ENOMEM; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci glue->dev = &pdev->dev; 8888c2ecf20Sopenharmony_ci glue->wrp = wrp; 8898c2ecf20Sopenharmony_ci glue->usbss_base = of_iomap(pdev->dev.parent->of_node, 0); 8908c2ecf20Sopenharmony_ci if (!glue->usbss_base) 8918c2ecf20Sopenharmony_ci return -ENXIO; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, glue); 8948c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 8958c2ecf20Sopenharmony_ci ret = dsps_create_musb_pdev(glue, pdev); 8968c2ecf20Sopenharmony_ci if (ret) 8978c2ecf20Sopenharmony_ci goto err; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) { 9008c2ecf20Sopenharmony_ci ret = dsps_setup_optional_vbus_irq(pdev, glue); 9018c2ecf20Sopenharmony_ci if (ret) 9028c2ecf20Sopenharmony_ci goto unregister_pdev; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return 0; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ciunregister_pdev: 9088c2ecf20Sopenharmony_ci platform_device_unregister(glue->musb); 9098c2ecf20Sopenharmony_cierr: 9108c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 9118c2ecf20Sopenharmony_ci iounmap(glue->usbss_base); 9128c2ecf20Sopenharmony_ci return ret; 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic int dsps_remove(struct platform_device *pdev) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct dsps_glue *glue = platform_get_drvdata(pdev); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci platform_device_unregister(glue->musb); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 9228c2ecf20Sopenharmony_ci iounmap(glue->usbss_base); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci return 0; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic const struct dsps_musb_wrapper am33xx_driver_data = { 9288c2ecf20Sopenharmony_ci .revision = 0x00, 9298c2ecf20Sopenharmony_ci .control = 0x14, 9308c2ecf20Sopenharmony_ci .status = 0x18, 9318c2ecf20Sopenharmony_ci .epintr_set = 0x38, 9328c2ecf20Sopenharmony_ci .epintr_clear = 0x40, 9338c2ecf20Sopenharmony_ci .epintr_status = 0x30, 9348c2ecf20Sopenharmony_ci .coreintr_set = 0x3c, 9358c2ecf20Sopenharmony_ci .coreintr_clear = 0x44, 9368c2ecf20Sopenharmony_ci .coreintr_status = 0x34, 9378c2ecf20Sopenharmony_ci .phy_utmi = 0xe0, 9388c2ecf20Sopenharmony_ci .mode = 0xe8, 9398c2ecf20Sopenharmony_ci .tx_mode = 0x70, 9408c2ecf20Sopenharmony_ci .rx_mode = 0x74, 9418c2ecf20Sopenharmony_ci .reset = 0, 9428c2ecf20Sopenharmony_ci .otg_disable = 21, 9438c2ecf20Sopenharmony_ci .iddig = 8, 9448c2ecf20Sopenharmony_ci .iddig_mux = 7, 9458c2ecf20Sopenharmony_ci .usb_shift = 0, 9468c2ecf20Sopenharmony_ci .usb_mask = 0x1ff, 9478c2ecf20Sopenharmony_ci .usb_bitmap = (0x1ff << 0), 9488c2ecf20Sopenharmony_ci .drvvbus = 8, 9498c2ecf20Sopenharmony_ci .txep_shift = 0, 9508c2ecf20Sopenharmony_ci .txep_mask = 0xffff, 9518c2ecf20Sopenharmony_ci .txep_bitmap = (0xffff << 0), 9528c2ecf20Sopenharmony_ci .rxep_shift = 16, 9538c2ecf20Sopenharmony_ci .rxep_mask = 0xfffe, 9548c2ecf20Sopenharmony_ci .rxep_bitmap = (0xfffe << 16), 9558c2ecf20Sopenharmony_ci .poll_timeout = 2000, /* ms */ 9568c2ecf20Sopenharmony_ci}; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic const struct of_device_id musb_dsps_of_match[] = { 9598c2ecf20Sopenharmony_ci { .compatible = "ti,musb-am33xx", 9608c2ecf20Sopenharmony_ci .data = &am33xx_driver_data, }, 9618c2ecf20Sopenharmony_ci { .compatible = "ti,musb-dm816", 9628c2ecf20Sopenharmony_ci .data = &am33xx_driver_data, }, 9638c2ecf20Sopenharmony_ci { }, 9648c2ecf20Sopenharmony_ci}; 9658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, musb_dsps_of_match); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 9688c2ecf20Sopenharmony_cistatic int dsps_suspend(struct device *dev) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev); 9718c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 9728c2ecf20Sopenharmony_ci struct musb *musb = platform_get_drvdata(glue->musb); 9738c2ecf20Sopenharmony_ci void __iomem *mbase; 9748c2ecf20Sopenharmony_ci int ret; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (!musb) 9778c2ecf20Sopenharmony_ci /* This can happen if the musb device is in -EPROBE_DEFER */ 9788c2ecf20Sopenharmony_ci return 0; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 9818c2ecf20Sopenharmony_ci if (ret < 0) { 9828c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 9838c2ecf20Sopenharmony_ci return ret; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci del_timer_sync(&musb->dev_timer); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci mbase = musb->ctrl_base; 9898c2ecf20Sopenharmony_ci glue->context.control = musb_readl(mbase, wrp->control); 9908c2ecf20Sopenharmony_ci glue->context.epintr = musb_readl(mbase, wrp->epintr_set); 9918c2ecf20Sopenharmony_ci glue->context.coreintr = musb_readl(mbase, wrp->coreintr_set); 9928c2ecf20Sopenharmony_ci glue->context.phy_utmi = musb_readl(mbase, wrp->phy_utmi); 9938c2ecf20Sopenharmony_ci glue->context.mode = musb_readl(mbase, wrp->mode); 9948c2ecf20Sopenharmony_ci glue->context.tx_mode = musb_readl(mbase, wrp->tx_mode); 9958c2ecf20Sopenharmony_ci glue->context.rx_mode = musb_readl(mbase, wrp->rx_mode); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci dsps_dma_controller_suspend(glue); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci return 0; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic int dsps_resume(struct device *dev) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct dsps_glue *glue = dev_get_drvdata(dev); 10058c2ecf20Sopenharmony_ci const struct dsps_musb_wrapper *wrp = glue->wrp; 10068c2ecf20Sopenharmony_ci struct musb *musb = platform_get_drvdata(glue->musb); 10078c2ecf20Sopenharmony_ci void __iomem *mbase; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (!musb) 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci dsps_dma_controller_resume(glue); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci mbase = musb->ctrl_base; 10158c2ecf20Sopenharmony_ci musb_writel(mbase, wrp->control, glue->context.control); 10168c2ecf20Sopenharmony_ci musb_writel(mbase, wrp->epintr_set, glue->context.epintr); 10178c2ecf20Sopenharmony_ci musb_writel(mbase, wrp->coreintr_set, glue->context.coreintr); 10188c2ecf20Sopenharmony_ci musb_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); 10198c2ecf20Sopenharmony_ci musb_writel(mbase, wrp->mode, glue->context.mode); 10208c2ecf20Sopenharmony_ci musb_writel(mbase, wrp->tx_mode, glue->context.tx_mode); 10218c2ecf20Sopenharmony_ci musb_writel(mbase, wrp->rx_mode, glue->context.rx_mode); 10228c2ecf20Sopenharmony_ci if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && 10238c2ecf20Sopenharmony_ci musb->port_mode == MUSB_OTG) 10248c2ecf20Sopenharmony_ci dsps_mod_timer(glue, -1); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci pm_runtime_put(dev); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci return 0; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci#endif 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic struct platform_driver dsps_usbss_driver = { 10358c2ecf20Sopenharmony_ci .probe = dsps_probe, 10368c2ecf20Sopenharmony_ci .remove = dsps_remove, 10378c2ecf20Sopenharmony_ci .driver = { 10388c2ecf20Sopenharmony_ci .name = "musb-dsps", 10398c2ecf20Sopenharmony_ci .pm = &dsps_pm_ops, 10408c2ecf20Sopenharmony_ci .of_match_table = musb_dsps_of_match, 10418c2ecf20Sopenharmony_ci }, 10428c2ecf20Sopenharmony_ci}; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); 10458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ravi B <ravibabu@ti.com>"); 10468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); 10478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cimodule_platform_driver(dsps_usbss_driver); 1050