2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2012-03-12 19:30:22 +05:30
/*
* Texas Instruments DSPS platforms " glue layer "
*
* Copyright ( C ) 2012 , by Texas Instruments
*
* Based on the am35x " glue layer " code .
*
* This file is part of the Inventra Controller Driver for Linux .
*
* musb_dsps . c will be a common file for all the TI DSPS platforms
* such as dm64x , dm36x , dm35x , da8x , am35x and ti81x .
* For now only ti81x is using this and in future davinci . c , am35x . c
* da8xx . c would be merged to this file after testing .
*/
# include <linux/io.h>
2012-06-26 17:40:32 +05:30
# include <linux/err.h>
2012-03-12 19:30:22 +05:30
# include <linux/platform_device.h>
# include <linux/dma-mapping.h>
# include <linux/pm_runtime.h>
# include <linux/module.h>
2014-04-16 15:28:32 -05:00
# include <linux/usb/usb_phy_generic.h>
2012-10-24 14:26:19 -07:00
# include <linux/platform_data/usb-omap.h>
2013-02-06 09:47:58 +02:00
# include <linux/sizes.h>
2012-03-12 19:30:22 +05:30
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/of_address.h>
2013-07-05 14:51:33 +02:00
# include <linux/of_irq.h>
2013-08-20 18:35:47 +02:00
# include <linux/usb/of.h>
2012-03-12 19:30:22 +05:30
2014-01-17 10:22:35 +01:00
# include <linux/debugfs.h>
2012-03-12 19:30:22 +05:30
# include "musb_core.h"
2012-08-31 11:09:53 +00:00
static const struct of_device_id musb_dsps_of_match [ ] ;
2020-07-03 18:41:46 +01:00
/*
2012-03-12 19:30:22 +05:30
* DSPS musb wrapper register offset .
* FIXME : This should be expanded to have all the wrapper registers from TI DSPS
* musb ips .
*/
struct dsps_musb_wrapper {
u16 revision ;
u16 control ;
u16 status ;
u16 epintr_set ;
u16 epintr_clear ;
u16 epintr_status ;
u16 coreintr_set ;
u16 coreintr_clear ;
u16 coreintr_status ;
u16 phy_utmi ;
u16 mode ;
2013-11-25 22:26:42 +01:00
u16 tx_mode ;
u16 rx_mode ;
2012-03-12 19:30:22 +05:30
/* bit positions for control */
unsigned reset : 5 ;
/* bit positions for interrupt */
unsigned usb_shift : 5 ;
u32 usb_mask ;
u32 usb_bitmap ;
unsigned drvvbus : 5 ;
unsigned txep_shift : 5 ;
u32 txep_mask ;
u32 txep_bitmap ;
unsigned rxep_shift : 5 ;
u32 rxep_mask ;
u32 rxep_bitmap ;
/* bit positions for phy_utmi */
unsigned otg_disable : 5 ;
/* bit positions for mode */
unsigned iddig : 5 ;
2013-10-29 12:17:16 -05:00
unsigned iddig_mux : 5 ;
2012-03-12 19:30:22 +05:30
/* miscellaneous stuff */
2015-02-27 19:02:41 -06:00
unsigned poll_timeout ;
2012-03-12 19:30:22 +05:30
} ;
2013-11-26 13:31:14 +01:00
/*
* register shadow for suspend
*/
struct dsps_context {
u32 control ;
u32 epintr ;
u32 coreintr ;
u32 phy_utmi ;
u32 mode ;
u32 tx_mode ;
u32 rx_mode ;
} ;
2020-07-03 18:41:46 +01:00
/*
2012-03-12 19:30:22 +05:30
* DSPS glue structure .
*/
struct dsps_glue {
struct device * dev ;
2013-07-05 14:51:33 +02:00
struct platform_device * musb ; /* child musb pdev */
2012-03-12 19:30:22 +05:30
const struct dsps_musb_wrapper * wrp ; /* wrapper register offsets */
2017-02-01 21:30:25 -06:00
int vbus_irq ; /* optional vbus irq */
2013-07-05 14:51:33 +02:00
unsigned long last_timer ; /* last timer data for each instance */
2014-07-16 18:22:12 +05:30
bool sw_babble_enabled ;
2017-02-06 22:53:56 -06:00
void __iomem * usbss_base ;
2013-11-26 13:31:14 +01:00
struct dsps_context context ;
2014-01-17 10:22:35 +01:00
struct debugfs_regset32 regset ;
struct dentry * dbgfs_root ;
} ;
static const struct debugfs_reg32 dsps_musb_regs [ ] = {
{ " revision " , 0x00 } ,
{ " control " , 0x14 } ,
{ " status " , 0x18 } ,
{ " eoi " , 0x24 } ,
{ " intr0_stat " , 0x30 } ,
{ " intr1_stat " , 0x34 } ,
{ " intr0_set " , 0x38 } ,
{ " intr1_set " , 0x3c } ,
{ " txmode " , 0x70 } ,
{ " rxmode " , 0x74 } ,
{ " autoreq " , 0xd0 } ,
{ " srpfixtime " , 0xd4 } ,
{ " tdown " , 0xd8 } ,
{ " phy_utmi " , 0xe0 } ,
{ " mode " , 0xe8 } ,
2012-03-12 19:30:22 +05:30
} ;
2017-02-01 21:30:25 -06:00
static void dsps_mod_timer ( struct dsps_glue * glue , int wait_ms )
{
2017-10-30 11:29:56 -05:00
struct musb * musb = platform_get_drvdata ( glue - > musb ) ;
2017-02-01 21:30:25 -06:00
int wait ;
if ( wait_ms < 0 )
wait = msecs_to_jiffies ( glue - > wrp - > poll_timeout ) ;
else
wait = msecs_to_jiffies ( wait_ms ) ;
2017-10-30 11:29:56 -05:00
mod_timer ( & musb - > dev_timer , jiffies + wait ) ;
2017-02-01 21:30:25 -06:00
}
/*
* If no vbus irq from the PMIC is configured , we need to poll VBUS status .
*/
static void dsps_mod_timer_optional ( struct dsps_glue * glue )
{
if ( glue - > vbus_irq )
return ;
dsps_mod_timer ( glue , - 1 ) ;
}
2017-02-06 22:53:56 -06:00
/* USBSS / USB AM335x */
# define USBSS_IRQ_STATUS 0x28
# define USBSS_IRQ_ENABLER 0x2c
# define USBSS_IRQ_CLEARR 0x30
# define USBSS_IRQ_PD_COMP (1 << 2)
2020-07-03 18:41:46 +01:00
/*
2012-03-12 19:30:22 +05:30
* dsps_musb_enable - enable interrupts
*/
static void dsps_musb_enable ( struct musb * musb )
{
struct device * dev = musb - > controller ;
2019-04-30 09:59:41 -05:00
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
2012-03-12 19:30:22 +05:30
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
void __iomem * reg_base = musb - > ctrl_base ;
u32 epmask , coremask ;
/* Workaround: setup IRQs through both register sets. */
epmask = ( ( musb - > epmask & wrp - > txep_mask ) < < wrp - > txep_shift ) |
( ( musb - > epmask & wrp - > rxep_mask ) < < wrp - > rxep_shift ) ;
coremask = ( wrp - > usb_bitmap & ~ MUSB_INTR_SOF ) ;
2016-06-30 12:12:23 -05:00
musb_writel ( reg_base , wrp - > epintr_set , epmask ) ;
musb_writel ( reg_base , wrp - > coreintr_set , coremask ) ;
2018-12-18 07:58:05 -06:00
/*
* start polling for runtime PM active and idle ,
* and for ID change in dual - role idle mode .
*/
if ( musb - > xceiv - > otg - > state = = OTG_STATE_B_IDLE )
2017-02-01 21:30:25 -06:00
dsps_mod_timer ( glue , - 1 ) ;
2012-03-12 19:30:22 +05:30
}
2020-07-03 18:41:46 +01:00
/*
2012-03-12 19:30:22 +05:30
* dsps_musb_disable - disable HDRC and flush interrupts
*/
static void dsps_musb_disable ( struct musb * musb )
{
struct device * dev = musb - > controller ;
2019-04-30 09:59:41 -05:00
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
2012-03-12 19:30:22 +05:30
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
void __iomem * reg_base = musb - > ctrl_base ;
2016-06-30 12:12:23 -05:00
musb_writel ( reg_base , wrp - > coreintr_clear , wrp - > usb_bitmap ) ;
musb_writel ( reg_base , wrp - > epintr_clear ,
2012-03-12 19:30:22 +05:30
wrp - > txep_bitmap | wrp - > rxep_bitmap ) ;
2017-10-30 11:29:56 -05:00
del_timer_sync ( & musb - > dev_timer ) ;
2012-03-12 19:30:22 +05:30
}
2016-11-16 13:21:23 -06:00
/* Caller must take musb->lock */
static int dsps_check_status ( struct musb * musb , void * unused )
2012-03-12 19:30:22 +05:30
{
void __iomem * mregs = musb - > mregs ;
struct device * dev = musb - > controller ;
2012-08-31 11:09:51 +00:00
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
2012-03-12 19:30:22 +05:30
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
u8 devctl ;
2013-10-15 18:29:25 +02:00
int skip_session = 0 ;
2012-03-12 19:30:22 +05:30
2017-02-01 21:30:25 -06:00
if ( glue - > vbus_irq )
2017-10-30 11:29:56 -05:00
del_timer ( & musb - > dev_timer ) ;
2017-02-01 21:30:25 -06:00
2012-03-12 19:30:22 +05:30
/*
* We poll because DSPS IP ' s won ' t expose several OTG - critical
* status change events ( from the transceiver ) otherwise .
*/
2016-06-30 12:12:23 -05:00
devctl = musb_readb ( mregs , MUSB_DEVCTL ) ;
2012-03-12 19:30:22 +05:30
dev_dbg ( musb - > controller , " Poll devctl %02x (%s) \n " , devctl ,
2014-10-30 18:41:13 +01:00
usb_otg_state_string ( musb - > xceiv - > otg - > state ) ) ;
2012-03-12 19:30:22 +05:30
2014-10-30 18:41:13 +01:00
switch ( musb - > xceiv - > otg - > state ) {
2016-09-12 21:48:29 -05:00
case OTG_STATE_A_WAIT_VRISE :
2018-12-18 07:58:04 -06:00
if ( musb - > port_mode = = MUSB_HOST ) {
musb - > xceiv - > otg - > state = OTG_STATE_A_WAIT_BCON ;
dsps_mod_timer_optional ( glue ) ;
break ;
}
2020-08-23 17:36:59 -05:00
fallthrough ;
2018-12-18 07:58:04 -06:00
2012-03-12 19:30:22 +05:30
case OTG_STATE_A_WAIT_BCON :
2017-05-25 13:42:39 -05:00
/* keep VBUS on for host-only mode */
2018-05-21 08:42:15 -05:00
if ( musb - > port_mode = = MUSB_HOST ) {
2017-05-25 13:42:39 -05:00
dsps_mod_timer_optional ( glue ) ;
break ;
}
2016-06-30 12:12:23 -05:00
musb_writeb ( musb - > mregs , MUSB_DEVCTL , 0 ) ;
2013-10-15 18:29:25 +02:00
skip_session = 1 ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2012-03-12 19:30:22 +05:30
2013-10-15 18:29:25 +02:00
case OTG_STATE_A_IDLE :
case OTG_STATE_B_IDLE :
2017-02-01 21:30:25 -06:00
if ( ! glue - > vbus_irq ) {
if ( devctl & MUSB_DEVCTL_BDEVICE ) {
musb - > xceiv - > otg - > state = OTG_STATE_B_IDLE ;
MUSB_DEV_MODE ( musb ) ;
} else {
musb - > xceiv - > otg - > state = OTG_STATE_A_IDLE ;
MUSB_HST_MODE ( musb ) ;
}
2018-12-18 07:58:05 -06:00
if ( musb - > port_mode = = MUSB_PERIPHERAL )
skip_session = 1 ;
2017-02-01 21:30:25 -06:00
if ( ! ( devctl & MUSB_DEVCTL_SESSION ) & & ! skip_session )
musb_writeb ( mregs , MUSB_DEVCTL ,
MUSB_DEVCTL_SESSION ) ;
2012-03-12 19:30:22 +05:30
}
2017-02-01 21:30:25 -06:00
dsps_mod_timer_optional ( glue ) ;
2012-03-12 19:30:22 +05:30
break ;
case OTG_STATE_A_WAIT_VFALL :
2014-10-30 18:41:13 +01:00
musb - > xceiv - > otg - > state = OTG_STATE_A_WAIT_VRISE ;
2016-06-30 12:12:23 -05:00
musb_writel ( musb - > ctrl_base , wrp - > coreintr_set ,
2012-03-12 19:30:22 +05:30
MUSB_INTR_VBUSERROR < < wrp - > usb_shift ) ;
break ;
default :
break ;
}
2016-09-12 21:48:31 -05:00
2016-11-16 13:21:23 -06:00
return 0 ;
}
2017-10-24 03:08:35 -07:00
static void otg_timer ( struct timer_list * t )
2016-11-16 13:21:23 -06:00
{
2017-10-30 11:29:56 -05:00
struct musb * musb = from_timer ( musb , t , dev_timer ) ;
2016-11-16 13:21:23 -06:00
struct device * dev = musb - > controller ;
unsigned long flags ;
int err ;
err = pm_runtime_get ( dev ) ;
if ( ( err ! = - EINPROGRESS ) & & err < 0 ) {
dev_err ( dev , " Poll could not pm_runtime_get: %i \n " , err ) ;
pm_runtime_put_noidle ( dev ) ;
return ;
}
spin_lock_irqsave ( & musb - > lock , flags ) ;
err = musb_queue_resume_work ( musb , dsps_check_status , NULL ) ;
if ( err < 0 )
dev_err ( dev , " %s resume work: %i \n " , __func__ , err ) ;
spin_unlock_irqrestore ( & musb - > lock , flags ) ;
2016-09-12 21:48:31 -05:00
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_put_autosuspend ( dev ) ;
2012-03-12 19:30:22 +05:30
}
2017-02-01 21:30:28 -06:00
static void dsps_musb_clear_ep_rxintr ( struct musb * musb , int epnum )
2017-01-03 18:13:47 -06:00
{
u32 epintr ;
struct dsps_glue * glue = dev_get_drvdata ( musb - > controller - > parent ) ;
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
/* musb->lock might already been held */
epintr = ( 1 < < epnum ) < < wrp - > rxep_shift ;
musb_writel ( musb - > ctrl_base , wrp - > epintr_status , epintr ) ;
}
2012-03-12 19:30:22 +05:30
static irqreturn_t dsps_interrupt ( int irq , void * hci )
{
struct musb * musb = hci ;
void __iomem * reg_base = musb - > ctrl_base ;
struct device * dev = musb - > controller ;
2012-08-31 11:09:51 +00:00
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
2012-03-12 19:30:22 +05:30
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
unsigned long flags ;
irqreturn_t ret = IRQ_NONE ;
u32 epintr , usbintr ;
spin_lock_irqsave ( & musb - > lock , flags ) ;
/* Get endpoint interrupts */
2016-06-30 12:12:23 -05:00
epintr = musb_readl ( reg_base , wrp - > epintr_status ) ;
2012-03-12 19:30:22 +05:30
musb - > int_rx = ( epintr & wrp - > rxep_bitmap ) > > wrp - > rxep_shift ;
musb - > int_tx = ( epintr & wrp - > txep_bitmap ) > > wrp - > txep_shift ;
if ( epintr )
2016-06-30 12:12:23 -05:00
musb_writel ( reg_base , wrp - > epintr_status , epintr ) ;
2012-03-12 19:30:22 +05:30
/* Get usb core interrupts */
2016-06-30 12:12:23 -05:00
usbintr = musb_readl ( reg_base , wrp - > coreintr_status ) ;
2012-03-12 19:30:22 +05:30
if ( ! usbintr & & ! epintr )
2013-07-26 11:11:38 +02:00
goto out ;
2012-03-12 19:30:22 +05:30
musb - > int_usb = ( usbintr & wrp - > usb_bitmap ) > > wrp - > usb_shift ;
if ( usbintr )
2016-06-30 12:12:23 -05:00
musb_writel ( reg_base , wrp - > coreintr_status , usbintr ) ;
2012-03-12 19:30:22 +05:30
dev_dbg ( musb - > controller , " usbintr (%x) epintr(%x) \n " ,
usbintr , epintr ) ;
2014-04-02 13:58:29 +02:00
2012-03-12 19:30:22 +05:30
if ( usbintr & ( ( 1 < < wrp - > drvvbus ) < < wrp - > usb_shift ) ) {
2016-06-30 12:12:23 -05:00
int drvvbus = musb_readl ( reg_base , wrp - > status ) ;
2012-03-12 19:30:22 +05:30
void __iomem * mregs = musb - > mregs ;
2016-06-30 12:12:23 -05:00
u8 devctl = musb_readb ( mregs , MUSB_DEVCTL ) ;
2012-03-12 19:30:22 +05:30
int err ;
2011-11-24 15:46:26 +02:00
err = musb - > int_usb & MUSB_INTR_VBUSERROR ;
2012-03-12 19:30:22 +05:30
if ( err ) {
/*
* The Mentor core doesn ' t debounce VBUS as needed
* to cope with device connect current spikes . This
* means it ' s not uncommon for bus - powered devices
* to get VBUS errors during enumeration .
*
* This is a workaround , but newer RTL from Mentor
* seems to allow a better one : " re " - starting sessions
* without waiting for VBUS to stop registering in
* devctl .
*/
musb - > int_usb & = ~ MUSB_INTR_VBUSERROR ;
2014-10-30 18:41:13 +01:00
musb - > xceiv - > otg - > state = OTG_STATE_A_WAIT_VFALL ;
2017-02-01 21:30:25 -06:00
dsps_mod_timer_optional ( glue ) ;
2012-03-12 19:30:22 +05:30
WARNING ( " VBUS error workaround (delay coming) \n " ) ;
2011-11-24 15:46:26 +02:00
} else if ( drvvbus ) {
2012-03-12 19:30:22 +05:30
MUSB_HST_MODE ( musb ) ;
2014-10-30 18:41:13 +01:00
musb - > xceiv - > otg - > state = OTG_STATE_A_WAIT_VRISE ;
2017-02-01 21:30:25 -06:00
dsps_mod_timer_optional ( glue ) ;
2012-03-12 19:30:22 +05:30
} else {
musb - > is_active = 0 ;
MUSB_DEV_MODE ( musb ) ;
2014-10-30 18:41:13 +01:00
musb - > xceiv - > otg - > state = OTG_STATE_B_IDLE ;
2012-03-12 19:30:22 +05:30
}
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg ( musb - > controller , " VBUS %s (%s)%s, devctl %02x \n " ,
drvvbus ? " on " : " off " ,
2014-10-30 18:41:13 +01:00
usb_otg_state_string ( musb - > xceiv - > otg - > state ) ,
2012-03-12 19:30:22 +05:30
err ? " ERROR " : " " ,
devctl ) ;
ret = IRQ_HANDLED ;
}
if ( musb - > int_tx | | musb - > int_rx | | musb - > int_usb )
ret | = musb_interrupt ( musb ) ;
2016-09-12 21:48:29 -05:00
/* Poll for ID change and connect */
switch ( musb - > xceiv - > otg - > state ) {
case OTG_STATE_B_IDLE :
case OTG_STATE_A_WAIT_BCON :
2017-02-01 21:30:25 -06:00
dsps_mod_timer_optional ( glue ) ;
2016-09-12 21:48:29 -05:00
break ;
default :
break ;
}
2013-07-26 11:11:38 +02:00
out :
2012-03-12 19:30:22 +05:30
spin_unlock_irqrestore ( & musb - > lock , flags ) ;
return ret ;
}
2014-01-17 10:22:35 +01:00
static int dsps_musb_dbg_init ( struct musb * musb , struct dsps_glue * glue )
{
struct dentry * root ;
char buf [ 128 ] ;
sprintf ( buf , " %s.dsps " , dev_name ( musb - > controller ) ) ;
2019-11-12 14:51:52 +08:00
root = debugfs_create_dir ( buf , usb_debug_root ) ;
2014-01-17 10:22:35 +01:00
glue - > dbgfs_root = root ;
glue - > regset . regs = dsps_musb_regs ;
glue - > regset . nregs = ARRAY_SIZE ( dsps_musb_regs ) ;
glue - > regset . base = musb - > ctrl_base ;
2018-05-29 17:30:48 +02:00
debugfs_create_regset32 ( " regdump " , S_IRUGO , root , & glue - > regset ) ;
2014-01-17 10:22:35 +01:00
return 0 ;
}
2012-03-12 19:30:22 +05:30
static int dsps_musb_init ( struct musb * musb )
{
struct device * dev = musb - > controller ;
2012-08-31 11:09:51 +00:00
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
2013-07-05 14:51:33 +02:00
struct platform_device * parent = to_platform_device ( dev - > parent ) ;
2012-03-12 19:30:22 +05:30
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
2013-07-05 14:51:33 +02:00
void __iomem * reg_base ;
2020-11-12 14:59:00 +01:00
struct resource * r ;
2012-03-12 19:30:22 +05:30
u32 rev , val ;
2014-01-17 10:22:35 +01:00
int ret ;
2012-03-12 19:30:22 +05:30
2020-11-12 14:59:00 +01:00
r = platform_get_resource_byname ( parent , IORESOURCE_MEM , " control " ) ;
reg_base = devm_ioremap_resource ( dev , r ) ;
2013-08-19 18:00:08 +02:00
if ( IS_ERR ( reg_base ) )
return PTR_ERR ( reg_base ) ;
2013-07-05 14:51:33 +02:00
musb - > ctrl_base = reg_base ;
2012-03-12 19:30:22 +05:30
2012-11-06 20:47:24 +05:30
/* NOP driver needs change if supporting dual instance */
2015-03-11 10:18:40 -05:00
musb - > xceiv = devm_usb_get_phy_by_phandle ( dev - > parent , " phys " , 0 ) ;
2013-07-05 14:51:33 +02:00
if ( IS_ERR ( musb - > xceiv ) )
return PTR_ERR ( musb - > xceiv ) ;
2012-03-12 19:30:22 +05:30
2015-02-04 06:28:49 -08:00
musb - > phy = devm_phy_get ( dev - > parent , " usb2-phy " ) ;
2012-03-12 19:30:22 +05:30
/* Returns zero if e.g. not clocked */
2016-06-30 12:12:23 -05:00
rev = musb_readl ( reg_base , wrp - > revision ) ;
2013-07-05 14:51:33 +02:00
if ( ! rev )
return - ENODEV ;
2012-03-12 19:30:22 +05:30
2015-02-04 06:28:49 -08:00
if ( IS_ERR ( musb - > phy ) ) {
musb - > phy = NULL ;
} else {
ret = phy_init ( musb - > phy ) ;
if ( ret < 0 )
return ret ;
ret = phy_power_on ( musb - > phy ) ;
if ( ret ) {
phy_exit ( musb - > phy ) ;
return ret ;
}
}
2017-10-30 11:29:56 -05:00
timer_setup ( & musb - > dev_timer , otg_timer , 0 ) ;
2012-03-12 19:30:22 +05:30
/* Reset the musb */
2016-06-30 12:12:23 -05:00
musb_writel ( reg_base , wrp - > control , ( 1 < < wrp - > reset ) ) ;
2012-03-12 19:30:22 +05:30
musb - > isr = dsps_interrupt ;
/* reset the otgdisable bit, needed for host mode to work */
2016-06-30 12:12:23 -05:00
val = musb_readl ( reg_base , wrp - > phy_utmi ) ;
2012-03-12 19:30:22 +05:30
val & = ~ ( 1 < < wrp - > otg_disable ) ;
2016-06-30 12:12:23 -05:00
musb_writel ( musb - > ctrl_base , wrp - > phy_utmi , val ) ;
2012-03-12 19:30:22 +05:30
2014-07-16 18:22:12 +05:30
/*
* Check whether the dsps version has babble control enabled .
* In latest silicon revision the babble control logic is enabled .
* If MUSB_BABBLE_CTL returns 0x4 then we have the babble control
* logic enabled .
*/
2016-06-30 12:12:23 -05:00
val = musb_readb ( musb - > mregs , MUSB_BABBLE_CTL ) ;
2015-02-26 11:01:03 -06:00
if ( val & MUSB_BABBLE_RCV_DISABLE ) {
2014-07-16 18:22:12 +05:30
glue - > sw_babble_enabled = true ;
val | = MUSB_BABBLE_SW_SESSION_CTRL ;
2016-06-30 12:12:23 -05:00
musb_writeb ( musb - > mregs , MUSB_BABBLE_CTL , val ) ;
2014-07-16 18:22:12 +05:30
}
2017-02-01 21:30:25 -06:00
dsps_mod_timer ( glue , - 1 ) ;
2016-09-12 21:48:29 -05:00
2015-08-04 14:02:28 +00:00
return dsps_musb_dbg_init ( musb , glue ) ;
2012-03-12 19:30:22 +05:30
}
static int dsps_musb_exit ( struct musb * musb )
{
struct device * dev = musb - > controller ;
2012-08-31 11:09:51 +00:00
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
2012-03-12 19:30:22 +05:30
2017-10-30 11:29:56 -05:00
del_timer_sync ( & musb - > dev_timer ) ;
2015-02-04 06:28:49 -08:00
phy_power_off ( musb - > phy ) ;
phy_exit ( musb - > phy ) ;
2014-04-02 11:46:51 +02:00
debugfs_remove_recursive ( glue - > dbgfs_root ) ;
2012-03-12 19:30:22 +05:30
return 0 ;
}
2013-10-29 12:17:16 -05:00
static int dsps_musb_set_mode ( struct musb * musb , u8 mode )
{
struct device * dev = musb - > controller ;
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
void __iomem * ctrl_base = musb - > ctrl_base ;
u32 reg ;
2016-06-30 12:12:23 -05:00
reg = musb_readl ( ctrl_base , wrp - > mode ) ;
2013-10-29 12:17:16 -05:00
switch ( mode ) {
case MUSB_HOST :
reg & = ~ ( 1 < < wrp - > iddig ) ;
/*
* if we ' re setting mode to host - only or device - only , we ' re
* going to ignore whatever the PHY sends us and just force
* ID pin status by SW
*/
reg | = ( 1 < < wrp - > iddig_mux ) ;
2016-06-30 12:12:23 -05:00
musb_writel ( ctrl_base , wrp - > mode , reg ) ;
musb_writel ( ctrl_base , wrp - > phy_utmi , 0x02 ) ;
2013-10-29 12:17:16 -05:00
break ;
case MUSB_PERIPHERAL :
reg | = ( 1 < < wrp - > iddig ) ;
/*
* if we ' re setting mode to host - only or device - only , we ' re
* going to ignore whatever the PHY sends us and just force
* ID pin status by SW
*/
reg | = ( 1 < < wrp - > iddig_mux ) ;
2016-06-30 12:12:23 -05:00
musb_writel ( ctrl_base , wrp - > mode , reg ) ;
2013-10-29 12:17:16 -05:00
break ;
case MUSB_OTG :
2016-06-30 12:12:23 -05:00
musb_writel ( ctrl_base , wrp - > phy_utmi , 0x02 ) ;
2013-10-29 12:17:16 -05:00
break ;
default :
dev_err ( glue - > dev , " unsupported mode %d \n " , mode ) ;
return - EINVAL ;
}
return 0 ;
}
2015-02-26 11:11:33 -06:00
static bool dsps_sw_babble_control ( struct musb * musb )
2014-07-16 18:22:12 +05:30
{
u8 babble_ctl ;
bool session_restart = false ;
2016-06-30 12:12:23 -05:00
babble_ctl = musb_readb ( musb - > mregs , MUSB_BABBLE_CTL ) ;
2014-07-16 18:22:12 +05:30
dev_dbg ( musb - > controller , " babble: MUSB_BABBLE_CTL value %x \n " ,
babble_ctl ) ;
/*
* check line monitor flag to check whether babble is
* due to noise
*/
dev_dbg ( musb - > controller , " STUCK_J is %s \n " ,
babble_ctl & MUSB_BABBLE_STUCK_J ? " set " : " reset " ) ;
if ( babble_ctl & MUSB_BABBLE_STUCK_J ) {
int timeout = 10 ;
/*
* babble is due to noise , then set transmit idle ( d7 bit )
* to resume normal operation
*/
2016-06-30 12:12:23 -05:00
babble_ctl = musb_readb ( musb - > mregs , MUSB_BABBLE_CTL ) ;
2014-07-16 18:22:12 +05:30
babble_ctl | = MUSB_BABBLE_FORCE_TXIDLE ;
2016-06-30 12:12:23 -05:00
musb_writeb ( musb - > mregs , MUSB_BABBLE_CTL , babble_ctl ) ;
2014-07-16 18:22:12 +05:30
/* wait till line monitor flag cleared */
dev_dbg ( musb - > controller , " Set TXIDLE, wait J to clear \n " ) ;
do {
2016-06-30 12:12:23 -05:00
babble_ctl = musb_readb ( musb - > mregs , MUSB_BABBLE_CTL ) ;
2014-07-16 18:22:12 +05:30
udelay ( 1 ) ;
} while ( ( babble_ctl & MUSB_BABBLE_STUCK_J ) & & timeout - - ) ;
/* check whether stuck_at_j bit cleared */
if ( babble_ctl & MUSB_BABBLE_STUCK_J ) {
/*
* real babble condition has occurred
* restart the controller to start the
* session again
*/
dev_dbg ( musb - > controller , " J not cleared, misc (%x) \n " ,
babble_ctl ) ;
session_restart = true ;
}
} else {
session_restart = true ;
}
return session_restart ;
}
2015-02-26 14:20:58 -06:00
static int dsps_musb_recover ( struct musb * musb )
2014-04-02 13:58:29 +02:00
{
struct device * dev = musb - > controller ;
struct dsps_glue * glue = dev_get_drvdata ( dev - > parent ) ;
2015-02-26 14:00:52 -06:00
int session_restart = 0 ;
2014-04-02 13:58:29 +02:00
2014-07-16 18:22:12 +05:30
if ( glue - > sw_babble_enabled )
2015-02-26 11:11:33 -06:00
session_restart = dsps_sw_babble_control ( musb ) ;
2015-02-26 14:00:52 -06:00
else
2014-07-16 18:22:12 +05:30
session_restart = 1 ;
2014-04-02 13:58:29 +02:00
2015-02-26 10:55:13 -06:00
return session_restart ? 0 : - EPIPE ;
2014-04-02 13:58:29 +02:00
}
2015-03-19 17:10:16 -07:00
/* Similar to am35x, dm81xx support only 32-bit read operation */
static void dsps_read_fifo32 ( struct musb_hw_ep * hw_ep , u16 len , u8 * dst )
{
void __iomem * fifo = hw_ep - > fifo ;
if ( len > = 4 ) {
2015-03-25 14:18:37 -07:00
ioread32_rep ( fifo , dst , len > > 2 ) ;
2015-03-19 17:10:16 -07:00
dst + = len & ~ 0x03 ;
len & = 0x03 ;
}
/* Read any remaining 1 to 3 bytes */
if ( len > 0 ) {
u32 val = musb_readl ( fifo , 0 ) ;
memcpy ( dst , & val , len ) ;
}
}
2017-02-06 22:53:56 -06:00
# ifdef CONFIG_USB_TI_CPPI41_DMA
static void dsps_dma_controller_callback ( struct dma_controller * c )
{
struct musb * musb = c - > musb ;
struct dsps_glue * glue = dev_get_drvdata ( musb - > controller - > parent ) ;
void __iomem * usbss_base = glue - > usbss_base ;
u32 status ;
status = musb_readl ( usbss_base , USBSS_IRQ_STATUS ) ;
if ( status & USBSS_IRQ_PD_COMP )
musb_writel ( usbss_base , USBSS_IRQ_STATUS , USBSS_IRQ_PD_COMP ) ;
}
static struct dma_controller *
dsps_dma_controller_create ( struct musb * musb , void __iomem * base )
{
struct dma_controller * controller ;
struct dsps_glue * glue = dev_get_drvdata ( musb - > controller - > parent ) ;
void __iomem * usbss_base = glue - > usbss_base ;
controller = cppi41_dma_controller_create ( musb , base ) ;
if ( IS_ERR_OR_NULL ( controller ) )
return controller ;
musb_writel ( usbss_base , USBSS_IRQ_ENABLER , USBSS_IRQ_PD_COMP ) ;
controller - > dma_callback = dsps_dma_controller_callback ;
return controller ;
}
# ifdef CONFIG_PM_SLEEP
static void dsps_dma_controller_suspend ( struct dsps_glue * glue )
{
void __iomem * usbss_base = glue - > usbss_base ;
musb_writel ( usbss_base , USBSS_IRQ_CLEARR , USBSS_IRQ_PD_COMP ) ;
}
static void dsps_dma_controller_resume ( struct dsps_glue * glue )
{
void __iomem * usbss_base = glue - > usbss_base ;
musb_writel ( usbss_base , USBSS_IRQ_ENABLER , USBSS_IRQ_PD_COMP ) ;
}
# endif
# else /* CONFIG_USB_TI_CPPI41_DMA */
# ifdef CONFIG_PM_SLEEP
static void dsps_dma_controller_suspend ( struct dsps_glue * glue ) { }
static void dsps_dma_controller_resume ( struct dsps_glue * glue ) { }
# endif
# endif /* CONFIG_USB_TI_CPPI41_DMA */
2012-03-12 19:30:22 +05:30
static struct musb_platform_ops dsps_ops = {
2015-05-01 12:29:27 -07:00
. quirks = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP ,
2012-03-12 19:30:22 +05:30
. init = dsps_musb_init ,
. exit = dsps_musb_exit ,
2015-05-01 12:29:28 -07:00
# ifdef CONFIG_USB_TI_CPPI41_DMA
2017-02-06 22:53:56 -06:00
. dma_init = dsps_dma_controller_create ,
2018-09-17 11:40:22 -05:00
. dma_exit = cppi41_dma_controller_destroy ,
2015-05-01 12:29:28 -07:00
# endif
2012-03-12 19:30:22 +05:30
. enable = dsps_musb_enable ,
. disable = dsps_musb_disable ,
2013-10-29 12:17:16 -05:00
. set_mode = dsps_musb_set_mode ,
2015-02-26 14:20:58 -06:00
. recover = dsps_musb_recover ,
2017-01-03 18:13:47 -06:00
. clear_ep_rxintr = dsps_musb_clear_ep_rxintr ,
2012-03-12 19:30:22 +05:30
} ;
static u64 musb_dmamask = DMA_BIT_MASK ( 32 ) ;
2013-07-05 14:51:33 +02:00
static int get_int_prop ( struct device_node * dn , const char * s )
2012-03-12 19:30:22 +05:30
{
2013-07-05 14:51:33 +02:00
int ret ;
u32 val ;
ret = of_property_read_u32 ( dn , s , & val ) ;
if ( ret )
return 0 ;
return val ;
}
static int dsps_create_musb_pdev ( struct dsps_glue * glue ,
struct platform_device * parent )
{
struct musb_hdrc_platform_data pdata ;
2012-03-12 19:30:22 +05:30
struct resource resources [ 2 ] ;
2013-08-20 18:35:47 +02:00
struct resource * res ;
2013-07-05 14:51:33 +02:00
struct device * dev = & parent - > dev ;
struct musb_hdrc_config * config ;
struct platform_device * musb ;
struct device_node * dn = parent - > dev . of_node ;
2015-02-04 06:28:49 -08:00
int ret , val ;
2012-03-12 19:30:22 +05:30
2013-07-05 14:51:33 +02:00
memset ( resources , 0 , sizeof ( resources ) ) ;
2013-08-20 18:35:47 +02:00
res = platform_get_resource_byname ( parent , IORESOURCE_MEM , " mc " ) ;
if ( ! res ) {
2013-07-05 14:51:33 +02:00
dev_err ( dev , " failed to get memory. \n " ) ;
2013-08-20 18:35:47 +02:00
return - EINVAL ;
2012-03-12 19:30:22 +05:30
}
2013-08-20 18:35:47 +02:00
resources [ 0 ] = * res ;
2013-07-05 14:51:33 +02:00
2013-08-20 18:35:47 +02:00
res = platform_get_resource_byname ( parent , IORESOURCE_IRQ , " mc " ) ;
if ( ! res ) {
2013-07-05 14:51:33 +02:00
dev_err ( dev , " failed to get irq. \n " ) ;
2013-08-20 18:35:47 +02:00
return - EINVAL ;
2012-03-12 19:30:22 +05:30
}
2013-08-20 18:35:47 +02:00
resources [ 1 ] = * res ;
2012-03-12 19:30:22 +05:30
/* allocate the child platform device */
2017-02-01 21:30:23 -06:00
musb = platform_device_alloc ( " musb-hdrc " ,
( resources [ 0 ] . start & 0xFFF ) = = 0x400 ? 0 : 1 ) ;
2012-03-12 19:30:22 +05:30
if ( ! musb ) {
dev_err ( dev , " failed to allocate musb device \n " ) ;
2013-07-05 14:51:33 +02:00
return - ENOMEM ;
2012-03-12 19:30:22 +05:30
}
musb - > dev . parent = dev ;
musb - > dev . dma_mask = & musb_dmamask ;
musb - > dev . coherent_dma_mask = musb_dmamask ;
2018-05-21 08:42:20 -05:00
device_set_of_node_from_dev ( & musb - > dev , & parent - > dev ) ;
2012-03-12 19:30:22 +05:30
2013-07-05 14:51:33 +02:00
glue - > musb = musb ;
2012-03-12 19:30:22 +05:30
2013-07-05 14:51:33 +02:00
ret = platform_device_add_resources ( musb , resources ,
ARRAY_SIZE ( resources ) ) ;
2012-03-12 19:30:22 +05:30
if ( ret ) {
dev_err ( dev , " failed to add resources \n " ) ;
2013-07-05 14:51:33 +02:00
goto err ;
2012-03-12 19:30:22 +05:30
}
2013-07-05 14:51:33 +02:00
config = devm_kzalloc ( & parent - > dev , sizeof ( * config ) , GFP_KERNEL ) ;
if ( ! config ) {
ret = - ENOMEM ;
goto err ;
2012-08-31 11:09:53 +00:00
}
2013-07-05 14:51:33 +02:00
pdata . config = config ;
pdata . platform_ops = & dsps_ops ;
2012-08-31 11:09:53 +00:00
2013-08-20 18:35:47 +02:00
config - > num_eps = get_int_prop ( dn , " mentor,num-eps " ) ;
config - > ram_bits = get_int_prop ( dn , " mentor,ram-bits " ) ;
2013-11-26 13:31:14 +01:00
config - > host_port_deassert_reset_at_resume = 1 ;
2018-05-21 08:42:14 -05:00
pdata . mode = musb_get_mode ( dev ) ;
2013-08-20 18:35:47 +02:00
/* DT keeps this entry in mA, musb expects it as per USB spec */
pdata . power = get_int_prop ( dn , " mentor,power " ) / 2 ;
2015-02-04 06:28:49 -08:00
ret = of_property_read_u32 ( dn , " mentor,multipoint " , & val ) ;
if ( ! ret & & val )
config - > multipoint = true ;
2012-08-31 11:09:53 +00:00
2015-09-21 11:14:32 +03:00
config - > maximum_speed = usb_get_maximum_speed ( & parent - > dev ) ;
2015-09-09 11:56:18 -05:00
switch ( config - > maximum_speed ) {
case USB_SPEED_LOW :
case USB_SPEED_FULL :
break ;
case USB_SPEED_SUPER :
dev_warn ( dev , " ignore incorrect maximum_speed "
" (super-speed) setting in dts " ) ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2015-09-09 11:56:18 -05:00
default :
config - > maximum_speed = USB_SPEED_HIGH ;
}
2013-07-05 14:51:33 +02:00
ret = platform_device_add_data ( musb , & pdata , sizeof ( pdata ) ) ;
2012-03-12 19:30:22 +05:30
if ( ret ) {
dev_err ( dev , " failed to add platform_data \n " ) ;
2013-07-05 14:51:33 +02:00
goto err ;
2012-03-12 19:30:22 +05:30
}
ret = platform_device_add ( musb ) ;
if ( ret ) {
dev_err ( dev , " failed to register musb device \n " ) ;
2013-07-05 14:51:33 +02:00
goto err ;
2012-03-12 19:30:22 +05:30
}
return 0 ;
2013-07-05 14:51:33 +02:00
err :
2012-03-12 19:30:22 +05:30
platform_device_put ( musb ) ;
return ret ;
}
2017-02-01 21:30:25 -06:00
static irqreturn_t dsps_vbus_threaded_irq ( int irq , void * priv )
{
struct dsps_glue * glue = priv ;
struct musb * musb = platform_get_drvdata ( glue - > musb ) ;
if ( ! musb )
return IRQ_NONE ;
dev_dbg ( glue - > dev , " VBUS interrupt \n " ) ;
dsps_mod_timer ( glue , 0 ) ;
return IRQ_HANDLED ;
}
static int dsps_setup_optional_vbus_irq ( struct platform_device * pdev ,
struct dsps_glue * glue )
{
int error ;
glue - > vbus_irq = platform_get_irq_byname ( pdev , " vbus " ) ;
if ( glue - > vbus_irq = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
if ( glue - > vbus_irq < = 0 ) {
glue - > vbus_irq = 0 ;
return 0 ;
}
error = devm_request_threaded_irq ( glue - > dev , glue - > vbus_irq ,
NULL , dsps_vbus_threaded_irq ,
IRQF_ONESHOT ,
" vbus " , glue ) ;
if ( error ) {
glue - > vbus_irq = 0 ;
return error ;
}
dev_dbg ( glue - > dev , " VBUS irq %i configured \n " , glue - > vbus_irq ) ;
return 0 ;
}
2012-11-19 13:21:48 -05:00
static int dsps_probe ( struct platform_device * pdev )
2012-03-12 19:30:22 +05:30
{
2012-08-31 11:09:53 +00:00
const struct of_device_id * match ;
const struct dsps_musb_wrapper * wrp ;
2012-03-12 19:30:22 +05:30
struct dsps_glue * glue ;
2013-07-05 14:51:33 +02:00
int ret ;
2012-03-12 19:30:22 +05:30
2013-10-01 14:31:53 +02:00
if ( ! strcmp ( pdev - > name , " musb-hdrc " ) )
return - ENODEV ;
2013-02-06 09:57:18 +02:00
match = of_match_node ( musb_dsps_of_match , pdev - > dev . of_node ) ;
2012-08-31 11:09:53 +00:00
if ( ! match ) {
dev_err ( & pdev - > dev , " fail to get matching of_match struct \n " ) ;
2013-07-05 14:51:33 +02:00
return - EINVAL ;
2012-08-31 11:09:53 +00:00
}
wrp = match - > data ;
2012-03-12 19:30:22 +05:30
2015-03-19 17:10:16 -07:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " ti,musb-dm816 " ) )
dsps_ops . read_fifo = dsps_read_fifo32 ;
2012-03-12 19:30:22 +05:30
/* allocate glue */
2014-01-17 10:22:36 +01:00
glue = devm_kzalloc ( & pdev - > dev , sizeof ( * glue ) , GFP_KERNEL ) ;
2014-10-14 15:56:11 +08:00
if ( ! glue )
2013-07-05 14:51:33 +02:00
return - ENOMEM ;
2012-03-12 19:30:22 +05:30
glue - > dev = & pdev - > dev ;
2013-07-05 14:51:33 +02:00
glue - > wrp = wrp ;
2017-02-06 22:53:56 -06:00
glue - > usbss_base = of_iomap ( pdev - > dev . parent - > of_node , 0 ) ;
if ( ! glue - > usbss_base )
return - ENXIO ;
2012-03-12 19:30:22 +05:30
2017-02-01 21:30:25 -06:00
if ( usb_get_dr_mode ( & pdev - > dev ) = = USB_DR_MODE_PERIPHERAL ) {
ret = dsps_setup_optional_vbus_irq ( pdev , glue ) ;
if ( ret )
2017-03-10 14:43:36 -06:00
goto err_iounmap ;
2017-02-01 21:30:25 -06:00
}
2012-03-12 19:30:22 +05:30
platform_set_drvdata ( pdev , glue ) ;
pm_runtime_enable ( & pdev - > dev ) ;
2013-07-05 14:51:33 +02:00
ret = dsps_create_musb_pdev ( glue , pdev ) ;
if ( ret )
2016-11-16 13:21:26 -06:00
goto err ;
2016-09-12 21:48:31 -05:00
2012-03-12 19:30:22 +05:30
return 0 ;
2016-11-16 13:21:26 -06:00
err :
2012-07-03 17:37:11 +05:30
pm_runtime_disable ( & pdev - > dev ) ;
2017-03-10 14:43:36 -06:00
err_iounmap :
iounmap ( glue - > usbss_base ) ;
2012-03-12 19:30:22 +05:30
return ret ;
}
2013-07-05 14:51:33 +02:00
2012-11-19 13:26:20 -05:00
static int dsps_remove ( struct platform_device * pdev )
2012-03-12 19:30:22 +05:30
{
struct dsps_glue * glue = platform_get_drvdata ( pdev ) ;
2013-07-05 14:51:33 +02:00
platform_device_unregister ( glue - > musb ) ;
2012-03-12 19:30:22 +05:30
pm_runtime_disable ( & pdev - > dev ) ;
2017-03-10 14:43:36 -06:00
iounmap ( glue - > usbss_base ) ;
2014-01-17 10:22:35 +01:00
2012-03-12 19:30:22 +05:30
return 0 ;
}
2013-07-26 11:11:37 +02:00
static const struct dsps_musb_wrapper am33xx_driver_data = {
2012-03-12 19:30:22 +05:30
. revision = 0x00 ,
. control = 0x14 ,
. status = 0x18 ,
. epintr_set = 0x38 ,
. epintr_clear = 0x40 ,
. epintr_status = 0x30 ,
. coreintr_set = 0x3c ,
. coreintr_clear = 0x44 ,
. coreintr_status = 0x34 ,
. phy_utmi = 0xe0 ,
. mode = 0xe8 ,
2013-11-25 22:26:42 +01:00
. tx_mode = 0x70 ,
. rx_mode = 0x74 ,
2012-03-12 19:30:22 +05:30
. reset = 0 ,
. otg_disable = 21 ,
. iddig = 8 ,
2013-10-29 12:17:16 -05:00
. iddig_mux = 7 ,
2012-03-12 19:30:22 +05:30
. usb_shift = 0 ,
. usb_mask = 0x1ff ,
. usb_bitmap = ( 0x1ff < < 0 ) ,
. drvvbus = 8 ,
. txep_shift = 0 ,
. txep_mask = 0xffff ,
. txep_bitmap = ( 0xffff < < 0 ) ,
. rxep_shift = 16 ,
. rxep_mask = 0xfffe ,
. rxep_bitmap = ( 0xfffe < < 16 ) ,
2015-02-27 19:02:41 -06:00
. poll_timeout = 2000 , /* ms */
2012-03-12 19:30:22 +05:30
} ;
2012-11-19 13:25:20 -05:00
static const struct of_device_id musb_dsps_of_match [ ] = {
2012-08-31 11:09:53 +00:00
{ . compatible = " ti,musb-am33xx " ,
2015-03-19 17:10:16 -07:00
. data = & am33xx_driver_data , } ,
{ . compatible = " ti,musb-dm816 " ,
. data = & am33xx_driver_data , } ,
2012-03-12 19:30:22 +05:30
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , musb_dsps_of_match ) ;
2014-04-17 10:20:32 +02:00
# ifdef CONFIG_PM_SLEEP
2013-11-26 13:31:14 +01:00
static int dsps_suspend ( struct device * dev )
{
struct dsps_glue * glue = dev_get_drvdata ( dev ) ;
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
struct musb * musb = platform_get_drvdata ( glue - > musb ) ;
2014-10-13 11:04:21 +02:00
void __iomem * mbase ;
2017-08-24 11:38:37 -05:00
int ret ;
2014-10-13 11:04:21 +02:00
if ( ! musb )
/* This can happen if the musb device is in -EPROBE_DEFER */
return 0 ;
2017-08-24 11:38:37 -05:00
ret = pm_runtime_get_sync ( dev ) ;
if ( ret < 0 ) {
pm_runtime_put_noidle ( dev ) ;
return ret ;
}
2017-10-30 11:29:56 -05:00
del_timer_sync ( & musb - > dev_timer ) ;
2017-08-24 11:38:37 -05:00
2014-10-13 11:04:21 +02:00
mbase = musb - > ctrl_base ;
2016-06-30 12:12:23 -05:00
glue - > context . control = musb_readl ( mbase , wrp - > control ) ;
glue - > context . epintr = musb_readl ( mbase , wrp - > epintr_set ) ;
glue - > context . coreintr = musb_readl ( mbase , wrp - > coreintr_set ) ;
glue - > context . phy_utmi = musb_readl ( mbase , wrp - > phy_utmi ) ;
glue - > context . mode = musb_readl ( mbase , wrp - > mode ) ;
glue - > context . tx_mode = musb_readl ( mbase , wrp - > tx_mode ) ;
glue - > context . rx_mode = musb_readl ( mbase , wrp - > rx_mode ) ;
2013-11-26 13:31:14 +01:00
2017-02-06 22:53:56 -06:00
dsps_dma_controller_suspend ( glue ) ;
2013-11-26 13:31:14 +01:00
return 0 ;
}
static int dsps_resume ( struct device * dev )
{
struct dsps_glue * glue = dev_get_drvdata ( dev ) ;
const struct dsps_musb_wrapper * wrp = glue - > wrp ;
struct musb * musb = platform_get_drvdata ( glue - > musb ) ;
2014-10-13 11:04:21 +02:00
void __iomem * mbase ;
if ( ! musb )
return 0 ;
2013-11-26 13:31:14 +01:00
2017-02-06 22:53:56 -06:00
dsps_dma_controller_resume ( glue ) ;
2014-10-13 11:04:21 +02:00
mbase = musb - > ctrl_base ;
2016-06-30 12:12:23 -05:00
musb_writel ( mbase , wrp - > control , glue - > context . control ) ;
musb_writel ( mbase , wrp - > epintr_set , glue - > context . epintr ) ;
musb_writel ( mbase , wrp - > coreintr_set , glue - > context . coreintr ) ;
musb_writel ( mbase , wrp - > phy_utmi , glue - > context . phy_utmi ) ;
musb_writel ( mbase , wrp - > mode , glue - > context . mode ) ;
musb_writel ( mbase , wrp - > tx_mode , glue - > context . tx_mode ) ;
musb_writel ( mbase , wrp - > rx_mode , glue - > context . rx_mode ) ;
2014-10-30 18:41:13 +01:00
if ( musb - > xceiv - > otg - > state = = OTG_STATE_B_IDLE & &
2018-05-21 08:42:15 -05:00
musb - > port_mode = = MUSB_OTG )
2017-02-01 21:30:25 -06:00
dsps_mod_timer ( glue , - 1 ) ;
2013-11-26 13:31:14 +01:00
2017-08-24 11:38:37 -05:00
pm_runtime_put ( dev ) ;
2013-11-26 13:31:14 +01:00
return 0 ;
}
# endif
static SIMPLE_DEV_PM_OPS ( dsps_pm_ops , dsps_suspend , dsps_resume ) ;
2012-03-12 19:30:22 +05:30
static struct platform_driver dsps_usbss_driver = {
. probe = dsps_probe ,
2012-11-19 13:21:08 -05:00
. remove = dsps_remove ,
2012-03-12 19:30:22 +05:30
. driver = {
. name = " musb-dsps " ,
2013-11-26 13:31:14 +01:00
. pm = & dsps_pm_ops ,
2013-09-30 09:44:44 +05:30
. of_match_table = musb_dsps_of_match ,
2012-03-12 19:30:22 +05:30
} ,
} ;
MODULE_DESCRIPTION ( " TI DSPS MUSB Glue Layer " ) ;
MODULE_AUTHOR ( " Ravi B <ravibabu@ti.com> " ) ;
MODULE_AUTHOR ( " Ajay Kumar Gupta <ajay.gupta@ti.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2013-07-05 14:51:33 +02:00
module_platform_driver ( dsps_usbss_driver ) ;