2005-04-16 15:20:36 -07: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
*
* Bus Glue for pxa27x
*
* Written by Christopher Hoover < ch @ hpl . hp . com >
* Based on fragments of previous driver by Russell King et al .
*
* Modified for LH7A404 from ohci - sa1111 . c
* by Durgesh Pattamatta < pattamattad @ sharpsec . com >
*
* Modified for pxa27x from ohci - lh7a404 . c
* by Nick Bane < nick @ cecomputing . co . uk > 26 - 8 - 2004
*
* This file is licenced under the GPL .
*/
2007-12-12 08:53:25 +08:00
# include <linux/clk.h>
2013-09-21 16:38:46 +05:30
# include <linux/device.h>
2013-11-15 14:19:02 +01:00
# include <linux/dma-mapping.h>
2013-09-21 16:38:46 +05:30
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
2012-07-30 09:29:12 +02:00
# include <linux/of_platform.h>
# include <linux/of_gpio.h>
2012-08-24 15:16:48 +02:00
# include <linux/platform_data/usb-ohci-pxa27x.h>
# include <linux/platform_data/usb-pxa3xx-ulpi.h>
2013-09-21 16:38:46 +05:30
# include <linux/platform_device.h>
2014-04-16 18:00:11 +02:00
# include <linux/regulator/consumer.h>
2013-09-21 16:38:46 +05:30
# include <linux/signal.h>
# include <linux/usb.h>
# include <linux/usb/hcd.h>
# include <linux/usb/otg.h>
# include <mach/hardware.h>
# include "ohci.h"
# define DRIVER_DESC "OHCI PXA27x / PXA3x driver"
2005-04-16 15:20:36 -07:00
2008-09-27 16:12:32 +08:00
/*
* UHC : USB Host Controller ( OHCI - like ) register definitions
*/
2008-10-04 12:57:21 +08:00
# define UHCREV (0x0000) /* UHC HCI Spec Revision */
# define UHCHCON (0x0004) /* UHC Host Control Register */
# define UHCCOMS (0x0008) /* UHC Command Status Register */
# define UHCINTS (0x000C) /* UHC Interrupt Status Register */
# define UHCINTE (0x0010) /* UHC Interrupt Enable */
# define UHCINTD (0x0014) /* UHC Interrupt Disable */
# define UHCHCCA (0x0018) /* UHC Host Controller Comm. Area */
# define UHCPCED (0x001C) /* UHC Period Current Endpt Descr */
# define UHCCHED (0x0020) /* UHC Control Head Endpt Descr */
# define UHCCCED (0x0024) /* UHC Control Current Endpt Descr */
# define UHCBHED (0x0028) /* UHC Bulk Head Endpt Descr */
# define UHCBCED (0x002C) /* UHC Bulk Current Endpt Descr */
# define UHCDHEAD (0x0030) /* UHC Done Head */
# define UHCFMI (0x0034) /* UHC Frame Interval */
# define UHCFMR (0x0038) /* UHC Frame Remaining */
# define UHCFMN (0x003C) /* UHC Frame Number */
# define UHCPERS (0x0040) /* UHC Periodic Start */
# define UHCLS (0x0044) /* UHC Low Speed Threshold */
# define UHCRHDA (0x0048) /* UHC Root Hub Descriptor A */
2008-09-27 16:12:32 +08:00
# define UHCRHDA_NOCP (1 << 12) /* No over current protection */
# define UHCRHDA_OCPM (1 << 11) /* Over Current Protection Mode */
# define UHCRHDA_POTPGT(x) \
( ( ( x ) & 0xff ) < < 24 ) /* Power On To Power Good Time */
2008-10-04 12:57:21 +08:00
# define UHCRHDB (0x004C) /* UHC Root Hub Descriptor B */
# define UHCRHS (0x0050) /* UHC Root Hub Status */
# define UHCRHPS1 (0x0054) /* UHC Root Hub Port 1 Status */
# define UHCRHPS2 (0x0058) /* UHC Root Hub Port 2 Status */
# define UHCRHPS3 (0x005C) /* UHC Root Hub Port 3 Status */
2008-09-27 16:12:32 +08:00
2008-10-04 12:57:21 +08:00
# define UHCSTAT (0x0060) /* UHC Status Register */
2008-09-27 16:12:32 +08:00
# define UHCSTAT_UPS3 (1 << 16) /* USB Power Sense Port3 */
# define UHCSTAT_SBMAI (1 << 15) /* System Bus Master Abort Interrupt*/
# define UHCSTAT_SBTAI (1 << 14) /* System Bus Target Abort Interrupt*/
# define UHCSTAT_UPRI (1 << 13) /* USB Port Resume Interrupt */
# define UHCSTAT_UPS2 (1 << 12) /* USB Power Sense Port 2 */
# define UHCSTAT_UPS1 (1 << 11) /* USB Power Sense Port 1 */
# define UHCSTAT_HTA (1 << 10) /* HCI Target Abort */
# define UHCSTAT_HBA (1 << 8) /* HCI Buffer Active */
# define UHCSTAT_RWUE (1 << 7) /* HCI Remote Wake Up Event */
2008-10-04 12:57:21 +08:00
# define UHCHR (0x0064) /* UHC Reset Register */
2008-09-27 16:12:32 +08:00
# define UHCHR_SSEP3 (1 << 11) /* Sleep Standby Enable for Port3 */
# define UHCHR_SSEP2 (1 << 10) /* Sleep Standby Enable for Port2 */
# define UHCHR_SSEP1 (1 << 9) /* Sleep Standby Enable for Port1 */
# define UHCHR_PCPL (1 << 7) /* Power control polarity low */
# define UHCHR_PSPL (1 << 6) /* Power sense polarity low */
# define UHCHR_SSE (1 << 5) /* Sleep Standby Enable */
# define UHCHR_UIT (1 << 4) /* USB Interrupt Test */
# define UHCHR_SSDC (1 << 3) /* Simulation Scale Down Clock */
# define UHCHR_CGR (1 << 2) /* Clock Generation Reset */
# define UHCHR_FHR (1 << 1) /* Force Host Controller Reset */
# define UHCHR_FSBIR (1 << 0) /* Force System Bus Iface Reset */
2008-10-04 12:57:21 +08:00
# define UHCHIE (0x0068) /* UHC Interrupt Enable Register*/
2008-09-27 16:12:32 +08:00
# define UHCHIE_UPS3IE (1 << 14) /* Power Sense Port3 IntEn */
# define UHCHIE_UPRIE (1 << 13) /* Port Resume IntEn */
# define UHCHIE_UPS2IE (1 << 12) /* Power Sense Port2 IntEn */
# define UHCHIE_UPS1IE (1 << 11) /* Power Sense Port1 IntEn */
# define UHCHIE_TAIE (1 << 10) / * HCI Interface Transfer Abort
Interrupt Enable */
# define UHCHIE_HBAIE (1 << 8) /* HCI Buffer Active IntEn */
# define UHCHIE_RWIE (1 << 7) /* Remote Wake-up IntEn */
2008-10-04 12:57:21 +08:00
# define UHCHIT (0x006C) /* UHC Interrupt Test register */
2008-09-27 16:12:32 +08:00
2005-04-16 15:20:36 -07:00
# define PXA_UHC_MAX_PORTNUM 3
2013-09-21 16:38:46 +05:30
static const char hcd_name [ ] = " ohci-pxa27x " ;
2005-04-16 15:20:36 -07:00
2013-09-21 16:38:46 +05:30
static struct hc_driver __read_mostly ohci_pxa27x_hc_driver ;
struct pxa27x_ohci {
2008-10-04 12:57:21 +08:00
struct clk * clk ;
void __iomem * mmio_base ;
2014-04-16 18:00:11 +02:00
struct regulator * vbus [ 3 ] ;
bool vbus_enabled [ 3 ] ;
2008-10-04 12:57:21 +08:00
} ;
2013-09-21 16:38:46 +05:30
# define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv)
2007-12-12 08:53:25 +08:00
2005-04-16 15:20:36 -07:00
/*
PMM_NPS_MODE - - PMM Non - power switching mode
Ports are powered continuously .
PMM_GLOBAL_MODE - - PMM global switching mode
All ports are powered at the same time .
PMM_PERPORT_MODE - - PMM per port switching mode
Ports are powered individually .
*/
2013-09-21 16:38:46 +05:30
static int pxa27x_ohci_select_pmm ( struct pxa27x_ohci * pxa_ohci , int mode )
2005-04-16 15:20:36 -07:00
{
2013-09-21 16:38:46 +05:30
uint32_t uhcrhda = __raw_readl ( pxa_ohci - > mmio_base + UHCRHDA ) ;
uint32_t uhcrhdb = __raw_readl ( pxa_ohci - > mmio_base + UHCRHDB ) ;
2008-10-04 12:57:21 +08:00
switch ( mode ) {
2005-04-16 15:20:36 -07:00
case PMM_NPS_MODE :
2008-10-04 12:57:21 +08:00
uhcrhda | = RH_A_NPS ;
2006-12-05 03:18:31 -08:00
break ;
2005-04-16 15:20:36 -07:00
case PMM_GLOBAL_MODE :
2008-10-04 12:57:21 +08:00
uhcrhda & = ~ ( RH_A_NPS & RH_A_PSM ) ;
2005-04-16 15:20:36 -07:00
break ;
case PMM_PERPORT_MODE :
2008-10-04 12:57:21 +08:00
uhcrhda & = ~ ( RH_A_NPS ) ;
uhcrhda | = RH_A_PSM ;
2005-04-16 15:20:36 -07:00
/* Set port power control mask bits, only 3 ports. */
2008-10-04 12:57:21 +08:00
uhcrhdb | = ( 0x7 < < 17 ) ;
2005-04-16 15:20:36 -07:00
break ;
default :
printk ( KERN_ERR
2006-12-05 03:18:31 -08:00
" Invalid mode %d, set to non-power switch mode. \n " ,
2005-04-16 15:20:36 -07:00
mode ) ;
2008-10-04 12:57:21 +08:00
uhcrhda | = RH_A_NPS ;
2005-04-16 15:20:36 -07:00
}
2013-09-21 16:38:46 +05:30
__raw_writel ( uhcrhda , pxa_ohci - > mmio_base + UHCRHDA ) ;
__raw_writel ( uhcrhdb , pxa_ohci - > mmio_base + UHCRHDB ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2014-04-16 18:00:11 +02:00
static int pxa27x_ohci_set_vbus_power ( struct pxa27x_ohci * pxa_ohci ,
unsigned int port , bool enable )
{
struct regulator * vbus = pxa_ohci - > vbus [ port ] ;
int ret = 0 ;
if ( IS_ERR_OR_NULL ( vbus ) )
return 0 ;
if ( enable & & ! pxa_ohci - > vbus_enabled [ port ] )
ret = regulator_enable ( vbus ) ;
else if ( ! enable & & pxa_ohci - > vbus_enabled [ port ] )
ret = regulator_disable ( vbus ) ;
if ( ret < 0 )
return ret ;
pxa_ohci - > vbus_enabled [ port ] = enable ;
return 0 ;
}
static int pxa27x_ohci_hub_control ( struct usb_hcd * hcd , u16 typeReq , u16 wValue ,
u16 wIndex , char * buf , u16 wLength )
{
struct pxa27x_ohci * pxa_ohci = to_pxa27x_ohci ( hcd ) ;
int ret ;
switch ( typeReq ) {
case SetPortFeature :
case ClearPortFeature :
if ( ! wIndex | | wIndex > 3 )
return - EPIPE ;
if ( wValue ! = USB_PORT_FEAT_POWER )
break ;
ret = pxa27x_ohci_set_vbus_power ( pxa_ohci , wIndex - 1 ,
typeReq = = SetPortFeature ) ;
if ( ret )
return ret ;
break ;
}
return ohci_hub_control ( hcd , typeReq , wValue , wIndex , buf , wLength ) ;
}
2005-04-16 15:20:36 -07:00
/*-------------------------------------------------------------------------*/
2013-09-21 16:38:46 +05:30
static inline void pxa27x_setup_hc ( struct pxa27x_ohci * pxa_ohci ,
2008-10-04 12:57:21 +08:00
struct pxaohci_platform_data * inf )
2008-09-27 15:49:57 +08:00
{
2013-09-21 16:38:46 +05:30
uint32_t uhchr = __raw_readl ( pxa_ohci - > mmio_base + UHCHR ) ;
uint32_t uhcrhda = __raw_readl ( pxa_ohci - > mmio_base + UHCRHDA ) ;
2008-09-27 15:49:57 +08:00
if ( inf - > flags & ENABLE_PORT1 )
uhchr & = ~ UHCHR_SSEP1 ;
if ( inf - > flags & ENABLE_PORT2 )
uhchr & = ~ UHCHR_SSEP2 ;
if ( inf - > flags & ENABLE_PORT3 )
uhchr & = ~ UHCHR_SSEP3 ;
if ( inf - > flags & POWER_CONTROL_LOW )
uhchr | = UHCHR_PCPL ;
if ( inf - > flags & POWER_SENSE_LOW )
uhchr | = UHCHR_PSPL ;
if ( inf - > flags & NO_OC_PROTECTION )
uhcrhda | = UHCRHDA_NOCP ;
2009-07-30 13:26:58 -04:00
else
uhcrhda & = ~ UHCRHDA_NOCP ;
2008-09-27 15:49:57 +08:00
if ( inf - > flags & OC_MODE_PERPORT )
uhcrhda | = UHCRHDA_OCPM ;
2009-07-30 13:26:58 -04:00
else
uhcrhda & = ~ UHCRHDA_OCPM ;
2008-09-27 15:49:57 +08:00
if ( inf - > power_on_delay ) {
uhcrhda & = ~ UHCRHDA_POTPGT ( 0xff ) ;
uhcrhda | = UHCRHDA_POTPGT ( inf - > power_on_delay / 2 ) ;
}
2013-09-21 16:38:46 +05:30
__raw_writel ( uhchr , pxa_ohci - > mmio_base + UHCHR ) ;
__raw_writel ( uhcrhda , pxa_ohci - > mmio_base + UHCRHDA ) ;
2008-10-04 12:57:21 +08:00
}
2013-09-21 16:38:46 +05:30
static inline void pxa27x_reset_hc ( struct pxa27x_ohci * pxa_ohci )
2008-10-04 12:57:21 +08:00
{
2013-09-21 16:38:46 +05:30
uint32_t uhchr = __raw_readl ( pxa_ohci - > mmio_base + UHCHR ) ;
2008-10-04 12:57:21 +08:00
2013-09-21 16:38:46 +05:30
__raw_writel ( uhchr | UHCHR_FHR , pxa_ohci - > mmio_base + UHCHR ) ;
2008-10-04 12:57:21 +08:00
udelay ( 11 ) ;
2013-09-21 16:38:46 +05:30
__raw_writel ( uhchr & ~ UHCHR_FHR , pxa_ohci - > mmio_base + UHCHR ) ;
2008-09-27 15:49:57 +08:00
}
2010-07-14 21:17:25 +08:00
# ifdef CONFIG_PXA27x
2008-10-04 12:45:39 +08:00
extern void pxa27x_clear_otgph ( void ) ;
# else
# define pxa27x_clear_otgph() do {} while (0)
# endif
2013-09-21 16:38:46 +05:30
static int pxa27x_start_hc ( struct pxa27x_ohci * pxa_ohci , struct device * dev )
2005-04-16 15:20:36 -07:00
{
2005-11-12 14:22:11 +00:00
int retval = 0 ;
struct pxaohci_platform_data * inf ;
2008-10-04 12:57:21 +08:00
uint32_t uhchr ;
2013-09-21 16:38:46 +05:30
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2005-11-12 14:22:11 +00:00
2013-07-30 19:59:40 +09:00
inf = dev_get_platdata ( dev ) ;
2005-11-12 14:22:11 +00:00
2013-09-21 16:38:46 +05:30
clk_prepare_enable ( pxa_ohci - > clk ) ;
2005-04-16 15:20:36 -07:00
2013-09-21 16:38:46 +05:30
pxa27x_reset_hc ( pxa_ohci ) ;
2005-04-16 15:20:36 -07:00
2013-09-21 16:38:46 +05:30
uhchr = __raw_readl ( pxa_ohci - > mmio_base + UHCHR ) | UHCHR_FSBIR ;
__raw_writel ( uhchr , pxa_ohci - > mmio_base + UHCHR ) ;
2008-10-04 12:57:21 +08:00
2013-09-21 16:38:46 +05:30
while ( __raw_readl ( pxa_ohci - > mmio_base + UHCHR ) & UHCHR_FSBIR )
2005-04-16 15:20:36 -07:00
cpu_relax ( ) ;
2013-09-21 16:38:46 +05:30
pxa27x_setup_hc ( pxa_ohci , inf ) ;
2008-09-27 15:49:57 +08:00
2005-11-12 14:22:11 +00:00
if ( inf - > init )
retval = inf - > init ( dev ) ;
2005-08-31 11:54:09 -07:00
2005-11-12 14:22:11 +00:00
if ( retval < 0 )
return retval ;
2005-04-16 15:20:36 -07:00
2010-07-27 15:06:59 +03:00
if ( cpu_is_pxa3xx ( ) )
2013-09-21 16:38:46 +05:30
pxa3xx_u2d_start_hc ( & hcd - > self ) ;
2010-07-27 15:06:59 +03:00
2013-09-21 16:38:46 +05:30
uhchr = __raw_readl ( pxa_ohci - > mmio_base + UHCHR ) & ~ UHCHR_SSE ;
__raw_writel ( uhchr , pxa_ohci - > mmio_base + UHCHR ) ;
__raw_writel ( UHCHIE_UPRIE | UHCHIE_RWIE , pxa_ohci - > mmio_base + UHCHIE ) ;
2005-08-31 11:54:09 -07:00
/* Clear any OTG Pin Hold */
2008-10-04 12:45:39 +08:00
pxa27x_clear_otgph ( ) ;
2005-11-12 14:22:11 +00:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2013-09-21 16:38:46 +05:30
static void pxa27x_stop_hc ( struct pxa27x_ohci * pxa_ohci , struct device * dev )
2005-04-16 15:20:36 -07:00
{
2005-11-12 14:22:11 +00:00
struct pxaohci_platform_data * inf ;
2013-09-21 16:38:46 +05:30
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2008-10-04 12:57:21 +08:00
uint32_t uhccoms ;
2005-11-12 14:22:11 +00:00
2013-07-30 19:59:40 +09:00
inf = dev_get_platdata ( dev ) ;
2005-11-12 14:22:11 +00:00
2010-07-27 15:06:59 +03:00
if ( cpu_is_pxa3xx ( ) )
2013-09-21 16:38:46 +05:30
pxa3xx_u2d_stop_hc ( & hcd - > self ) ;
2010-07-27 15:06:59 +03:00
2005-11-12 14:22:11 +00:00
if ( inf - > exit )
inf - > exit ( dev ) ;
2013-09-21 16:38:46 +05:30
pxa27x_reset_hc ( pxa_ohci ) ;
2005-04-16 15:20:36 -07:00
2008-10-04 12:57:21 +08:00
/* Host Controller Reset */
2013-09-21 16:38:46 +05:30
uhccoms = __raw_readl ( pxa_ohci - > mmio_base + UHCCOMS ) | 0x01 ;
__raw_writel ( uhccoms , pxa_ohci - > mmio_base + UHCCOMS ) ;
2005-04-16 15:20:36 -07:00
udelay ( 10 ) ;
2013-09-21 16:38:46 +05:30
clk_disable_unprepare ( pxa_ohci - > clk ) ;
2005-04-16 15:20:36 -07:00
}
2012-07-30 09:29:12 +02:00
# ifdef CONFIG_OF
static const struct of_device_id pxa_ohci_dt_ids [ ] = {
{ . compatible = " marvell,pxa-ohci " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , pxa_ohci_dt_ids ) ;
2012-11-19 13:21:48 -05:00
static int ohci_pxa_of_init ( struct platform_device * pdev )
2012-07-30 09:29:12 +02:00
{
struct device_node * np = pdev - > dev . of_node ;
struct pxaohci_platform_data * pdata ;
u32 tmp ;
2013-06-10 16:28:49 +01:00
int ret ;
2012-07-30 09:29:12 +02:00
if ( ! np )
return 0 ;
/* 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 12:36:37 +01:00
ret = dma_coerce_mask_and_coherent ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
2013-06-10 16:28:49 +01:00
if ( ret )
return ret ;
2012-07-30 09:29:12 +02:00
pdata = devm_kzalloc ( & pdev - > dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return - ENOMEM ;
2015-11-16 18:18:33 +05:30
if ( of_property_read_bool ( np , " marvell,enable-port1 " ) )
2012-07-30 09:29:12 +02:00
pdata - > flags | = ENABLE_PORT1 ;
2015-11-16 18:18:33 +05:30
if ( of_property_read_bool ( np , " marvell,enable-port2 " ) )
2012-07-30 09:29:12 +02:00
pdata - > flags | = ENABLE_PORT2 ;
2015-11-16 18:18:33 +05:30
if ( of_property_read_bool ( np , " marvell,enable-port3 " ) )
2012-07-30 09:29:12 +02:00
pdata - > flags | = ENABLE_PORT3 ;
2015-11-16 18:18:33 +05:30
if ( of_property_read_bool ( np , " marvell,port-sense-low " ) )
2012-07-30 09:29:12 +02:00
pdata - > flags | = POWER_SENSE_LOW ;
2015-11-16 18:18:33 +05:30
if ( of_property_read_bool ( np , " marvell,power-control-low " ) )
2012-07-30 09:29:12 +02:00
pdata - > flags | = POWER_CONTROL_LOW ;
2015-11-16 18:18:33 +05:30
if ( of_property_read_bool ( np , " marvell,no-oc-protection " ) )
2012-07-30 09:29:12 +02:00
pdata - > flags | = NO_OC_PROTECTION ;
2015-11-16 18:18:33 +05:30
if ( of_property_read_bool ( np , " marvell,oc-mode-perport " ) )
2012-07-30 09:29:12 +02:00
pdata - > flags | = OC_MODE_PERPORT ;
if ( ! of_property_read_u32 ( np , " marvell,power-on-delay " , & tmp ) )
pdata - > power_on_delay = tmp ;
if ( ! of_property_read_u32 ( np , " marvell,port-mode " , & tmp ) )
pdata - > port_mode = tmp ;
if ( ! of_property_read_u32 ( np , " marvell,power-budget " , & tmp ) )
pdata - > power_budget = tmp ;
pdev - > dev . platform_data = pdata ;
return 0 ;
}
# else
2012-11-19 13:21:48 -05:00
static int ohci_pxa_of_init ( struct platform_device * pdev )
2012-07-30 09:29:12 +02:00
{
return 0 ;
}
# endif
2005-04-16 15:20:36 -07:00
/*-------------------------------------------------------------------------*/
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
/**
* usb_hcd_pxa27x_probe - initialize pxa27x - based HCDs
* Context : ! in_interrupt ( )
*
* 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 .
*
*/
2005-11-12 14:22:11 +00:00
int usb_hcd_pxa27x_probe ( const struct hc_driver * driver , struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
2008-10-03 22:37:21 +08:00
int retval , irq ;
2005-04-16 15:20:36 -07:00
struct usb_hcd * hcd ;
2005-11-12 14:22:11 +00:00
struct pxaohci_platform_data * inf ;
2013-09-21 16:38:46 +05:30
struct pxa27x_ohci * pxa_ohci ;
struct ohci_hcd * ohci ;
2008-10-03 22:37:21 +08:00
struct resource * r ;
2008-10-04 12:57:21 +08:00
struct clk * usb_clk ;
2014-04-16 18:00:11 +02:00
unsigned int i ;
2005-11-12 14:22:11 +00:00
2012-07-30 09:29:12 +02:00
retval = ohci_pxa_of_init ( pdev ) ;
if ( retval )
return retval ;
2013-07-30 19:59:40 +09:00
inf = dev_get_platdata ( & pdev - > dev ) ;
2005-04-16 15:20:36 -07:00
2005-11-12 14:22:11 +00:00
if ( ! inf )
return - ENODEV ;
2008-10-03 22:37:21 +08:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
pr_err ( " no resource of IORESOURCE_IRQ " ) ;
return - ENXIO ;
2005-04-16 15:20:36 -07:00
}
2013-12-11 16:26:21 +09:00
usb_clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2007-12-12 08:53:25 +08:00
if ( IS_ERR ( usb_clk ) )
return PTR_ERR ( usb_clk ) ;
2005-11-12 14:22:11 +00:00
hcd = usb_create_hcd ( driver , & pdev - > dev , " pxa27x " ) ;
2013-12-11 16:26:21 +09:00
if ( ! hcd )
return - ENOMEM ;
2008-10-03 22:37:21 +08:00
r = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-12-11 16:26:21 +09:00
hcd - > regs = devm_ioremap_resource ( & pdev - > dev , r ) ;
if ( IS_ERR ( hcd - > regs ) ) {
retval = PTR_ERR ( hcd - > regs ) ;
goto err ;
2005-04-16 15:20:36 -07:00
}
2014-11-04 07:51:17 +05:30
hcd - > rsrc_start = r - > start ;
hcd - > rsrc_len = resource_size ( r ) ;
2005-04-16 15:20:36 -07:00
2008-10-04 12:57:21 +08:00
/* initialize "struct pxa27x_ohci" */
2013-09-21 16:38:46 +05:30
pxa_ohci = to_pxa27x_ohci ( hcd ) ;
pxa_ohci - > clk = usb_clk ;
pxa_ohci - > mmio_base = ( void __iomem * ) hcd - > regs ;
2008-10-04 12:57:21 +08:00
2014-04-16 18:00:11 +02:00
for ( i = 0 ; i < 3 ; + + i ) {
char name [ 6 ] ;
if ( ! ( inf - > flags & ( ENABLE_PORT1 < < i ) ) )
continue ;
sprintf ( name , " vbus%u " , i + 1 ) ;
pxa_ohci - > vbus [ i ] = devm_regulator_get ( & pdev - > dev , name ) ;
}
2013-09-21 16:38:46 +05:30
retval = pxa27x_start_hc ( pxa_ohci , & pdev - > dev ) ;
if ( retval < 0 ) {
2005-11-12 14:22:11 +00:00
pr_debug ( " pxa27x_start_hc failed " ) ;
2013-12-11 16:26:21 +09:00
goto err ;
2005-11-12 14:22:11 +00:00
}
2005-04-16 15:20:36 -07:00
/* Select Power Management Mode */
2013-09-21 16:38:46 +05:30
pxa27x_ohci_select_pmm ( pxa_ohci , inf - > port_mode ) ;
2005-04-16 15:20:36 -07:00
2006-06-08 22:44:07 +01:00
if ( inf - > power_budget )
hcd - > power_budget = inf - > power_budget ;
2013-09-21 16:38:46 +05:30
/* The value of NDP in roothub_a is incorrect on this hardware */
ohci = hcd_to_ohci ( hcd ) ;
ohci - > num_ports = 3 ;
2005-04-16 15:20:36 -07:00
2011-09-07 16:10:52 +08:00
retval = usb_add_hcd ( hcd , irq , 0 ) ;
2013-11-05 10:46:02 +08:00
if ( retval = = 0 ) {
device_wakeup_enable ( hcd - > self . controller ) ;
2005-04-16 15:20:36 -07:00
return retval ;
2013-11-05 10:46:02 +08:00
}
2005-04-16 15:20:36 -07:00
2013-09-21 16:38:46 +05:30
pxa27x_stop_hc ( pxa_ohci , & pdev - > dev ) ;
2013-12-11 16:26:21 +09:00
err :
2005-04-16 15:20:36 -07:00
usb_put_hcd ( hcd ) ;
return retval ;
}
/* may be called without controller electrically present */
/* may be called with controller, bus, and devices active */
/**
* usb_hcd_pxa27x_remove - shutdown processing for pxa27x - based HCDs
* @ dev : USB Host Controller being removed
* Context : ! in_interrupt ( )
*
* Reverses the effect of usb_hcd_pxa27x_probe ( ) , first invoking
* the HCD ' s stop ( ) method . It is always called from a thread
* context , normally " rmmod " , " apmd " , or something similar .
*
*/
2005-11-12 14:22:11 +00:00
void usb_hcd_pxa27x_remove ( struct usb_hcd * hcd , struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
2013-09-21 16:38:46 +05:30
struct pxa27x_ohci * pxa_ohci = to_pxa27x_ohci ( hcd ) ;
2014-04-16 18:00:11 +02:00
unsigned int i ;
2008-10-04 12:57:21 +08:00
2005-04-16 15:20:36 -07:00
usb_remove_hcd ( hcd ) ;
2013-09-21 16:38:46 +05:30
pxa27x_stop_hc ( pxa_ohci , & pdev - > dev ) ;
2014-04-16 18:00:11 +02:00
for ( i = 0 ; i < 3 ; + + i )
pxa27x_ohci_set_vbus_power ( pxa_ohci , i , false ) ;
2005-04-16 15:20:36 -07:00
usb_put_hcd ( hcd ) ;
}
/*-------------------------------------------------------------------------*/
2005-11-09 22:32:44 +00:00
static int ohci_hcd_pxa27x_drv_probe ( struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
pr_debug ( " In ohci_hcd_pxa27x_drv_probe " ) ;
if ( usb_disabled ( ) )
return - ENODEV ;
2005-11-12 14:22:11 +00:00
return usb_hcd_pxa27x_probe ( & ohci_pxa27x_hc_driver , pdev ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-09 22:32:44 +00:00
static int ohci_hcd_pxa27x_drv_remove ( struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
2005-11-09 22:32:44 +00:00
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
2005-04-16 15:20:36 -07:00
usb_hcd_pxa27x_remove ( hcd , pdev ) ;
return 0 ;
}
2009-07-21 17:49:39 +03:00
# ifdef CONFIG_PM
static int ohci_hcd_pxa27x_drv_suspend ( struct device * dev )
2005-04-16 15:20:36 -07:00
{
2009-07-21 17:49:39 +03:00
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2013-09-21 16:38:46 +05:30
struct pxa27x_ohci * pxa_ohci = to_pxa27x_ohci ( hcd ) ;
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
2013-10-04 09:58:15 +05:30
bool do_wakeup = device_may_wakeup ( dev ) ;
int ret ;
2005-11-12 14:22:14 +00:00
2013-09-21 16:38:46 +05:30
if ( time_before ( jiffies , ohci - > next_statechange ) )
2005-11-12 14:22:14 +00:00
msleep ( 5 ) ;
2013-09-21 16:38:46 +05:30
ohci - > next_statechange = jiffies ;
2005-11-12 14:22:14 +00:00
2013-10-04 09:58:15 +05:30
ret = ohci_suspend ( hcd , do_wakeup ) ;
if ( ret )
return ret ;
2013-09-21 16:38:46 +05:30
pxa27x_stop_hc ( pxa_ohci , dev ) ;
2013-10-04 09:58:15 +05:30
return ret ;
2005-04-16 15:20:36 -07:00
}
2009-07-21 17:49:39 +03:00
static int ohci_hcd_pxa27x_drv_resume ( struct device * dev )
2005-04-16 15:20:36 -07:00
{
2009-07-21 17:49:39 +03:00
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2013-09-21 16:38:46 +05:30
struct pxa27x_ohci * pxa_ohci = to_pxa27x_ohci ( hcd ) ;
2013-07-30 19:59:40 +09:00
struct pxaohci_platform_data * inf = dev_get_platdata ( dev ) ;
2013-09-21 16:38:46 +05:30
struct ohci_hcd * ohci = hcd_to_ohci ( hcd ) ;
2005-11-12 14:22:14 +00:00
int status ;
2013-09-21 16:38:46 +05:30
if ( time_before ( jiffies , ohci - > next_statechange ) )
2005-11-12 14:22:14 +00:00
msleep ( 5 ) ;
2013-09-21 16:38:46 +05:30
ohci - > next_statechange = jiffies ;
2005-11-12 14:22:14 +00:00
2013-09-21 16:38:46 +05:30
status = pxa27x_start_hc ( pxa_ohci , dev ) ;
if ( status < 0 )
2005-11-12 14:22:14 +00:00
return status ;
2009-07-30 13:42:30 -04:00
/* Select Power Management Mode */
2013-09-21 16:38:46 +05:30
pxa27x_ohci_select_pmm ( pxa_ohci , inf - > port_mode ) ;
2009-07-30 13:42:30 -04:00
2012-10-08 15:11:29 +02:00
ohci_resume ( hcd , false ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2009-07-21 17:49:39 +03:00
2009-12-14 18:00:08 -08:00
static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = {
2009-07-21 17:49:39 +03:00
. suspend = ohci_hcd_pxa27x_drv_suspend ,
. resume = ohci_hcd_pxa27x_drv_resume ,
} ;
2005-11-12 14:22:14 +00:00
# endif
2005-04-16 15:20:36 -07:00
2005-11-09 22:32:44 +00:00
static struct platform_driver ohci_hcd_pxa27x_driver = {
2005-04-16 15:20:36 -07:00
. probe = ohci_hcd_pxa27x_drv_probe ,
. remove = ohci_hcd_pxa27x_drv_remove ,
2006-12-05 03:18:31 -08:00
. shutdown = usb_hcd_platform_shutdown ,
2005-11-09 22:32:44 +00:00
. driver = {
. name = " pxa27x-ohci " ,
2012-07-30 09:29:12 +02:00
. of_match_table = of_match_ptr ( pxa_ohci_dt_ids ) ,
2009-07-21 17:49:39 +03:00
# ifdef CONFIG_PM
. pm = & ohci_hcd_pxa27x_pm_ops ,
# endif
2005-11-09 22:32:44 +00:00
} ,
2005-04-16 15:20:36 -07:00
} ;
2013-09-21 16:38:46 +05:30
static const struct ohci_driver_overrides pxa27x_overrides __initconst = {
. extra_priv_size = sizeof ( struct pxa27x_ohci ) ,
} ;
static int __init ohci_pxa27x_init ( void )
{
if ( usb_disabled ( ) )
return - ENODEV ;
pr_info ( " %s: " DRIVER_DESC " \n " , hcd_name ) ;
2014-04-16 18:00:11 +02:00
2013-09-21 16:38:46 +05:30
ohci_init_driver ( & ohci_pxa27x_hc_driver , & pxa27x_overrides ) ;
2014-04-16 18:00:11 +02:00
ohci_pxa27x_hc_driver . hub_control = pxa27x_ohci_hub_control ;
2013-09-21 16:38:46 +05:30
return platform_driver_register ( & ohci_hcd_pxa27x_driver ) ;
}
module_init ( ohci_pxa27x_init ) ;
static void __exit ohci_pxa27x_cleanup ( void )
{
platform_driver_unregister ( & ohci_hcd_pxa27x_driver ) ;
}
module_exit ( ohci_pxa27x_cleanup ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:pxa27x-ohci " ) ;