2006-01-20 13:53:38 -08:00
/*
2009-12-14 18:41:12 +03:00
* Copyright 2005 - 2009 MontaVista Software , Inc .
2015-05-14 19:04:46 +05:30
* Copyright 2008 , 2012 , 2015 Freescale Semiconductor , Inc .
2006-01-20 13:53:38 -08:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
* Ported to 834 x by Randy Vinson < rvinson @ mvista . com > using code provided
* by Hunter Wu .
2009-12-14 18:41:12 +03:00
* Power Management support by Dave Liu < daveliu @ freescale . com > ,
* Jerry Huang < Chang - Ming . Huang @ freescale . com > and
* Anton Vorontsov < avorontsov @ ru . mvista . com > .
2006-01-20 13:53:38 -08:00
*/
2009-12-14 18:41:12 +03:00
# include <linux/kernel.h>
2015-05-14 19:04:46 +05:30
# include <linux/module.h>
2009-12-14 18:41:12 +03:00
# include <linux/types.h>
# include <linux/delay.h>
# include <linux/pm.h>
2012-06-26 17:40:32 +05:30
# include <linux/err.h>
2015-05-14 19:04:46 +05:30
# include <linux/usb.h>
# include <linux/usb/ehci_def.h>
# include <linux/usb/hcd.h>
# include <linux/usb/otg.h>
2006-01-20 13:53:38 -08:00
# include <linux/platform_device.h>
# include <linux/fsl_devices.h>
2015-05-14 19:04:46 +05:30
# include "ehci.h"
2006-01-20 13:53:38 -08:00
# include "ehci-fsl.h"
2015-05-14 19:04:46 +05:30
# define DRIVER_DESC "Freescale EHCI Host controller driver"
# define DRV_NAME "ehci-fsl"
static struct hc_driver __read_mostly fsl_ehci_hc_driver ;
2006-01-20 13:53:38 -08:00
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
2015-05-14 19:04:46 +05:30
/*
* fsl_ehci_drv_probe - initialize FSL - based HCDs
2006-01-20 13:53:38 -08:00
* @ pdev : USB Host Controller being probed
* Context : ! in_interrupt ( )
*
* Allocates basic resources for this USB host controller .
*
*/
2015-05-14 19:04:46 +05:30
static int fsl_ehci_drv_probe ( struct platform_device * pdev )
2006-01-20 13:53:38 -08:00
{
struct fsl_usb2_platform_data * pdata ;
struct usb_hcd * hcd ;
struct resource * res ;
int irq ;
int retval ;
pr_debug ( " initializing FSL-SOC USB Controller \n " ) ;
/* Need platform data for setup */
2013-09-09 14:04:44 +09:00
pdata = dev_get_platdata ( & pdev - > dev ) ;
2006-01-20 13:53:38 -08:00
if ( ! pdata ) {
dev_err ( & pdev - > dev ,
2008-05-02 06:02:41 +02:00
" No platform data for %s. \n " , dev_name ( & pdev - > dev ) ) ;
2006-01-20 13:53:38 -08:00
return - ENODEV ;
}
/*
* This is a host mode driver , verify that we ' re supposed to be
* in host mode .
*/
if ( ! ( ( pdata - > operating_mode = = FSL_USB2_DR_HOST ) | |
2007-05-11 17:09:55 +08:00
( pdata - > operating_mode = = FSL_USB2_MPH_HOST ) | |
( pdata - > operating_mode = = FSL_USB2_DR_OTG ) ) ) {
2006-01-20 13:53:38 -08:00
dev_err ( & pdev - > dev ,
" Non Host Mode configured for %s. Wrong driver linked. \n " ,
2008-05-02 06:02:41 +02:00
dev_name ( & pdev - > dev ) ) ;
2006-01-20 13:53:38 -08:00
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 06:02:41 +02:00
dev_name ( & pdev - > dev ) ) ;
2006-01-20 13:53:38 -08:00
return - ENODEV ;
}
irq = res - > start ;
2015-05-14 19:04:46 +05:30
hcd = usb_create_hcd ( & fsl_ehci_hc_driver , & pdev - > dev ,
dev_name ( & pdev - > dev ) ) ;
2006-01-20 13:53:38 -08:00
if ( ! hcd ) {
retval = - ENOMEM ;
goto err1 ;
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-12-11 16:18:53 +09:00
hcd - > regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( hcd - > regs ) ) {
retval = PTR_ERR ( hcd - > regs ) ;
2006-01-20 13:53:38 -08:00
goto err2 ;
}
2014-11-04 07:51:32 +05:30
hcd - > rsrc_start = res - > start ;
hcd - > rsrc_len = resource_size ( res ) ;
2010-09-28 20:55:21 +02:00
pdata - > regs = hcd - > regs ;
2006-01-20 13:53:38 -08:00
2011-04-18 22:02:00 +02:00
if ( pdata - > power_budget )
hcd - > power_budget = pdata - > power_budget ;
2010-09-28 20:55:21 +02:00
/*
* do platform specific init : check the clock , grab / config pins , etc .
*/
if ( pdata - > init & & pdata - > init ( pdev ) ) {
retval = - ENODEV ;
2013-12-11 16:18:53 +09:00
goto err2 ;
2010-09-28 20:55:21 +02:00
}
/* Enable USB controller, 83xx or 8536 */
2013-09-16 15:11:33 +05:30
if ( pdata - > have_sysif_regs & & pdata - > controller_ver < FSL_USB_VER_1_6 )
2010-09-28 20:55:21 +02:00
setbits32 ( hcd - > regs + FSL_SOC_USB_CTRL , 0x4 ) ;
2015-06-15 15:47:29 +05:30
/*
* Enable UTMI phy and program PTS field in UTMI mode before asserting
* controller reset for USB Controller version 2.5
*/
if ( pdata - > has_fsl_erratum_a007792 ) {
writel_be ( CTRL_UTMI_PHY_EN , hcd - > regs + FSL_SOC_USB_CTRL ) ;
writel ( PORT_PTS_UTMI , hcd - > regs + FSL_SOC_USB_PORTSC1 ) ;
}
2010-09-28 20:55:21 +02:00
/* Don't need to set host mode here. It will be done by tdi_reset() */
2006-01-20 13:53:38 -08:00
2011-09-07 16:10:52 +08:00
retval = usb_add_hcd ( hcd , irq , IRQF_SHARED ) ;
2006-01-20 13:53:38 -08:00
if ( retval ! = 0 )
2013-12-11 16:18:53 +09:00
goto err2 ;
2013-11-05 10:46:02 +08:00
device_wakeup_enable ( hcd - > self . controller ) ;
2011-04-18 22:02:00 +02:00
# ifdef CONFIG_USB_OTG
if ( pdata - > operating_mode = = FSL_USB2_DR_OTG ) {
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
2014-09-24 23:05:50 +04:00
hcd - > usb_phy = usb_get_phy ( USB_PHY_TYPE_USB2 ) ;
2012-06-13 20:34:12 +08:00
dev_dbg ( & pdev - > dev , " hcd=0x%p ehci=0x%p, phy=0x%p \n " ,
2014-09-24 23:05:50 +04:00
hcd , ehci , hcd - > usb_phy ) ;
2011-04-18 22:02:00 +02:00
2014-09-24 23:05:50 +04:00
if ( ! IS_ERR_OR_NULL ( hcd - > usb_phy ) ) {
retval = otg_set_host ( hcd - > usb_phy - > otg ,
2011-04-18 22:02:00 +02:00
& ehci_to_hcd ( ehci ) - > self ) ;
if ( retval ) {
2014-09-24 23:05:50 +04:00
usb_put_phy ( hcd - > usb_phy ) ;
2013-12-11 16:18:53 +09:00
goto err2 ;
2011-04-18 22:02:00 +02:00
}
} else {
2012-06-13 20:34:12 +08:00
dev_err ( & pdev - > dev , " can't find phy \n " ) ;
2011-04-18 22:02:00 +02:00
retval = - ENODEV ;
2013-12-11 16:18:53 +09:00
goto err2 ;
2011-04-18 22:02:00 +02:00
}
}
# endif
2006-01-20 13:53:38 -08:00
return retval ;
err2 :
usb_put_hcd ( hcd ) ;
err1 :
2008-05-02 06:02:41 +02:00
dev_err ( & pdev - > dev , " init %s fail, %d \n " , dev_name ( & pdev - > dev ) , retval ) ;
2010-09-28 20:55:21 +02:00
if ( pdata - > exit )
pdata - > exit ( pdev ) ;
2006-01-20 13:53:38 -08:00
return retval ;
}
2012-08-22 18:17:00 +08:00
static int ehci_fsl_setup_phy ( struct usb_hcd * hcd ,
2010-09-28 20:55:21 +02:00
enum fsl_usb2_phy_modes phy_mode ,
unsigned int port_offset )
2006-01-20 13:53:38 -08:00
{
2012-08-22 18:17:00 +08:00
u32 portsc ;
2012-03-20 10:35:50 +05:30
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
2012-02-16 18:02:20 +08:00
void __iomem * non_ehci = hcd - > regs ;
2012-03-20 10:35:50 +05:30
struct device * dev = hcd - > self . controller ;
2013-07-30 19:59:40 +09:00
struct fsl_usb2_platform_data * pdata = dev_get_platdata ( dev ) ;
2012-04-10 10:48:11 +02:00
2012-03-20 10:35:50 +05:30
if ( pdata - > controller_ver < 0 ) {
dev_warn ( hcd - > self . controller , " Could not get controller version \n " ) ;
2012-10-19 10:24:12 -04:00
return - ENODEV ;
2012-03-20 10:35:50 +05:30
}
2010-09-28 20:55:21 +02:00
portsc = ehci_readl ( ehci , & ehci - > regs - > port_status [ port_offset ] ) ;
portsc & = ~ ( PORT_PTS_MSK | PORT_PTS_PTW ) ;
2006-01-20 13:53:38 -08:00
switch ( phy_mode ) {
case FSL_USB2_PHY_ULPI :
2012-12-04 14:24:30 +01:00
if ( pdata - > have_sysif_regs & & pdata - > controller_ver ) {
2012-03-20 10:35:50 +05:30
/* controller version 1.6 or above */
2013-09-16 15:11:33 +05:30
clrbits32 ( non_ehci + FSL_SOC_USB_CTRL , UTMI_PHY_EN ) ;
2012-08-22 18:17:00 +08:00
setbits32 ( non_ehci + FSL_SOC_USB_CTRL ,
2013-09-16 15:11:33 +05:30
ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN ) ;
2012-03-20 10:35:50 +05:30
}
2006-01-20 13:53:38 -08:00
portsc | = PORT_PTS_ULPI ;
break ;
case FSL_USB2_PHY_SERIAL :
portsc | = PORT_PTS_SERIAL ;
break ;
case FSL_USB2_PHY_UTMI_WIDE :
portsc | = PORT_PTS_PTW ;
/* fall through */
case FSL_USB2_PHY_UTMI :
2012-12-04 14:24:30 +01:00
if ( pdata - > have_sysif_regs & & pdata - > controller_ver ) {
2012-03-20 10:35:50 +05:30
/* controller version 1.6 or above */
2012-08-22 18:17:00 +08:00
setbits32 ( non_ehci + FSL_SOC_USB_CTRL , UTMI_PHY_EN ) ;
2012-03-20 10:35:50 +05:30
mdelay ( FSL_UTMI_PHY_DLY ) ; /* Delay for UTMI PHY CLK to
become stable - 10 ms */
}
2012-02-16 18:02:20 +08:00
/* enable UTMI PHY */
2012-04-10 10:48:11 +02:00
if ( pdata - > have_sysif_regs )
setbits32 ( non_ehci + FSL_SOC_USB_CTRL ,
CTRL_UTMI_PHY_EN ) ;
2006-01-20 13:53:38 -08:00
portsc | = PORT_PTS_UTMI ;
break ;
case FSL_USB2_PHY_NONE :
break ;
}
2012-08-22 18:17:00 +08:00
2014-04-28 19:23:44 +04:00
if ( pdata - > have_sysif_regs & &
pdata - > controller_ver > FSL_USB_VER_1_6 & &
2012-12-04 14:24:30 +01:00
( phy_mode = = FSL_USB2_PHY_ULPI ) ) {
2012-08-22 18:17:00 +08:00
/* check PHY_CLK_VALID to get phy clk valid */
2013-09-02 13:25:52 +08:00
if ( ! ( spin_event_timeout ( in_be32 ( non_ehci + FSL_SOC_USB_CTRL ) &
PHY_CLK_VALID , FSL_USB_PHY_CLK_TIMEOUT , 0 ) | |
in_be32 ( non_ehci + FSL_SOC_USB_PRICTRL ) ) ) {
2013-12-10 21:17:54 +09:00
dev_warn ( hcd - > self . controller , " USB PHY clock invalid \n " ) ;
2012-08-22 18:17:00 +08:00
return - EINVAL ;
}
}
2006-12-15 06:54:08 +11:00
ehci_writel ( ehci , portsc , & ehci - > regs - > port_status [ port_offset ] ) ;
2012-08-22 18:17:00 +08:00
2012-12-04 14:24:30 +01:00
if ( phy_mode ! = FSL_USB2_PHY_ULPI & & pdata - > have_sysif_regs )
2012-08-22 18:17:00 +08:00
setbits32 ( non_ehci + FSL_SOC_USB_CTRL , USB_CTRL_USB_EN ) ;
return 0 ;
2006-01-20 13:53:38 -08:00
}
2012-08-22 18:17:00 +08:00
static int ehci_fsl_usb_setup ( struct ehci_hcd * ehci )
2006-01-20 13:53:38 -08:00
{
2010-09-28 20:55:21 +02:00
struct usb_hcd * hcd = ehci_to_hcd ( ehci ) ;
2006-01-20 13:53:38 -08:00
struct fsl_usb2_platform_data * pdata ;
void __iomem * non_ehci = hcd - > regs ;
2013-07-30 19:59:40 +09:00
pdata = dev_get_platdata ( hcd - > self . controller ) ;
2010-09-28 20:55:21 +02:00
if ( pdata - > have_sysif_regs ) {
2012-02-17 13:57:16 +08:00
/*
* Turn on cache snooping hardware , since some PowerPC platforms
* wholly rely on hardware to deal with cache coherent
*/
2007-05-23 13:58:17 -07:00
2012-02-17 13:57:16 +08:00
/* Setup Snooping for all the 4GB space */
/* SNOOP1 starts from 0x0, size 2G */
out_be32 ( non_ehci + FSL_SOC_USB_SNOOP1 , 0x0 | SNOOP_SIZE_2GB ) ;
/* SNOOP2 starts from 0x80000000, size 2G */
out_be32 ( non_ehci + FSL_SOC_USB_SNOOP2 , 0x80000000 | SNOOP_SIZE_2GB ) ;
}
2007-05-23 13:58:17 -07:00
2007-05-11 17:09:55 +08:00
if ( ( pdata - > operating_mode = = FSL_USB2_DR_HOST ) | |
( pdata - > operating_mode = = FSL_USB2_DR_OTG ) )
2012-08-22 18:17:00 +08:00
if ( ehci_fsl_setup_phy ( hcd , pdata - > phy_mode , 0 ) )
return - EINVAL ;
2006-01-20 13:53:38 -08:00
if ( pdata - > operating_mode = = FSL_USB2_MPH_HOST ) {
2006-01-20 13:57:52 -08:00
unsigned int chip , rev , svr ;
svr = mfspr ( SPRN_SVR ) ;
chip = svr > > 16 ;
rev = ( svr > > 4 ) & 0xf ;
/* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
if ( ( rev = = 1 ) & & ( chip > = 0x8050 ) & & ( chip < = 0x8055 ) )
ehci - > has_fsl_port_bug = 1 ;
2006-01-20 13:53:38 -08:00
if ( pdata - > port_enables & FSL_USB2_PORT0_ENABLED )
2012-08-22 18:17:00 +08:00
if ( ehci_fsl_setup_phy ( hcd , pdata - > phy_mode , 0 ) )
return - EINVAL ;
2006-01-20 13:53:38 -08:00
if ( pdata - > port_enables & FSL_USB2_PORT1_ENABLED )
2012-08-22 18:17:00 +08:00
if ( ehci_fsl_setup_phy ( hcd , pdata - > phy_mode , 1 ) )
return - EINVAL ;
2006-01-20 13:53:38 -08:00
}
2010-09-28 20:55:21 +02:00
if ( pdata - > have_sysif_regs ) {
2012-07-10 06:58:48 -05:00
# ifdef CONFIG_FSL_SOC_BOOKE
2010-09-28 20:55:21 +02:00
out_be32 ( non_ehci + FSL_SOC_USB_PRICTRL , 0x00000008 ) ;
out_be32 ( non_ehci + FSL_SOC_USB_AGECNTTHRSH , 0x00000080 ) ;
2008-07-02 02:14:33 -05:00
# else
2010-09-28 20:55:21 +02:00
out_be32 ( non_ehci + FSL_SOC_USB_PRICTRL , 0x0000000c ) ;
out_be32 ( non_ehci + FSL_SOC_USB_AGECNTTHRSH , 0x00000040 ) ;
2008-07-02 02:14:33 -05:00
# endif
2010-09-28 20:55:21 +02:00
out_be32 ( non_ehci + FSL_SOC_USB_SICTRL , 0x00000001 ) ;
}
2012-08-22 18:17:00 +08:00
return 0 ;
2006-01-20 13:53:38 -08:00
}
/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_fsl_reinit ( struct ehci_hcd * ehci )
{
2012-08-22 18:17:00 +08:00
if ( ehci_fsl_usb_setup ( ehci ) )
return - EINVAL ;
2006-01-20 13:53:38 -08:00
return 0 ;
}
/* called during probe() after chip reset completes */
static int ehci_fsl_setup ( struct usb_hcd * hcd )
{
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
int retval ;
2010-09-28 20:55:21 +02:00
struct fsl_usb2_platform_data * pdata ;
2012-01-24 22:17:38 +01:00
struct device * dev ;
2010-09-28 20:55:21 +02:00
2012-01-24 22:17:38 +01:00
dev = hcd - > self . controller ;
2013-07-30 19:59:40 +09:00
pdata = dev_get_platdata ( hcd - > self . controller ) ;
2010-09-28 20:55:21 +02:00
ehci - > big_endian_desc = pdata - > big_endian_desc ;
ehci - > big_endian_mmio = pdata - > big_endian_mmio ;
2006-01-20 13:53:38 -08:00
/* EHCI registers start at offset 0x100 */
ehci - > caps = hcd - > regs + 0x100 ;
2013-04-03 12:18:51 +02:00
# ifdef CONFIG_PPC_83xx
/*
* Deal with MPC834X that need port power to be cycled after the power
* fault condition is removed . Otherwise the state machine does not
* reflect PORTSC [ CSC ] correctly .
*/
ehci - > need_oc_pp_cycle = 1 ;
# endif
2010-09-06 18:26:56 +02:00
hcd - > has_tt = 1 ;
2012-07-09 15:55:14 -04:00
retval = ehci_setup ( hcd ) ;
2006-01-20 13:53:38 -08:00
if ( retval )
return retval ;
2012-01-24 22:17:38 +01:00
if ( of_device_is_compatible ( dev - > parent - > of_node ,
" fsl,mpc5121-usb2-dr " ) ) {
/*
* set SBUSCFG : AHBBRST so that control msgs don ' t
* fail when doing heavy PATA writes .
*/
ehci_writel ( ehci , SBUSCFG_INCR8 ,
hcd - > regs + FSL_SOC_USB_SBUSCFG ) ;
}
2006-01-20 13:53:38 -08:00
retval = ehci_fsl_reinit ( ehci ) ;
return retval ;
}
2009-12-14 18:41:12 +03:00
struct ehci_fsl {
struct ehci_hcd ehci ;
# ifdef CONFIG_PM
/* Saved USB PHY settings, need to restore after deep sleep. */
u32 usb_ctrl ;
# endif
} ;
# ifdef CONFIG_PM
2011-04-18 22:01:55 +02:00
# ifdef CONFIG_PPC_MPC512x
static int ehci_fsl_mpc512x_drv_suspend ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
2013-07-30 19:59:40 +09:00
struct fsl_usb2_platform_data * pdata = dev_get_platdata ( dev ) ;
2011-04-18 22:01:55 +02:00
u32 tmp ;
2013-11-18 13:23:16 +01:00
# ifdef CONFIG_DYNAMIC_DEBUG
2011-04-18 22:01:55 +02:00
u32 mode = ehci_readl ( ehci , hcd - > regs + FSL_SOC_USB_USBMODE ) ;
mode & = USBMODE_CM_MASK ;
tmp = ehci_readl ( ehci , hcd - > regs + 0x140 ) ; /* usbcmd */
dev_dbg ( dev , " suspend=%d already_suspended=%d "
" mode=%d usbcmd %08x \n " , pdata - > suspended ,
pdata - > already_suspended , mode , tmp ) ;
# endif
/*
* If the controller is already suspended , then this must be a
* PM suspend . Remember this fact , so that we will leave the
* controller suspended at PM resume time .
*/
if ( pdata - > suspended ) {
dev_dbg ( dev , " already suspended, leaving early \n " ) ;
pdata - > already_suspended = 1 ;
return 0 ;
}
dev_dbg ( dev , " suspending... \n " ) ;
2011-08-18 16:31:30 -04:00
ehci - > rh_state = EHCI_RH_SUSPENDED ;
2011-04-18 22:01:55 +02:00
dev - > power . power_state = PMSG_SUSPEND ;
/* ignore non-host interrupts */
clear_bit ( HCD_FLAG_HW_ACCESSIBLE , & hcd - > flags ) ;
/* stop the controller */
tmp = ehci_readl ( ehci , & ehci - > regs - > command ) ;
tmp & = ~ CMD_RUN ;
ehci_writel ( ehci , tmp , & ehci - > regs - > command ) ;
/* save EHCI registers */
pdata - > pm_command = ehci_readl ( ehci , & ehci - > regs - > command ) ;
pdata - > pm_command & = ~ CMD_RUN ;
pdata - > pm_status = ehci_readl ( ehci , & ehci - > regs - > status ) ;
pdata - > pm_intr_enable = ehci_readl ( ehci , & ehci - > regs - > intr_enable ) ;
pdata - > pm_frame_index = ehci_readl ( ehci , & ehci - > regs - > frame_index ) ;
pdata - > pm_segment = ehci_readl ( ehci , & ehci - > regs - > segment ) ;
pdata - > pm_frame_list = ehci_readl ( ehci , & ehci - > regs - > frame_list ) ;
pdata - > pm_async_next = ehci_readl ( ehci , & ehci - > regs - > async_next ) ;
pdata - > pm_configured_flag =
ehci_readl ( ehci , & ehci - > regs - > configured_flag ) ;
pdata - > pm_portsc = ehci_readl ( ehci , & ehci - > regs - > port_status [ 0 ] ) ;
pdata - > pm_usbgenctrl = ehci_readl ( ehci ,
hcd - > regs + FSL_SOC_USB_USBGENCTRL ) ;
/* clear the W1C bits */
pdata - > pm_portsc & = cpu_to_hc32 ( ehci , ~ PORT_RWC_BITS ) ;
pdata - > suspended = 1 ;
/* clear PP to cut power to the port */
tmp = ehci_readl ( ehci , & ehci - > regs - > port_status [ 0 ] ) ;
tmp & = ~ PORT_POWER ;
ehci_writel ( ehci , tmp , & ehci - > regs - > port_status [ 0 ] ) ;
return 0 ;
}
static int ehci_fsl_mpc512x_drv_resume ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
2013-07-30 19:59:40 +09:00
struct fsl_usb2_platform_data * pdata = dev_get_platdata ( dev ) ;
2011-04-18 22:01:55 +02:00
u32 tmp ;
dev_dbg ( dev , " suspend=%d already_suspended=%d \n " ,
pdata - > suspended , pdata - > already_suspended ) ;
/*
* If the controller was already suspended at suspend time ,
* then don ' t resume it now .
*/
if ( pdata - > already_suspended ) {
dev_dbg ( dev , " already suspended, leaving early \n " ) ;
pdata - > already_suspended = 0 ;
return 0 ;
}
if ( ! pdata - > suspended ) {
dev_dbg ( dev , " not suspended, leaving early \n " ) ;
return 0 ;
}
pdata - > suspended = 0 ;
dev_dbg ( dev , " resuming... \n " ) ;
/* set host mode */
tmp = USBMODE_CM_HOST | ( pdata - > es ? USBMODE_ES : 0 ) ;
ehci_writel ( ehci , tmp , hcd - > regs + FSL_SOC_USB_USBMODE ) ;
ehci_writel ( ehci , pdata - > pm_usbgenctrl ,
hcd - > regs + FSL_SOC_USB_USBGENCTRL ) ;
ehci_writel ( ehci , ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE ,
hcd - > regs + FSL_SOC_USB_ISIPHYCTRL ) ;
2012-01-24 22:17:38 +01:00
ehci_writel ( ehci , SBUSCFG_INCR8 , hcd - > regs + FSL_SOC_USB_SBUSCFG ) ;
2011-04-18 22:01:55 +02:00
/* restore EHCI registers */
ehci_writel ( ehci , pdata - > pm_command , & ehci - > regs - > command ) ;
ehci_writel ( ehci , pdata - > pm_intr_enable , & ehci - > regs - > intr_enable ) ;
ehci_writel ( ehci , pdata - > pm_frame_index , & ehci - > regs - > frame_index ) ;
ehci_writel ( ehci , pdata - > pm_segment , & ehci - > regs - > segment ) ;
ehci_writel ( ehci , pdata - > pm_frame_list , & ehci - > regs - > frame_list ) ;
ehci_writel ( ehci , pdata - > pm_async_next , & ehci - > regs - > async_next ) ;
ehci_writel ( ehci , pdata - > pm_configured_flag ,
& ehci - > regs - > configured_flag ) ;
ehci_writel ( ehci , pdata - > pm_portsc , & ehci - > regs - > port_status [ 0 ] ) ;
set_bit ( HCD_FLAG_HW_ACCESSIBLE , & hcd - > flags ) ;
2011-08-18 16:31:30 -04:00
ehci - > rh_state = EHCI_RH_RUNNING ;
2011-04-18 22:01:55 +02:00
dev - > power . power_state = PMSG_ON ;
tmp = ehci_readl ( ehci , & ehci - > regs - > command ) ;
tmp | = CMD_RUN ;
ehci_writel ( ehci , tmp , & ehci - > regs - > command ) ;
usb_hcd_resume_root_hub ( hcd ) ;
return 0 ;
}
# else
static inline int ehci_fsl_mpc512x_drv_suspend ( struct device * dev )
{
return 0 ;
}
static inline int ehci_fsl_mpc512x_drv_resume ( struct device * dev )
{
return 0 ;
}
# endif /* CONFIG_PPC_MPC512x */
2009-12-14 18:41:12 +03:00
static struct ehci_fsl * hcd_to_ehci_fsl ( struct usb_hcd * hcd )
{
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
return container_of ( ehci , struct ehci_fsl , ehci ) ;
}
static int ehci_fsl_drv_suspend ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
struct ehci_fsl * ehci_fsl = hcd_to_ehci_fsl ( hcd ) ;
void __iomem * non_ehci = hcd - > regs ;
2011-04-18 22:01:55 +02:00
if ( of_device_is_compatible ( dev - > parent - > of_node ,
" fsl,mpc5121-usb2-dr " ) ) {
return ehci_fsl_mpc512x_drv_suspend ( dev ) ;
}
2010-06-25 14:02:14 -04:00
ehci_prepare_ports_for_controller_suspend ( hcd_to_ehci ( hcd ) ,
device_may_wakeup ( dev ) ) ;
2009-12-14 18:41:12 +03:00
if ( ! fsl_deep_sleep ( ) )
return 0 ;
ehci_fsl - > usb_ctrl = in_be32 ( non_ehci + FSL_SOC_USB_CTRL ) ;
return 0 ;
}
static int ehci_fsl_drv_resume ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
struct ehci_fsl * ehci_fsl = hcd_to_ehci_fsl ( hcd ) ;
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
void __iomem * non_ehci = hcd - > regs ;
2011-04-18 22:01:55 +02:00
if ( of_device_is_compatible ( dev - > parent - > of_node ,
" fsl,mpc5121-usb2-dr " ) ) {
return ehci_fsl_mpc512x_drv_resume ( dev ) ;
}
2010-05-12 18:21:35 -04:00
ehci_prepare_ports_for_controller_resume ( ehci ) ;
2009-12-14 18:41:12 +03:00
if ( ! fsl_deep_sleep ( ) )
return 0 ;
usb_root_hub_lost_power ( hcd - > self . root_hub ) ;
/* Restore USB PHY settings and enable the controller. */
out_be32 ( non_ehci + FSL_SOC_USB_CTRL , ehci_fsl - > usb_ctrl ) ;
ehci_reset ( ehci ) ;
ehci_fsl_reinit ( ehci ) ;
return 0 ;
}
static int ehci_fsl_drv_restore ( struct device * dev )
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
usb_root_hub_lost_power ( hcd - > self . root_hub ) ;
return 0 ;
}
static struct dev_pm_ops ehci_fsl_pm_ops = {
. suspend = ehci_fsl_drv_suspend ,
. resume = ehci_fsl_drv_resume ,
. restore = ehci_fsl_drv_restore ,
} ;
# define EHCI_FSL_PM_OPS (&ehci_fsl_pm_ops)
# else
# define EHCI_FSL_PM_OPS NULL
# endif /* CONFIG_PM */
2011-04-18 22:02:00 +02:00
# ifdef CONFIG_USB_OTG
static int ehci_start_port_reset ( struct usb_hcd * hcd , unsigned port )
{
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
u32 status ;
if ( ! port )
return - EINVAL ;
port - - ;
/* start port reset before HNP protocol time out */
status = readl ( & ehci - > regs - > port_status [ port ] ) ;
if ( ! ( status & PORT_CONNECT ) )
return - ENODEV ;
2014-09-19 17:32:23 +02:00
/* hub_wq will finish the reset later */
2011-04-18 22:02:00 +02:00
if ( ehci_is_TDI ( ehci ) ) {
writel ( PORT_RESET |
( status & ~ ( PORT_CSC | PORT_PEC | PORT_OCC ) ) ,
& ehci - > regs - > port_status [ port ] ) ;
} else {
writel ( PORT_RESET , & ehci - > regs - > port_status [ port ] ) ;
}
return 0 ;
}
# else
# define ehci_start_port_reset NULL
# endif /* CONFIG_USB_OTG */
2015-05-14 19:04:46 +05:30
static struct ehci_driver_overrides ehci_fsl_overrides __initdata = {
. extra_priv_size = sizeof ( struct ehci_fsl ) ,
. reset = ehci_fsl_setup ,
} ;
2011-04-18 22:02:00 +02:00
2015-05-14 19:04:46 +05:30
/**
* fsl_ehci_drv_remove - shutdown processing for FSL - based HCDs
* @ dev : USB Host Controller being removed
* Context : ! in_interrupt ( )
*
* Reverses the effect of usb_hcd_fsl_probe ( ) .
*
*/
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
static int fsl_ehci_drv_remove ( struct platform_device * pdev )
{
struct fsl_usb2_platform_data * pdata = dev_get_platdata ( & pdev - > dev ) ;
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
if ( ! IS_ERR_OR_NULL ( hcd - > usb_phy ) ) {
otg_set_host ( hcd - > usb_phy - > otg , NULL ) ;
usb_put_phy ( hcd - > usb_phy ) ;
}
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
usb_remove_hcd ( hcd ) ;
2006-01-20 13:53:38 -08:00
/*
2015-05-14 19:04:46 +05:30
* do platform specific un - initialization :
* release iomux pins , disable clock , etc .
2006-01-20 13:53:38 -08:00
*/
2015-05-14 19:04:46 +05:30
if ( pdata - > exit )
pdata - > exit ( pdev ) ;
usb_put_hcd ( hcd ) ;
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
return 0 ;
}
static struct platform_driver ehci_fsl_driver = {
. probe = fsl_ehci_drv_probe ,
. remove = fsl_ehci_drv_remove ,
. shutdown = usb_hcd_platform_shutdown ,
. driver = {
. name = " fsl-ehci " ,
. pm = EHCI_FSL_PM_OPS ,
} ,
2006-01-20 13:53:38 -08:00
} ;
2015-05-14 19:04:46 +05:30
static int __init ehci_fsl_init ( void )
2006-01-20 13:53:38 -08:00
{
if ( usb_disabled ( ) )
return - ENODEV ;
2015-05-14 19:04:46 +05:30
pr_info ( DRV_NAME " : " DRIVER_DESC " \n " ) ;
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
ehci_init_driver ( & fsl_ehci_hc_driver , & ehci_fsl_overrides ) ;
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
fsl_ehci_hc_driver . product_desc =
" Freescale On-Chip EHCI Host Controller " ;
fsl_ehci_hc_driver . start_port_reset = ehci_start_port_reset ;
return platform_driver_register ( & ehci_fsl_driver ) ;
2006-01-20 13:53:38 -08:00
}
2015-05-14 19:04:46 +05:30
module_init ( ehci_fsl_init ) ;
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
static void __exit ehci_fsl_cleanup ( void )
{
platform_driver_unregister ( & ehci_fsl_driver ) ;
}
module_exit ( ehci_fsl_cleanup ) ;
2006-01-20 13:53:38 -08:00
2015-05-14 19:04:46 +05:30
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform: " DRV_NAME ) ;