2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0
2020-02-18 18:12:19 +03:00
/*
2011-10-12 15:08:26 +04:00
* host . c - DesignWare USB3 DRD Controller Host Glue
*
* Copyright ( C ) 2011 Texas Instruments Incorporated - http : //www.ti.com
*
* Authors : Felipe Balbi < balbi @ ti . com > ,
*/
2020-02-18 18:12:18 +03:00
# include <linux/acpi.h>
2011-10-12 15:08:26 +04:00
# include <linux/platform_device.h>
# include "core.h"
2016-10-03 12:31:48 +03:00
static int dwc3_host_get_irq ( struct dwc3 * dwc )
{
struct platform_device * dwc3_pdev = to_platform_device ( dwc - > dev ) ;
int irq ;
2019-10-06 00:04:48 +03:00
irq = platform_get_irq_byname_optional ( dwc3_pdev , " host " ) ;
2016-10-03 12:31:48 +03:00
if ( irq > 0 )
goto out ;
if ( irq = = - EPROBE_DEFER )
goto out ;
2019-10-06 00:04:48 +03:00
irq = platform_get_irq_byname_optional ( dwc3_pdev , " dwc_usb3 " ) ;
2016-10-03 12:31:48 +03:00
if ( irq > 0 )
goto out ;
if ( irq = = - EPROBE_DEFER )
goto out ;
irq = platform_get_irq ( dwc3_pdev , 0 ) ;
if ( irq > 0 )
goto out ;
if ( ! irq )
irq = - EINVAL ;
out :
return irq ;
}
2011-10-12 15:08:26 +04:00
int dwc3_host_init ( struct dwc3 * dwc )
{
2018-11-08 05:10:42 +03:00
struct property_entry props [ 4 ] ;
2011-10-12 15:08:26 +04:00
struct platform_device * xhci ;
2016-06-30 14:54:17 +03:00
int ret , irq ;
struct resource * res ;
struct platform_device * dwc3_pdev = to_platform_device ( dwc - > dev ) ;
2017-01-26 12:17:37 +03:00
int prop_idx = 0 ;
2016-06-30 14:54:17 +03:00
2016-10-03 12:31:48 +03:00
irq = dwc3_host_get_irq ( dwc ) ;
if ( irq < 0 )
2016-06-30 14:54:17 +03:00
return irq ;
2016-10-03 12:31:48 +03:00
res = platform_get_resource_byname ( dwc3_pdev , IORESOURCE_IRQ , " host " ) ;
if ( ! res )
2016-06-30 14:54:17 +03:00
res = platform_get_resource_byname ( dwc3_pdev , IORESOURCE_IRQ ,
2016-10-03 12:31:48 +03:00
" dwc_usb3 " ) ;
if ( ! res )
res = platform_get_resource ( dwc3_pdev , IORESOURCE_IRQ , 0 ) ;
if ( ! res )
return - ENOMEM ;
2016-06-30 14:54:17 +03:00
dwc - > xhci_resources [ 1 ] . start = irq ;
dwc - > xhci_resources [ 1 ] . end = irq ;
dwc - > xhci_resources [ 1 ] . flags = res - > flags ;
dwc - > xhci_resources [ 1 ] . name = res - > name ;
2011-10-12 15:08:26 +04:00
2013-01-25 15:22:02 +04:00
xhci = platform_device_alloc ( " xhci-hcd " , PLATFORM_DEVID_AUTO ) ;
2011-10-12 15:08:26 +04:00
if ( ! xhci ) {
dev_err ( dwc - > dev , " couldn't allocate xHCI device \n " ) ;
2014-11-19 18:28:23 +03:00
return - ENOMEM ;
2011-10-12 15:08:26 +04:00
}
xhci - > dev . parent = dwc - > dev ;
2020-02-18 18:12:18 +03:00
ACPI_COMPANION_SET ( & xhci - > dev , ACPI_COMPANION ( dwc - > dev ) ) ;
2011-10-12 15:08:26 +04:00
dwc - > xhci = xhci ;
2012-04-24 15:18:39 +04:00
ret = platform_device_add_resources ( xhci , dwc - > xhci_resources ,
DWC3_XHCI_RESOURCES_NUM ) ;
2011-10-12 15:08:26 +04:00
if ( ret ) {
dev_err ( dwc - > dev , " couldn't add resources to xHCI device \n " ) ;
2019-07-19 12:30:37 +03:00
goto err ;
2011-10-12 15:08:26 +04:00
}
2016-06-21 10:58:09 +03:00
memset ( props , 0 , sizeof ( struct property_entry ) * ARRAY_SIZE ( props ) ) ;
2014-07-04 18:01:26 +04:00
2017-01-26 12:17:37 +03:00
if ( dwc - > usb3_lpm_capable )
2019-12-13 20:46:23 +03:00
props [ prop_idx + + ] = PROPERTY_ENTRY_BOOL ( " usb3-lpm-capable " ) ;
2017-01-26 12:17:37 +03:00
2018-11-08 05:10:42 +03:00
if ( dwc - > usb2_lpm_disable )
2019-12-13 20:46:23 +03:00
props [ prop_idx + + ] = PROPERTY_ENTRY_BOOL ( " usb2-lpm-disable " ) ;
2018-11-08 05:10:42 +03:00
2017-01-26 12:17:37 +03:00
/**
* WORKAROUND : dwc3 revisions < = 3.00 a have a limitation
* where Port Disable command doesn ' t work .
*
* The suggested workaround is that we avoid Port Disable
* completely .
*
* This following flag tells XHCI to do just that .
*/
if ( dwc - > revision < = DWC3_REVISION_300A )
2019-12-13 20:46:23 +03:00
props [ prop_idx + + ] = PROPERTY_ENTRY_BOOL ( " quirk-broken-port-ped " ) ;
2017-01-26 12:17:37 +03:00
if ( prop_idx ) {
2016-06-21 10:58:09 +03:00
ret = platform_device_add_properties ( xhci , props ) ;
if ( ret ) {
dev_err ( dwc - > dev , " failed to add properties to xHCI \n " ) ;
2019-07-19 12:30:37 +03:00
goto err ;
2016-06-21 10:58:09 +03:00
}
2014-07-04 18:01:26 +04:00
}
2011-10-12 15:08:26 +04:00
ret = platform_device_add ( xhci ) ;
if ( ret ) {
dev_err ( dwc - > dev , " failed to register xHCI device \n " ) ;
2019-07-19 12:30:37 +03:00
goto err ;
2011-10-12 15:08:26 +04:00
}
return 0 ;
2019-07-19 12:30:37 +03:00
err :
2011-10-12 15:08:26 +04:00
platform_device_put ( xhci ) ;
return ret ;
}
void dwc3_host_exit ( struct dwc3 * dwc )
{
platform_device_unregister ( dwc - > xhci ) ;
}