2014-07-22 15:23:45 -06:00
/*
* pcie - dra7xx - PCIe controller driver for TI DRA7xx SoCs
*
* Copyright ( C ) 2013 - 2014 Texas Instruments Incorporated - http : //www.ti.com
*
* Authors : Kishon Vijay Abraham I < kishon @ ti . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/err.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/irqdomain.h>
# include <linux/kernel.h>
2016-08-24 16:57:47 -04:00
# include <linux/init.h>
2015-07-28 19:09:09 +05:30
# include <linux/of_gpio.h>
2017-01-11 17:36:53 +05:30
# include <linux/of_pci.h>
2014-07-22 15:23:45 -06:00
# include <linux/pci.h>
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
# include <linux/resource.h>
# include <linux/types.h>
# include "pcie-designware.h"
/* PCIe controller wrapper DRA7XX configuration registers */
# define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN 0x0024
# define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN 0x0028
# define ERR_SYS BIT(0)
# define ERR_FATAL BIT(1)
# define ERR_NONFATAL BIT(2)
# define ERR_COR BIT(3)
# define ERR_AXI BIT(4)
# define ERR_ECRC BIT(5)
# define PME_TURN_OFF BIT(8)
# define PME_TO_ACK BIT(9)
# define PM_PME BIT(10)
# define LINK_REQ_RST BIT(11)
# define LINK_UP_EVT BIT(12)
# define CFG_BME_EVT BIT(13)
# define CFG_MSE_EVT BIT(14)
# define INTERRUPTS (ERR_SYS | ERR_FATAL | ERR_NONFATAL | ERR_COR | ERR_AXI | \
ERR_ECRC | PME_TURN_OFF | PME_TO_ACK | PM_PME | \
LINK_REQ_RST | LINK_UP_EVT | CFG_BME_EVT | CFG_MSE_EVT )
# define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI 0x0034
# define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI 0x0038
# define INTA BIT(0)
# define INTB BIT(1)
# define INTC BIT(2)
# define INTD BIT(3)
# define MSI BIT(4)
# define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD)
# define PCIECTRL_DRA7XX_CONF_DEVICE_CMD 0x0104
# define LTSSM_EN 0x1
# define PCIECTRL_DRA7XX_CONF_PHY_CS 0x010C
# define LINK_UP BIT(16)
2015-10-29 19:56:51 -05:00
# define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF
2014-07-22 15:23:45 -06:00
2017-01-11 17:36:53 +05:30
# define EXP_CAP_ID_OFFSET 0x70
2014-07-22 15:23:45 -06:00
struct dra7xx_pcie {
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci ;
2016-10-06 13:33:06 -05:00
void __iomem * base ; /* DT ti_conf */
int phy_count ; /* DT phy-names count */
struct phy * * phy ;
2017-01-11 17:36:53 +05:30
int link_gen ;
2017-01-11 17:36:54 +05:30
struct irq_domain * irq_domain ;
2014-07-22 15:23:45 -06:00
} ;
2017-02-15 18:48:14 +05:30
# define to_dra7xx_pcie(x) dev_get_drvdata((x)->dev)
2014-07-22 15:23:45 -06:00
static inline u32 dra7xx_pcie_readl ( struct dra7xx_pcie * pcie , u32 offset )
{
return readl ( pcie - > base + offset ) ;
}
static inline void dra7xx_pcie_writel ( struct dra7xx_pcie * pcie , u32 offset ,
u32 value )
{
writel ( value , pcie - > base + offset ) ;
}
2017-03-13 19:13:23 +05:30
static u64 dra7xx_pcie_cpu_addr_fixup ( u64 pci_addr )
{
return pci_addr & DRA7XX_CPU_TO_BUS_ADDR ;
}
2017-02-15 18:48:14 +05:30
static int dra7xx_pcie_link_up ( struct dw_pcie * pci )
2014-07-22 15:23:45 -06:00
{
2017-02-15 18:48:14 +05:30
struct dra7xx_pcie * dra7xx = to_dra7xx_pcie ( pci ) ;
2014-07-22 15:23:45 -06:00
u32 reg = dra7xx_pcie_readl ( dra7xx , PCIECTRL_DRA7XX_CONF_PHY_CS ) ;
return ! ! ( reg & LINK_UP ) ;
}
2016-10-06 13:33:05 -05:00
static int dra7xx_pcie_establish_link ( struct dra7xx_pcie * dra7xx )
2014-07-22 15:23:45 -06:00
{
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = dra7xx - > pci ;
struct device * dev = pci - > dev ;
2015-06-02 16:47:17 -05:00
u32 reg ;
2017-01-11 17:36:53 +05:30
u32 exp_cap_off = EXP_CAP_ID_OFFSET ;
2014-07-22 15:23:45 -06:00
2017-02-15 18:48:14 +05:30
if ( dw_pcie_link_up ( pci ) ) {
2016-10-06 13:33:06 -05:00
dev_err ( dev , " link is already up \n " ) ;
2014-07-22 15:23:45 -06:00
return 0 ;
}
2017-01-11 17:36:53 +05:30
if ( dra7xx - > link_gen = = 1 ) {
2017-02-15 18:48:14 +05:30
dw_pcie_read ( pci - > dbi_base + exp_cap_off + PCI_EXP_LNKCAP ,
2017-02-15 18:48:12 +05:30
4 , & reg ) ;
2017-01-11 17:36:53 +05:30
if ( ( reg & PCI_EXP_LNKCAP_SLS ) ! = PCI_EXP_LNKCAP_SLS_2_5GB ) {
reg & = ~ ( ( u32 ) PCI_EXP_LNKCAP_SLS ) ;
reg | = PCI_EXP_LNKCAP_SLS_2_5GB ;
2017-02-15 18:48:14 +05:30
dw_pcie_write ( pci - > dbi_base + exp_cap_off +
2017-02-15 18:48:12 +05:30
PCI_EXP_LNKCAP , 4 , reg ) ;
2017-01-11 17:36:53 +05:30
}
2017-02-15 18:48:14 +05:30
dw_pcie_read ( pci - > dbi_base + exp_cap_off + PCI_EXP_LNKCTL2 ,
2017-02-15 18:48:12 +05:30
2 , & reg ) ;
2017-01-11 17:36:53 +05:30
if ( ( reg & PCI_EXP_LNKCAP_SLS ) ! = PCI_EXP_LNKCAP_SLS_2_5GB ) {
reg & = ~ ( ( u32 ) PCI_EXP_LNKCAP_SLS ) ;
reg | = PCI_EXP_LNKCAP_SLS_2_5GB ;
2017-02-15 18:48:14 +05:30
dw_pcie_write ( pci - > dbi_base + exp_cap_off +
2017-02-15 18:48:12 +05:30
PCI_EXP_LNKCTL2 , 2 , reg ) ;
2017-01-11 17:36:53 +05:30
}
}
2014-07-22 15:23:45 -06:00
reg = dra7xx_pcie_readl ( dra7xx , PCIECTRL_DRA7XX_CONF_DEVICE_CMD ) ;
reg | = LTSSM_EN ;
dra7xx_pcie_writel ( dra7xx , PCIECTRL_DRA7XX_CONF_DEVICE_CMD , reg ) ;
2017-02-15 18:48:14 +05:30
return dw_pcie_wait_for_link ( pci ) ;
2014-07-22 15:23:45 -06:00
}
2016-10-06 13:33:05 -05:00
static void dra7xx_pcie_enable_interrupts ( struct dra7xx_pcie * dra7xx )
2014-07-22 15:23:45 -06:00
{
dra7xx_pcie_writel ( dra7xx , PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN ,
~ INTERRUPTS ) ;
dra7xx_pcie_writel ( dra7xx ,
PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN , INTERRUPTS ) ;
dra7xx_pcie_writel ( dra7xx , PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI ,
~ LEG_EP_INTERRUPTS & ~ MSI ) ;
2017-01-11 17:36:54 +05:30
dra7xx_pcie_writel ( dra7xx , PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI ,
MSI | LEG_EP_INTERRUPTS ) ;
2014-07-22 15:23:45 -06:00
}
static void dra7xx_pcie_host_init ( struct pcie_port * pp )
{
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = to_dw_pcie_from_pp ( pp ) ;
struct dra7xx_pcie * dra7xx = to_dra7xx_pcie ( pci ) ;
2016-10-06 13:33:05 -05:00
2016-03-16 19:40:33 +08:00
dw_pcie_setup_rc ( pp ) ;
2016-10-06 13:33:05 -05:00
dra7xx_pcie_establish_link ( dra7xx ) ;
2017-01-11 17:36:54 +05:30
dw_pcie_msi_init ( pp ) ;
2016-10-06 13:33:05 -05:00
dra7xx_pcie_enable_interrupts ( dra7xx ) ;
2014-07-22 15:23:45 -06:00
}
2017-02-15 18:48:14 +05:30
static struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
2014-07-22 15:23:45 -06:00
. host_init = dra7xx_pcie_host_init ,
} ;
static int dra7xx_pcie_intx_map ( struct irq_domain * domain , unsigned int irq ,
irq_hw_number_t hwirq )
{
irq_set_chip_and_handler ( irq , & dummy_irq_chip , handle_simple_irq ) ;
irq_set_chip_data ( irq , domain - > host_data ) ;
return 0 ;
}
static const struct irq_domain_ops intx_domain_ops = {
. map = dra7xx_pcie_intx_map ,
} ;
static int dra7xx_pcie_init_irq_domain ( struct pcie_port * pp )
{
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = to_dw_pcie_from_pp ( pp ) ;
struct device * dev = pci - > dev ;
struct dra7xx_pcie * dra7xx = to_dra7xx_pcie ( pci ) ;
2014-07-22 15:23:45 -06:00
struct device_node * node = dev - > of_node ;
struct device_node * pcie_intc_node = of_get_next_child ( node , NULL ) ;
if ( ! pcie_intc_node ) {
dev_err ( dev , " No PCIe Intc node found \n " ) ;
2016-07-14 23:18:27 +02:00
return - ENODEV ;
2014-07-22 15:23:45 -06:00
}
2017-01-11 17:36:54 +05:30
dra7xx - > irq_domain = irq_domain_add_linear ( pcie_intc_node , 4 ,
& intx_domain_ops , pp ) ;
if ( ! dra7xx - > irq_domain ) {
2014-07-22 15:23:45 -06:00
dev_err ( dev , " Failed to get a INTx IRQ domain \n " ) ;
2016-07-14 23:18:27 +02:00
return - ENODEV ;
2014-07-22 15:23:45 -06:00
}
return 0 ;
}
static irqreturn_t dra7xx_pcie_msi_irq_handler ( int irq , void * arg )
{
2016-10-06 13:33:05 -05:00
struct dra7xx_pcie * dra7xx = arg ;
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = dra7xx - > pci ;
struct pcie_port * pp = & pci - > pp ;
2014-07-22 15:23:45 -06:00
u32 reg ;
reg = dra7xx_pcie_readl ( dra7xx , PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI ) ;
switch ( reg ) {
case MSI :
dw_handle_msi_irq ( pp ) ;
break ;
case INTA :
case INTB :
case INTC :
case INTD :
2017-01-11 17:36:54 +05:30
generic_handle_irq ( irq_find_mapping ( dra7xx - > irq_domain ,
ffs ( reg ) ) ) ;
2014-07-22 15:23:45 -06:00
break ;
}
dra7xx_pcie_writel ( dra7xx , PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI , reg ) ;
return IRQ_HANDLED ;
}
static irqreturn_t dra7xx_pcie_irq_handler ( int irq , void * arg )
{
struct dra7xx_pcie * dra7xx = arg ;
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = dra7xx - > pci ;
struct device * dev = pci - > dev ;
2014-07-22 15:23:45 -06:00
u32 reg ;
reg = dra7xx_pcie_readl ( dra7xx , PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN ) ;
if ( reg & ERR_SYS )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " System Error \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & ERR_FATAL )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " Fatal Error \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & ERR_NONFATAL )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " Non Fatal Error \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & ERR_COR )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " Correctable Error \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & ERR_AXI )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " AXI tag lookup fatal Error \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & ERR_ECRC )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " ECRC Error \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & PME_TURN_OFF )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev ,
2014-07-22 15:23:45 -06:00
" Power Management Event Turn-Off message received \n " ) ;
if ( reg & PME_TO_ACK )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev ,
2014-07-22 15:23:45 -06:00
" Power Management Turn-Off Ack message received \n " ) ;
if ( reg & PM_PME )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " PM Power Management Event message received \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & LINK_REQ_RST )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " Link Request Reset \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & LINK_UP_EVT )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " Link-up state change \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & CFG_BME_EVT )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " CFG 'Bus Master Enable' change \n " ) ;
2014-07-22 15:23:45 -06:00
if ( reg & CFG_MSE_EVT )
2016-10-06 13:33:06 -05:00
dev_dbg ( dev , " CFG 'Memory Space Enable' change \n " ) ;
2014-07-22 15:23:45 -06:00
dra7xx_pcie_writel ( dra7xx , PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN , reg ) ;
return IRQ_HANDLED ;
}
2014-11-06 14:37:39 +09:00
static int __init dra7xx_add_pcie_port ( struct dra7xx_pcie * dra7xx ,
struct platform_device * pdev )
2014-07-22 15:23:45 -06:00
{
int ret ;
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = dra7xx - > pci ;
struct pcie_port * pp = & pci - > pp ;
struct device * dev = pci - > dev ;
2014-07-22 15:23:45 -06:00
struct resource * res ;
pp - > irq = platform_get_irq ( pdev , 1 ) ;
if ( pp - > irq < 0 ) {
dev_err ( dev , " missing IRQ resource \n " ) ;
return - EINVAL ;
}
2016-10-06 13:33:06 -05:00
ret = devm_request_irq ( dev , pp - > irq , dra7xx_pcie_msi_irq_handler ,
2015-12-10 21:18:20 +02:00
IRQF_SHARED | IRQF_NO_THREAD ,
2016-10-06 13:33:05 -05:00
" dra7-pcie-msi " , dra7xx ) ;
2014-07-22 15:23:45 -06:00
if ( ret ) {
2016-10-06 13:33:06 -05:00
dev_err ( dev , " failed to request irq \n " ) ;
2014-07-22 15:23:45 -06:00
return ret ;
}
2017-01-11 17:36:54 +05:30
ret = dra7xx_pcie_init_irq_domain ( pp ) ;
if ( ret < 0 )
return ret ;
2014-07-22 15:23:45 -06:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " rc_dbics " ) ;
2017-02-15 18:48:14 +05:30
pci - > dbi_base = devm_ioremap ( dev , res - > start , resource_size ( res ) ) ;
if ( ! pci - > dbi_base )
2014-07-22 15:23:45 -06:00
return - ENOMEM ;
ret = dw_pcie_host_init ( pp ) ;
if ( ret ) {
2016-10-06 13:33:06 -05:00
dev_err ( dev , " failed to initialize host \n " ) ;
2014-07-22 15:23:45 -06:00
return ret ;
}
return 0 ;
}
2017-02-15 18:48:14 +05:30
static const struct dw_pcie_ops dw_pcie_ops = {
2017-03-13 19:13:23 +05:30
. cpu_addr_fixup = dra7xx_pcie_cpu_addr_fixup ,
2017-02-15 18:48:14 +05:30
. link_up = dra7xx_pcie_link_up ,
} ;
2017-01-11 17:36:55 +05:30
static void dra7xx_pcie_disable_phy ( struct dra7xx_pcie * dra7xx )
{
int phy_count = dra7xx - > phy_count ;
while ( phy_count - - ) {
phy_power_off ( dra7xx - > phy [ phy_count ] ) ;
phy_exit ( dra7xx - > phy [ phy_count ] ) ;
}
}
static int dra7xx_pcie_enable_phy ( struct dra7xx_pcie * dra7xx )
{
int phy_count = dra7xx - > phy_count ;
int ret ;
int i ;
for ( i = 0 ; i < phy_count ; i + + ) {
ret = phy_init ( dra7xx - > phy [ i ] ) ;
if ( ret < 0 )
goto err_phy ;
ret = phy_power_on ( dra7xx - > phy [ i ] ) ;
if ( ret < 0 ) {
phy_exit ( dra7xx - > phy [ i ] ) ;
goto err_phy ;
}
}
return 0 ;
err_phy :
while ( - - i > = 0 ) {
phy_power_off ( dra7xx - > phy [ i ] ) ;
phy_exit ( dra7xx - > phy [ i ] ) ;
}
return ret ;
}
2014-07-22 15:23:45 -06:00
static int __init dra7xx_pcie_probe ( struct platform_device * pdev )
{
u32 reg ;
int ret ;
int irq ;
int i ;
int phy_count ;
struct phy * * phy ;
void __iomem * base ;
struct resource * res ;
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci ;
2016-10-06 13:33:06 -05:00
struct pcie_port * pp ;
2017-02-15 18:48:14 +05:30
struct dra7xx_pcie * dra7xx ;
2014-07-22 15:23:45 -06:00
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
char name [ 10 ] ;
2017-01-11 17:36:52 +05:30
struct gpio_desc * reset ;
2014-07-22 15:23:45 -06:00
dra7xx = devm_kzalloc ( dev , sizeof ( * dra7xx ) , GFP_KERNEL ) ;
if ( ! dra7xx )
return - ENOMEM ;
2017-02-15 18:48:14 +05:30
pci = devm_kzalloc ( dev , sizeof ( * pci ) , GFP_KERNEL ) ;
if ( ! pci )
return - ENOMEM ;
pci - > dev = dev ;
pci - > ops = & dw_pcie_ops ;
pp = & pci - > pp ;
2016-10-06 13:33:06 -05:00
pp - > ops = & dra7xx_pcie_host_ops ;
2014-07-22 15:23:45 -06:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
dev_err ( dev , " missing IRQ resource \n " ) ;
return - EINVAL ;
}
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " ti_conf " ) ;
base = devm_ioremap_nocache ( dev , res - > start , resource_size ( res ) ) ;
if ( ! base )
return - ENOMEM ;
phy_count = of_property_count_strings ( np , " phy-names " ) ;
if ( phy_count < 0 ) {
dev_err ( dev , " unable to find the strings \n " ) ;
return phy_count ;
}
phy = devm_kzalloc ( dev , sizeof ( * phy ) * phy_count , GFP_KERNEL ) ;
if ( ! phy )
return - ENOMEM ;
for ( i = 0 ; i < phy_count ; i + + ) {
snprintf ( name , sizeof ( name ) , " pcie-phy%d " , i ) ;
phy [ i ] = devm_phy_get ( dev , name ) ;
if ( IS_ERR ( phy [ i ] ) )
return PTR_ERR ( phy [ i ] ) ;
}
dra7xx - > base = base ;
dra7xx - > phy = phy ;
2017-02-15 18:48:14 +05:30
dra7xx - > pci = pci ;
2014-07-22 15:23:45 -06:00
dra7xx - > phy_count = phy_count ;
2017-01-11 17:36:55 +05:30
ret = dra7xx_pcie_enable_phy ( dra7xx ) ;
if ( ret ) {
dev_err ( dev , " failed to enable phy \n " ) ;
return ret ;
}
2017-02-15 18:48:11 +05:30
platform_set_drvdata ( pdev , dra7xx ) ;
2014-07-22 15:23:45 -06:00
pm_runtime_enable ( dev ) ;
ret = pm_runtime_get_sync ( dev ) ;
2015-08-20 01:30:36 -05:00
if ( ret < 0 ) {
2014-07-22 15:23:45 -06:00
dev_err ( dev , " pm_runtime_get_sync failed \n " ) ;
2015-07-31 17:55:10 +05:30
goto err_get_sync ;
2014-07-22 15:23:45 -06:00
}
2017-01-11 17:36:52 +05:30
reset = devm_gpiod_get_optional ( dev , NULL , GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( reset ) ) {
ret = PTR_ERR ( reset ) ;
dev_err ( & pdev - > dev , " gpio request failed, ret %d \n " , ret ) ;
2015-07-28 19:09:09 +05:30
goto err_gpio ;
2014-07-22 15:23:45 -06:00
}
reg = dra7xx_pcie_readl ( dra7xx , PCIECTRL_DRA7XX_CONF_DEVICE_CMD ) ;
reg & = ~ LTSSM_EN ;
dra7xx_pcie_writel ( dra7xx , PCIECTRL_DRA7XX_CONF_DEVICE_CMD , reg ) ;
2017-01-11 17:36:53 +05:30
dra7xx - > link_gen = of_pci_get_max_link_speed ( np ) ;
if ( dra7xx - > link_gen < 0 | | dra7xx - > link_gen > 2 )
dra7xx - > link_gen = 2 ;
2014-11-06 14:30:49 +09:00
ret = dra7xx_add_pcie_port ( dra7xx , pdev ) ;
2014-07-22 15:23:45 -06:00
if ( ret < 0 )
2015-07-28 19:09:09 +05:30
goto err_gpio ;
2014-07-22 15:23:45 -06:00
2017-03-13 19:13:28 +05:30
ret = devm_request_irq ( dev , irq , dra7xx_pcie_irq_handler ,
IRQF_SHARED , " dra7xx-pcie-main " , dra7xx ) ;
if ( ret ) {
dev_err ( dev , " failed to request irq \n " ) ;
goto err_gpio ;
}
2014-07-22 15:23:45 -06:00
return 0 ;
2015-07-28 19:09:09 +05:30
err_gpio :
2014-07-22 15:23:45 -06:00
pm_runtime_put ( dev ) ;
2015-07-31 17:55:10 +05:30
err_get_sync :
2014-07-22 15:23:45 -06:00
pm_runtime_disable ( dev ) ;
2017-01-11 17:36:55 +05:30
dra7xx_pcie_disable_phy ( dra7xx ) ;
2014-07-22 15:23:45 -06:00
return ret ;
}
2015-07-31 17:55:11 +05:30
# ifdef CONFIG_PM_SLEEP
2015-07-31 17:55:12 +05:30
static int dra7xx_pcie_suspend ( struct device * dev )
{
struct dra7xx_pcie * dra7xx = dev_get_drvdata ( dev ) ;
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = dra7xx - > pci ;
2015-07-31 17:55:12 +05:30
u32 val ;
/* clear MSE */
2017-02-15 18:48:14 +05:30
val = dw_pcie_readl_dbi ( pci , PCI_COMMAND ) ;
2015-07-31 17:55:12 +05:30
val & = ~ PCI_COMMAND_MEMORY ;
2017-02-15 18:48:14 +05:30
dw_pcie_writel_dbi ( pci , PCI_COMMAND , val ) ;
2015-07-31 17:55:12 +05:30
return 0 ;
}
static int dra7xx_pcie_resume ( struct device * dev )
{
struct dra7xx_pcie * dra7xx = dev_get_drvdata ( dev ) ;
2017-02-15 18:48:14 +05:30
struct dw_pcie * pci = dra7xx - > pci ;
2015-07-31 17:55:12 +05:30
u32 val ;
/* set MSE */
2017-02-15 18:48:14 +05:30
val = dw_pcie_readl_dbi ( pci , PCI_COMMAND ) ;
2015-07-31 17:55:12 +05:30
val | = PCI_COMMAND_MEMORY ;
2017-02-15 18:48:14 +05:30
dw_pcie_writel_dbi ( pci , PCI_COMMAND , val ) ;
2015-07-31 17:55:12 +05:30
return 0 ;
}
2015-07-31 17:55:11 +05:30
static int dra7xx_pcie_suspend_noirq ( struct device * dev )
{
struct dra7xx_pcie * dra7xx = dev_get_drvdata ( dev ) ;
2017-01-11 17:36:55 +05:30
dra7xx_pcie_disable_phy ( dra7xx ) ;
2015-07-31 17:55:11 +05:30
return 0 ;
}
static int dra7xx_pcie_resume_noirq ( struct device * dev )
{
struct dra7xx_pcie * dra7xx = dev_get_drvdata ( dev ) ;
int ret ;
2017-01-11 17:36:55 +05:30
ret = dra7xx_pcie_enable_phy ( dra7xx ) ;
if ( ret ) {
dev_err ( dev , " failed to enable phy \n " ) ;
return ret ;
2015-07-31 17:55:11 +05:30
}
return 0 ;
}
# endif
static const struct dev_pm_ops dra7xx_pcie_pm_ops = {
2015-07-31 17:55:12 +05:30
SET_SYSTEM_SLEEP_PM_OPS ( dra7xx_pcie_suspend , dra7xx_pcie_resume )
2015-07-31 17:55:11 +05:30
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS ( dra7xx_pcie_suspend_noirq ,
dra7xx_pcie_resume_noirq )
} ;
2014-07-22 15:23:45 -06:00
static const struct of_device_id of_dra7xx_pcie_match [ ] = {
{ . compatible = " ti,dra7-pcie " , } ,
{ } ,
} ;
static struct platform_driver dra7xx_pcie_driver = {
. driver = {
. name = " dra7-pcie " ,
. of_match_table = of_dra7xx_pcie_match ,
2016-08-24 16:57:47 -04:00
. suppress_bind_attrs = true ,
2015-07-31 17:55:11 +05:30
. pm = & dra7xx_pcie_pm_ops ,
2014-07-22 15:23:45 -06:00
} ,
} ;
2016-08-24 16:57:47 -04:00
builtin_platform_driver_probe ( dra7xx_pcie_driver , dra7xx_pcie_probe ) ;