2010-11-07 19:28:55 +03:00
/*
* drivers / usb / host / ehci - vt8500 . c
*
* Copyright ( C ) 2010 Alexey Charkov < alchark @ gmail . com >
*
* Based on ehci - au1xxx . c
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* 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 .
*
*/
# include <linux/platform_device.h>
static int ehci_update_device ( struct usb_hcd * hcd , struct usb_device * udev )
{
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
int rc = 0 ;
if ( ! udev - > parent ) /* udev is root hub itself, impossible */
rc = - 1 ;
/* we only support lpm device connected to root hub yet */
if ( ehci - > has_lpm & & ! udev - > parent - > parent ) {
rc = ehci_lpm_set_da ( ehci , udev - > devnum , udev - > portnum ) ;
if ( ! rc )
rc = ehci_lpm_check ( ehci , udev - > portnum ) ;
}
return rc ;
}
static const struct hc_driver vt8500_ehci_hc_driver = {
. description = hcd_name ,
. product_desc = " VT8500 EHCI " ,
. hcd_priv_size = sizeof ( struct ehci_hcd ) ,
/*
* generic hardware linkage
*/
. irq = ehci_irq ,
. flags = HCD_MEMORY | HCD_USB2 ,
/*
* basic lifecycle operations
*/
. reset = ehci_init ,
. start = ehci_run ,
. stop = ehci_stop ,
. shutdown = ehci_shutdown ,
/*
* managing i / o requests and associated device resources
*/
. urb_enqueue = ehci_urb_enqueue ,
. urb_dequeue = ehci_urb_dequeue ,
. endpoint_disable = ehci_endpoint_disable ,
. endpoint_reset = ehci_endpoint_reset ,
/*
* scheduling support
*/
. get_frame_number = ehci_get_frame ,
/*
* root hub support
*/
. hub_status_data = ehci_hub_status_data ,
. hub_control = ehci_hub_control ,
. bus_suspend = ehci_bus_suspend ,
. bus_resume = ehci_bus_resume ,
. relinquish_port = ehci_relinquish_port ,
. port_handed_over = ehci_port_handed_over ,
/*
* call back when device connected and addressed
*/
. update_device = ehci_update_device ,
. clear_tt_buffer_complete = ehci_clear_tt_buffer_complete ,
} ;
static int vt8500_ehci_drv_probe ( struct platform_device * pdev )
{
struct usb_hcd * hcd ;
struct ehci_hcd * ehci ;
struct resource * res ;
int ret ;
if ( usb_disabled ( ) )
return - ENODEV ;
if ( pdev - > resource [ 1 ] . flags ! = IORESOURCE_IRQ ) {
pr_debug ( " resource[1] is not IORESOURCE_IRQ " ) ;
return - ENOMEM ;
}
hcd = usb_create_hcd ( & vt8500_ehci_hc_driver , & pdev - > dev , " VT8500 " ) ;
if ( ! hcd )
return - ENOMEM ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
hcd - > rsrc_start = res - > start ;
hcd - > rsrc_len = resource_size ( res ) ;
if ( ! request_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len , hcd_name ) ) {
pr_debug ( " request_mem_region failed " ) ;
ret = - EBUSY ;
goto err1 ;
}
hcd - > regs = ioremap ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
if ( ! hcd - > regs ) {
pr_debug ( " ioremap failed " ) ;
ret = - ENOMEM ;
goto err2 ;
}
ehci = hcd_to_ehci ( hcd ) ;
ehci - > caps = hcd - > regs ;
2011-05-03 22:11:57 +04:00
ehci - > regs = hcd - > regs +
HC_LENGTH ( ehci , readl ( & ehci - > caps - > hc_capbase ) ) ;
2010-11-07 19:28:55 +03:00
dbg_hcs_params ( ehci , " reset " ) ;
dbg_hcc_params ( ehci , " reset " ) ;
/* cache this readonly data; minimize chip reads */
ehci - > hcs_params = readl ( & ehci - > caps - > hcs_params ) ;
ehci_port_power ( ehci , 1 ) ;
ret = usb_add_hcd ( hcd , pdev - > resource [ 1 ] . start ,
2011-09-07 12:10:52 +04:00
IRQF_SHARED ) ;
2010-11-07 19:28:55 +03:00
if ( ret = = 0 ) {
platform_set_drvdata ( pdev , hcd ) ;
return ret ;
}
iounmap ( hcd - > regs ) ;
err2 :
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
err1 :
usb_put_hcd ( hcd ) ;
return ret ;
}
static int vt8500_ehci_drv_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 ) ;
platform_set_drvdata ( pdev , NULL ) ;
return 0 ;
}
static struct platform_driver vt8500_ehci_driver = {
. probe = vt8500_ehci_drv_probe ,
. remove = vt8500_ehci_drv_remove ,
. shutdown = usb_hcd_platform_shutdown ,
. driver = {
. name = " vt8500-ehci " ,
. owner = THIS_MODULE ,
}
} ;
MODULE_ALIAS ( " platform:vt8500-ehci " ) ;