2007-12-31 02:21:11 +03:00
/*
* IXP4XX EHCI Host Controller Driver
*
2008-09-29 23:14:11 +04:00
* Author : Vladimir Barinov < vbarinov @ embeddedalley . com >
2007-12-31 02:21:11 +03:00
*
* Based on " ehci-fsl.c " by Randy Vinson < rvinson @ mvista . com >
*
* 2007 ( c ) MontaVista Software , Inc . 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 .
*/
# include <linux/platform_device.h>
static int ixp4xx_ehci_init ( struct usb_hcd * hcd )
{
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
int retval = 0 ;
ehci - > big_endian_desc = 1 ;
ehci - > big_endian_mmio = 1 ;
ehci - > caps = hcd - > regs + 0x100 ;
ehci - > regs = hcd - > regs + 0x100
+ HC_LENGTH ( ehci_readl ( ehci , & ehci - > caps - > hc_capbase ) ) ;
ehci - > hcs_params = ehci_readl ( ehci , & ehci - > caps - > hcs_params ) ;
2008-05-21 00:58:11 +04:00
hcd - > has_tt = 1 ;
2007-12-31 02:21:11 +03:00
ehci_reset ( ehci ) ;
retval = ehci_init ( hcd ) ;
if ( retval )
return retval ;
ehci_port_power ( ehci , 0 ) ;
return retval ;
}
static const struct hc_driver ixp4xx_ehci_hc_driver = {
. description = hcd_name ,
. product_desc = " IXP4XX EHCI Host Controller " ,
. hcd_priv_size = sizeof ( struct ehci_hcd ) ,
. irq = ehci_irq ,
. flags = HCD_MEMORY | HCD_USB2 ,
. reset = ixp4xx_ehci_init ,
. start = ehci_run ,
. stop = ehci_stop ,
. shutdown = ehci_shutdown ,
. urb_enqueue = ehci_urb_enqueue ,
. urb_dequeue = ehci_urb_dequeue ,
. endpoint_disable = ehci_endpoint_disable ,
2009-05-28 02:21:56 +04:00
. endpoint_reset = ehci_endpoint_reset ,
2007-12-31 02:21:11 +03:00
. get_frame_number = ehci_get_frame ,
. hub_status_data = ehci_hub_status_data ,
. hub_control = ehci_hub_control ,
# if defined(CONFIG_PM)
. bus_suspend = ehci_bus_suspend ,
. bus_resume = ehci_bus_resume ,
# endif
2008-05-21 00:58:11 +04:00
. relinquish_port = ehci_relinquish_port ,
2008-05-21 00:58:29 +04:00
. port_handed_over = ehci_port_handed_over ,
2009-06-29 18:47:30 +04:00
. clear_tt_buffer_complete = ehci_clear_tt_buffer_complete ,
2007-12-31 02:21:11 +03:00
} ;
static int ixp4xx_ehci_probe ( struct platform_device * pdev )
{
struct usb_hcd * hcd ;
const struct hc_driver * driver = & ixp4xx_ehci_hc_driver ;
struct resource * res ;
int irq ;
int retval ;
if ( usb_disabled ( ) )
return - ENODEV ;
res = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev ,
" Found HC with no IRQ. Check %s setup! \n " ,
2008-05-02 08:02:41 +04:00
dev_name ( & pdev - > dev ) ) ;
2007-12-31 02:21:11 +03:00
return - ENODEV ;
}
irq = res - > start ;
2008-05-02 08:02:41 +04:00
hcd = usb_create_hcd ( driver , & pdev - > dev , dev_name ( & pdev - > dev ) ) ;
2007-12-31 02:21:11 +03:00
if ( ! hcd ) {
retval = - ENOMEM ;
goto fail_create_hcd ;
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev ,
" Found HC with no register addr. Check %s setup! \n " ,
2008-05-02 08:02:41 +04:00
dev_name ( & pdev - > dev ) ) ;
2007-12-31 02:21:11 +03:00
retval = - ENODEV ;
goto fail_request_resource ;
}
hcd - > rsrc_start = res - > start ;
hcd - > rsrc_len = res - > end - res - > start + 1 ;
if ( ! request_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ,
driver - > description ) ) {
dev_dbg ( & pdev - > dev , " controller already in use \n " ) ;
retval = - EBUSY ;
goto fail_request_resource ;
}
hcd - > regs = ioremap_nocache ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
if ( hcd - > regs = = NULL ) {
dev_dbg ( & pdev - > dev , " error mapping memory \n " ) ;
retval = - EFAULT ;
goto fail_ioremap ;
}
retval = usb_add_hcd ( hcd , irq , IRQF_SHARED ) ;
if ( retval )
goto fail_add_hcd ;
return retval ;
fail_add_hcd :
iounmap ( hcd - > regs ) ;
fail_ioremap :
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
fail_request_resource :
usb_put_hcd ( hcd ) ;
fail_create_hcd :
2008-05-02 08:02:41 +04:00
dev_err ( & pdev - > dev , " init %s fail, %d \n " , dev_name ( & pdev - > dev ) , retval ) ;
2007-12-31 02:21:11 +03:00
return retval ;
}
static int ixp4xx_ehci_remove ( struct platform_device * pdev )
{
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
usb_remove_hcd ( hcd ) ;
iounmap ( hcd - > regs ) ;
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
usb_put_hcd ( hcd ) ;
return 0 ;
}
2008-02-12 05:40:46 +03:00
MODULE_ALIAS ( " platform:ixp4xx-ehci " ) ;
2007-12-31 02:21:11 +03:00
static struct platform_driver ixp4xx_ehci_driver = {
. probe = ixp4xx_ehci_probe ,
. remove = ixp4xx_ehci_remove ,
. driver = {
. name = " ixp4xx-ehci " ,
} ,
} ;