2012-07-16 17:31:08 +04:00
/**
* omap - usb - tll . c - The USB TLL driver for OMAP EHCI & OHCI
*
2013-01-29 17:00:03 +04:00
* Copyright ( C ) 2012 - 2013 Texas Instruments Incorporated - http : //www.ti.com
2012-07-16 17:31:08 +04:00
* Author : Keshava Munegowda < keshava_mgowda @ ti . com >
2013-01-29 17:00:03 +04:00
* Author : Roger Quadros < rogerq @ ti . com >
2012-07-16 17:31:08 +04:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/platform_device.h>
# include <linux/clk.h>
# include <linux/io.h>
# include <linux/err.h>
# include <linux/pm_runtime.h>
2012-10-25 01:26:19 +04:00
# include <linux/platform_data/usb-omap.h>
2013-01-29 17:20:55 +04:00
# include <linux/of.h>
2012-07-16 17:31:08 +04:00
2016-06-08 21:06:20 +03:00
# include "omap-usb.h"
2012-07-16 17:31:08 +04:00
# define USBTLL_DRIVER_NAME "usbhs_tll"
/* TLL Register Set */
# define OMAP_USBTLL_REVISION (0x00)
# define OMAP_USBTLL_SYSCONFIG (0x10)
# define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8)
# define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3)
# define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2)
# define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1)
# define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0)
# define OMAP_USBTLL_SYSSTATUS (0x14)
# define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0)
# define OMAP_USBTLL_IRQSTATUS (0x18)
# define OMAP_USBTLL_IRQENABLE (0x1C)
# define OMAP_TLL_SHARED_CONF (0x30)
# define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6)
# define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5)
# define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2)
# define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1)
# define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0)
# define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num)
# define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24
2012-11-08 18:10:41 +04:00
# define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16)
# define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15)
2012-07-16 17:31:08 +04:00
# define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11)
# define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10)
# define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9)
# define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8)
2012-11-08 18:10:41 +04:00
# define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI (2 << 1)
2012-07-16 17:31:08 +04:00
# define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1)
# define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
# define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0
# define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1
# define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2
# define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3
# define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4
# define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5
# define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6
# define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7
# define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA
# define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB
# define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num)
# define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num)
# define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num)
# define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num)
# define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num)
# define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num)
# define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num)
# define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num)
# define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num)
# define OMAP_REV2_TLL_CHANNEL_COUNT 2
# define OMAP_TLL_CHANNEL_COUNT 3
# define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0)
# define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1)
# define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2)
/* Values of USBTLL_REVISION - Note: these are not given in the TRM */
# define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */
# define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */
# define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */
2012-11-08 18:10:41 +04:00
# define OMAP_USBTLL_REV4 0x00000006 /* OMAP5 */
2012-07-16 17:31:08 +04:00
# define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
2012-11-08 16:40:45 +04:00
/* only PHY and UNUSED modes don't need TLL */
# define omap_usb_mode_needs_tll(x) ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\
( x ) ! = OMAP_EHCI_PORT_MODE_PHY )
2012-07-16 17:31:08 +04:00
struct usbtll_omap {
2012-11-26 14:28:44 +04:00
int nch ; /* num. of channels */
2012-11-08 15:07:09 +04:00
struct clk * * ch_clk ;
2013-01-29 17:00:03 +04:00
void __iomem * base ;
2012-07-16 17:31:08 +04:00
} ;
/*-------------------------------------------------------------------------*/
2012-11-26 17:26:28 +04:00
static const char usbtll_driver_name [ ] = USBTLL_DRIVER_NAME ;
static struct device * tll_dev ;
2012-11-26 18:56:26 +04:00
static DEFINE_SPINLOCK ( tll_lock ) ; /* serialize access to tll_dev */
2012-07-16 17:31:08 +04:00
/*-------------------------------------------------------------------------*/
static inline void usbtll_write ( void __iomem * base , u32 reg , u32 val )
{
2013-11-16 04:01:15 +04:00
writel_relaxed ( val , base + reg ) ;
2012-07-16 17:31:08 +04:00
}
static inline u32 usbtll_read ( void __iomem * base , u32 reg )
{
2013-11-16 04:01:15 +04:00
return readl_relaxed ( base + reg ) ;
2012-07-16 17:31:08 +04:00
}
static inline void usbtll_writeb ( void __iomem * base , u8 reg , u8 val )
{
2013-11-16 04:01:15 +04:00
writeb_relaxed ( val , base + reg ) ;
2012-07-16 17:31:08 +04:00
}
static inline u8 usbtll_readb ( void __iomem * base , u8 reg )
{
2013-11-16 04:01:15 +04:00
return readb_relaxed ( base + reg ) ;
2012-07-16 17:31:08 +04:00
}
/*-------------------------------------------------------------------------*/
static bool is_ohci_port ( enum usbhs_omap_port_mode pmode )
{
switch ( pmode ) {
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0 :
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM :
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0 :
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM :
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0 :
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM :
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0 :
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM :
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0 :
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM :
return true ;
default :
return false ;
}
}
/*
* convert the port - mode enum to a value we can use in the FSLSMODE
* field of USBTLL_CHANNEL_CONF
*/
static unsigned ohci_omap3_fslsmode ( enum usbhs_omap_port_mode mode )
{
switch ( mode ) {
case OMAP_USBHS_PORT_MODE_UNUSED :
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0 :
return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 ;
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM :
return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM ;
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0 :
return OMAP_TLL_FSLSMODE_3PIN_PHY ;
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM :
return OMAP_TLL_FSLSMODE_4PIN_PHY ;
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0 :
return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 ;
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM :
return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM ;
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0 :
return OMAP_TLL_FSLSMODE_3PIN_TLL ;
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM :
return OMAP_TLL_FSLSMODE_4PIN_TLL ;
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0 :
return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 ;
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM :
return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM ;
default :
pr_warn ( " Invalid port mode, using default \n " ) ;
return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 ;
}
}
/**
* usbtll_omap_probe - initialize TI - based HCDs
*
* Allocates basic resources for this USB host controller .
*/
2012-11-19 22:23:04 +04:00
static int usbtll_omap_probe ( struct platform_device * pdev )
2012-07-16 17:31:08 +04:00
{
struct device * dev = & pdev - > dev ;
struct resource * res ;
struct usbtll_omap * tll ;
int ret = 0 ;
2012-11-26 14:28:44 +04:00
int i , ver ;
2012-07-16 17:31:08 +04:00
dev_dbg ( dev , " starting TI HSUSB TLL Controller \n " ) ;
2012-11-26 14:56:37 +04:00
tll = devm_kzalloc ( dev , sizeof ( struct usbtll_omap ) , GFP_KERNEL ) ;
2012-07-16 17:31:08 +04:00
if ( ! tll ) {
dev_err ( dev , " Memory allocation failed \n " ) ;
2012-11-26 14:56:37 +04:00
return - ENOMEM ;
2012-07-16 17:31:08 +04:00
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-04-09 14:46:37 +04:00
tll - > base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( tll - > base ) )
return PTR_ERR ( tll - > base ) ;
2012-07-16 17:31:08 +04:00
platform_set_drvdata ( pdev , tll ) ;
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
2013-01-29 17:00:03 +04:00
ver = usbtll_read ( tll - > base , OMAP_USBTLL_REVISION ) ;
2012-07-16 17:31:08 +04:00
switch ( ver ) {
case OMAP_USBTLL_REV1 :
2012-11-08 18:10:41 +04:00
case OMAP_USBTLL_REV4 :
2012-11-26 14:28:44 +04:00
tll - > nch = OMAP_TLL_CHANNEL_COUNT ;
2012-07-16 17:31:08 +04:00
break ;
2012-11-26 14:28:44 +04:00
case OMAP_USBTLL_REV2 :
2012-07-16 17:31:08 +04:00
case OMAP_USBTLL_REV3 :
2012-11-26 14:28:44 +04:00
tll - > nch = OMAP_REV2_TLL_CHANNEL_COUNT ;
2012-07-16 17:31:08 +04:00
break ;
default :
2012-11-26 14:28:44 +04:00
tll - > nch = OMAP_TLL_CHANNEL_COUNT ;
dev_dbg ( dev ,
" USB TLL Rev : 0x%x not recognized, assuming %d channels \n " ,
ver , tll - > nch ) ;
break ;
2012-07-16 17:31:08 +04:00
}
2014-02-11 13:38:53 +04:00
tll - > ch_clk = devm_kzalloc ( dev , sizeof ( struct clk * ) * tll - > nch ,
2012-11-08 15:07:09 +04:00
GFP_KERNEL ) ;
if ( ! tll - > ch_clk ) {
ret = - ENOMEM ;
dev_err ( dev , " Couldn't allocate memory for channel clocks \n " ) ;
goto err_clk_alloc ;
}
for ( i = 0 ; i < tll - > nch ; i + + ) {
char clkname [ ] = " usb_tll_hs_usb_chx_clk " ;
snprintf ( clkname , sizeof ( clkname ) ,
" usb_tll_hs_usb_ch%d_clk " , i ) ;
tll - > ch_clk [ i ] = clk_get ( dev , clkname ) ;
if ( IS_ERR ( tll - > ch_clk [ i ] ) )
dev_dbg ( dev , " can't get clock : %s \n " , clkname ) ;
2016-05-09 11:28:37 +03:00
else
clk_prepare ( tll - > ch_clk [ i ] ) ;
2012-11-08 15:07:09 +04:00
}
2013-01-29 17:00:03 +04:00
pm_runtime_put_sync ( dev ) ;
/* only after this can omap_tll_enable/disable work */
spin_lock ( & tll_lock ) ;
tll_dev = dev ;
spin_unlock ( & tll_lock ) ;
return 0 ;
err_clk_alloc :
pm_runtime_put_sync ( dev ) ;
pm_runtime_disable ( dev ) ;
return ret ;
}
/**
* usbtll_omap_remove - shutdown processing for UHH & TLL HCDs
* @ pdev : USB Host Controller being removed
*
* Reverses the effect of usbtll_omap_probe ( ) .
*/
static int usbtll_omap_remove ( struct platform_device * pdev )
{
struct usbtll_omap * tll = platform_get_drvdata ( pdev ) ;
int i ;
spin_lock ( & tll_lock ) ;
tll_dev = NULL ;
spin_unlock ( & tll_lock ) ;
2016-05-09 11:28:37 +03:00
for ( i = 0 ; i < tll - > nch ; i + + ) {
if ( ! IS_ERR ( tll - > ch_clk [ i ] ) ) {
clk_unprepare ( tll - > ch_clk [ i ] ) ;
2013-01-29 17:00:03 +04:00
clk_put ( tll - > ch_clk [ i ] ) ;
2016-05-09 11:28:37 +03:00
}
}
2013-01-29 17:00:03 +04:00
pm_runtime_disable ( & pdev - > dev ) ;
return 0 ;
}
2013-01-29 17:20:55 +04:00
static const struct of_device_id usbtll_omap_dt_ids [ ] = {
{ . compatible = " ti,usbhs-tll " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , usbtll_omap_dt_ids ) ;
2013-01-29 17:00:03 +04:00
static struct platform_driver usbtll_omap_driver = {
. driver = {
. name = ( char * ) usbtll_driver_name ,
2013-10-15 07:48:50 +04:00
. of_match_table = usbtll_omap_dt_ids ,
2013-01-29 17:00:03 +04:00
} ,
. probe = usbtll_omap_probe ,
. remove = usbtll_omap_remove ,
} ;
int omap_tll_init ( struct usbhs_omap_platform_data * pdata )
{
int i ;
bool needs_tll ;
unsigned reg ;
struct usbtll_omap * tll ;
2014-01-08 11:15:33 +04:00
if ( ! tll_dev )
2013-01-29 17:00:03 +04:00
return - ENODEV ;
2014-01-08 11:15:33 +04:00
pm_runtime_get_sync ( tll_dev ) ;
2013-01-29 17:00:03 +04:00
2014-01-08 11:15:33 +04:00
spin_lock ( & tll_lock ) ;
tll = dev_get_drvdata ( tll_dev ) ;
2012-11-08 16:40:45 +04:00
needs_tll = false ;
for ( i = 0 ; i < tll - > nch ; i + + )
needs_tll | = omap_usb_mode_needs_tll ( pdata - > port_mode [ i ] ) ;
if ( needs_tll ) {
2013-01-29 17:00:03 +04:00
void __iomem * base = tll - > base ;
2012-07-16 17:31:08 +04:00
/* Program Common TLL register */
reg = usbtll_read ( base , OMAP_TLL_SHARED_CONF ) ;
reg | = ( OMAP_TLL_SHARED_CONF_FCLK_IS_ON
| OMAP_TLL_SHARED_CONF_USB_DIVRATION ) ;
reg & = ~ OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN ;
reg & = ~ OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN ;
usbtll_write ( base , OMAP_TLL_SHARED_CONF , reg ) ;
/* Enable channels now */
2012-11-26 14:28:44 +04:00
for ( i = 0 ; i < tll - > nch ; i + + ) {
2012-07-16 17:31:08 +04:00
reg = usbtll_read ( base , OMAP_TLL_CHANNEL_CONF ( i ) ) ;
if ( is_ohci_port ( pdata - > port_mode [ i ] ) ) {
reg | = ohci_omap3_fslsmode ( pdata - > port_mode [ i ] )
< < OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT ;
reg | = OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS ;
} else if ( pdata - > port_mode [ i ] = =
OMAP_EHCI_PORT_MODE_TLL ) {
/*
2017-04-15 20:05:09 +03:00
* Disable UTMI AutoIdle , BitStuffing
* and use SDR Mode . Enable ULPI AutoIdle .
2012-07-16 17:31:08 +04:00
*/
reg & = ~ ( OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE ) ;
2017-04-15 20:05:08 +03:00
reg | = OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF ;
2017-04-15 20:05:09 +03:00
reg | = OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE ;
2012-11-08 18:10:41 +04:00
} else if ( pdata - > port_mode [ i ] = =
OMAP_EHCI_PORT_MODE_HSIC ) {
/*
* HSIC Mode requires UTMI port configurations
*/
reg | = OMAP_TLL_CHANNEL_CONF_DRVVBUS
| OMAP_TLL_CHANNEL_CONF_CHRGVBUS
| OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF ;
2012-07-16 17:31:08 +04:00
} else {
continue ;
}
reg | = OMAP_TLL_CHANNEL_CONF_CHANEN ;
usbtll_write ( base , OMAP_TLL_CHANNEL_CONF ( i ) , reg ) ;
usbtll_writeb ( base ,
OMAP_TLL_ULPI_SCRATCH_REGISTER ( i ) ,
0xbe ) ;
}
}
2012-11-26 18:56:26 +04:00
spin_unlock ( & tll_lock ) ;
2014-01-08 11:15:33 +04:00
pm_runtime_put_sync ( tll_dev ) ;
2012-07-16 17:31:08 +04:00
2012-11-26 14:56:37 +04:00
return 0 ;
2012-07-16 17:31:08 +04:00
}
2013-01-29 17:00:03 +04:00
EXPORT_SYMBOL_GPL ( omap_tll_init ) ;
2012-07-16 17:31:08 +04:00
2013-01-29 17:00:03 +04:00
int omap_tll_enable ( struct usbhs_omap_platform_data * pdata )
2012-07-16 17:31:08 +04:00
{
2012-11-08 15:07:09 +04:00
int i ;
2013-01-29 17:00:03 +04:00
struct usbtll_omap * tll ;
2012-11-08 15:07:09 +04:00
2014-01-08 11:15:33 +04:00
if ( ! tll_dev )
2013-01-29 17:00:03 +04:00
return - ENODEV ;
2012-07-16 17:31:08 +04:00
2013-01-29 17:00:03 +04:00
pm_runtime_get_sync ( tll_dev ) ;
2012-07-16 17:31:08 +04:00
2014-01-08 11:15:33 +04:00
spin_lock ( & tll_lock ) ;
tll = dev_get_drvdata ( tll_dev ) ;
2012-11-08 15:07:09 +04:00
for ( i = 0 ; i < tll - > nch ; i + + ) {
2012-11-08 16:40:45 +04:00
if ( omap_usb_mode_needs_tll ( pdata - > port_mode [ i ] ) ) {
2012-11-08 15:07:09 +04:00
int r ;
2012-07-16 17:31:08 +04:00
2012-11-08 15:07:09 +04:00
if ( IS_ERR ( tll - > ch_clk [ i ] ) )
continue ;
2016-05-09 11:28:37 +03:00
r = clk_enable ( tll - > ch_clk [ i ] ) ;
2012-11-08 15:07:09 +04:00
if ( r ) {
2013-01-29 17:00:03 +04:00
dev_err ( tll_dev ,
2012-11-08 15:07:09 +04:00
" Error enabling ch %d clock: %d \n " , i , r ) ;
}
}
}
2012-07-16 17:31:08 +04:00
2013-01-29 17:00:03 +04:00
spin_unlock ( & tll_lock ) ;
2012-07-16 17:31:08 +04:00
return 0 ;
}
2013-01-29 17:00:03 +04:00
EXPORT_SYMBOL_GPL ( omap_tll_enable ) ;
2012-07-16 17:31:08 +04:00
2013-01-29 17:00:03 +04:00
int omap_tll_disable ( struct usbhs_omap_platform_data * pdata )
2012-07-16 17:31:08 +04:00
{
2012-11-08 15:07:09 +04:00
int i ;
2013-01-29 17:00:03 +04:00
struct usbtll_omap * tll ;
2014-01-08 11:15:33 +04:00
if ( ! tll_dev )
2013-01-29 17:00:03 +04:00
return - ENODEV ;
2012-07-16 17:31:08 +04:00
2014-01-08 11:15:33 +04:00
spin_lock ( & tll_lock ) ;
2013-01-29 17:00:03 +04:00
tll = dev_get_drvdata ( tll_dev ) ;
2012-07-16 17:31:08 +04:00
2012-11-08 15:07:09 +04:00
for ( i = 0 ; i < tll - > nch ; i + + ) {
2012-11-08 16:40:45 +04:00
if ( omap_usb_mode_needs_tll ( pdata - > port_mode [ i ] ) ) {
2012-11-08 15:07:09 +04:00
if ( ! IS_ERR ( tll - > ch_clk [ i ] ) )
2016-05-09 11:28:37 +03:00
clk_disable ( tll - > ch_clk [ i ] ) ;
2012-11-08 15:07:09 +04:00
}
}
2012-07-16 17:31:08 +04:00
2012-11-26 18:56:26 +04:00
spin_unlock ( & tll_lock ) ;
2014-01-08 11:15:33 +04:00
pm_runtime_put_sync ( tll_dev ) ;
2012-11-26 18:56:26 +04:00
2013-01-29 17:00:03 +04:00
return 0 ;
2012-07-16 17:31:08 +04:00
}
EXPORT_SYMBOL_GPL ( omap_tll_disable ) ;
MODULE_AUTHOR ( " Keshava Munegowda <keshava_mgowda@ti.com> " ) ;
2013-01-29 17:20:55 +04:00
MODULE_AUTHOR ( " Roger Quadros <rogerq@ti.com> " ) ;
2012-07-16 17:31:08 +04:00
MODULE_ALIAS ( " platform: " USBHS_DRIVER_NAME ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " usb tll driver for TI OMAP EHCI and OHCI controllers " ) ;
static int __init omap_usbtll_drvinit ( void )
{
return platform_driver_register ( & usbtll_omap_driver ) ;
}
/*
* init before usbhs core driver ;
* The usbtll driver should be initialized before
* the usbhs core driver probe function is called .
*/
fs_initcall ( omap_usbtll_drvinit ) ;
static void __exit omap_usbtll_drvexit ( void )
{
platform_driver_unregister ( & usbtll_omap_driver ) ;
}
module_exit ( omap_usbtll_drvexit ) ;