2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0
2010-12-07 15:23:59 +03:00
/*
2013-06-24 15:46:36 +04:00
* ci_hdrc_pci . c - MIPS USB IP core family device controller
2010-12-07 15:23:59 +03:00
*
* Copyright ( C ) 2008 Chipidea - MIPS Technologies , Inc . All rights reserved .
*
* Author : David Lopo
*/
2012-05-09 00:29:01 +04:00
# include <linux/platform_device.h>
2010-12-07 15:23:59 +03:00
# include <linux/module.h>
# include <linux/pci.h>
2012-05-09 00:29:01 +04:00
# include <linux/interrupt.h>
# include <linux/usb/gadget.h>
2012-05-11 18:25:46 +04:00
# include <linux/usb/chipidea.h>
2015-02-11 07:45:00 +03:00
# include <linux/usb/usb_phy_generic.h>
2010-12-07 15:23:59 +03:00
/* driver name */
2013-06-24 15:46:36 +04:00
# define UDC_DRIVER_NAME "ci_hdrc_pci"
2010-12-07 15:23:59 +03:00
2015-02-11 07:45:00 +03:00
struct ci_hdrc_pci {
struct platform_device * ci ;
struct platform_device * phy ;
} ;
2010-12-07 15:23:59 +03:00
/******************************************************************************
* PCI block
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-06-24 15:46:36 +04:00
static struct ci_hdrc_platform_data pci_platdata = {
2012-05-09 00:29:01 +04:00
. name = UDC_DRIVER_NAME ,
. capoffset = DEF_CAPOFFSET ,
} ;
2010-12-07 15:23:59 +03:00
2013-06-24 15:46:36 +04:00
static struct ci_hdrc_platform_data langwell_pci_platdata = {
2010-12-07 15:24:02 +03:00
. name = UDC_DRIVER_NAME ,
2012-05-09 00:29:01 +04:00
. capoffset = 0 ,
2010-12-07 15:24:02 +03:00
} ;
2013-06-24 15:46:36 +04:00
static struct ci_hdrc_platform_data penwell_pci_platdata = {
2012-05-11 18:25:55 +04:00
. name = UDC_DRIVER_NAME ,
. capoffset = 0 ,
. power_budget = 200 ,
} ;
2010-12-07 15:23:59 +03:00
/**
2013-06-24 15:46:36 +04:00
* ci_hdrc_pci_probe : PCI probe
2010-12-07 15:23:59 +03:00
* @ pdev : USB device controller being probed
* @ id : PCI hotplug ID connecting controller to UDC framework
*
* This function returns an error code
* Allocates basic PCI resources for this USB device controller , and then
* invokes the udc_probe ( ) method to start the UDC associated with it
*/
2013-06-24 15:46:36 +04:00
static int ci_hdrc_pci_probe ( struct pci_dev * pdev ,
2010-12-07 15:23:59 +03:00
const struct pci_device_id * id )
{
2013-06-24 15:46:36 +04:00
struct ci_hdrc_platform_data * platdata = ( void * ) id - > driver_data ;
2015-02-11 07:45:00 +03:00
struct ci_hdrc_pci * ci ;
2012-05-09 00:29:01 +04:00
struct resource res [ 3 ] ;
int retval = 0 , nres = 2 ;
2010-12-07 15:23:59 +03:00
2012-06-29 13:48:53 +04:00
if ( ! platdata ) {
2012-05-11 18:25:40 +04:00
dev_err ( & pdev - > dev , " device doesn't provide driver data \n " ) ;
return - ENODEV ;
}
2015-02-11 07:45:00 +03:00
ci = devm_kzalloc ( & pdev - > dev , sizeof ( * ci ) , GFP_KERNEL ) ;
if ( ! ci )
return - ENOMEM ;
2013-06-13 19:00:02 +04:00
retval = pcim_enable_device ( pdev ) ;
2010-12-07 15:23:59 +03:00
if ( retval )
2013-06-13 19:00:02 +04:00
return retval ;
2010-12-07 15:23:59 +03:00
if ( ! pdev - > irq ) {
dev_err ( & pdev - > dev , " No IRQ, check BIOS/PCI setup! " ) ;
2013-06-13 19:00:02 +04:00
return - ENODEV ;
2010-12-07 15:23:59 +03:00
}
pci_set_master ( pdev ) ;
pci_try_set_mwi ( pdev ) ;
2015-02-11 07:45:00 +03:00
/* register a nop PHY */
ci - > phy = usb_phy_generic_register ( ) ;
2016-02-06 17:57:06 +03:00
if ( IS_ERR ( ci - > phy ) )
return PTR_ERR ( ci - > phy ) ;
2015-02-11 07:45:00 +03:00
2012-05-09 00:29:01 +04:00
memset ( res , 0 , sizeof ( res ) ) ;
res [ 0 ] . start = pci_resource_start ( pdev , 0 ) ;
res [ 0 ] . end = pci_resource_end ( pdev , 0 ) ;
res [ 0 ] . flags = IORESOURCE_MEM ;
res [ 1 ] . start = pdev - > irq ;
res [ 1 ] . flags = IORESOURCE_IRQ ;
2015-02-11 07:45:00 +03:00
ci - > ci = ci_hdrc_add_device ( & pdev - > dev , res , nres , platdata ) ;
if ( IS_ERR ( ci - > ci ) ) {
2013-06-24 15:46:36 +04:00
dev_err ( & pdev - > dev , " ci_hdrc_add_device failed! \n " ) ;
2015-02-11 07:45:00 +03:00
usb_phy_generic_unregister ( ci - > phy ) ;
return PTR_ERR ( ci - > ci ) ;
2012-05-09 00:29:01 +04:00
}
2015-02-11 07:45:00 +03:00
pci_set_drvdata ( pdev , ci ) ;
2012-05-09 00:29:01 +04:00
2010-12-07 15:23:59 +03:00
return 0 ;
}
/**
2013-06-24 15:46:36 +04:00
* ci_hdrc_pci_remove : PCI remove
2010-12-07 15:23:59 +03:00
* @ pdev : USB Device Controller being removed
*
2013-06-24 15:46:36 +04:00
* Reverses the effect of ci_hdrc_pci_probe ( ) ,
2010-12-07 15:23:59 +03:00
* first invoking the udc_remove ( ) and then releases
* all PCI resources allocated for this USB device controller
*/
2013-06-24 15:46:36 +04:00
static void ci_hdrc_pci_remove ( struct pci_dev * pdev )
2010-12-07 15:23:59 +03:00
{
2015-02-11 07:45:00 +03:00
struct ci_hdrc_pci * ci = pci_get_drvdata ( pdev ) ;
2012-05-09 00:29:01 +04:00
2015-02-11 07:45:00 +03:00
ci_hdrc_remove_device ( ci - > ci ) ;
usb_phy_generic_unregister ( ci - > phy ) ;
2010-12-07 15:23:59 +03:00
}
/**
* PCI device table
* PCI device structure
*
* Check " pci.h " for details
2015-02-03 19:08:39 +03:00
*
* Note : ehci - pci driver may try to probe the device first . You have to add an
* ID to the bypass_pci_id_table in ehci - pci driver to prevent this .
2010-12-07 15:23:59 +03:00
*/
2013-11-28 09:15:26 +04:00
static const struct pci_device_id ci_hdrc_pci_id_table [ ] = {
2012-05-09 00:29:01 +04:00
{
PCI_DEVICE ( 0x153F , 0x1004 ) ,
2012-06-29 13:48:53 +04:00
. driver_data = ( kernel_ulong_t ) & pci_platdata ,
2012-05-09 00:29:01 +04:00
} ,
{
PCI_DEVICE ( 0x153F , 0x1006 ) ,
2012-06-29 13:48:53 +04:00
. driver_data = ( kernel_ulong_t ) & pci_platdata ,
2012-05-09 00:29:01 +04:00
} ,
{
2015-10-04 23:55:35 +03:00
PCI_VDEVICE ( INTEL , 0x0811 ) ,
2012-06-29 13:48:53 +04:00
. driver_data = ( kernel_ulong_t ) & langwell_pci_platdata ,
2012-05-09 00:29:01 +04:00
} ,
{
2015-10-04 23:55:35 +03:00
PCI_VDEVICE ( INTEL , 0x0829 ) ,
2012-06-29 13:48:53 +04:00
. driver_data = ( kernel_ulong_t ) & penwell_pci_platdata ,
2012-05-09 00:29:01 +04:00
} ,
2013-10-02 01:32:58 +04:00
{
/* Intel Clovertrail */
2015-10-04 23:55:35 +03:00
PCI_VDEVICE ( INTEL , 0xe006 ) ,
2013-10-02 01:32:58 +04:00
. driver_data = ( kernel_ulong_t ) & penwell_pci_platdata ,
} ,
{ 0 } /* end: all zeroes */
2010-12-07 15:23:59 +03:00
} ;
2013-06-24 15:46:36 +04:00
MODULE_DEVICE_TABLE ( pci , ci_hdrc_pci_id_table ) ;
2010-12-07 15:23:59 +03:00
2013-06-24 15:46:36 +04:00
static struct pci_driver ci_hdrc_pci_driver = {
2010-12-07 15:23:59 +03:00
. name = UDC_DRIVER_NAME ,
2013-06-24 15:46:36 +04:00
. id_table = ci_hdrc_pci_id_table ,
. probe = ci_hdrc_pci_probe ,
. remove = ci_hdrc_pci_remove ,
2010-12-07 15:23:59 +03:00
} ;
2013-06-24 15:46:36 +04:00
module_pci_driver ( ci_hdrc_pci_driver ) ;
2010-12-07 15:23:59 +03:00
MODULE_AUTHOR ( " MIPS - David Lopo <dlopo@chipidea.mips.com> " ) ;
MODULE_DESCRIPTION ( " MIPS CI13XXX USB Peripheral Controller " ) ;
MODULE_LICENSE ( " GPL " ) ;
2013-06-24 15:46:36 +04:00
MODULE_ALIAS ( " platform:ci13xxx_pci " ) ;