2019-08-26 12:19:30 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
2020-12-07 11:32:24 +01:00
* Cadence USBSS and USBSSP DRD Driver .
2019-08-26 12:19:30 +01:00
*
* Copyright ( C ) 2018 - 2019 Cadence .
* Copyright ( C ) 2017 - 2018 NXP
* Copyright ( C ) 2019 Texas Instruments
*
* Author : Peter Chen < peter . chen @ nxp . com >
* Pawel Laszczak < pawell @ cadence . com >
* Roger Quadros < rogerq @ ti . com >
*/
# include <linux/dma-mapping.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/pm_runtime.h>
# include "core.h"
# include "host-export.h"
# include "drd.h"
2020-12-07 11:32:21 +01:00
static int cdns_idle_init ( struct cdns * cdns ) ;
2019-08-26 12:19:30 +01:00
2020-12-07 11:32:21 +01:00
static int cdns_role_start ( struct cdns * cdns , enum usb_role role )
2019-08-26 12:19:30 +01:00
{
int ret ;
if ( WARN_ON ( role > USB_ROLE_DEVICE ) )
return 0 ;
mutex_lock ( & cdns - > mutex ) ;
cdns - > role = role ;
mutex_unlock ( & cdns - > mutex ) ;
if ( ! cdns - > roles [ role ] )
return - ENXIO ;
2020-12-07 11:32:21 +01:00
if ( cdns - > roles [ role ] - > state = = CDNS_ROLE_STATE_ACTIVE )
2019-08-26 12:19:30 +01:00
return 0 ;
mutex_lock ( & cdns - > mutex ) ;
ret = cdns - > roles [ role ] - > start ( cdns ) ;
if ( ! ret )
2020-12-07 11:32:21 +01:00
cdns - > roles [ role ] - > state = CDNS_ROLE_STATE_ACTIVE ;
2019-08-26 12:19:30 +01:00
mutex_unlock ( & cdns - > mutex ) ;
return ret ;
}
2020-12-07 11:32:21 +01:00
static void cdns_role_stop ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
enum usb_role role = cdns - > role ;
if ( WARN_ON ( role > USB_ROLE_DEVICE ) )
return ;
2020-12-07 11:32:21 +01:00
if ( cdns - > roles [ role ] - > state = = CDNS_ROLE_STATE_INACTIVE )
2019-08-26 12:19:30 +01:00
return ;
mutex_lock ( & cdns - > mutex ) ;
cdns - > roles [ role ] - > stop ( cdns ) ;
2020-12-07 11:32:21 +01:00
cdns - > roles [ role ] - > state = CDNS_ROLE_STATE_INACTIVE ;
2019-08-26 12:19:30 +01:00
mutex_unlock ( & cdns - > mutex ) ;
}
2020-12-07 11:32:21 +01:00
static void cdns_exit_roles ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
2020-12-07 11:32:21 +01:00
cdns_role_stop ( cdns ) ;
cdns_drd_exit ( cdns ) ;
2019-08-26 12:19:30 +01:00
}
/**
2020-12-07 11:32:21 +01:00
* cdns_core_init_role - initialize role of operation
* @ cdns : Pointer to cdns structure
2019-08-26 12:19:30 +01:00
*
* Returns 0 on success otherwise negative errno
*/
2020-12-07 11:32:21 +01:00
static int cdns_core_init_role ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
struct device * dev = cdns - > dev ;
enum usb_dr_mode best_dr_mode ;
enum usb_dr_mode dr_mode ;
2020-07-13 12:05:47 +02:00
int ret ;
2019-08-26 12:19:30 +01:00
dr_mode = usb_get_dr_mode ( dev ) ;
cdns - > role = USB_ROLE_NONE ;
/*
* If driver can ' t read mode by means of usb_get_dr_mode function then
* chooses mode according with Kernel configuration . This setting
* can be restricted later depending on strap pin configuration .
*/
if ( dr_mode = = USB_DR_MODE_UNKNOWN ) {
2020-12-07 11:32:18 +01:00
if ( cdns - > version = = CDNSP_CONTROLLER_V2 ) {
if ( IS_ENABLED ( CONFIG_USB_CDNSP_HOST ) & &
IS_ENABLED ( CONFIG_USB_CDNSP_GADGET ) )
dr_mode = USB_DR_MODE_OTG ;
else if ( IS_ENABLED ( CONFIG_USB_CDNSP_HOST ) )
dr_mode = USB_DR_MODE_HOST ;
else if ( IS_ENABLED ( CONFIG_USB_CDNSP_GADGET ) )
dr_mode = USB_DR_MODE_PERIPHERAL ;
} else {
if ( IS_ENABLED ( CONFIG_USB_CDNS3_HOST ) & &
IS_ENABLED ( CONFIG_USB_CDNS3_GADGET ) )
dr_mode = USB_DR_MODE_OTG ;
else if ( IS_ENABLED ( CONFIG_USB_CDNS3_HOST ) )
dr_mode = USB_DR_MODE_HOST ;
else if ( IS_ENABLED ( CONFIG_USB_CDNS3_GADGET ) )
dr_mode = USB_DR_MODE_PERIPHERAL ;
}
2019-08-26 12:19:30 +01:00
}
/*
* At this point cdns - > dr_mode contains strap configuration .
* Driver try update this setting considering kernel configuration
*/
best_dr_mode = cdns - > dr_mode ;
2020-12-07 11:32:21 +01:00
ret = cdns_idle_init ( cdns ) ;
2019-08-26 12:19:30 +01:00
if ( ret )
return ret ;
if ( dr_mode = = USB_DR_MODE_OTG ) {
best_dr_mode = cdns - > dr_mode ;
} else if ( cdns - > dr_mode = = USB_DR_MODE_OTG ) {
best_dr_mode = dr_mode ;
} else if ( cdns - > dr_mode ! = dr_mode ) {
dev_err ( dev , " Incorrect DRD configuration \n " ) ;
return - EINVAL ;
}
dr_mode = best_dr_mode ;
if ( dr_mode = = USB_DR_MODE_OTG | | dr_mode = = USB_DR_MODE_HOST ) {
2020-12-07 11:32:24 +01:00
if ( ( cdns - > version = = CDNSP_CONTROLLER_V2 & &
IS_ENABLED ( CONFIG_USB_CDNSP_HOST ) ) | |
( cdns - > version < CDNSP_CONTROLLER_V2 & &
IS_ENABLED ( CONFIG_USB_CDNS3_HOST ) ) )
ret = cdns_host_init ( cdns ) ;
else
ret = - ENXIO ;
2019-08-26 12:19:30 +01:00
if ( ret ) {
dev_err ( dev , " Host initialization failed with %d \n " ,
ret ) ;
goto err ;
}
}
if ( dr_mode = = USB_DR_MODE_OTG | | dr_mode = = USB_DR_MODE_PERIPHERAL ) {
2020-12-07 11:32:20 +01:00
if ( cdns - > gadget_init )
ret = cdns - > gadget_init ( cdns ) ;
else
ret = - ENXIO ;
2019-08-26 12:19:30 +01:00
if ( ret ) {
dev_err ( dev , " Device initialization failed with %d \n " ,
ret ) ;
goto err ;
}
}
cdns - > dr_mode = dr_mode ;
2020-12-07 11:32:21 +01:00
ret = cdns_drd_update_mode ( cdns ) ;
2019-08-26 12:19:30 +01:00
if ( ret )
goto err ;
2019-10-07 15:16:00 +03:00
/* Initialize idle role to start with */
2020-12-07 11:32:21 +01:00
ret = cdns_role_start ( cdns , USB_ROLE_NONE ) ;
2019-10-07 15:16:00 +03:00
if ( ret )
goto err ;
switch ( cdns - > dr_mode ) {
case USB_DR_MODE_OTG :
2020-12-07 11:32:21 +01:00
ret = cdns_hw_role_switch ( cdns ) ;
2019-08-26 12:19:30 +01:00
if ( ret )
goto err ;
2019-10-07 15:16:00 +03:00
break ;
case USB_DR_MODE_PERIPHERAL :
2020-12-07 11:32:21 +01:00
ret = cdns_role_start ( cdns , USB_ROLE_DEVICE ) ;
2019-10-07 15:16:00 +03:00
if ( ret )
goto err ;
break ;
case USB_DR_MODE_HOST :
2020-12-07 11:32:21 +01:00
ret = cdns_role_start ( cdns , USB_ROLE_HOST ) ;
2019-10-07 15:16:00 +03:00
if ( ret )
goto err ;
break ;
2019-10-17 10:58:01 +03:00
default :
ret = - EINVAL ;
goto err ;
2019-08-26 12:19:30 +01:00
}
2020-07-13 12:05:47 +02:00
return 0 ;
2019-08-26 12:19:30 +01:00
err :
2020-12-07 11:32:21 +01:00
cdns_exit_roles ( cdns ) ;
2019-08-26 12:19:30 +01:00
return ret ;
}
/**
2020-12-07 11:32:21 +01:00
* cdns_hw_role_state_machine - role switch state machine based on hw events .
2019-08-26 12:19:30 +01:00
* @ cdns : Pointer to controller structure .
*
* Returns next role to be entered based on hw events .
*/
2020-12-07 11:32:21 +01:00
static enum usb_role cdns_hw_role_state_machine ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
2020-07-13 12:05:52 +02:00
enum usb_role role = USB_ROLE_NONE ;
2019-08-26 12:19:30 +01:00
int id , vbus ;
2020-07-13 12:05:52 +02:00
if ( cdns - > dr_mode ! = USB_DR_MODE_OTG ) {
2020-12-07 11:32:21 +01:00
if ( cdns_is_host ( cdns ) )
2020-07-13 12:05:52 +02:00
role = USB_ROLE_HOST ;
2020-12-07 11:32:21 +01:00
if ( cdns_is_device ( cdns ) )
2020-07-13 12:05:52 +02:00
role = USB_ROLE_DEVICE ;
return role ;
}
2019-08-26 12:19:30 +01:00
2020-12-07 11:32:21 +01:00
id = cdns_get_id ( cdns ) ;
vbus = cdns_get_vbus ( cdns ) ;
2019-08-26 12:19:30 +01:00
/*
* Role change state machine
* Inputs : ID , VBUS
* Previous state : cdns - > role
* Next state : role
*/
role = cdns - > role ;
switch ( role ) {
case USB_ROLE_NONE :
/*
* Driver treats USB_ROLE_NONE synonymous to IDLE state from
* controller specification .
*/
if ( ! id )
role = USB_ROLE_HOST ;
else if ( vbus )
role = USB_ROLE_DEVICE ;
break ;
case USB_ROLE_HOST : /* from HOST, we can only change to NONE */
if ( id )
role = USB_ROLE_NONE ;
break ;
case USB_ROLE_DEVICE : /* from GADGET, we can only change to NONE*/
if ( ! vbus )
role = USB_ROLE_NONE ;
break ;
}
dev_dbg ( cdns - > dev , " role %d -> %d \n " , cdns - > role , role ) ;
return role ;
}
2020-12-07 11:32:21 +01:00
static int cdns_idle_role_start ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
return 0 ;
}
2020-12-07 11:32:21 +01:00
static void cdns_idle_role_stop ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
/* Program Lane swap and bring PHY out of RESET */
phy_reset ( cdns - > usb3_phy ) ;
}
2020-12-07 11:32:21 +01:00
static int cdns_idle_init ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
2020-12-07 11:32:21 +01:00
struct cdns_role_driver * rdrv ;
2019-08-26 12:19:30 +01:00
rdrv = devm_kzalloc ( cdns - > dev , sizeof ( * rdrv ) , GFP_KERNEL ) ;
if ( ! rdrv )
return - ENOMEM ;
2020-12-07 11:32:21 +01:00
rdrv - > start = cdns_idle_role_start ;
rdrv - > stop = cdns_idle_role_stop ;
rdrv - > state = CDNS_ROLE_STATE_INACTIVE ;
2019-08-26 12:19:30 +01:00
rdrv - > suspend = NULL ;
rdrv - > resume = NULL ;
rdrv - > name = " idle " ;
cdns - > roles [ USB_ROLE_NONE ] = rdrv ;
return 0 ;
}
/**
2020-12-07 11:32:21 +01:00
* cdns_hw_role_switch - switch roles based on HW state
2020-07-02 15:46:08 +01:00
* @ cdns : controller
2019-08-26 12:19:30 +01:00
*/
2020-12-07 11:32:21 +01:00
int cdns_hw_role_switch ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
enum usb_role real_role , current_role ;
int ret = 0 ;
2020-09-01 10:33:48 +08:00
/* Depends on role switch class */
if ( cdns - > role_sw )
return 0 ;
2019-08-26 12:19:30 +01:00
pm_runtime_get_sync ( cdns - > dev ) ;
current_role = cdns - > role ;
2020-12-07 11:32:21 +01:00
real_role = cdns_hw_role_state_machine ( cdns ) ;
2019-08-26 12:19:30 +01:00
/* Do nothing if nothing changed */
if ( current_role = = real_role )
goto exit ;
2020-12-07 11:32:21 +01:00
cdns_role_stop ( cdns ) ;
2019-08-26 12:19:30 +01:00
dev_dbg ( cdns - > dev , " Switching role %d -> %d " , current_role , real_role ) ;
2020-12-07 11:32:21 +01:00
ret = cdns_role_start ( cdns , real_role ) ;
2019-08-26 12:19:30 +01:00
if ( ret ) {
/* Back to current role */
dev_err ( cdns - > dev , " set %d has failed, back to %d \n " ,
real_role , current_role ) ;
2020-12-07 11:32:21 +01:00
ret = cdns_role_start ( cdns , current_role ) ;
2019-08-26 12:19:30 +01:00
if ( ret )
dev_err ( cdns - > dev , " back to %d failed too \n " ,
current_role ) ;
}
exit :
pm_runtime_put_sync ( cdns - > dev ) ;
return ret ;
}
/**
* cdsn3_role_get - get current role of controller .
*
2020-07-02 15:46:08 +01:00
* @ sw : pointer to USB role switch structure
2019-08-26 12:19:30 +01:00
*
* Returns role
*/
2020-12-07 11:32:21 +01:00
static enum usb_role cdns_role_get ( struct usb_role_switch * sw )
2019-08-26 12:19:30 +01:00
{
2020-12-07 11:32:21 +01:00
struct cdns * cdns = usb_role_switch_get_drvdata ( sw ) ;
2019-08-26 12:19:30 +01:00
return cdns - > role ;
}
/**
2020-12-07 11:32:21 +01:00
* cdns_role_set - set current role of controller .
2019-08-26 12:19:30 +01:00
*
2020-07-02 15:46:08 +01:00
* @ sw : pointer to USB role switch structure
* @ role : the previous role
2019-08-26 12:19:30 +01:00
* Handles below events :
* - Role switch for dual - role devices
* - USB_ROLE_GADGET < - - > USB_ROLE_NONE for peripheral - only devices
*/
2020-12-07 11:32:21 +01:00
static int cdns_role_set ( struct usb_role_switch * sw , enum usb_role role )
2019-08-26 12:19:30 +01:00
{
2020-12-07 11:32:21 +01:00
struct cdns * cdns = usb_role_switch_get_drvdata ( sw ) ;
2019-08-26 12:19:30 +01:00
int ret = 0 ;
pm_runtime_get_sync ( cdns - > dev ) ;
if ( cdns - > role = = role )
goto pm_put ;
if ( cdns - > dr_mode = = USB_DR_MODE_HOST ) {
switch ( role ) {
case USB_ROLE_NONE :
case USB_ROLE_HOST :
break ;
default :
goto pm_put ;
}
}
if ( cdns - > dr_mode = = USB_DR_MODE_PERIPHERAL ) {
switch ( role ) {
case USB_ROLE_NONE :
case USB_ROLE_DEVICE :
break ;
default :
goto pm_put ;
}
}
2020-12-07 11:32:21 +01:00
cdns_role_stop ( cdns ) ;
ret = cdns_role_start ( cdns , role ) ;
2020-07-13 12:05:53 +02:00
if ( ret )
2019-08-26 12:19:30 +01:00
dev_err ( cdns - > dev , " set role %d has failed \n " , role ) ;
pm_put :
pm_runtime_put_sync ( cdns - > dev ) ;
return ret ;
}
2020-09-02 17:57:31 +08:00
2020-09-02 17:57:32 +08:00
/**
2020-12-07 11:32:21 +01:00
* cdns_wakeup_irq - interrupt handler for wakeup events
* @ irq : irq number for cdns3 / cdnsp core device
* @ data : structure of cdns
2020-09-02 17:57:32 +08:00
*
* Returns IRQ_HANDLED or IRQ_NONE
*/
2020-12-07 11:32:21 +01:00
static irqreturn_t cdns_wakeup_irq ( int irq , void * data )
2020-09-02 17:57:32 +08:00
{
2020-12-07 11:32:21 +01:00
struct cdns * cdns = data ;
2020-09-02 17:57:32 +08:00
if ( cdns - > in_lpm ) {
disable_irq_nosync ( irq ) ;
cdns - > wakeup_pending = true ;
if ( ( cdns - > role = = USB_ROLE_HOST ) & & cdns - > host_dev )
pm_request_resume ( & cdns - > host_dev - > dev ) ;
return IRQ_HANDLED ;
}
return IRQ_NONE ;
}
2019-08-26 12:19:30 +01:00
/**
2020-12-07 11:32:21 +01:00
* cdns_probe - probe for cdns3 / cdnsp core device
* @ cdns : Pointer to cdns structure .
2019-08-26 12:19:30 +01:00
*
* Returns 0 on success otherwise negative errno
*/
2020-12-07 11:32:21 +01:00
int cdns_init ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
2020-12-07 11:32:19 +01:00
struct device * dev = cdns - > dev ;
2019-08-26 12:19:30 +01:00
int ret ;
ret = dma_set_mask_and_coherent ( dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret ) {
dev_err ( dev , " error setting dma mask: %d \n " , ret ) ;
2020-07-13 12:05:53 +02:00
return ret ;
2019-08-26 12:19:30 +01:00
}
mutex_init ( & cdns - > mutex ) ;
2020-11-25 14:49:36 +02:00
if ( device_property_read_bool ( dev , " usb-role-switch " ) ) {
struct usb_role_switch_desc sw_desc = { } ;
2020-12-07 11:32:21 +01:00
sw_desc . set = cdns_role_set ;
sw_desc . get = cdns_role_get ;
2020-11-25 14:49:36 +02:00
sw_desc . allow_userspace_control = true ;
sw_desc . driver_data = cdns ;
2020-03-31 16:10:02 +08:00
sw_desc . fwnode = dev - > fwnode ;
2020-03-02 16:53:49 +03:00
2020-11-25 14:49:36 +02:00
cdns - > role_sw = usb_role_switch_register ( dev , & sw_desc ) ;
if ( IS_ERR ( cdns - > role_sw ) ) {
dev_warn ( dev , " Unable to register Role Switch \n " ) ;
2020-12-07 11:32:19 +01:00
return PTR_ERR ( cdns - > role_sw ) ;
2020-11-25 14:49:36 +02:00
}
2019-08-26 12:19:30 +01:00
}
2020-09-02 17:57:32 +08:00
if ( cdns - > wakeup_irq ) {
ret = devm_request_irq ( cdns - > dev , cdns - > wakeup_irq ,
2020-12-07 11:32:21 +01:00
cdns_wakeup_irq ,
2020-09-02 17:57:32 +08:00
IRQF_SHARED ,
dev_name ( cdns - > dev ) , cdns ) ;
if ( ret ) {
dev_err ( cdns - > dev , " couldn't register wakeup irq handler \n " ) ;
2020-12-07 11:32:19 +01:00
goto role_switch_unregister ;
2020-09-02 17:57:32 +08:00
}
}
2020-12-07 11:32:21 +01:00
ret = cdns_drd_init ( cdns ) ;
2019-08-26 12:19:30 +01:00
if ( ret )
2020-12-07 11:32:19 +01:00
goto init_failed ;
2019-08-26 12:19:30 +01:00
2020-12-07 11:32:21 +01:00
ret = cdns_core_init_role ( cdns ) ;
2019-08-26 12:19:30 +01:00
if ( ret )
2020-12-07 11:32:19 +01:00
goto init_failed ;
2019-08-26 12:19:30 +01:00
2020-09-02 17:57:32 +08:00
spin_lock_init ( & cdns - > lock ) ;
2019-08-26 12:19:30 +01:00
dev_dbg ( dev , " Cadence USB3 core: probe succeed \n " ) ;
return 0 ;
2020-12-07 11:32:19 +01:00
init_failed :
2020-12-07 11:32:21 +01:00
cdns_drd_exit ( cdns ) ;
2020-12-07 11:32:19 +01:00
role_switch_unregister :
2020-11-25 14:49:36 +02:00
if ( cdns - > role_sw )
usb_role_switch_unregister ( cdns - > role_sw ) ;
2019-08-26 12:19:30 +01:00
return ret ;
}
2020-12-07 11:32:21 +01:00
EXPORT_SYMBOL_GPL ( cdns_init ) ;
2019-08-26 12:19:30 +01:00
/**
2020-12-07 11:32:21 +01:00
* cdns_remove - unbind drd driver and clean up
* @ cdns : Pointer to cdns structure .
2019-08-26 12:19:30 +01:00
*
* Returns 0 on success otherwise negative errno
*/
2020-12-07 11:32:21 +01:00
int cdns_remove ( struct cdns * cdns )
2019-08-26 12:19:30 +01:00
{
2020-12-07 11:32:21 +01:00
cdns_exit_roles ( cdns ) ;
2019-08-26 12:19:30 +01:00
usb_role_switch_unregister ( cdns - > role_sw ) ;
return 0 ;
}
2020-12-07 11:32:21 +01:00
EXPORT_SYMBOL_GPL ( cdns_remove ) ;
2019-08-26 12:19:30 +01:00
2020-09-02 17:57:32 +08:00
# ifdef CONFIG_PM_SLEEP
2020-12-07 11:32:21 +01:00
int cdns_suspend ( struct cdns * cdns )
2020-09-02 17:57:32 +08:00
{
2020-12-07 11:32:19 +01:00
struct device * dev = cdns - > dev ;
2020-09-02 17:57:32 +08:00
unsigned long flags ;
if ( pm_runtime_status_suspended ( dev ) )
pm_runtime_resume ( dev ) ;
if ( cdns - > roles [ cdns - > role ] - > suspend ) {
spin_lock_irqsave ( & cdns - > lock , flags ) ;
cdns - > roles [ cdns - > role ] - > suspend ( cdns , false ) ;
spin_unlock_irqrestore ( & cdns - > lock , flags ) ;
2019-08-26 12:19:30 +01:00
}
2020-12-07 11:32:19 +01:00
return 0 ;
2020-09-02 17:57:32 +08:00
}
2020-12-07 11:32:21 +01:00
EXPORT_SYMBOL_GPL ( cdns_suspend ) ;
2020-09-02 17:57:32 +08:00
2020-12-07 11:32:21 +01:00
int cdns_resume ( struct cdns * cdns , u8 set_active )
2020-09-02 17:57:32 +08:00
{
2020-12-07 11:32:19 +01:00
struct device * dev = cdns - > dev ;
2020-09-02 17:57:32 +08:00
2020-12-07 11:32:19 +01:00
if ( cdns - > roles [ cdns - > role ] - > resume )
cdns - > roles [ cdns - > role ] - > resume ( cdns , false ) ;
2020-09-02 17:57:32 +08:00
2020-12-07 11:32:19 +01:00
if ( set_active ) {
pm_runtime_disable ( dev ) ;
pm_runtime_set_active ( dev ) ;
pm_runtime_enable ( dev ) ;
}
2019-08-26 12:19:30 +01:00
2020-12-07 11:32:19 +01:00
return 0 ;
2019-08-26 12:19:30 +01:00
}
2020-12-07 11:32:21 +01:00
EXPORT_SYMBOL_GPL ( cdns_resume ) ;
2020-09-02 17:57:32 +08:00
# endif /* CONFIG_PM_SLEEP */
2020-12-07 11:32:20 +01:00
MODULE_AUTHOR ( " Peter Chen <peter.chen@nxp.com> " ) ;
MODULE_AUTHOR ( " Pawel Laszczak <pawell@cadence.com> " ) ;
MODULE_AUTHOR ( " Roger Quadros <rogerq@ti.com> " ) ;
MODULE_DESCRIPTION ( " Cadence USBSS and USBSSP DRD Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;