2012-03-13 04:04:47 +04:00
/*
* Generic platform ohci driver
*
* Copyright 2007 Michael Buesch < m @ bues . ch >
* Copyright 2011 - 2012 Hauke Mehrtens < hauke @ hauke - m . de >
*
* Derived from the OCHI - SSB driver
* Derived from the OHCI - PCI driver
* Copyright 1999 Roman Weissgaerber
* Copyright 2000 - 2002 David Brownell
* Copyright 1999 Linus Torvalds
* Copyright 1999 Gregory P . Smith
*
* Licensed under the GNU / GPL . See COPYING for details .
*/
# include <linux/platform_device.h>
# include <linux/usb/ohci_pdriver.h>
static int ohci_platform_reset ( struct usb_hcd * hcd )
{
struct platform_device * pdev = to_platform_device ( hcd - > self . controller ) ;
struct usb_ohci_pdata * pdata = pdev - > dev . platform_data ;
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
int err ;
if ( pdata - > big_endian_desc )
ohci - > flags | = OHCI_QUIRK_BE_DESC ;
if ( pdata - > big_endian_mmio )
ohci - > flags | = OHCI_QUIRK_BE_MMIO ;
if ( pdata - > no_big_frame_no )
ohci - > flags | = OHCI_QUIRK_FRAME_NO ;
ohci_hcd_init ( ohci ) ;
2012-10-08 17:11:26 +04:00
if ( pdata - > num_ports )
ohci - > num_ports = pdata - > num_ports ;
2012-03-13 04:04:47 +04:00
err = ohci_init ( ohci ) ;
return err ;
}
static int ohci_platform_start ( struct usb_hcd * hcd )
{
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
int err ;
err = ohci_run ( ohci ) ;
if ( err < 0 ) {
ohci_err ( ohci , " can't start \n " ) ;
ohci_stop ( hcd ) ;
}
return err ;
}
static const struct hc_driver ohci_platform_hc_driver = {
. description = hcd_name ,
. product_desc = " Generic Platform OHCI Controller " ,
. hcd_priv_size = sizeof ( struct ohci_hcd ) ,
. irq = ohci_irq ,
. flags = HCD_MEMORY | HCD_USB11 ,
. reset = ohci_platform_reset ,
. start = ohci_platform_start ,
. stop = ohci_stop ,
. shutdown = ohci_shutdown ,
. urb_enqueue = ohci_urb_enqueue ,
. urb_dequeue = ohci_urb_dequeue ,
. endpoint_disable = ohci_endpoint_disable ,
. get_frame_number = ohci_get_frame ,
. hub_status_data = ohci_hub_status_data ,
. hub_control = ohci_hub_control ,
# ifdef CONFIG_PM
. bus_suspend = ohci_bus_suspend ,
. bus_resume = ohci_bus_resume ,
# endif
. start_port_reset = ohci_start_port_reset ,
} ;
2012-11-19 22:21:48 +04:00
static int ohci_platform_probe ( struct platform_device * dev )
2012-03-13 04:04:47 +04:00
{
struct usb_hcd * hcd ;
struct resource * res_mem ;
2012-08-07 05:07:30 +04:00
struct usb_ohci_pdata * pdata = dev - > dev . platform_data ;
2012-03-13 04:04:47 +04:00
int irq ;
int err = - ENOMEM ;
2012-08-07 05:07:30 +04:00
if ( ! pdata ) {
WARN_ON ( 1 ) ;
return - ENODEV ;
}
2012-03-13 04:04:47 +04:00
if ( usb_disabled ( ) )
return - ENODEV ;
irq = platform_get_irq ( dev , 0 ) ;
if ( irq < 0 ) {
2012-10-08 17:11:42 +04:00
dev_err ( & dev - > dev , " no irq provided " ) ;
2012-03-13 04:04:47 +04:00
return irq ;
}
res_mem = platform_get_resource ( dev , IORESOURCE_MEM , 0 ) ;
if ( ! res_mem ) {
2012-10-08 17:11:44 +04:00
dev_err ( & dev - > dev , " no memory resource provided " ) ;
2012-03-13 04:04:47 +04:00
return - ENXIO ;
}
2012-08-07 05:09:10 +04:00
if ( pdata - > power_on ) {
err = pdata - > power_on ( dev ) ;
if ( err < 0 )
return err ;
}
2012-03-13 04:04:47 +04:00
hcd = usb_create_hcd ( & ohci_platform_hc_driver , & dev - > dev ,
dev_name ( & dev - > dev ) ) ;
2012-08-07 05:09:10 +04:00
if ( ! hcd ) {
err = - ENOMEM ;
goto err_power ;
}
2012-03-13 04:04:47 +04:00
hcd - > rsrc_start = res_mem - > start ;
hcd - > rsrc_len = resource_size ( res_mem ) ;
2012-10-08 17:11:46 +04:00
hcd - > regs = devm_request_and_ioremap ( & dev - > dev , res_mem ) ;
2012-08-14 10:47:37 +04:00
if ( ! hcd - > regs ) {
err = - ENOMEM ;
2012-10-08 17:11:46 +04:00
goto err_put_hcd ;
2012-08-14 10:47:37 +04:00
}
2012-03-13 04:04:47 +04:00
err = usb_add_hcd ( hcd , irq , IRQF_SHARED ) ;
if ( err )
2012-10-08 17:11:46 +04:00
goto err_put_hcd ;
2012-03-13 04:04:47 +04:00
platform_set_drvdata ( dev , hcd ) ;
return err ;
err_put_hcd :
usb_put_hcd ( hcd ) ;
2012-08-07 05:09:10 +04:00
err_power :
if ( pdata - > power_off )
pdata - > power_off ( dev ) ;
2012-03-13 04:04:47 +04:00
return err ;
}
2012-11-19 22:26:20 +04:00
static int ohci_platform_remove ( struct platform_device * dev )
2012-03-13 04:04:47 +04:00
{
struct usb_hcd * hcd = platform_get_drvdata ( dev ) ;
2012-08-07 05:09:10 +04:00
struct usb_ohci_pdata * pdata = dev - > dev . platform_data ;
2012-03-13 04:04:47 +04:00
usb_remove_hcd ( hcd ) ;
usb_put_hcd ( hcd ) ;
platform_set_drvdata ( dev , NULL ) ;
2012-08-07 05:09:10 +04:00
if ( pdata - > power_off )
pdata - > power_off ( dev ) ;
2012-03-13 04:04:47 +04:00
return 0 ;
}
# ifdef CONFIG_PM
static int ohci_platform_suspend ( struct device * dev )
{
2012-08-07 05:09:10 +04:00
struct usb_ohci_pdata * pdata = dev - > platform_data ;
struct platform_device * pdev =
container_of ( dev , struct platform_device , dev ) ;
if ( pdata - > power_suspend )
pdata - > power_suspend ( pdev ) ;
2012-03-13 04:04:47 +04:00
return 0 ;
}
static int ohci_platform_resume ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2012-08-07 05:09:10 +04:00
struct usb_ohci_pdata * pdata = dev - > platform_data ;
struct platform_device * pdev =
container_of ( dev , struct platform_device , dev ) ;
if ( pdata - > power_on ) {
int err = pdata - > power_on ( pdev ) ;
if ( err < 0 )
return err ;
}
2012-03-13 04:04:47 +04:00
2012-10-08 17:11:29 +04:00
ohci_resume ( hcd , false ) ;
2012-03-13 04:04:47 +04:00
return 0 ;
}
# else /* !CONFIG_PM */
# define ohci_platform_suspend NULL
# define ohci_platform_resume NULL
# endif /* CONFIG_PM */
static const struct platform_device_id ohci_platform_table [ ] = {
{ " ohci-platform " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( platform , ohci_platform_table ) ;
static const struct dev_pm_ops ohci_platform_pm_ops = {
. suspend = ohci_platform_suspend ,
. resume = ohci_platform_resume ,
} ;
static struct platform_driver ohci_platform_driver = {
. id_table = ohci_platform_table ,
. probe = ohci_platform_probe ,
2012-11-19 22:21:08 +04:00
. remove = ohci_platform_remove ,
2012-03-13 04:04:47 +04:00
. shutdown = usb_hcd_platform_shutdown ,
. driver = {
. owner = THIS_MODULE ,
. name = " ohci-platform " ,
. pm = & ohci_platform_pm_ops ,
}
} ;