2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0
2012-03-13 04:04:48 +04:00
/*
* Generic platform ehci driver
*
* Copyright 2007 Steven Brown < sbrown @ cortland . com >
* Copyright 2010 - 2012 Hauke Mehrtens < hauke @ hauke - m . de >
2014-02-07 19:36:41 +04:00
* Copyright 2014 Hans de Goede < hdegoede @ redhat . com >
2012-03-13 04:04:48 +04:00
*
* Derived from the ohci - ssb driver
* Copyright 2007 Michael Buesch < m @ bues . ch >
*
* Derived from the EHCI - PCI driver
* Copyright ( c ) 2000 - 2004 by David Brownell
*
* Derived from the ohci - pci driver
* Copyright 1999 Roman Weissgaerber
* Copyright 2000 - 2002 David Brownell
* Copyright 1999 Linus Torvalds
* Copyright 1999 Gregory P . Smith
*/
2015-08-20 00:36:32 +03:00
# include <linux/acpi.h>
2014-02-07 19:36:41 +04:00
# include <linux/clk.h>
2013-03-28 01:44:22 +04:00
# include <linux/dma-mapping.h>
2013-01-21 14:09:22 +04:00
# include <linux/err.h>
2012-11-01 19:13:08 +04:00
# include <linux/kernel.h>
2012-11-02 18:13:24 +04:00
# include <linux/hrtimer.h>
# include <linux/io.h>
2012-11-01 19:13:08 +04:00
# include <linux/module.h>
2013-03-28 01:44:22 +04:00
# include <linux/of.h>
2012-03-13 04:04:48 +04:00
# include <linux/platform_device.h>
2014-05-13 19:44:19 +04:00
# include <linux/reset.h>
2020-01-27 11:37:42 +03:00
# include <linux/sys_soc.h>
# include <linux/timer.h>
2012-11-01 19:13:08 +04:00
# include <linux/usb.h>
# include <linux/usb/hcd.h>
2012-03-13 04:04:48 +04:00
# include <linux/usb/ehci_pdriver.h>
2017-02-21 13:59:48 +03:00
# include <linux/usb/of.h>
2012-03-13 04:04:48 +04:00
2012-11-01 19:13:08 +04:00
# include "ehci.h"
# define DRIVER_DESC "EHCI generic platform driver"
2016-08-12 06:06:22 +03:00
# define EHCI_MAX_CLKS 4
2014-02-07 19:36:41 +04:00
# define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
2020-09-14 00:59:26 +03:00
# define BCM_USB_FIFO_THRESHOLD 0x00800040
2014-02-07 19:36:41 +04:00
struct ehci_platform_priv {
struct clk * clks [ EHCI_MAX_CLKS ] ;
2017-11-01 19:01:58 +03:00
struct reset_control * rsts ;
2015-08-04 11:59:17 +03:00
bool reset_on_resume ;
2020-01-27 11:37:42 +03:00
bool quirk_poll ;
struct timer_list poll_timer ;
struct delayed_work poll_work ;
2014-02-07 19:36:41 +04:00
} ;
2012-11-01 19:13:08 +04:00
static const char hcd_name [ ] = " ehci-platform " ;
2012-03-13 04:04:48 +04:00
static int ehci_platform_reset ( struct usb_hcd * hcd )
{
struct platform_device * pdev = to_platform_device ( hcd - > self . controller ) ;
2013-07-30 14:59:40 +04:00
struct usb_ehci_pdata * pdata = dev_get_platdata ( & pdev - > dev ) ;
2012-03-13 04:04:48 +04:00
struct ehci_hcd * ehci = hcd_to_ehci ( hcd ) ;
int retval ;
ehci - > has_synopsys_hc_bug = pdata - > has_synopsys_hc_bug ;
2013-06-02 01:33:56 +04:00
if ( pdata - > pre_setup ) {
retval = pdata - > pre_setup ( hcd ) ;
if ( retval < 0 )
return retval ;
}
2012-03-13 04:04:48 +04:00
ehci - > caps = hcd - > regs + pdata - > caps_offset ;
retval = ehci_setup ( hcd ) ;
if ( retval )
return retval ;
2012-10-08 17:11:21 +04:00
if ( pdata - > no_io_watchdog )
ehci - > need_io_watchdog = 0 ;
2020-09-14 00:59:26 +03:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " brcm,xgs-iproc-ehci " ) )
ehci_writel ( ehci , BCM_USB_FIFO_THRESHOLD ,
2022-02-15 03:08:13 +03:00
& ehci - > regs - > brcm_insnreg [ 1 ] ) ;
2020-09-14 00:59:26 +03:00
2012-03-13 04:04:48 +04:00
return 0 ;
}
2014-02-07 19:36:41 +04:00
static int ehci_platform_power_on ( struct platform_device * dev )
{
struct usb_hcd * hcd = platform_get_drvdata ( dev ) ;
struct ehci_platform_priv * priv = hcd_to_ehci_priv ( hcd ) ;
2018-03-04 00:43:07 +03:00
int clk , ret ;
2014-02-07 19:36:41 +04:00
for ( clk = 0 ; clk < EHCI_MAX_CLKS & & priv - > clks [ clk ] ; clk + + ) {
ret = clk_prepare_enable ( priv - > clks [ clk ] ) ;
if ( ret )
goto err_disable_clks ;
}
return 0 ;
err_disable_clks :
while ( - - clk > = 0 )
clk_disable_unprepare ( priv - > clks [ clk ] ) ;
return ret ;
}
static void ehci_platform_power_off ( struct platform_device * dev )
{
struct usb_hcd * hcd = platform_get_drvdata ( dev ) ;
struct ehci_platform_priv * priv = hcd_to_ehci_priv ( hcd ) ;
2018-03-04 00:43:07 +03:00
int clk ;
2014-02-07 19:36:41 +04:00
for ( clk = EHCI_MAX_CLKS - 1 ; clk > = 0 ; clk - - )
if ( priv - > clks [ clk ] )
clk_disable_unprepare ( priv - > clks [ clk ] ) ;
}
2012-11-01 19:13:08 +04:00
static struct hc_driver __read_mostly ehci_platform_hc_driver ;
2012-03-13 04:04:48 +04:00
2013-04-22 20:44:56 +04:00
static const struct ehci_driver_overrides platform_overrides __initconst = {
2014-02-07 19:36:41 +04:00
. reset = ehci_platform_reset ,
. extra_priv_size = sizeof ( struct ehci_platform_priv ) ,
2012-03-13 04:04:48 +04:00
} ;
2014-02-07 19:36:41 +04:00
static struct usb_ehci_pdata ehci_platform_defaults = {
. power_on = ehci_platform_power_on ,
. power_suspend = ehci_platform_power_off ,
. power_off = ehci_platform_power_off ,
} ;
2013-03-28 01:44:22 +04:00
2020-01-27 11:37:42 +03:00
/**
* quirk_poll_check_port_status - Poll port_status if the device sticks
* @ ehci : the ehci hcd pointer
*
* Since EHCI / OHCI controllers on R - Car Gen3 SoCs are possible to be getting
* stuck very rarely after a full / low usb device was disconnected . To
* detect such a situation , the controllers require a special way which poll
* the EHCI PORTSC register .
*
* Return : true if the controller ' s port_status indicated getting stuck
*/
static bool quirk_poll_check_port_status ( struct ehci_hcd * ehci )
{
u32 port_status = ehci_readl ( ehci , & ehci - > regs - > port_status [ 0 ] ) ;
if ( ! ( port_status & PORT_OWNER ) & &
( port_status & PORT_POWER ) & &
! ( port_status & PORT_CONNECT ) & &
( port_status & PORT_LS_MASK ) )
return true ;
return false ;
}
/**
* quirk_poll_rebind_companion - rebind comanion device to recover
* @ ehci : the ehci hcd pointer
*
* Since EHCI / OHCI controllers on R - Car Gen3 SoCs are possible to be getting
* stuck very rarely after a full / low usb device was disconnected . To
* recover from such a situation , the controllers require changing the OHCI
* functional state .
*/
static void quirk_poll_rebind_companion ( struct ehci_hcd * ehci )
{
struct device * companion_dev ;
struct usb_hcd * hcd = ehci_to_hcd ( ehci ) ;
companion_dev = usb_of_get_companion_dev ( hcd - > self . controller ) ;
if ( ! companion_dev )
return ;
device_release_driver ( companion_dev ) ;
if ( device_attach ( companion_dev ) < 0 )
ehci_err ( ehci , " %s: failed \n " , __func__ ) ;
put_device ( companion_dev ) ;
}
static void quirk_poll_work ( struct work_struct * work )
{
struct ehci_platform_priv * priv =
container_of ( to_delayed_work ( work ) , struct ehci_platform_priv ,
poll_work ) ;
struct ehci_hcd * ehci = container_of ( ( void * ) priv , struct ehci_hcd ,
priv ) ;
/* check the status twice to reduce misdetection rate */
if ( ! quirk_poll_check_port_status ( ehci ) )
return ;
udelay ( 10 ) ;
if ( ! quirk_poll_check_port_status ( ehci ) )
return ;
ehci_dbg ( ehci , " %s: detected getting stuck. rebind now! \n " , __func__ ) ;
quirk_poll_rebind_companion ( ehci ) ;
}
static void quirk_poll_timer ( struct timer_list * t )
{
struct ehci_platform_priv * priv = from_timer ( priv , t , poll_timer ) ;
struct ehci_hcd * ehci = container_of ( ( void * ) priv , struct ehci_hcd ,
priv ) ;
if ( quirk_poll_check_port_status ( ehci ) ) {
/*
* Now scheduling the work for testing the port more . Note that
* updating the status is possible to be delayed when
* reconnection . So , this uses delayed work with 5 ms delay
* to avoid misdetection .
*/
schedule_delayed_work ( & priv - > poll_work , msecs_to_jiffies ( 5 ) ) ;
}
mod_timer ( & priv - > poll_timer , jiffies + HZ ) ;
}
static void quirk_poll_init ( struct ehci_platform_priv * priv )
{
INIT_DELAYED_WORK ( & priv - > poll_work , quirk_poll_work ) ;
timer_setup ( & priv - > poll_timer , quirk_poll_timer , 0 ) ;
mod_timer ( & priv - > poll_timer , jiffies + HZ ) ;
}
static void quirk_poll_end ( struct ehci_platform_priv * priv )
{
del_timer_sync ( & priv - > poll_timer ) ;
cancel_delayed_work ( & priv - > poll_work ) ;
}
static const struct soc_device_attribute quirk_poll_match [ ] = {
{ . family = " R-Car Gen3 " } ,
{ /* sentinel*/ }
} ;
2012-11-19 22:21:48 +04:00
static int ehci_platform_probe ( struct platform_device * dev )
2012-03-13 04:04:48 +04:00
{
struct usb_hcd * hcd ;
struct resource * res_mem ;
2014-02-07 19:36:41 +04:00
struct usb_ehci_pdata * pdata = dev_get_platdata ( & dev - > dev ) ;
struct ehci_platform_priv * priv ;
2014-02-07 19:36:43 +04:00
struct ehci_hcd * ehci ;
2018-03-04 00:43:07 +03:00
int err , irq , clk = 0 ;
2012-03-13 04:04:48 +04:00
if ( usb_disabled ( ) )
return - ENODEV ;
2013-03-28 01:44:22 +04:00
/*
2014-02-07 19:36:41 +04:00
* Use reasonable defaults so platforms don ' t have to provide these
* with DT probing on ARM .
2013-03-28 01:44:22 +04:00
*/
2014-02-07 19:36:41 +04:00
if ( ! pdata )
pdata = & ehci_platform_defaults ;
2013-06-27 15:36:37 +04:00
2015-01-12 18:05:52 +03:00
err = dma_coerce_mask_and_coherent ( & dev - > dev ,
pdata - > dma_mask_64 ? DMA_BIT_MASK ( 64 ) : DMA_BIT_MASK ( 32 ) ) ;
2015-08-20 00:36:31 +03:00
if ( err ) {
dev_err ( & dev - > dev , " Error: DMA mask configuration failed \n " ) ;
2013-06-10 19:28:49 +04:00
return err ;
2015-08-20 00:36:31 +03:00
}
2013-03-28 01:44:22 +04:00
2012-03-13 04:04:48 +04:00
irq = platform_get_irq ( dev , 0 ) ;
2019-07-30 21:15:46 +03:00
if ( irq < 0 )
2012-03-13 04:04:48 +04:00
return irq ;
2014-02-07 19:36:41 +04:00
hcd = usb_create_hcd ( & ehci_platform_hc_driver , & dev - > dev ,
dev_name ( & dev - > dev ) ) ;
if ( ! hcd )
return - ENOMEM ;
platform_set_drvdata ( dev , hcd ) ;
dev - > dev . platform_data = pdata ;
priv = hcd_to_ehci_priv ( hcd ) ;
2014-02-07 19:36:43 +04:00
ehci = hcd_to_ehci ( hcd ) ;
2014-02-07 19:36:41 +04:00
if ( pdata = = & ehci_platform_defaults & & dev - > dev . of_node ) {
2014-02-07 19:36:43 +04:00
if ( of_property_read_bool ( dev - > dev . of_node , " big-endian-regs " ) )
ehci - > big_endian_mmio = 1 ;
if ( of_property_read_bool ( dev - > dev . of_node , " big-endian-desc " ) )
ehci - > big_endian_desc = 1 ;
if ( of_property_read_bool ( dev - > dev . of_node , " big-endian " ) )
ehci - > big_endian_mmio = ehci - > big_endian_desc = 1 ;
2021-02-23 20:44:55 +03:00
if ( of_property_read_bool ( dev - > dev . of_node , " spurious-oc " ) )
ehci - > spurious_oc = 1 ;
2014-12-24 13:22:19 +03:00
if ( of_property_read_bool ( dev - > dev . of_node ,
" needs-reset-on-resume " ) )
2015-08-04 11:59:17 +03:00
priv - > reset_on_resume = true ;
2014-12-24 13:22:19 +03:00
2015-05-16 18:17:40 +03:00
if ( of_property_read_bool ( dev - > dev . of_node ,
" has-transaction-translator " ) )
2015-08-04 11:59:17 +03:00
hcd - > has_tt = 1 ;
2015-05-16 18:17:40 +03:00
2021-09-10 10:36:19 +03:00
if ( of_device_is_compatible ( dev - > dev . of_node ,
" aspeed,ast2500-ehci " ) | |
of_device_is_compatible ( dev - > dev . of_node ,
" aspeed,ast2600-ehci " ) )
ehci - > is_aspeed = 1 ;
2020-01-27 11:37:42 +03:00
if ( soc_device_match ( quirk_poll_match ) )
priv - > quirk_poll = true ;
2014-02-07 19:36:41 +04:00
for ( clk = 0 ; clk < EHCI_MAX_CLKS ; clk + + ) {
priv - > clks [ clk ] = of_clk_get ( dev - > dev . of_node , clk ) ;
if ( IS_ERR ( priv - > clks [ clk ] ) ) {
err = PTR_ERR ( priv - > clks [ clk ] ) ;
if ( err = = - EPROBE_DEFER )
goto err_put_clks ;
priv - > clks [ clk ] = NULL ;
break ;
}
}
}
2017-11-01 19:01:58 +03:00
priv - > rsts = devm_reset_control_array_get_optional_shared ( & dev - > dev ) ;
if ( IS_ERR ( priv - > rsts ) ) {
err = PTR_ERR ( priv - > rsts ) ;
goto err_put_clks ;
2014-05-13 19:44:19 +04:00
}
2017-11-01 19:01:58 +03:00
err = reset_control_deassert ( priv - > rsts ) ;
if ( err )
goto err_put_clks ;
2014-02-11 20:26:10 +04:00
if ( pdata - > big_endian_desc )
ehci - > big_endian_desc = 1 ;
if ( pdata - > big_endian_mmio )
ehci - > big_endian_mmio = 1 ;
2015-08-04 11:59:17 +03:00
if ( pdata - > has_tt )
hcd - > has_tt = 1 ;
if ( pdata - > reset_on_resume )
priv - > reset_on_resume = true ;
2021-02-23 20:44:53 +03:00
if ( pdata - > spurious_oc )
ehci - > spurious_oc = 1 ;
2014-02-11 20:26:10 +04:00
# ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
if ( ehci - > big_endian_mmio ) {
dev_err ( & dev - > dev ,
" Error: CONFIG_USB_EHCI_BIG_ENDIAN_MMIO not set \n " ) ;
err = - EINVAL ;
2014-05-13 19:44:19 +04:00
goto err_reset ;
2014-02-11 20:26:10 +04:00
}
# endif
# ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
if ( ehci - > big_endian_desc ) {
dev_err ( & dev - > dev ,
" Error: CONFIG_USB_EHCI_BIG_ENDIAN_DESC not set \n " ) ;
err = - EINVAL ;
2014-05-13 19:44:19 +04:00
goto err_reset ;
2014-02-11 20:26:10 +04:00
}
# endif
2012-08-07 05:08:39 +04:00
if ( pdata - > power_on ) {
err = pdata - > power_on ( dev ) ;
if ( err < 0 )
2014-05-13 19:44:19 +04:00
goto err_reset ;
2012-08-07 05:08:39 +04:00
}
2012-03-13 04:04:48 +04:00
2014-11-04 05:21:25 +03:00
res_mem = platform_get_resource ( dev , IORESOURCE_MEM , 0 ) ;
2013-01-21 14:09:22 +04:00
hcd - > regs = devm_ioremap_resource ( & dev - > dev , res_mem ) ;
if ( IS_ERR ( hcd - > regs ) ) {
err = PTR_ERR ( hcd - > regs ) ;
2014-02-07 19:36:41 +04:00
goto err_power ;
2012-08-14 10:47:38 +04:00
}
2014-11-04 05:21:25 +03:00
hcd - > rsrc_start = res_mem - > start ;
hcd - > rsrc_len = resource_size ( res_mem ) ;
2022-06-21 18:23:48 +03:00
hcd - > tpl_support = of_usb_host_tpl_support ( dev - > dev . of_node ) ;
2012-03-13 04:04:48 +04:00
err = usb_add_hcd ( hcd , irq , IRQF_SHARED ) ;
if ( err )
2014-02-07 19:36:41 +04:00
goto err_power ;
2012-03-13 04:04:48 +04:00
2013-11-05 06:46:02 +04:00
device_wakeup_enable ( hcd - > self . controller ) ;
2017-02-21 13:59:48 +03:00
device_enable_async_suspend ( hcd - > self . controller ) ;
2012-03-13 04:04:48 +04:00
platform_set_drvdata ( dev , hcd ) ;
2020-01-27 11:37:42 +03:00
if ( priv - > quirk_poll )
quirk_poll_init ( priv ) ;
2012-03-13 04:04:48 +04:00
return err ;
2012-08-07 05:08:39 +04:00
err_power :
if ( pdata - > power_off )
pdata - > power_off ( dev ) ;
2014-05-13 19:44:19 +04:00
err_reset :
2017-11-01 19:01:58 +03:00
reset_control_assert ( priv - > rsts ) ;
2014-02-07 19:36:41 +04:00
err_put_clks :
while ( - - clk > = 0 )
clk_put ( priv - > clks [ clk ] ) ;
2018-03-04 00:43:07 +03:00
2014-02-07 19:36:41 +04:00
if ( pdata = = & ehci_platform_defaults )
dev - > dev . platform_data = NULL ;
usb_put_hcd ( hcd ) ;
2012-08-07 05:08:39 +04:00
2012-03-13 04:04:48 +04:00
return err ;
}
2012-11-19 22:26:20 +04:00
static int ehci_platform_remove ( struct platform_device * dev )
2012-03-13 04:04:48 +04:00
{
struct usb_hcd * hcd = platform_get_drvdata ( dev ) ;
2013-07-30 14:59:40 +04:00
struct usb_ehci_pdata * pdata = dev_get_platdata ( & dev - > dev ) ;
2014-02-07 19:36:41 +04:00
struct ehci_platform_priv * priv = hcd_to_ehci_priv ( hcd ) ;
2017-11-01 19:01:58 +03:00
int clk ;
2012-03-13 04:04:48 +04:00
2020-01-27 11:37:42 +03:00
if ( priv - > quirk_poll )
quirk_poll_end ( priv ) ;
2012-03-13 04:04:48 +04:00
usb_remove_hcd ( hcd ) ;
2012-08-07 05:08:39 +04:00
if ( pdata - > power_off )
pdata - > power_off ( dev ) ;
2017-11-01 19:01:58 +03:00
reset_control_assert ( priv - > rsts ) ;
2014-05-13 19:44:19 +04:00
2014-02-07 19:36:41 +04:00
for ( clk = 0 ; clk < EHCI_MAX_CLKS & & priv - > clks [ clk ] ; clk + + )
clk_put ( priv - > clks [ clk ] ) ;
usb_put_hcd ( hcd ) ;
2013-03-28 01:44:22 +04:00
if ( pdata = = & ehci_platform_defaults )
dev - > dev . platform_data = NULL ;
2012-03-13 04:04:48 +04:00
return 0 ;
}
2020-09-03 14:25:38 +03:00
static int __maybe_unused ehci_platform_suspend ( struct device * dev )
2012-03-13 04:04:48 +04:00
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2013-07-30 14:59:40 +04:00
struct usb_ehci_pdata * pdata = dev_get_platdata ( dev ) ;
2015-12-23 16:26:52 +03:00
struct platform_device * pdev = to_platform_device ( dev ) ;
2020-01-27 11:37:42 +03:00
struct ehci_platform_priv * priv = hcd_to_ehci_priv ( hcd ) ;
2012-06-28 19:19:02 +04:00
bool do_wakeup = device_may_wakeup ( dev ) ;
2012-08-07 05:08:39 +04:00
int ret ;
2020-01-27 11:37:42 +03:00
if ( priv - > quirk_poll )
quirk_poll_end ( priv ) ;
2012-08-07 05:08:39 +04:00
ret = ehci_suspend ( hcd , do_wakeup ) ;
2014-04-10 14:28:02 +04:00
if ( ret )
return ret ;
2012-03-13 04:04:48 +04:00
2012-08-07 05:08:39 +04:00
if ( pdata - > power_suspend )
pdata - > power_suspend ( pdev ) ;
return ret ;
2012-03-13 04:04:48 +04:00
}
2020-09-03 14:25:38 +03:00
static int __maybe_unused ehci_platform_resume ( struct device * dev )
2012-03-13 04:04:48 +04:00
{
struct usb_hcd * hcd = dev_get_drvdata ( dev ) ;
2013-07-30 14:59:40 +04:00
struct usb_ehci_pdata * pdata = dev_get_platdata ( dev ) ;
2015-12-23 16:26:52 +03:00
struct platform_device * pdev = to_platform_device ( dev ) ;
2015-08-04 11:59:17 +03:00
struct ehci_platform_priv * priv = hcd_to_ehci_priv ( hcd ) ;
2017-02-21 13:59:48 +03:00
struct device * companion_dev ;
2012-08-07 05:08:39 +04:00
if ( pdata - > power_on ) {
int err = pdata - > power_on ( pdev ) ;
if ( err < 0 )
return err ;
}
2012-03-13 04:04:48 +04:00
2017-02-21 13:59:48 +03:00
companion_dev = usb_of_get_companion_dev ( hcd - > self . controller ) ;
2017-05-16 17:26:13 +03:00
if ( companion_dev ) {
2017-02-21 13:59:48 +03:00
device_pm_wait_for_dev ( hcd - > self . controller , companion_dev ) ;
2017-05-16 17:26:13 +03:00
put_device ( companion_dev ) ;
}
2017-02-21 13:59:48 +03:00
2015-08-04 11:59:17 +03:00
ehci_resume ( hcd , priv - > reset_on_resume ) ;
2020-01-27 11:37:42 +03:00
2020-05-18 18:49:31 +03:00
pm_runtime_disable ( dev ) ;
pm_runtime_set_active ( dev ) ;
pm_runtime_enable ( dev ) ;
2020-01-27 11:37:42 +03:00
if ( priv - > quirk_poll )
quirk_poll_init ( priv ) ;
2012-03-13 04:04:48 +04:00
return 0 ;
}
2013-03-28 01:44:22 +04:00
static const struct of_device_id vt8500_ehci_ids [ ] = {
{ . compatible = " via,vt8500-ehci " , } ,
{ . compatible = " wm,prizm-ehci " , } ,
ehci-platform: Change compatible string from usb-ehci to generic-ehci
The initial versions of the devicetree enablement patches for ehci-platform
used "ehci-platform" as compatible string. However this was disliked by various
reviewers because the platform bus is a Linux invention and devicetree is
supposed to be OS agnostic. After much discussion I gave up, added a:
"depends on !PPC_OF" to Kconfig to avoid a known conflict with PPC-OF platforms
and went with the generic usb-ehci as requested.
In retro-spect I should have chosen something different, the dts files for many
existing boards already claim to be compatible with "usb-ehci", ie they have:
compatible = "ti,ehci-omap", "usb-ehci";
In theory this should not be a problem since the "ti,ehci-omap" entry takes
presedence, but in practice using a conflicting compatible string is an issue,
because it makes which driver gets used depend on driver registration order.
This patch changes the compatible string claimed by ehci-platform to
"generic-ehci", avoiding the driver registration / module loading ordering
problems, and removes the "depends on !PPC_OF" workaround.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-02-11 20:35:29 +04:00
{ . compatible = " generic-ehci " , } ,
2015-01-06 15:48:56 +03:00
{ . compatible = " cavium,octeon-6335-ehci " , } ,
2013-03-28 01:44:22 +04:00
{ }
} ;
2014-02-07 19:36:41 +04:00
MODULE_DEVICE_TABLE ( of , vt8500_ehci_ids ) ;
2013-03-28 01:44:22 +04:00
2020-07-06 16:33:37 +03:00
# ifdef CONFIG_ACPI
2015-08-20 00:36:32 +03:00
static const struct acpi_device_id ehci_acpi_match [ ] = {
{ " PNP0D20 " , 0 } , /* EHCI controller without debug */
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , ehci_acpi_match ) ;
2020-07-06 16:33:37 +03:00
# endif
2015-08-20 00:36:32 +03:00
2012-03-13 04:04:48 +04:00
static const struct platform_device_id ehci_platform_table [ ] = {
{ " ehci-platform " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( platform , ehci_platform_table ) ;
2014-10-24 08:45:47 +04:00
static SIMPLE_DEV_PM_OPS ( ehci_platform_pm_ops , ehci_platform_suspend ,
ehci_platform_resume ) ;
2012-03-13 04:04:48 +04:00
static struct platform_driver ehci_platform_driver = {
. id_table = ehci_platform_table ,
. probe = ehci_platform_probe ,
2012-11-19 22:21:08 +04:00
. remove = ehci_platform_remove ,
2012-03-13 04:04:48 +04:00
. shutdown = usb_hcd_platform_shutdown ,
. driver = {
. name = " ehci-platform " ,
2020-09-03 14:25:38 +03:00
. pm = pm_ptr ( & ehci_platform_pm_ops ) ,
2013-05-21 15:47:16 +04:00
. of_match_table = vt8500_ehci_ids ,
2015-08-20 00:36:32 +03:00
. acpi_match_table = ACPI_PTR ( ehci_acpi_match ) ,
2022-05-19 01:02:51 +03:00
. probe_type = PROBE_PREFER_ASYNCHRONOUS ,
2012-03-13 04:04:48 +04:00
}
} ;
2012-11-01 19:13:08 +04:00
static int __init ehci_platform_init ( void )
{
if ( usb_disabled ( ) )
return - ENODEV ;
pr_info ( " %s: " DRIVER_DESC " \n " , hcd_name ) ;
ehci_init_driver ( & ehci_platform_hc_driver , & platform_overrides ) ;
return platform_driver_register ( & ehci_platform_driver ) ;
}
module_init ( ehci_platform_init ) ;
static void __exit ehci_platform_cleanup ( void )
{
platform_driver_unregister ( & ehci_platform_driver ) ;
}
module_exit ( ehci_platform_cleanup ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_AUTHOR ( " Hauke Mehrtens " ) ;
MODULE_AUTHOR ( " Alan Stern " ) ;
MODULE_LICENSE ( " GPL " ) ;