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 - 2002 David Brownell < dbrownell @ users . sourceforge . net >
* ( C ) Copyright 2002 Hewlett - Packard Company
2006-12-05 14:18:31 +03:00
*
2005-04-17 02:20:36 +04:00
* SA1111 Bus Glue
*
* Written by Christopher Hoover < ch @ hpl . hp . com >
2008-07-11 04:30:46 +04:00
* Based on fragments of previous driver by Russell King et al .
2005-04-17 02:20:36 +04:00
*
* This file is licenced under the GPL .
*/
2006-12-05 14:18:31 +03:00
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-04-17 02:20:36 +04:00
# include <asm/mach-types.h>
2008-08-05 19:14:15 +04:00
# include <mach/assabet.h>
2005-04-17 02:20:36 +04:00
# include <asm/hardware/sa1111.h>
# ifndef CONFIG_SA1111
# error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined."
# endif
2012-01-16 15:37:03 +04:00
# define USB_STATUS 0x0118
# define USB_RESET 0x011c
# define USB_IRQTEST 0x0120
# define USB_RESET_FORCEIFRESET (1 << 0)
# define USB_RESET_FORCEHCRESET (1 << 1)
# define USB_RESET_CLKGENRESET (1 << 2)
# define USB_RESET_SIMSCALEDOWN (1 << 3)
# define USB_RESET_USBINTTEST (1 << 4)
# define USB_RESET_SLEEPSTBYEN (1 << 5)
# define USB_RESET_PWRSENSELOW (1 << 6)
# define USB_RESET_PWRCTRLLOW (1 << 7)
# define USB_STATUS_IRQHCIRMTWKUP (1 << 7)
# define USB_STATUS_IRQHCIBUFFACC (1 << 8)
# define USB_STATUS_NIRQHCIM (1 << 9)
# define USB_STATUS_NHCIMFCLR (1 << 10)
# define USB_STATUS_USBPWRSENSE (1 << 11)
2012-01-26 14:52:34 +04:00
#if 0
static void dump_hci_status ( struct usb_hcd * hcd , const char * label )
{
unsigned long status = sa1111_readl ( hcd - > regs + USB_STATUS ) ;
2012-05-02 08:33:39 +04:00
printk ( KERN_DEBUG " %s USB_STATUS = { %s%s%s%s%s} \n " , label ,
2012-01-26 14:52:34 +04:00
( ( status & USB_STATUS_IRQHCIRMTWKUP ) ? " IRQHCIRMTWKUP " : " " ) ,
( ( status & USB_STATUS_IRQHCIBUFFACC ) ? " IRQHCIBUFFACC " : " " ) ,
( ( status & USB_STATUS_NIRQHCIM ) ? " " : " IRQHCIM " ) ,
( ( status & USB_STATUS_NHCIMFCLR ) ? " " : " HCIMFCLR " ) ,
( ( status & USB_STATUS_USBPWRSENSE ) ? " USBPWRSENSE " : " " ) ) ;
}
# endif
2012-01-26 15:45:27 +04:00
static int ohci_sa1111_reset ( struct usb_hcd * hcd )
{
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
ohci_hcd_init ( ohci ) ;
return ohci_init ( ohci ) ;
}
2012-11-19 22:21:48 +04:00
static int ohci_sa1111_start ( struct usb_hcd * hcd )
2012-01-26 14:52:34 +04:00
{
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
int ret ;
ret = ohci_run ( ohci ) ;
if ( ret < 0 ) {
2012-01-26 15:45:27 +04:00
ohci_err ( ohci , " can't start \n " ) ;
2012-01-26 14:52:34 +04:00
ohci_stop ( hcd ) ;
}
2012-01-26 15:45:27 +04:00
return ret ;
2012-01-26 14:52:34 +04:00
}
static const struct hc_driver ohci_sa1111_hc_driver = {
. description = hcd_name ,
. product_desc = " SA-1111 OHCI " ,
. hcd_priv_size = sizeof ( struct ohci_hcd ) ,
/*
* generic hardware linkage
*/
. irq = ohci_irq ,
. flags = HCD_USB11 | HCD_MEMORY ,
/*
* basic lifecycle operations
*/
2012-01-26 15:45:27 +04:00
. reset = ohci_sa1111_reset ,
2012-01-26 14:52:34 +04:00
. start = ohci_sa1111_start ,
. stop = ohci_stop ,
2012-01-26 15:10:20 +04:00
. shutdown = ohci_shutdown ,
2012-01-26 14:52:34 +04:00
/*
* managing i / o requests and associated device resources
*/
. urb_enqueue = ohci_urb_enqueue ,
. urb_dequeue = ohci_urb_dequeue ,
. endpoint_disable = ohci_endpoint_disable ,
/*
* scheduling support
*/
. get_frame_number = ohci_get_frame ,
/*
* root hub support
*/
. 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 ,
} ;
2005-04-17 02:20:36 +04:00
2012-01-26 17:25:47 +04:00
static int sa1111_start_hc ( struct sa1111_dev * dev )
2005-04-17 02:20:36 +04:00
{
unsigned int usb_rst = 0 ;
2012-01-26 17:25:47 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
2012-01-26 14:39:57 +04:00
dev_dbg ( & dev - > dev , " starting SA-1111 OHCI USB Controller \n " ) ;
2005-04-17 02:20:36 +04:00
if ( machine_is_xp860 ( ) | |
machine_has_neponset ( ) | |
machine_is_pfs168 ( ) | |
machine_is_badge4 ( ) )
usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW ;
/*
* Configure the power sense and control lines . Place the USB
* host controller in reset .
*/
sa1111_writel ( usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET ,
2012-01-16 15:37:03 +04:00
dev - > mapbase + USB_RESET ) ;
2005-04-17 02:20:36 +04:00
/*
* Now , carefully enable the USB clock , and take
* the USB host controller out of reset .
*/
2012-01-26 17:25:47 +04:00
ret = sa1111_enable_device ( dev ) ;
if ( ret = = 0 ) {
udelay ( 11 ) ;
2012-01-16 15:37:03 +04:00
sa1111_writel ( usb_rst , dev - > mapbase + USB_RESET ) ;
2012-01-26 17:25:47 +04:00
}
return ret ;
2005-04-17 02:20:36 +04:00
}
static void sa1111_stop_hc ( struct sa1111_dev * dev )
{
unsigned int usb_rst ;
2012-01-26 14:37:46 +04:00
2012-01-26 14:39:57 +04:00
dev_dbg ( & dev - > dev , " stopping SA-1111 OHCI USB Controller \n " ) ;
2005-04-17 02:20:36 +04:00
/*
* Put the USB host controller into reset .
*/
2012-01-16 15:37:03 +04:00
usb_rst = sa1111_readl ( dev - > mapbase + USB_RESET ) ;
2005-04-17 02:20:36 +04:00
sa1111_writel ( usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET ,
2012-01-16 15:37:03 +04:00
dev - > mapbase + USB_RESET ) ;
2005-04-17 02:20:36 +04:00
/*
* Stop the USB clock .
*/
sa1111_disable_device ( dev ) ;
}
/**
2012-01-26 14:52:34 +04:00
* ohci_hcd_sa1111_probe - initialize SA - 1111 - based HCDs
2005-04-17 02:20:36 +04:00
*
* Allocates basic resources for this USB host controller , and
2012-01-26 14:52:34 +04:00
* then invokes the start ( ) method for the HCD associated with it .
2005-04-17 02:20:36 +04:00
*/
2012-01-26 14:52:34 +04:00
static int ohci_hcd_sa1111_probe ( struct sa1111_dev * dev )
2005-04-17 02:20:36 +04:00
{
struct usb_hcd * hcd ;
2012-01-26 14:52:34 +04:00
int ret ;
if ( usb_disabled ( ) )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2012-01-26 14:52:34 +04:00
hcd = usb_create_hcd ( & ohci_sa1111_hc_driver , & dev - > dev , " sa1111 " ) ;
2005-04-17 02:20:36 +04:00
if ( ! hcd )
return - ENOMEM ;
2012-01-26 14:37:46 +04:00
2005-04-17 02:20:36 +04:00
hcd - > rsrc_start = dev - > res . start ;
2011-06-09 20:13:32 +04:00
hcd - > rsrc_len = resource_size ( & dev - > res ) ;
2005-04-17 02:20:36 +04:00
if ( ! request_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len , hcd_name ) ) {
2012-05-02 08:33:39 +04:00
dev_dbg ( & dev - > dev , " request_mem_region failed \n " ) ;
2012-01-26 14:52:34 +04:00
ret = - EBUSY ;
2005-04-17 02:20:36 +04:00
goto err1 ;
}
2012-01-26 14:37:46 +04:00
2005-04-17 02:20:36 +04:00
hcd - > regs = dev - > mapbase ;
2012-01-26 17:25:47 +04:00
ret = sa1111_start_hc ( dev ) ;
if ( ret )
goto err2 ;
2012-01-26 14:52:34 +04:00
ret = usb_add_hcd ( hcd , dev - > irq [ 1 ] , 0 ) ;
if ( ret = = 0 )
return ret ;
2005-04-17 02:20:36 +04:00
sa1111_stop_hc ( dev ) ;
2012-01-26 17:25:47 +04:00
err2 :
2005-04-17 02:20:36 +04:00
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
err1 :
usb_put_hcd ( hcd ) ;
2012-01-26 14:52:34 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
/**
2012-01-26 14:52:34 +04:00
* ohci_hcd_sa1111_remove - shutdown processing for SA - 1111 - based HCDs
2005-04-17 02:20:36 +04:00
* @ dev : USB Host Controller being removed
*
2012-01-26 14:52:34 +04:00
* Reverses the effect of ohci_hcd_sa1111_probe ( ) , first invoking
* the HCD ' s stop ( ) method .
2005-04-17 02:20:36 +04:00
*/
2012-01-26 14:52:34 +04:00
static int ohci_hcd_sa1111_remove ( struct sa1111_dev * dev )
2005-04-17 02:20:36 +04:00
{
2012-01-26 14:52:34 +04:00
struct usb_hcd * hcd = sa1111_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
usb_remove_hcd ( hcd ) ;
sa1111_stop_hc ( dev ) ;
release_mem_region ( hcd - > rsrc_start , hcd - > rsrc_len ) ;
usb_put_hcd ( hcd ) ;
return 0 ;
}
2012-01-26 15:10:20 +04:00
static void ohci_hcd_sa1111_shutdown ( struct sa1111_dev * dev )
{
struct usb_hcd * hcd = sa1111_get_drvdata ( dev ) ;
if ( test_bit ( HCD_FLAG_HW_ACCESSIBLE , & hcd - > flags ) ) {
hcd - > driver - > shutdown ( hcd ) ;
sa1111_stop_hc ( dev ) ;
}
}
2005-04-17 02:20:36 +04:00
static struct sa1111_driver ohci_hcd_sa1111_driver = {
. drv = {
. name = " sa1111-ohci " ,
2012-01-26 15:19:48 +04:00
. owner = THIS_MODULE ,
2005-04-17 02:20:36 +04:00
} ,
. devid = SA1111_DEVID_USB ,
2012-01-26 14:52:34 +04:00
. probe = ohci_hcd_sa1111_probe ,
. remove = ohci_hcd_sa1111_remove ,
2012-01-26 15:10:20 +04:00
. shutdown = ohci_hcd_sa1111_shutdown ,
2005-04-17 02:20:36 +04:00
} ;