2010-02-12 22:52:34 +03:00
/*
* OHCI HCD ( Host Controller Driver ) for USB .
*
* TI DA8xx ( OMAP - L1x ) Bus Glue
*
* Derived from : ohci - omap . c and ohci - s3c2410 . c
* Copyright ( C ) 2008 - 2009 MontaVista Software , Inc . < source @ mvista . com >
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed " as is " without any warranty of any
* kind , whether express or implied .
*/
2016-10-27 16:52:29 +03:00
# include <linux/clk.h>
# include <linux/io.h>
2010-02-12 22:52:34 +03:00
# include <linux/interrupt.h>
# include <linux/jiffies.h>
2016-10-27 16:52:29 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
2010-02-12 22:52:34 +03:00
# include <linux/platform_device.h>
2016-10-13 04:44:46 +03:00
# include <linux/phy/phy.h>
2012-08-24 17:11:34 +04:00
# include <linux/platform_data/usb-davinci.h>
2016-11-23 21:06:47 +03:00
# include <linux/regulator/consumer.h>
2016-10-27 16:52:29 +03:00
# include <linux/usb.h>
# include <linux/usb/hcd.h>
# include <asm/unaligned.h>
2010-02-12 22:52:34 +03:00
2016-10-27 16:52:29 +03:00
# include "ohci.h"
# define DRIVER_DESC "DA8XX"
2016-11-03 19:03:08 +03:00
# define DRV_NAME "ohci-da8xx"
2016-10-27 16:52:29 +03:00
static struct hc_driver __read_mostly ohci_da8xx_hc_driver ;
static int ( * orig_ohci_hub_control ) ( struct usb_hcd * hcd , u16 typeReq ,
u16 wValue , u16 wIndex , char * buf , u16 wLength ) ;
static int ( * orig_ohci_hub_status_data ) ( struct usb_hcd * hcd , char * buf ) ;
2010-02-12 22:52:34 +03:00
2016-11-23 21:06:45 +03:00
struct da8xx_ohci_hcd {
2016-11-23 21:06:47 +03:00
struct usb_hcd * hcd ;
2016-11-23 21:06:45 +03:00
struct clk * usb11_clk ;
struct phy * usb11_phy ;
2016-11-23 21:06:47 +03:00
struct regulator * vbus_reg ;
struct notifier_block nb ;
unsigned int reg_enabled ;
2016-11-23 21:06:45 +03:00
} ;
# define to_da8xx_ohci(hcd) (struct da8xx_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
2010-02-12 22:52:34 +03:00
/* Over-current indicator change bitmask */
static volatile u16 ocic_mask ;
2016-11-23 21:06:45 +03:00
static int ohci_da8xx_enable ( struct usb_hcd * hcd )
2010-02-12 22:52:34 +03:00
{
2016-11-23 21:06:45 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-10-13 04:44:46 +03:00
int ret ;
2010-02-12 22:52:34 +03:00
2016-11-23 21:06:45 +03:00
ret = clk_prepare_enable ( da8xx_ohci - > usb11_clk ) ;
2016-10-13 04:44:46 +03:00
if ( ret )
return ret ;
2010-02-12 22:52:34 +03:00
2016-11-23 21:06:45 +03:00
ret = phy_init ( da8xx_ohci - > usb11_phy ) ;
2016-10-13 04:44:46 +03:00
if ( ret )
goto err_phy_init ;
2016-11-23 21:06:45 +03:00
ret = phy_power_on ( da8xx_ohci - > usb11_phy ) ;
2016-10-13 04:44:46 +03:00
if ( ret )
goto err_phy_power_on ;
return 0 ;
err_phy_power_on :
2016-11-23 21:06:45 +03:00
phy_exit ( da8xx_ohci - > usb11_phy ) ;
2016-10-13 04:44:46 +03:00
err_phy_init :
2016-11-23 21:06:45 +03:00
clk_disable_unprepare ( da8xx_ohci - > usb11_clk ) ;
2016-10-13 04:44:46 +03:00
return ret ;
}
2016-11-23 21:06:45 +03:00
static void ohci_da8xx_disable ( struct usb_hcd * hcd )
2016-10-13 04:44:46 +03:00
{
2016-11-23 21:06:45 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
phy_power_off ( da8xx_ohci - > usb11_phy ) ;
phy_exit ( da8xx_ohci - > usb11_phy ) ;
clk_disable_unprepare ( da8xx_ohci - > usb11_clk ) ;
2010-02-12 22:52:34 +03:00
}
2016-11-23 21:06:46 +03:00
static int ohci_da8xx_set_power ( struct usb_hcd * hcd , int on )
{
2016-11-23 21:06:47 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-11-23 21:06:46 +03:00
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
2016-11-23 21:06:47 +03:00
int ret ;
2016-11-23 21:06:46 +03:00
if ( hub & & hub - > set_power )
return hub - > set_power ( 1 , on ) ;
2016-11-23 21:06:47 +03:00
if ( ! da8xx_ohci - > vbus_reg )
return 0 ;
if ( on & & ! da8xx_ohci - > reg_enabled ) {
ret = regulator_enable ( da8xx_ohci - > vbus_reg ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable regulator: %d \n " , ret ) ;
return ret ;
}
da8xx_ohci - > reg_enabled = 1 ;
} else if ( ! on & & da8xx_ohci - > reg_enabled ) {
ret = regulator_disable ( da8xx_ohci - > vbus_reg ) ;
if ( ret ) {
dev_err ( dev , " Failed to disable regulator: %d \n " , ret ) ;
return ret ;
}
da8xx_ohci - > reg_enabled = 0 ;
}
2016-11-23 21:06:46 +03:00
return 0 ;
}
static int ohci_da8xx_get_power ( struct usb_hcd * hcd )
{
2016-11-23 21:06:47 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-11-23 21:06:46 +03:00
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
if ( hub & & hub - > get_power )
return hub - > get_power ( 1 ) ;
2016-11-23 21:06:47 +03:00
if ( da8xx_ohci - > vbus_reg )
return regulator_is_enabled ( da8xx_ohci - > vbus_reg ) ;
2016-11-23 21:06:46 +03:00
return 1 ;
}
static int ohci_da8xx_get_oci ( struct usb_hcd * hcd )
{
2016-11-23 21:06:47 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-11-23 21:06:46 +03:00
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
2016-11-23 21:06:47 +03:00
unsigned int flags ;
int ret ;
2016-11-23 21:06:46 +03:00
if ( hub & & hub - > get_oci )
return hub - > get_oci ( 1 ) ;
2016-11-23 21:06:47 +03:00
if ( ! da8xx_ohci - > vbus_reg )
return 0 ;
ret = regulator_get_error_flags ( da8xx_ohci - > vbus_reg , & flags ) ;
if ( ret )
return ret ;
if ( flags & REGULATOR_ERROR_OVER_CURRENT )
return 1 ;
2016-11-23 21:06:46 +03:00
return 0 ;
}
static int ohci_da8xx_has_set_power ( struct usb_hcd * hcd )
{
2016-11-23 21:06:47 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-11-23 21:06:46 +03:00
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
if ( hub & & hub - > set_power )
return 1 ;
2016-11-23 21:06:47 +03:00
if ( da8xx_ohci - > vbus_reg )
return 1 ;
2016-11-23 21:06:46 +03:00
return 0 ;
}
static int ohci_da8xx_has_oci ( struct usb_hcd * hcd )
{
2016-11-23 21:06:47 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-11-23 21:06:46 +03:00
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
if ( hub & & hub - > get_oci )
return 1 ;
2016-11-23 21:06:47 +03:00
if ( da8xx_ohci - > vbus_reg )
return 1 ;
2016-11-23 21:06:46 +03:00
return 0 ;
}
static int ohci_da8xx_has_potpgt ( struct usb_hcd * hcd )
{
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
if ( hub & & hub - > potpgt )
return 1 ;
return 0 ;
}
2010-02-12 22:52:34 +03:00
/*
* Handle the port over - current indicator change .
*/
static void ohci_da8xx_ocic_handler ( struct da8xx_ohci_root_hub * hub ,
unsigned port )
{
ocic_mask | = 1 < < port ;
/* Once over-current is detected, the port needs to be powered down */
if ( hub - > get_oci ( port ) > 0 )
hub - > set_power ( port , 0 ) ;
}
2016-11-23 21:06:47 +03:00
static int ohci_da8xx_regulator_event ( struct notifier_block * nb ,
unsigned long event , void * data )
{
struct da8xx_ohci_hcd * da8xx_ohci =
container_of ( nb , struct da8xx_ohci_hcd , nb ) ;
if ( event & REGULATOR_EVENT_OVER_CURRENT ) {
ocic_mask | = 1 < < 1 ;
ohci_da8xx_set_power ( da8xx_ohci - > hcd , 0 ) ;
}
return 0 ;
}
2016-11-23 21:06:46 +03:00
static int ohci_da8xx_register_notify ( struct usb_hcd * hcd )
{
2016-11-23 21:06:47 +03:00
struct da8xx_ohci_hcd * da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-11-23 21:06:46 +03:00
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
2016-11-23 21:06:47 +03:00
int ret = 0 ;
if ( hub & & hub - > ocic_notify ) {
ret = hub - > ocic_notify ( ohci_da8xx_ocic_handler ) ;
} else if ( da8xx_ohci - > vbus_reg ) {
da8xx_ohci - > nb . notifier_call = ohci_da8xx_regulator_event ;
ret = devm_regulator_register_notifier ( da8xx_ohci - > vbus_reg ,
& da8xx_ohci - > nb ) ;
}
2016-11-23 21:06:46 +03:00
2016-11-23 21:06:47 +03:00
if ( ret )
dev_err ( dev , " Failed to register notifier: %d \n " , ret ) ;
2016-11-23 21:06:46 +03:00
2016-11-23 21:06:47 +03:00
return ret ;
2016-11-23 21:06:46 +03:00
}
static void ohci_da8xx_unregister_notify ( struct usb_hcd * hcd )
{
struct device * dev = hcd - > self . controller ;
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
if ( hub & & hub - > ocic_notify )
hub - > ocic_notify ( NULL ) ;
}
2016-10-27 16:52:29 +03:00
static int ohci_da8xx_reset ( struct usb_hcd * hcd )
2010-02-12 22:52:34 +03:00
{
struct device * dev = hcd - > self . controller ;
2013-07-30 14:59:40 +04:00
struct da8xx_ohci_root_hub * hub = dev_get_platdata ( dev ) ;
2010-02-12 22:52:34 +03:00
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
int result ;
u32 rh_a ;
dev_dbg ( dev , " starting USB controller \n " ) ;
2016-11-23 21:06:45 +03:00
result = ohci_da8xx_enable ( hcd ) ;
2016-10-13 04:44:46 +03:00
if ( result < 0 )
return result ;
2010-02-12 22:52:34 +03:00
/*
* DA8xx only have 1 port connected to the pins but the HC root hub
* register A reports 2 ports , thus we ' ll have to override it . . .
*/
ohci - > num_ports = 1 ;
2016-10-27 16:52:29 +03:00
result = ohci_setup ( hcd ) ;
2016-10-13 04:44:46 +03:00
if ( result < 0 ) {
2016-11-23 21:06:45 +03:00
ohci_da8xx_disable ( hcd ) ;
2010-02-12 22:52:34 +03:00
return result ;
2016-10-13 04:44:46 +03:00
}
2010-02-12 22:52:34 +03:00
/*
* Since we ' re providing a board - specific root hub port power control
* and over - current reporting , we have to override the HC root hub A
* register ' s default value , so that ohci_hub_control ( ) could return
* the correct hub descriptor . . .
*/
rh_a = ohci_readl ( ohci , & ohci - > regs - > roothub . a ) ;
2016-11-23 21:06:46 +03:00
if ( ohci_da8xx_has_set_power ( hcd ) ) {
2010-02-12 22:52:34 +03:00
rh_a & = ~ RH_A_NPS ;
rh_a | = RH_A_PSM ;
}
2016-11-23 21:06:46 +03:00
if ( ohci_da8xx_has_oci ( hcd ) ) {
2010-02-12 22:52:34 +03:00
rh_a & = ~ RH_A_NOCP ;
rh_a | = RH_A_OCPM ;
}
2016-11-23 21:06:46 +03:00
if ( ohci_da8xx_has_potpgt ( hcd ) ) {
rh_a & = ~ RH_A_POTPGT ;
rh_a | = hub - > potpgt < < 24 ;
}
2010-02-12 22:52:34 +03:00
ohci_writel ( ohci , rh_a , & ohci - > regs - > roothub . a ) ;
return result ;
}
/*
* Update the status data from the hub with the over - current indicator change .
*/
static int ohci_da8xx_hub_status_data ( struct usb_hcd * hcd , char * buf )
{
2016-10-27 16:52:29 +03:00
int length = orig_ohci_hub_status_data ( hcd , buf ) ;
2010-02-12 22:52:34 +03:00
/* See if we have OCIC bit set on port 1 */
if ( ocic_mask & ( 1 < < 1 ) ) {
dev_dbg ( hcd - > self . controller , " over-current indicator change "
" on port 1 \n " ) ;
if ( ! length )
length = 1 ;
buf [ 0 ] | = 1 < < 1 ;
}
return length ;
}
/*
* Look at the control requests to the root hub and see if we need to override .
*/
static int ohci_da8xx_hub_control ( struct usb_hcd * hcd , u16 typeReq , u16 wValue ,
u16 wIndex , char * buf , u16 wLength )
{
struct device * dev = hcd - > self . controller ;
int temp ;
switch ( typeReq ) {
case GetPortStatus :
/* Check the port number */
if ( wIndex ! = 1 )
break ;
dev_dbg ( dev , " GetPortStatus(%u) \n " , wIndex ) ;
temp = roothub_portstatus ( hcd_to_ohci ( hcd ) , wIndex - 1 ) ;
/* The port power status (PPS) bit defaults to 1 */
2016-11-23 21:06:46 +03:00
if ( ! ohci_da8xx_get_power ( hcd ) )
2010-02-12 22:52:34 +03:00
temp & = ~ RH_PS_PPS ;
/* The port over-current indicator (POCI) bit is always 0 */
2016-11-23 21:06:46 +03:00
if ( ohci_da8xx_get_oci ( hcd ) > 0 )
2010-02-12 22:52:34 +03:00
temp | = RH_PS_POCI ;
/* The over-current indicator change (OCIC) bit is 0 too */
if ( ocic_mask & ( 1 < < wIndex ) )
temp | = RH_PS_OCIC ;
put_unaligned ( cpu_to_le32 ( temp ) , ( __le32 * ) buf ) ;
return 0 ;
case SetPortFeature :
temp = 1 ;
goto check_port ;
case ClearPortFeature :
temp = 0 ;
check_port :
/* Check the port number */
if ( wIndex ! = 1 )
break ;
switch ( wValue ) {
case USB_PORT_FEAT_POWER :
dev_dbg ( dev , " %sPortFeature(%u): %s \n " ,
temp ? " Set " : " Clear " , wIndex , " POWER " ) ;
2016-11-23 21:06:46 +03:00
return ohci_da8xx_set_power ( hcd , temp ) ? - EPIPE : 0 ;
2010-02-12 22:52:34 +03:00
case USB_PORT_FEAT_C_OVER_CURRENT :
dev_dbg ( dev , " %sPortFeature(%u): %s \n " ,
temp ? " Set " : " Clear " , wIndex ,
" C_OVER_CURRENT " ) ;
if ( temp )
ocic_mask | = 1 < < wIndex ;
else
ocic_mask & = ~ ( 1 < < wIndex ) ;
return 0 ;
}
}
2016-10-27 16:52:29 +03:00
return orig_ohci_hub_control ( hcd , typeReq , wValue ,
wIndex , buf , wLength ) ;
2010-02-12 22:52:34 +03:00
}
/*-------------------------------------------------------------------------*/
2016-11-23 21:06:49 +03:00
# ifdef CONFIG_OF
static const struct of_device_id da8xx_ohci_ids [ ] = {
{ . compatible = " ti,da830-ohci " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , da8xx_ohci_ids ) ;
# endif
2010-02-12 22:52:34 +03:00
2016-10-27 16:52:29 +03:00
static int ohci_da8xx_probe ( struct platform_device * pdev )
2010-02-12 22:52:34 +03:00
{
2016-11-23 21:06:45 +03:00
struct da8xx_ohci_hcd * da8xx_ohci ;
2010-02-12 22:52:34 +03:00
struct usb_hcd * hcd ;
struct resource * mem ;
int error , irq ;
2016-11-23 21:06:45 +03:00
hcd = usb_create_hcd ( & ohci_da8xx_hc_driver , & pdev - > dev ,
dev_name ( & pdev - > dev ) ) ;
if ( ! hcd )
return - ENOMEM ;
da8xx_ohci = to_da8xx_ohci ( hcd ) ;
2016-11-23 21:06:47 +03:00
da8xx_ohci - > hcd = hcd ;
2016-11-23 21:06:45 +03:00
da8xx_ohci - > usb11_clk = devm_clk_get ( & pdev - > dev , " usb11 " ) ;
if ( IS_ERR ( da8xx_ohci - > usb11_clk ) ) {
error = PTR_ERR ( da8xx_ohci - > usb11_clk ) ;
if ( error ! = - EPROBE_DEFER )
2016-10-13 04:44:46 +03:00
dev_err ( & pdev - > dev , " Failed to get clock. \n " ) ;
2016-11-23 21:06:45 +03:00
goto err ;
2016-10-13 04:44:46 +03:00
}
2010-02-12 22:52:34 +03:00
2016-11-23 21:06:45 +03:00
da8xx_ohci - > usb11_phy = devm_phy_get ( & pdev - > dev , " usb-phy " ) ;
if ( IS_ERR ( da8xx_ohci - > usb11_phy ) ) {
error = PTR_ERR ( da8xx_ohci - > usb11_phy ) ;
if ( error ! = - EPROBE_DEFER )
2016-10-13 04:44:46 +03:00
dev_err ( & pdev - > dev , " Failed to get phy. \n " ) ;
2016-11-23 21:06:45 +03:00
goto err ;
2016-10-13 04:44:46 +03:00
}
2010-02-12 22:52:34 +03:00
2016-11-23 21:06:47 +03:00
da8xx_ohci - > vbus_reg = devm_regulator_get_optional ( & pdev - > dev , " vbus " ) ;
if ( IS_ERR ( da8xx_ohci - > vbus_reg ) ) {
error = PTR_ERR ( da8xx_ohci - > vbus_reg ) ;
if ( error = = - ENODEV ) {
da8xx_ohci - > vbus_reg = NULL ;
} else if ( error = = - EPROBE_DEFER ) {
goto err ;
} else {
dev_err ( & pdev - > dev , " Failed to get regulator \n " ) ;
goto err ;
}
}
2010-02-12 22:52:34 +03:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-12-11 11:23:39 +04:00
hcd - > regs = devm_ioremap_resource ( & pdev - > dev , mem ) ;
if ( IS_ERR ( hcd - > regs ) ) {
error = PTR_ERR ( hcd - > regs ) ;
goto err ;
2010-02-12 22:52:34 +03:00
}
2014-11-04 05:21:09 +03:00
hcd - > rsrc_start = mem - > start ;
hcd - > rsrc_len = resource_size ( mem ) ;
2010-02-12 22:52:34 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
error = - ENODEV ;
2013-12-11 11:23:39 +04:00
goto err ;
2010-02-12 22:52:34 +03:00
}
2016-10-27 16:52:29 +03:00
2011-09-07 12:10:52 +04:00
error = usb_add_hcd ( hcd , irq , 0 ) ;
2010-02-12 22:52:34 +03:00
if ( error )
2013-12-11 11:23:39 +04:00
goto err ;
2010-02-12 22:52:34 +03:00
2013-11-05 06:46:02 +04:00
device_wakeup_enable ( hcd - > self . controller ) ;
2016-11-23 21:06:46 +03:00
error = ohci_da8xx_register_notify ( hcd ) ;
if ( error )
goto err_remove_hcd ;
return 0 ;
2010-02-12 22:52:34 +03:00
2016-11-23 21:06:46 +03:00
err_remove_hcd :
2010-02-12 22:52:34 +03:00
usb_remove_hcd ( hcd ) ;
2013-12-11 11:23:39 +04:00
err :
2010-02-12 22:52:34 +03:00
usb_put_hcd ( hcd ) ;
return error ;
}
2016-10-27 16:52:29 +03:00
static int ohci_da8xx_remove ( struct platform_device * pdev )
2010-02-12 22:52:34 +03:00
{
2016-10-27 16:52:29 +03:00
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
2010-02-12 22:52:34 +03:00
2016-11-23 21:06:46 +03:00
ohci_da8xx_unregister_notify ( hcd ) ;
2010-02-12 22:52:34 +03:00
usb_remove_hcd ( hcd ) ;
usb_put_hcd ( hcd ) ;
return 0 ;
}
# ifdef CONFIG_PM
2013-11-13 16:10:19 +04:00
static int ohci_da8xx_suspend ( struct platform_device * pdev ,
pm_message_t message )
2010-02-12 22:52:34 +03:00
{
2013-11-13 16:10:19 +04:00
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
2010-02-12 22:52:34 +03:00
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
2013-11-13 16:10:19 +04:00
bool do_wakeup = device_may_wakeup ( & pdev - > dev ) ;
int ret ;
2010-02-12 22:52:34 +03:00
if ( time_before ( jiffies , ohci - > next_statechange ) )
msleep ( 5 ) ;
ohci - > next_statechange = jiffies ;
2013-11-13 16:10:19 +04:00
ret = ohci_suspend ( hcd , do_wakeup ) ;
if ( ret )
return ret ;
2016-11-23 21:06:45 +03:00
ohci_da8xx_disable ( hcd ) ;
2010-02-12 22:52:34 +03:00
hcd - > state = HC_STATE_SUSPENDED ;
2013-11-13 16:10:19 +04:00
return ret ;
2010-02-12 22:52:34 +03:00
}
static int ohci_da8xx_resume ( struct platform_device * dev )
{
struct usb_hcd * hcd = platform_get_drvdata ( dev ) ;
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
2016-10-13 04:44:46 +03:00
int ret ;
2010-02-12 22:52:34 +03:00
if ( time_before ( jiffies , ohci - > next_statechange ) )
msleep ( 5 ) ;
ohci - > next_statechange = jiffies ;
2016-11-23 21:06:45 +03:00
ret = ohci_da8xx_enable ( hcd ) ;
2016-10-13 04:44:46 +03:00
if ( ret )
return ret ;
2016-11-24 13:50:56 +03:00
ohci_resume ( hcd , false ) ;
2016-10-13 04:44:46 +03:00
2010-02-12 22:52:34 +03:00
return 0 ;
}
# endif
2016-10-27 16:52:29 +03:00
static const struct ohci_driver_overrides da8xx_overrides __initconst = {
2016-11-23 21:06:45 +03:00
. reset = ohci_da8xx_reset ,
. extra_priv_size = sizeof ( struct da8xx_ohci_hcd ) ,
2016-10-27 16:52:29 +03:00
} ;
2010-02-12 22:52:34 +03:00
/*
* Driver definition to register with platform structure .
*/
static struct platform_driver ohci_hcd_da8xx_driver = {
2016-10-27 16:52:29 +03:00
. probe = ohci_da8xx_probe ,
. remove = ohci_da8xx_remove ,
2010-02-12 22:52:34 +03:00
. shutdown = usb_hcd_platform_shutdown ,
# ifdef CONFIG_PM
. suspend = ohci_da8xx_suspend ,
. resume = ohci_da8xx_resume ,
# endif
. driver = {
2016-10-27 16:52:29 +03:00
. name = DRV_NAME ,
2016-11-23 21:06:49 +03:00
. of_match_table = of_match_ptr ( da8xx_ohci_ids ) ,
2010-02-12 22:52:34 +03:00
} ,
} ;
2012-05-07 12:25:16 +04:00
2016-10-27 16:52:29 +03:00
static int __init ohci_da8xx_init ( void )
{
if ( usb_disabled ( ) )
return - ENODEV ;
pr_info ( " %s: " DRIVER_DESC " \n " , DRV_NAME ) ;
ohci_init_driver ( & ohci_da8xx_hc_driver , & da8xx_overrides ) ;
/*
* The Davinci da8xx HW has some unusual quirks , which require
* da8xx - specific workarounds . We override certain hc_driver
* functions here to achieve that . We explicitly do not enhance
* ohci_driver_overrides to allow this more easily , since this
* is an unusual case , and we don ' t want to encourage others to
* override these functions by making it too easy .
*/
orig_ohci_hub_control = ohci_da8xx_hc_driver . hub_control ;
orig_ohci_hub_status_data = ohci_da8xx_hc_driver . hub_status_data ;
ohci_da8xx_hc_driver . hub_status_data = ohci_da8xx_hub_status_data ;
ohci_da8xx_hc_driver . hub_control = ohci_da8xx_hub_control ;
return platform_driver_register ( & ohci_hcd_da8xx_driver ) ;
}
module_init ( ohci_da8xx_init ) ;
static void __exit ohci_da8xx_exit ( void )
{
platform_driver_unregister ( & ohci_hcd_da8xx_driver ) ;
}
module_exit ( ohci_da8xx_exit ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform: " DRV_NAME ) ;