2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-05-11 12:21:33 +01:00
/*
* Synopsys G210 Test Chip driver
*
* Copyright ( C ) 2015 - 2016 Synopsys , Inc . ( www . synopsys . com )
*
* Authors : Joao Pinto < jpinto @ synopsys . com >
*/
# include "ufshcd.h"
# include "ufshcd-dwc.h"
# include "tc-dwc-g210.h"
# include <linux/pci.h>
# include <linux/pm_runtime.h>
/* Test Chip type expected values */
# define TC_G210_20BIT 20
# define TC_G210_40BIT 40
# define TC_G210_INV 0
static int tc_type = TC_G210_INV ;
module_param ( tc_type , int , 0 ) ;
MODULE_PARM_DESC ( tc_type , " Test Chip Type (20 = 20-bit, 40 = 40-bit) " ) ;
static int tc_dwc_g210_pci_suspend ( struct device * dev )
{
return ufshcd_system_suspend ( dev_get_drvdata ( dev ) ) ;
}
static int tc_dwc_g210_pci_resume ( struct device * dev )
{
return ufshcd_system_resume ( dev_get_drvdata ( dev ) ) ;
}
static int tc_dwc_g210_pci_runtime_suspend ( struct device * dev )
{
return ufshcd_runtime_suspend ( dev_get_drvdata ( dev ) ) ;
}
static int tc_dwc_g210_pci_runtime_resume ( struct device * dev )
{
return ufshcd_runtime_resume ( dev_get_drvdata ( dev ) ) ;
}
static int tc_dwc_g210_pci_runtime_idle ( struct device * dev )
{
return ufshcd_runtime_idle ( dev_get_drvdata ( dev ) ) ;
}
2018-03-01 15:07:20 -08:00
/*
2016-05-11 12:21:33 +01:00
* struct ufs_hba_dwc_vops - UFS DWC specific variant operations
*/
static struct ufs_hba_variant_ops tc_dwc_g210_pci_hba_vops = {
. name = " tc-dwc-g210-pci " ,
. link_startup_notify = ufshcd_dwc_link_startup_notify ,
} ;
/**
* tc_dwc_g210_pci_shutdown - main function to put the controller in reset state
* @ pdev : pointer to PCI device handle
*/
static void tc_dwc_g210_pci_shutdown ( struct pci_dev * pdev )
{
ufshcd_shutdown ( ( struct ufs_hba * ) pci_get_drvdata ( pdev ) ) ;
}
/**
* tc_dwc_g210_pci_remove - de - allocate PCI / SCSI host and host memory space
* data structure memory
2018-03-01 15:07:20 -08:00
* @ pdev : pointer to PCI handle
2016-05-11 12:21:33 +01:00
*/
static void tc_dwc_g210_pci_remove ( struct pci_dev * pdev )
{
struct ufs_hba * hba = pci_get_drvdata ( pdev ) ;
pm_runtime_forbid ( & pdev - > dev ) ;
pm_runtime_get_noresume ( & pdev - > dev ) ;
ufshcd_remove ( hba ) ;
}
/**
* tc_dwc_g210_pci_probe - probe routine of the driver
* @ pdev : pointer to PCI device handle
* @ id : PCI device id
*
* Returns 0 on success , non - zero value on failure
*/
static int
tc_dwc_g210_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * id )
{
struct ufs_hba * hba ;
void __iomem * mmio_base ;
int err ;
/* Check Test Chip type and set the specific setup routine */
if ( tc_type = = TC_G210_20BIT ) {
tc_dwc_g210_pci_hba_vops . phy_initialization =
tc_dwc_g210_config_20_bit ;
} else if ( tc_type = = TC_G210_40BIT ) {
tc_dwc_g210_pci_hba_vops . phy_initialization =
tc_dwc_g210_config_40_bit ;
} else {
dev_err ( & pdev - > dev , " test chip version not specified \n " ) ;
return - EPERM ;
}
err = pcim_enable_device ( pdev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " pcim_enable_device failed \n " ) ;
return err ;
}
pci_set_master ( pdev ) ;
err = pcim_iomap_regions ( pdev , 1 < < 0 , UFSHCD ) ;
if ( err < 0 ) {
dev_err ( & pdev - > dev , " request and iomap failed \n " ) ;
return err ;
}
mmio_base = pcim_iomap_table ( pdev ) [ 0 ] ;
err = ufshcd_alloc_host ( & pdev - > dev , & hba ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Allocation failed \n " ) ;
return err ;
}
hba - > vops = & tc_dwc_g210_pci_hba_vops ;
err = ufshcd_init ( hba , mmio_base , pdev - > irq ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Initialization failed \n " ) ;
return err ;
}
pci_set_drvdata ( pdev , hba ) ;
pm_runtime_put_noidle ( & pdev - > dev ) ;
pm_runtime_allow ( & pdev - > dev ) ;
return 0 ;
}
static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
. suspend = tc_dwc_g210_pci_suspend ,
. resume = tc_dwc_g210_pci_resume ,
. runtime_suspend = tc_dwc_g210_pci_runtime_suspend ,
. runtime_resume = tc_dwc_g210_pci_runtime_resume ,
. runtime_idle = tc_dwc_g210_pci_runtime_idle ,
} ;
static const struct pci_device_id tc_dwc_g210_pci_tbl [ ] = {
{ PCI_VENDOR_ID_SYNOPSYS , 0xB101 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_SYNOPSYS , 0xB102 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ } /* terminate list */
} ;
MODULE_DEVICE_TABLE ( pci , tc_dwc_g210_pci_tbl ) ;
static struct pci_driver tc_dwc_g210_pci_driver = {
. name = " tc-dwc-g210-pci " ,
. id_table = tc_dwc_g210_pci_tbl ,
. probe = tc_dwc_g210_pci_probe ,
. remove = tc_dwc_g210_pci_remove ,
. shutdown = tc_dwc_g210_pci_shutdown ,
. driver = {
. pm = & tc_dwc_g210_pci_pm_ops
} ,
} ;
module_pci_driver ( tc_dwc_g210_pci_driver ) ;
MODULE_AUTHOR ( " Joao Pinto <Joao.Pinto@synopsys.com> " ) ;
MODULE_DESCRIPTION ( " Synopsys Test Chip G210 PCI glue driver " ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;