2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-1.0+
2005-04-17 02:20:36 +04:00
/*
* OHCI HCD ( Host Controller Driver ) for USB .
*
* ( C ) Copyright 1999 Roman Weissgaerber < weissg @ vienna . at >
* ( C ) Copyright 2000 - 2005 David Brownell
* ( C ) Copyright 2002 Hewlett - Packard Company
2006-07-31 18:29:39 +04:00
*
2005-04-17 02:20:36 +04:00
* OMAP Bus Glue
*
* Modified for OMAP by Tony Lindgren < tony @ atomide . com >
* Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc .
* and on ohci - sa1111 . c by Christopher Hoover < ch @ hpl . hp . com >
*
* This file is licenced under the GPL .
*/
2006-01-07 19:15:52 +03:00
# include <linux/clk.h>
2013-09-21 15:08:39 +04:00
# include <linux/dma-mapping.h>
2012-06-26 16:10:32 +04:00
# include <linux/err.h>
2020-07-20 16:55:24 +03:00
# include <linux/gpio/consumer.h>
2013-09-21 15:08:39 +04:00
# include <linux/io.h>
# include <linux/jiffies.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/usb/otg.h>
# include <linux/platform_device.h>
# include <linux/signal.h>
# include <linux/usb.h>
# include <linux/usb/hcd.h>
# include "ohci.h"
2005-10-31 02:03:48 +03:00
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/mach-types.h>
2012-09-19 21:46:56 +04:00
# include <mach/mux.h>
2012-06-04 11:56:15 +04:00
# include <mach/hardware.h>
# include <mach/usb.h>
2005-04-17 02:20:36 +04:00
/* OMAP-1510 OHCI has its own MMU for DMA */
# define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */
# define OMAP1510_LB_CLOCK_DIV 0xfffec10c
# define OMAP1510_LB_MMU_CTL 0xfffec208
# define OMAP1510_LB_MMU_LCK 0xfffec224
# define OMAP1510_LB_MMU_LD_TLB 0xfffec228
# define OMAP1510_LB_MMU_CAM_H 0xfffec22c
# define OMAP1510_LB_MMU_CAM_L 0xfffec230
# define OMAP1510_LB_MMU_RAM_H 0xfffec234
# define OMAP1510_LB_MMU_RAM_L 0xfffec238
2013-09-21 15:08:39 +04:00
# define DRIVER_DESC "OHCI OMAP driver"
2005-04-17 02:20:36 +04:00
2020-07-20 16:55:23 +03:00
struct ohci_omap_priv {
struct clk * usb_host_ck ;
struct clk * usb_dc_ck ;
2020-07-20 16:55:24 +03:00
struct gpio_desc * power ;
struct gpio_desc * overcurrent ;
2020-07-20 16:55:23 +03:00
} ;
2013-09-21 15:08:39 +04:00
static const char hcd_name [ ] = " ohci-omap " ;
static struct hc_driver __read_mostly ohci_omap_hc_driver ;
2005-04-17 02:20:36 +04:00
2020-07-20 16:55:23 +03:00
# define hcd_to_ohci_omap_priv(h) \
( ( struct ohci_omap_priv * ) hcd_to_ohci ( h ) - > priv )
static void omap_ohci_clock_power ( struct ohci_omap_priv * priv , int on )
2005-04-17 02:20:36 +04:00
{
if ( on ) {
2020-07-20 16:55:23 +03:00
clk_enable ( priv - > usb_dc_ck ) ;
clk_enable ( priv - > usb_host_ck ) ;
2005-04-17 02:20:36 +04:00
/* guesstimate for T5 == 1x 32K clock + APLL lock time */
udelay ( 100 ) ;
} else {
2020-07-20 16:55:23 +03:00
clk_disable ( priv - > usb_host_ck ) ;
clk_disable ( priv - > usb_dc_ck ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* Board specific gang - switched transceiver power on / off .
* NOTE : OSK supplies power from DC , not battery .
*/
2020-07-20 16:55:24 +03:00
static int omap_ohci_transceiver_power ( struct ohci_omap_priv * priv , int on )
2005-04-17 02:20:36 +04:00
{
if ( on ) {
if ( machine_is_omap_innovator ( ) & & cpu_is_omap1510 ( ) )
2012-10-02 23:39:09 +04:00
__raw_writeb ( __raw_readb ( INNOVATOR_FPGA_CAM_USB_CONTROL )
2006-07-31 18:29:39 +04:00
| ( ( 1 < < 5 /*usb1*/ ) | ( 1 < < 3 /*usb2*/ ) ) ,
2005-04-17 02:20:36 +04:00
INNOVATOR_FPGA_CAM_USB_CONTROL ) ;
2020-07-20 16:55:24 +03:00
else if ( priv - > power )
2020-11-30 11:30:33 +03:00
gpiod_set_value_cansleep ( priv - > power , 0 ) ;
2005-04-17 02:20:36 +04:00
} else {
if ( machine_is_omap_innovator ( ) & & cpu_is_omap1510 ( ) )
2012-10-02 23:39:09 +04:00
__raw_writeb ( __raw_readb ( INNOVATOR_FPGA_CAM_USB_CONTROL )
2006-07-31 18:29:39 +04:00
& ~ ( ( 1 < < 5 /*usb1*/ ) | ( 1 < < 3 /*usb2*/ ) ) ,
2005-04-17 02:20:36 +04:00
INNOVATOR_FPGA_CAM_USB_CONTROL ) ;
2020-07-20 16:55:24 +03:00
else if ( priv - > power )
2020-11-30 11:30:33 +03:00
gpiod_set_value_cansleep ( priv - > power , 1 ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2006-07-31 18:29:39 +04:00
# ifdef CONFIG_ARCH_OMAP15XX
2005-04-17 02:20:36 +04:00
/*
* OMAP - 1510 specific Local Bus clock on / off
*/
static int omap_1510_local_bus_power ( int on )
{
if ( on ) {
omap_writel ( ( 1 < < 1 ) | ( 1 < < 0 ) , OMAP1510_LB_MMU_CTL ) ;
udelay ( 200 ) ;
} else {
omap_writel ( 0 , OMAP1510_LB_MMU_CTL ) ;
}
return 0 ;
}
/*
* OMAP - 1510 specific Local Bus initialization
* NOTE : This assumes 32 MB memory size in OMAP1510LB_MEMSIZE .
2006-07-31 18:29:39 +04:00
* See also arch / mach - omap / memory . h for __virt_to_dma ( ) and
* __dma_to_virt ( ) which need to match with the physical
2005-04-17 02:20:36 +04:00
* Local Bus address below .
*/
static int omap_1510_local_bus_init ( void )
{
unsigned int tlb ;
unsigned long lbaddr , physaddr ;
2006-07-31 18:29:39 +04:00
omap_writel ( ( omap_readl ( OMAP1510_LB_CLOCK_DIV ) & 0xfffffff8 ) | 0x4 ,
2005-04-17 02:20:36 +04:00
OMAP1510_LB_CLOCK_DIV ) ;
/* Configure the Local Bus MMU table */
for ( tlb = 0 ; tlb < OMAP1510_LB_MEMSIZE ; tlb + + ) {
lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET ;
physaddr = tlb * 0x00100000 + PHYS_OFFSET ;
omap_writel ( ( lbaddr & 0x0fffffff ) > > 22 , OMAP1510_LB_MMU_CAM_H ) ;
2006-07-31 18:29:39 +04:00
omap_writel ( ( ( lbaddr & 0x003ffc00 ) > > 6 ) | 0xc ,
2005-04-17 02:20:36 +04:00
OMAP1510_LB_MMU_CAM_L ) ;
omap_writel ( physaddr > > 16 , OMAP1510_LB_MMU_RAM_H ) ;
omap_writel ( ( physaddr & 0x0000fc00 ) | 0x300 , OMAP1510_LB_MMU_RAM_L ) ;
omap_writel ( tlb < < 4 , OMAP1510_LB_MMU_LCK ) ;
omap_writel ( 0x1 , OMAP1510_LB_MMU_LD_TLB ) ;
}
/* Enable the walking table */
omap_writel ( omap_readl ( OMAP1510_LB_MMU_CTL ) | ( 1 < < 3 ) , OMAP1510_LB_MMU_CTL ) ;
udelay ( 200 ) ;
return 0 ;
}
2006-07-31 18:29:39 +04:00
# else
# define omap_1510_local_bus_power(x) {}
# define omap_1510_local_bus_init() {}
# endif
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_USB_OTG
static void start_hnp ( struct ohci_hcd * ohci )
{
2012-06-13 16:34:12 +04:00
struct usb_hcd * hcd = ohci_to_hcd ( ohci ) ;
const unsigned port = hcd - > self . otg_port - 1 ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2008-07-03 13:24:43 +04:00
u32 l ;
2005-04-17 02:20:36 +04:00
2014-09-24 23:05:50 +04:00
otg_start_hnp ( hcd - > usb_phy - > otg ) ;
2005-04-17 02:20:36 +04:00
local_irq_save ( flags ) ;
2014-11-08 04:43:45 +03:00
hcd - > usb_phy - > otg - > state = OTG_STATE_A_SUSPEND ;
2005-04-17 02:20:36 +04:00
writel ( RH_PS_PSS , & ohci - > regs - > roothub . portstatus [ port ] ) ;
2008-07-03 13:24:43 +04:00
l = omap_readl ( OTG_CTRL ) ;
l & = ~ OTG_A_BUSREQ ;
omap_writel ( l , OTG_CTRL ) ;
2005-04-17 02:20:36 +04:00
local_irq_restore ( flags ) ;
}
# endif
/*-------------------------------------------------------------------------*/
2013-09-21 15:08:39 +04:00
static int ohci_omap_reset ( struct usb_hcd * hcd )
2005-04-17 02:20:36 +04:00
{
2006-07-31 18:29:39 +04:00
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
2013-07-30 14:59:40 +04:00
struct omap_usb_config * config = dev_get_platdata ( hcd - > self . controller ) ;
2020-07-20 16:55:23 +03:00
struct ohci_omap_priv * priv = hcd_to_ohci_omap_priv ( hcd ) ;
2005-04-17 02:20:36 +04:00
int need_transceiver = ( config - > otg ! = 0 ) ;
int ret ;
2006-07-31 18:29:39 +04:00
dev_dbg ( hcd - > self . controller , " starting USB Controller \n " ) ;
2005-04-17 02:20:36 +04:00
if ( config - > otg ) {
2013-09-21 15:08:39 +04:00
hcd - > self . otg_port = config - > otg ;
2005-04-17 02:20:36 +04:00
/* default/minimum OTG power budget: 8 mA */
2013-09-21 15:08:39 +04:00
hcd - > power_budget = 8 ;
2005-04-17 02:20:36 +04:00
}
/* boards can use OTG transceivers in non-OTG modes */
need_transceiver = need_transceiver
| | machine_is_omap_h2 ( ) | | machine_is_omap_h3 ( ) ;
2012-04-13 16:34:27 +04:00
/* XXX OMAP16xx only */
if ( config - > ocpi_enable )
config - > ocpi_enable ( ) ;
2005-04-17 02:20:36 +04:00
2008-09-04 02:59:23 +04:00
# ifdef CONFIG_USB_OTG
2005-04-17 02:20:36 +04:00
if ( need_transceiver ) {
2014-09-24 23:05:50 +04:00
hcd - > usb_phy = usb_get_phy ( USB_PHY_TYPE_USB2 ) ;
if ( ! IS_ERR_OR_NULL ( hcd - > usb_phy ) ) {
int status = otg_set_host ( hcd - > usb_phy - > otg ,
2005-04-17 02:20:36 +04:00
& ohci_to_hcd ( ohci ) - > self ) ;
2012-06-13 16:34:12 +04:00
dev_dbg ( hcd - > self . controller , " init %s phy, status %d \n " ,
2014-09-24 23:05:50 +04:00
hcd - > usb_phy - > label , status ) ;
2005-04-17 02:20:36 +04:00
if ( status ) {
2014-09-24 23:05:50 +04:00
usb_put_phy ( hcd - > usb_phy ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
} else {
2017-01-02 23:53:55 +03:00
return - EPROBE_DEFER ;
2005-04-17 02:20:36 +04:00
}
2018-03-04 00:43:03 +03:00
hcd - > skip_phy_initialization = 1 ;
2008-07-06 14:26:30 +04:00
ohci - > start_hnp = start_hnp ;
2005-04-17 02:20:36 +04:00
}
# endif
2020-07-20 16:55:23 +03:00
omap_ohci_clock_power ( priv , 1 ) ;
2005-04-17 02:20:36 +04:00
2008-09-05 03:29:55 +04:00
if ( cpu_is_omap15xx ( ) ) {
2005-04-17 02:20:36 +04:00
omap_1510_local_bus_power ( 1 ) ;
omap_1510_local_bus_init ( ) ;
}
2013-09-21 15:08:39 +04:00
ret = ohci_setup ( hcd ) ;
if ( ret < 0 )
2005-04-17 02:20:36 +04:00
return ret ;
2013-09-21 15:08:39 +04:00
if ( config - > otg | | config - > rwc ) {
ohci - > hc_control = OHCI_CTRL_RWC ;
writel ( OHCI_CTRL_RWC , & ohci - > regs - > control ) ;
}
2005-04-17 02:20:36 +04:00
/* board-specific power switching and overcurrent support */
if ( machine_is_omap_osk ( ) | | machine_is_omap_innovator ( ) ) {
u32 rh = roothub_a ( ohci ) ;
/* power switching (ganged by default) */
rh & = ~ RH_A_NPS ;
/* TPS2045 switch for internal transceiver (port 1) */
if ( machine_is_omap_osk ( ) ) {
2005-04-25 19:21:31 +04:00
ohci_to_hcd ( ohci ) - > power_budget = 250 ;
2005-04-17 02:20:36 +04:00
rh & = ~ RH_A_NOCP ;
/* gpio9 for overcurrent detction */
omap_cfg_reg ( W8_1610_GPIO9 ) ;
/* for paranoia's sake: disable USB.PUEN */
omap_cfg_reg ( W4_USB_HIGHZ ) ;
}
ohci_writel ( ohci , rh , & ohci - > regs - > roothub . a ) ;
2008-07-06 23:35:01 +04:00
ohci - > flags & = ~ OHCI_QUIRK_HUB_POWER ;
2006-07-31 18:29:39 +04:00
} else if ( machine_is_nokia770 ( ) ) {
/* We require a self-powered hub, which should have
* plenty of power . */
ohci_to_hcd ( ohci ) - > power_budget = 0 ;
2005-04-17 02:20:36 +04:00
}
2014-09-19 19:32:23 +04:00
/* FIXME hub_wq hub requests should manage power switching */
2020-07-20 16:55:24 +03:00
omap_ohci_transceiver_power ( priv , 1 ) ;
2005-04-17 02:20:36 +04:00
/* board init will have already handled HMC and mux setup.
* any external transceiver should already be initialized
* too , so all configured ports use the right signaling now .
*/
return 0 ;
}
/*-------------------------------------------------------------------------*/
/**
2016-12-03 06:34:53 +03:00
* ohci_hcd_omap_probe - initialize OMAP - based HCDs
2020-10-19 13:06:37 +03:00
* @ pdev : USB controller to probe
*
* Context : task context , might sleep
2005-04-17 02:20:36 +04:00
*
* Allocates basic resources for this USB host controller , and
* then invokes the start ( ) method for the HCD associated with it
* through the hotplug entry ' s driver_data .
*/
2016-12-03 06:34:53 +03:00
static int ohci_hcd_omap_probe ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2006-01-19 20:56:29 +03:00
int retval , irq ;
2005-04-17 02:20:36 +04:00
struct usb_hcd * hcd = 0 ;
2020-07-20 16:55:23 +03:00
struct ohci_omap_priv * priv ;
2005-04-17 02:20:36 +04:00
if ( pdev - > num_resources ! = 2 ) {
2013-12-10 16:25:09 +04:00
dev_err ( & pdev - > dev , " invalid num_resources: %i \n " ,
2005-04-17 02:20:36 +04:00
pdev - > num_resources ) ;
return - ENODEV ;
}
2006-07-31 18:29:39 +04:00
if ( pdev - > resource [ 0 ] . flags ! = IORESOURCE_MEM
2005-04-17 02:20:36 +04:00
| | pdev - > resource [ 1 ] . flags ! = IORESOURCE_IRQ ) {
2013-12-10 16:25:09 +04:00
dev_err ( & pdev - > dev , " invalid resource type \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
2020-07-20 16:55:23 +03:00
hcd = usb_create_hcd ( & ohci_omap_hc_driver , & pdev - > dev ,
dev_name ( & pdev - > dev ) ) ;
if ( ! hcd )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2020-07-20 16:55:23 +03:00
hcd - > rsrc_start = pdev - > resource [ 0 ] . start ;
hcd - > rsrc_len = pdev - > resource [ 0 ] . end - pdev - > resource [ 0 ] . start + 1 ;
priv = hcd_to_ohci_omap_priv ( hcd ) ;
2006-07-31 18:29:39 +04:00
2020-07-20 16:55:24 +03:00
/* Obtain two optional GPIO lines */
priv - > power = devm_gpiod_get_optional ( & pdev - > dev , " power " , GPIOD_ASIS ) ;
if ( IS_ERR ( priv - > power ) ) {
retval = PTR_ERR ( priv - > power ) ;
goto err_put_hcd ;
}
if ( priv - > power )
gpiod_set_consumer_name ( priv - > power , " OHCI power " ) ;
/*
* This " overcurrent " GPIO line isn ' t really used in the code ,
* but has a designated hardware function .
* TODO : implement proper overcurrent handling .
*/
priv - > overcurrent = devm_gpiod_get_optional ( & pdev - > dev , " overcurrent " ,
GPIOD_IN ) ;
if ( IS_ERR ( priv - > overcurrent ) ) {
retval = PTR_ERR ( priv - > overcurrent ) ;
goto err_put_hcd ;
}
if ( priv - > overcurrent )
gpiod_set_consumer_name ( priv - > overcurrent , " OHCI overcurrent " ) ;
2020-07-20 16:55:23 +03:00
priv - > usb_host_ck = clk_get ( & pdev - > dev , " usb_hhc_ck " ) ;
if ( IS_ERR ( priv - > usb_host_ck ) ) {
retval = PTR_ERR ( priv - > usb_host_ck ) ;
goto err_put_hcd ;
2006-07-31 18:29:39 +04:00
}
2020-07-20 16:55:23 +03:00
if ( ! cpu_is_omap15xx ( ) )
priv - > usb_dc_ck = clk_get ( & pdev - > dev , " usb_dc_ck " ) ;
else
priv - > usb_dc_ck = clk_get ( & pdev - > dev , " lb_ck " ) ;
2006-07-31 18:29:39 +04:00
2020-07-20 16:55:23 +03:00
if ( IS_ERR ( priv - > usb_dc_ck ) ) {
retval = PTR_ERR ( priv - > usb_dc_ck ) ;
goto err_put_host_ck ;
2005-04-17 02:20:36 +04:00
}
if ( ! request_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len , hcd_name ) ) {
dev_dbg ( & pdev - > dev , " request_mem_region failed \n " ) ;
retval = - EBUSY ;
2020-07-20 16:55:23 +03:00
goto err_put_dc_ck ;
2005-04-17 02:20:36 +04:00
}
2008-09-04 17:07:22 +04:00
hcd - > regs = ioremap ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
if ( ! hcd - > regs ) {
dev_err ( & pdev - > dev , " can't ioremap OHCI HCD \n " ) ;
retval = - ENOMEM ;
goto err2 ;
}
2005-04-17 02:20:36 +04:00
2006-01-19 20:56:29 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
retval = - ENXIO ;
2008-09-04 17:07:22 +04:00
goto err3 ;
2006-01-19 20:56:29 +03:00
}
2011-09-07 12:10:52 +04:00
retval = usb_add_hcd ( hcd , irq , 0 ) ;
2006-07-31 18:29:39 +04:00
if ( retval )
2008-09-04 17:07:22 +04:00
goto err3 ;
2006-07-31 18:29:39 +04:00
2013-11-05 06:46:02 +04:00
device_wakeup_enable ( hcd - > self . controller ) ;
2006-07-31 18:29:39 +04:00
return 0 ;
2008-09-04 17:07:22 +04:00
err3 :
iounmap ( hcd - > regs ) ;
2005-04-17 02:20:36 +04:00
err2 :
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
2020-07-20 16:55:23 +03:00
err_put_dc_ck :
clk_put ( priv - > usb_dc_ck ) ;
err_put_host_ck :
clk_put ( priv - > usb_host_ck ) ;
err_put_hcd :
2005-04-17 02:20:36 +04:00
usb_put_hcd ( hcd ) ;
return retval ;
}
/* may be called with controller, bus, and devices active */
/**
2016-12-03 06:34:53 +03:00
* ohci_hcd_omap_remove - shutdown processing for OMAP - based HCDs
2020-10-19 13:06:37 +03:00
* @ pdev : USB Host Controller being removed
*
* Context : task context , might sleep
2005-04-17 02:20:36 +04:00
*
2016-12-03 06:34:53 +03:00
* Reverses the effect of ohci_hcd_omap_probe ( ) , first invoking
2005-04-17 02:20:36 +04:00
* the HCD ' s stop ( ) method . It is always called from a thread
* context , normally " rmmod " , " apmd " , or something similar .
*/
2016-12-03 06:34:53 +03:00
static int ohci_hcd_omap_remove ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2016-12-03 06:34:53 +03:00
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
2020-07-20 16:55:23 +03:00
struct ohci_omap_priv * priv = hcd_to_ohci_omap_priv ( hcd ) ;
2016-12-03 06:34:53 +03:00
2013-09-21 15:08:39 +04:00
dev_dbg ( hcd - > self . controller , " stopping USB Controller \n " ) ;
2005-04-17 02:20:36 +04:00
usb_remove_hcd ( hcd ) ;
2020-07-20 16:55:23 +03:00
omap_ohci_clock_power ( priv , 0 ) ;
2014-09-24 23:05:50 +04:00
if ( ! IS_ERR_OR_NULL ( hcd - > usb_phy ) ) {
( void ) otg_set_host ( hcd - > usb_phy - > otg , 0 ) ;
usb_put_phy ( hcd - > usb_phy ) ;
2006-07-31 18:29:39 +04:00
}
2008-09-04 17:07:22 +04:00
iounmap ( hcd - > regs ) ;
2005-04-17 02:20:36 +04:00
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
2020-07-20 16:55:23 +03:00
clk_put ( priv - > usb_dc_ck ) ;
clk_put ( priv - > usb_host_ck ) ;
2005-04-17 02:20:36 +04:00
usb_put_hcd ( hcd ) ;
return 0 ;
}
/*-------------------------------------------------------------------------*/
# ifdef CONFIG_PM
2013-10-04 08:28:13 +04:00
static int ohci_omap_suspend ( struct platform_device * pdev , pm_message_t message )
2005-04-17 02:20:36 +04:00
{
2013-10-04 08:28:13 +04:00
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
2020-07-20 16:55:23 +03:00
struct ohci_omap_priv * priv = hcd_to_ohci_omap_priv ( hcd ) ;
2013-10-04 08:28:13 +04:00
bool do_wakeup = device_may_wakeup ( & pdev - > dev ) ;
int ret ;
2005-09-23 09:42:53 +04:00
if ( time_before ( jiffies , ohci - > next_statechange ) )
msleep ( 5 ) ;
ohci - > next_statechange = jiffies ;
2013-10-04 08:28:13 +04:00
ret = ohci_suspend ( hcd , do_wakeup ) ;
if ( ret )
return ret ;
2020-07-20 16:55:23 +03:00
omap_ohci_clock_power ( priv , 0 ) ;
2013-10-04 08:28:13 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2005-11-10 01:32:44 +03:00
static int ohci_omap_resume ( struct platform_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-04-04 02:03:17 +04:00
struct usb_hcd * hcd = platform_get_drvdata ( dev ) ;
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
2020-07-20 16:55:23 +03:00
struct ohci_omap_priv * priv = hcd_to_ohci_omap_priv ( hcd ) ;
2005-04-17 02:20:36 +04:00
2005-06-29 17:59:14 +04:00
if ( time_before ( jiffies , ohci - > next_statechange ) )
msleep ( 5 ) ;
ohci - > next_statechange = jiffies ;
2005-09-23 09:42:53 +04:00
2020-07-20 16:55:23 +03:00
omap_ohci_clock_power ( priv , 1 ) ;
2012-10-08 17:11:29 +04:00
ohci_resume ( hcd , false ) ;
2005-09-23 09:42:53 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
# endif
/*-------------------------------------------------------------------------*/
/*
* Driver definition to register with the OMAP bus
*/
2005-11-10 01:32:44 +03:00
static struct platform_driver ohci_hcd_omap_driver = {
2016-12-03 06:34:53 +03:00
. probe = ohci_hcd_omap_probe ,
. remove = ohci_hcd_omap_remove ,
2006-12-05 14:18:31 +03:00
. shutdown = usb_hcd_platform_shutdown ,
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PM
. suspend = ohci_omap_suspend ,
. resume = ohci_omap_resume ,
# endif
2005-11-10 01:32:44 +03:00
. driver = {
. name = " ohci " ,
} ,
2005-04-17 02:20:36 +04:00
} ;
2013-09-21 15:08:39 +04:00
static const struct ohci_driver_overrides omap_overrides __initconst = {
. product_desc = " OMAP OHCI " ,
2020-07-20 16:55:23 +03:00
. reset = ohci_omap_reset ,
. extra_priv_size = sizeof ( struct ohci_omap_priv ) ,
2013-09-21 15:08:39 +04:00
} ;
static int __init ohci_omap_init ( void )
{
if ( usb_disabled ( ) )
return - ENODEV ;
pr_info ( " %s: " DRIVER_DESC " \n " , hcd_name ) ;
ohci_init_driver ( & ohci_omap_hc_driver , & omap_overrides ) ;
return platform_driver_register ( & ohci_hcd_omap_driver ) ;
}
module_init ( ohci_omap_init ) ;
static void __exit ohci_omap_cleanup ( void )
{
platform_driver_unregister ( & ohci_hcd_omap_driver ) ;
}
module_exit ( ohci_omap_cleanup ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2008-04-11 08:29:22 +04:00
MODULE_ALIAS ( " platform:ohci " ) ;
2013-09-21 15:08:39 +04:00
MODULE_LICENSE ( " GPL " ) ;