2010-05-10 20:26:11 +04:00
/*
* ohci - omap3 . c - driver for OHCI on OMAP3 and later processors
*
* Bus Glue for OMAP3 USBHOST 3 port OHCI controller
* This controller is also used in later OMAPs and AM35x chips
*
* Copyright ( C ) 2007 - 2010 Texas Instruments , Inc .
* Author : Vikram Pandita < vikram . pandita @ ti . com >
* Author : Anand Gadiyar < gadiyar @ ti . com >
2011-03-01 17:38:21 +03:00
* Author : Keshava Munegowda < keshava_mgowda @ ti . com >
2010-05-10 20:26:11 +04:00
*
* Based on ehci - omap . c and some other ohci glue layers
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
2011-03-01 17:38:21 +03:00
* TODO ( last updated Feb 27 , 2011 ) :
2010-05-10 20:26:11 +04:00
* - add kernel - doc
*/
2013-09-21 15:08:40 +04:00
# include <linux/dma-mapping.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/usb/otg.h>
2010-05-10 20:26:11 +04:00
# include <linux/platform_device.h>
2011-10-11 11:52:11 +04:00
# include <linux/pm_runtime.h>
2013-09-21 15:08:40 +04:00
# include <linux/usb.h>
# include <linux/usb/hcd.h>
2010-05-10 20:26:11 +04:00
2013-09-21 15:08:40 +04:00
# include "ohci.h"
2010-05-10 20:26:11 +04:00
2013-09-21 15:08:40 +04:00
# define DRIVER_DESC "OHCI OMAP3 driver"
2010-05-10 20:26:11 +04:00
2013-09-21 15:08:40 +04:00
static const char hcd_name [ ] = " ohci-omap3 " ;
static struct hc_driver __read_mostly ohci_omap3_hc_driver ;
2010-05-10 20:26:11 +04:00
/*
* configure so an HC device and id are always provided
* always called with process context ; sleeping is OK
*/
/**
* ohci_hcd_omap3_probe - initialize OMAP - based HCDs
*
* 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 .
*/
2012-11-19 22:21:48 +04:00
static int ohci_hcd_omap3_probe ( struct platform_device * pdev )
2010-05-10 20:26:11 +04:00
{
2011-03-01 17:38:21 +03:00
struct device * dev = & pdev - > dev ;
2013-09-21 15:08:40 +04:00
struct ohci_hcd * ohci ;
2011-03-01 17:38:21 +03:00
struct usb_hcd * hcd = NULL ;
void __iomem * regs = NULL ;
struct resource * res ;
2013-06-10 19:28:49 +04:00
int ret ;
2011-03-01 17:38:21 +03:00
int irq ;
2010-05-10 20:26:11 +04:00
if ( usb_disabled ( ) )
2011-10-11 11:52:11 +04:00
return - ENODEV ;
2010-05-10 20:26:11 +04:00
2011-03-01 17:38:21 +03:00
if ( ! dev - > parent ) {
dev_err ( dev , " Missing parent device \n " ) ;
return - ENODEV ;
2010-05-10 20:26:11 +04:00
}
2013-03-12 14:44:46 +04:00
irq = platform_get_irq ( pdev , 0 ) ;
2011-03-01 17:38:21 +03:00
if ( irq < 0 ) {
dev_err ( dev , " OHCI irq failed \n " ) ;
return - ENODEV ;
}
2010-05-10 20:26:11 +04:00
2013-03-12 14:44:46 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2011-08-22 18:00:35 +04:00
if ( ! res ) {
2011-03-01 17:38:21 +03:00
dev_err ( dev , " UHH OHCI get resource failed \n " ) ;
return - ENOMEM ;
2010-05-10 20:26:11 +04:00
}
2011-03-01 17:38:21 +03:00
regs = ioremap ( res - > start , resource_size ( res ) ) ;
if ( ! regs ) {
dev_err ( dev , " UHH OHCI ioremap failed \n " ) ;
return - ENOMEM ;
2010-05-10 20:26:11 +04:00
}
2013-03-12 14:44:47 +04:00
/*
* Right now device - tree probed devices don ' t get dma_mask set .
* Since shared usb code relies on it , set it here for now .
* Once we have dma capability bindings this can go away .
*/
2013-06-27 15:36:37 +04:00
ret = dma_coerce_mask_and_coherent ( dev , DMA_BIT_MASK ( 32 ) ) ;
2013-06-10 19:28:49 +04:00
if ( ret )
goto err_io ;
2010-05-10 20:26:11 +04:00
2013-06-10 19:28:49 +04:00
ret = - ENODEV ;
2011-03-01 17:38:21 +03:00
hcd = usb_create_hcd ( & ohci_omap3_hc_driver , dev ,
dev_name ( dev ) ) ;
if ( ! hcd ) {
dev_err ( dev , " usb_create_hcd failed \n " ) ;
goto err_io ;
}
2010-05-10 20:26:11 +04:00
hcd - > rsrc_start = res - > start ;
hcd - > rsrc_len = resource_size ( res ) ;
2011-03-01 17:38:21 +03:00
hcd - > regs = regs ;
2010-05-10 20:26:11 +04:00
2011-10-11 11:52:11 +04:00
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
2010-05-10 20:26:11 +04:00
2013-09-21 15:08:40 +04:00
ohci = hcd_to_ohci ( hcd ) ;
/*
* RemoteWakeupConnected has to be set explicitly before
* calling ohci_run . The reset value of RWC is 0.
*/
ohci - > hc_control = OHCI_CTRL_RWC ;
2010-05-10 20:26:11 +04:00
2011-09-07 12:10:52 +04:00
ret = usb_add_hcd ( hcd , irq , 0 ) ;
2010-05-10 20:26:11 +04:00
if ( ret ) {
2011-03-01 17:38:21 +03:00
dev_dbg ( dev , " failed to add hcd with err %d \n " , ret ) ;
2010-05-10 20:26:11 +04:00
goto err_add_hcd ;
}
2013-11-05 06:46:02 +04:00
device_wakeup_enable ( hcd - > self . controller ) ;
2010-05-10 20:26:11 +04:00
return 0 ;
err_add_hcd :
2011-10-11 11:52:11 +04:00
pm_runtime_put_sync ( dev ) ;
2010-05-10 20:26:11 +04:00
usb_put_hcd ( hcd ) ;
2011-03-01 17:38:21 +03:00
err_io :
iounmap ( regs ) ;
2010-05-10 20:26:11 +04:00
return ret ;
}
/*
* may be called without controller electrically present
* may be called with controller , bus , and devices active
*/
/**
* ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs
* @ pdev : USB Host Controller being removed
*
* Reverses the effect of ohci_hcd_omap3_probe ( ) , first invoking
* the HCD ' s stop ( ) method . It is always called from a thread
* context , normally " rmmod " , " apmd " , or something similar .
*/
2012-11-19 22:26:20 +04:00
static int ohci_hcd_omap3_remove ( struct platform_device * pdev )
2010-05-10 20:26:11 +04:00
{
2011-03-01 17:38:21 +03:00
struct device * dev = & pdev - > dev ;
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2010-05-10 20:26:11 +04:00
iounmap ( hcd - > regs ) ;
2011-03-01 17:38:21 +03:00
usb_remove_hcd ( hcd ) ;
2011-10-11 11:52:11 +04:00
pm_runtime_put_sync ( dev ) ;
pm_runtime_disable ( dev ) ;
2010-05-10 20:26:11 +04:00
usb_put_hcd ( hcd ) ;
return 0 ;
}
2013-03-12 14:44:47 +04:00
static const struct of_device_id omap_ohci_dt_ids [ ] = {
{ . compatible = " ti,ohci-omap3 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , omap_ohci_dt_ids ) ;
2010-05-10 20:26:11 +04:00
static struct platform_driver ohci_hcd_omap3_driver = {
. probe = ohci_hcd_omap3_probe ,
2012-11-19 22:21:08 +04:00
. remove = ohci_hcd_omap3_remove ,
2013-07-22 16:04:50 +04:00
. shutdown = usb_hcd_platform_shutdown ,
2010-05-10 20:26:11 +04:00
. driver = {
. name = " ohci-omap3 " ,
2013-05-21 15:47:19 +04:00
. of_match_table = omap_ohci_dt_ids ,
2010-05-10 20:26:11 +04:00
} ,
} ;
2013-09-21 15:08:40 +04:00
static int __init ohci_omap3_init ( void )
{
if ( usb_disabled ( ) )
return - ENODEV ;
pr_info ( " %s: " DRIVER_DESC " \n " , hcd_name ) ;
ohci_init_driver ( & ohci_omap3_hc_driver , NULL ) ;
return platform_driver_register ( & ohci_hcd_omap3_driver ) ;
}
module_init ( ohci_omap3_init ) ;
static void __exit ohci_omap3_cleanup ( void )
{
platform_driver_unregister ( & ohci_hcd_omap3_driver ) ;
}
module_exit ( ohci_omap3_cleanup ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2010-05-10 20:26:11 +04:00
MODULE_ALIAS ( " platform:ohci-omap3 " ) ;
MODULE_AUTHOR ( " Anand Gadiyar <gadiyar@ti.com> " ) ;
2013-09-21 15:08:40 +04:00
MODULE_LICENSE ( " GPL " ) ;