This commit adds a platform device driver for the PCIe controller on
Tegra SOCs. Current users of the old code (TrimSlice and Harmony) are
converted and now initialize and register a corresponding platform
device.

Signed-off-by: Thierry Reding <thierry.red...@avionic-design.de>

---
Changes in v2:
- use struct hw_pci's new private_data field
- fix DT initialization for TrimSlice
---
 arch/arm/mach-tegra/board-dt-tegra20.c       |   15 +-
 arch/arm/mach-tegra/board-harmony-pcie.c     |   38 +-
 arch/arm/mach-tegra/board-harmony.c          |    1 +
 arch/arm/mach-tegra/board-harmony.h          |    1 +
 arch/arm/mach-tegra/board-trimslice.c        |   18 +-
 arch/arm/mach-tegra/board.h                  |    2 +-
 arch/arm/mach-tegra/devices.c                |   25 ++
 arch/arm/mach-tegra/devices.h                |    1 +
 arch/arm/mach-tegra/include/mach/iomap.h     |    6 +
 arch/arm/mach-tegra/include/mach/pci-tegra.h |   29 ++
 arch/arm/mach-tegra/pcie.c                   |  514 ++++++++++++++++----------
 11 files changed, 419 insertions(+), 231 deletions(-)
 create mode 100644 arch/arm/mach-tegra/include/mach/pci-tegra.h

diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c 
b/arch/arm/mach-tegra/board-dt-tegra20.c
index 9c444a0..0f29c05 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -40,6 +40,7 @@
 
 #include <mach/iomap.h>
 #include <mach/irqs.h>
+#include <mach/pci-tegra.h>
 
 #include "board.h"
 #include "board-harmony.h"
@@ -116,13 +117,17 @@ static void __init tegra_dt_init(void)
 }
 
 #ifdef CONFIG_MACH_TRIMSLICE
+static struct tegra_pcie_pdata trimslice_pcie_pdata = {
+       .enable_ports = {
+               [0] = true,
+               [1] = true,
+       },
+};
+
 static void __init trimslice_init(void)
 {
-       int ret;
-
-       ret = tegra_pcie_init(true, true);
-       if (ret)
-               pr_err("tegra_pci_init() failed: %d\n", ret);
+       tegra_pcie_device.dev.platform_data = &trimslice_pcie_pdata;
+       platform_device_register(&tegra_pcie_device);
 }
 #endif
 
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c 
b/arch/arm/mach-tegra/board-harmony-pcie.c
index e8c3fda..8373271 100644
--- a/arch/arm/mach-tegra/board-harmony-pcie.c
+++ b/arch/arm/mach-tegra/board-harmony-pcie.c
@@ -22,12 +22,14 @@
 
 #include <asm/mach-types.h>
 
+#include <mach/pci-tegra.h>
+
 #include "board.h"
+#include "devices.h"
 #include "board-harmony.h"
 
 #ifdef CONFIG_TEGRA_PCI
-
-int __init harmony_pcie_init(void)
+static int harmony_pcie_board_init(struct platform_device *pdev)
 {
        struct regulator *regulator = NULL;
        int err;
@@ -44,30 +46,32 @@ int __init harmony_pcie_init(void)
 
        regulator_enable(regulator);
 
-       err = tegra_pcie_init(true, true);
-       if (err)
-               goto err_pcie;
-
        return 0;
 
-err_pcie:
-       regulator_disable(regulator);
-       regulator_put(regulator);
 err_reg:
        gpio_free(TEGRA_GPIO_EN_VDD_1V05_GPIO);
 
        return err;
 }
 
-static int __init harmony_pcie_initcall(void)
+static struct tegra_pcie_pdata harmony_pcie_pdata = {
+       .init = harmony_pcie_board_init,
+       .enable_ports = {
+               [0] = true,
+               [1] = true,
+       },
+};
+
+int __init harmony_pcie_init(void)
 {
-       if (!machine_is_harmony())
-               return 0;
+       tegra_pcie_device.dev.platform_data = &harmony_pcie_pdata;
+       platform_device_register(&tegra_pcie_device);
 
-       return harmony_pcie_init();
+       return 0;
+}
+#else
+int __init harmony_pcie_init(void)
+{
+       return 0;
 }
-
-/* PCI should be initialized after I2C, mfd and regulators */
-subsys_initcall_sync(harmony_pcie_initcall);
-
 #endif
diff --git a/arch/arm/mach-tegra/board-harmony.c 
b/arch/arm/mach-tegra/board-harmony.c
index e5f3352..063c7d5 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -204,6 +204,7 @@ static void __init tegra_harmony_init(void)
        pwm_add_table(harmony_pwm_lookup, ARRAY_SIZE(harmony_pwm_lookup));
        harmony_i2c_init();
        harmony_regulator_init();
+       harmony_pcie_init();
 }
 
 MACHINE_START(HARMONY, "harmony")
diff --git a/arch/arm/mach-tegra/board-harmony.h 
b/arch/arm/mach-tegra/board-harmony.h
index 139d96c..afa68e2 100644
--- a/arch/arm/mach-tegra/board-harmony.h
+++ b/arch/arm/mach-tegra/board-harmony.h
@@ -37,5 +37,6 @@
 
 void harmony_pinmux_init(void);
 int harmony_regulator_init(void);
+int harmony_pcie_init(void);
 
 #endif
diff --git a/arch/arm/mach-tegra/board-trimslice.c 
b/arch/arm/mach-tegra/board-trimslice.c
index 776aa95..30246d2 100644
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ b/arch/arm/mach-tegra/board-trimslice.c
@@ -34,6 +34,7 @@
 #include <asm/setup.h>
 
 #include <mach/iomap.h>
+#include <mach/pci-tegra.h>
 #include <mach/sdhci.h>
 
 #include "board.h"
@@ -145,14 +146,20 @@ static __initdata struct tegra_clk_init_table 
trimslice_clk_init_table[] = {
        { NULL,         NULL,           0,              0},
 };
 
-static int __init tegra_trimslice_pci_init(void)
+static struct tegra_pcie_pdata trimslice_pcie_pdata = {
+       .enable_ports = {
+               [0] = true,
+               [1] = true,
+       },
+};
+
+static int __init trimslice_pci_init(void)
 {
-       if (!machine_is_trimslice())
-               return 0;
+       tegra_pcie_device.dev.platform_data = &trimslice_pcie_pdata;
+       platform_device_register(&tegra_pcie_device);
 
-       return tegra_pcie_init(true, true);
+       return 0;
 }
-subsys_initcall(tegra_trimslice_pci_init);
 
 static void __init tegra_trimslice_init(void)
 {
@@ -167,6 +174,7 @@ static void __init tegra_trimslice_init(void)
 
        trimslice_i2c_init();
        trimslice_usb_init();
+       trimslice_pci_init();
 }
 
 MACHINE_START(TRIMSLICE, "trimslice")
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index f88e514..3a2a7e9 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -30,7 +30,6 @@ void __init tegra30_init_early(void);
 void __init tegra_map_common_io(void);
 void __init tegra_init_irq(void);
 void __init tegra_dt_init_irq(void);
-int __init tegra_pcie_init(bool init_port0, bool init_port1);
 
 void tegra_init_late(void);
 
@@ -56,4 +55,5 @@ static inline int harmony_pcie_init(void) { return 0; }
 void __init tegra_paz00_wifikill_init(void);
 
 extern struct sys_timer tegra_timer;
+
 #endif
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 4529561..de4aef9 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -735,3 +735,28 @@ struct platform_device tegra_nand_device = {
        .num_resources = ARRAY_SIZE(tegra_nand_resources),
        .resource = tegra_nand_resources,
 };
+
+static struct resource tegra_pcie_resources[] = {
+       [0] = {
+               .start = TEGRA_PCIE_BASE,
+               .end = TEGRA_PCIE_BASE + TEGRA_PCIE_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = TEGRA_PCIE_MMIO_BASE,
+               .end = TEGRA_PCIE_MMIO_BASE + TEGRA_PCIE_MMIO_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start = INT_PCIE_INTR,
+               .end = INT_PCIE_INTR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device tegra_pcie_device = {
+       .name = "tegra-pcie",
+       .id = -1,
+       .resource = tegra_pcie_resources,
+       .num_resources = ARRAY_SIZE(tegra_pcie_resources),
+};
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index f054d10..b2caed4 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -57,5 +57,6 @@ extern struct platform_device tegra_i2s_device1;
 extern struct platform_device tegra_i2s_device2;
 extern struct platform_device tegra_das_device;
 extern struct platform_device tegra_pwm_device;
+extern struct platform_device tegra_pcie_device;
 
 #endif
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h 
b/arch/arm/mach-tegra/include/mach/iomap.h
index 3e80f3f..aee9d27 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -248,6 +248,12 @@
 #define TEGRA_CSITE_BASE               0x70040000
 #define TEGRA_CSITE_SIZE               SZ_256K
 
+#define TEGRA_PCIE_BASE                        0x80000000
+#define TEGRA_PCIE_SIZE                        SZ_4M
+
+#define TEGRA_PCIE_MMIO_BASE           0x80400000
+#define TEGRA_PCIE_MMIO_SIZE           SZ_64K
+
 #define TEGRA_USB_BASE                 0xC5000000
 #define TEGRA_USB_SIZE                 SZ_16K
 
diff --git a/arch/arm/mach-tegra/include/mach/pci-tegra.h 
b/arch/arm/mach-tegra/include/mach/pci-tegra.h
new file mode 100644
index 0000000..348a68a
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/pci-tegra.h
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-tegra/include/mach/tegra-pcie.h
+ *
+ * Copyright (C) 2012 Avionic Design GmbH
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MACH_TEGRA_PCIE_H
+#define __MACH_TEGRA_PCIE_H
+
+#include <linux/platform_device.h>
+
+#define TEGRA_PCIE_MAX_PORTS 2
+
+struct tegra_pcie_pdata {
+       int (*init)(struct platform_device *pdev);
+       int (*exit)(struct platform_device *pdev);
+       bool enable_ports[TEGRA_PCIE_MAX_PORTS];
+};
+
+#endif
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index fcdf8bc..291d55d 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -27,7 +27,9 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
@@ -40,8 +42,8 @@
 #include <mach/iomap.h>
 #include <mach/clk.h>
 #include <mach/powergate.h>
+#include <mach/pci-tegra.h>
 
-#include "board.h"
 #include "pmc.h"
 
 /* register definitions */
@@ -161,17 +163,12 @@
  * 0x90000000 - 0x9fffffff - non-prefetchable memory
  * 0xa0000000 - 0xbfffffff - prefetchable memory
  */
-#define TEGRA_PCIE_BASE                0x80000000
-
 #define PCIE_REGS_SZ           SZ_16K
 #define PCIE_CFG_OFF           PCIE_REGS_SZ
 #define PCIE_CFG_SZ            SZ_1M
 #define PCIE_EXT_CFG_OFF       (PCIE_CFG_SZ + PCIE_CFG_OFF)
 #define PCIE_EXT_CFG_SZ                SZ_1M
-#define PCIE_IOMAP_SZ          (PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
 
-#define MMIO_BASE              (TEGRA_PCIE_BASE + SZ_4M)
-#define MMIO_SIZE              SZ_64K
 #define MEM_BASE_0             (TEGRA_PCIE_BASE + SZ_256M)
 #define MEM_SIZE_0             SZ_128M
 #define MEM_BASE_1             (MEM_BASE_0 + MEM_SIZE_0)
@@ -201,11 +198,14 @@ struct tegra_pcie_port {
 };
 
 struct tegra_pcie_info {
-       struct tegra_pcie_port  port[2];
+       struct device           *dev;
+
+       struct tegra_pcie_port  port[TEGRA_PCIE_MAX_PORTS];
        int                     num_ports;
 
        void __iomem            *regs;
-       struct resource         res_mmio;
+       void __iomem            *mmio;
+       int                     irq;
 
        struct clk              *pex_clk;
        struct clk              *afi_clk;
@@ -213,55 +213,53 @@ struct tegra_pcie_info {
        struct clk              *pll_e;
 };
 
-static struct tegra_pcie_info tegra_pcie = {
-       .res_mmio = {
-               .name = "PCI IO",
-               .start = MMIO_BASE,
-               .end = MMIO_BASE + MMIO_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-};
+static inline struct tegra_pcie_info *sys_to_pcie(struct pci_sys_data *sys)
+{
+       return sys->private_data;
+}
 
 void __iomem *tegra_pcie_io_base;
 EXPORT_SYMBOL(tegra_pcie_io_base);
 
-static inline void afi_writel(u32 value, unsigned long offset)
+static inline void afi_writel(struct tegra_pcie_info *pcie, u32 value, 
unsigned long offset)
 {
-       writel(value, offset + AFI_OFFSET + tegra_pcie.regs);
+       writel(value, offset + AFI_OFFSET + pcie->regs);
 }
 
-static inline u32 afi_readl(unsigned long offset)
+static inline u32 afi_readl(struct tegra_pcie_info *pcie, unsigned long offset)
 {
-       return readl(offset + AFI_OFFSET + tegra_pcie.regs);
+       return readl(offset + AFI_OFFSET + pcie->regs);
 }
 
-static inline void pads_writel(u32 value, unsigned long offset)
+static inline void pads_writel(struct tegra_pcie_info *pcie, u32 value, 
unsigned long offset)
 {
-       writel(value, offset + PADS_OFFSET + tegra_pcie.regs);
+       writel(value, offset + PADS_OFFSET + pcie->regs);
 }
 
-static inline u32 pads_readl(unsigned long offset)
+static inline u32 pads_readl(struct tegra_pcie_info *pcie, unsigned long 
offset)
 {
-       return readl(offset + PADS_OFFSET + tegra_pcie.regs);
+       return readl(offset + PADS_OFFSET + pcie->regs);
 }
 
-static struct tegra_pcie_port *bus_to_port(int bus)
+static struct tegra_pcie_port *bus_to_port(struct pci_bus *bus)
 {
+       struct tegra_pcie_info *pcie = sys_to_pcie(bus->sysdata);
        int i;
 
-       for (i = tegra_pcie.num_ports - 1; i >= 0; i--) {
-               int rbus = tegra_pcie.port[i].root_bus_nr;
-               if (rbus != -1 && rbus == bus)
+       for (i = pcie->num_ports - 1; i >= 0; i--) {
+               int rbus = pcie->port[i].root_bus_nr;
+               if (rbus != -1 && rbus == bus->number)
                        break;
        }
 
-       return i >= 0 ? tegra_pcie.port + i : NULL;
+       return i >= 0 ? pcie->port + i : NULL;
 }
 
 static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
                                int where, int size, u32 *val)
 {
-       struct tegra_pcie_port *pp = bus_to_port(bus->number);
+       struct tegra_pcie_info *pcie = sys_to_pcie(bus->sysdata);
+       struct tegra_pcie_port *pp = bus_to_port(bus);
        void __iomem *addr;
 
        if (pp) {
@@ -272,10 +270,10 @@ static int tegra_pcie_read_conf(struct pci_bus *bus, 
unsigned int devfn,
 
                addr = pp->base + (where & ~0x3);
        } else {
-               addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
-                                         PCIE_CONF_DEV(PCI_SLOT(devfn)) +
-                                         PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
-                                         PCIE_CONF_REG(where));
+               addr = pcie->regs + (PCIE_CONF_BUS(bus->number) +
+                                    PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+                                    PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+                                    PCIE_CONF_REG(where));
        }
 
        *val = readl(addr);
@@ -291,7 +289,8 @@ static int tegra_pcie_read_conf(struct pci_bus *bus, 
unsigned int devfn,
 static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
                                 int where, int size, u32 val)
 {
-       struct tegra_pcie_port *pp = bus_to_port(bus->number);
+       struct tegra_pcie_info *pcie = sys_to_pcie(bus->sysdata);
+       struct tegra_pcie_port *pp = bus_to_port(bus);
        void __iomem *addr;
 
        u32 mask;
@@ -303,10 +302,10 @@ static int tegra_pcie_write_conf(struct pci_bus *bus, 
unsigned int devfn,
 
                addr = pp->base + (where & ~0x3);
        } else {
-               addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
-                                         PCIE_CONF_DEV(PCI_SLOT(devfn)) +
-                                         PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
-                                         PCIE_CONF_REG(where));
+               addr = pcie->regs + (PCIE_CONF_BUS(bus->number) +
+                                    PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+                                    PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+                                    PCIE_CONF_REG(where));
        }
 
        if (size == 4) {
@@ -373,12 +372,13 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, 
tegra_pcie_relax_enable);
 
 static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
 {
+       struct tegra_pcie_info *pcie = sys_to_pcie(sys);
        struct tegra_pcie_port *pp;
 
-       if (nr >= tegra_pcie.num_ports)
+       if (nr >= pcie->num_ports)
                return 0;
 
-       pp = tegra_pcie.port + nr;
+       pp = pcie->port + nr;
        pp->root_bus_nr = sys->busnr;
 
        /*
@@ -441,34 +441,29 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data 
*sys)
        return 1;
 }
 
-static int tegra_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
-       return INT_PCIE_INTR;
+       struct tegra_pcie_info *pcie = sys_to_pcie(pdev->bus->sysdata);
+
+       return pcie->irq;
 }
 
-static struct pci_bus __init *tegra_pcie_scan_bus(int nr,
-                                                 struct pci_sys_data *sys)
+static struct pci_bus __devinit *tegra_pcie_scan_bus(int nr,
+                                                    struct pci_sys_data *sys)
 {
+       struct tegra_pcie_info *pcie = sys_to_pcie(sys);
        struct tegra_pcie_port *pp;
 
-       if (nr >= tegra_pcie.num_ports)
+       if (nr >= pcie->num_ports)
                return NULL;
 
-       pp = tegra_pcie.port + nr;
+       pp = pcie->port + nr;
        pp->root_bus_nr = sys->busnr;
 
        return pci_scan_root_bus(NULL, sys->busnr, &tegra_pcie_ops, sys,
                                 &sys->resources);
 }
 
-static struct hw_pci tegra_pcie_hw __initdata = {
-       .nr_controllers = 2,
-       .setup          = tegra_pcie_setup,
-       .scan           = tegra_pcie_scan_bus,
-       .map_irq        = tegra_pcie_map_irq,
-};
-
-
 static irqreturn_t tegra_pcie_isr(int irq, void *arg)
 {
        const char *err_msg[] = {
@@ -482,12 +477,12 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
                "AXI response decoding error",
                "Transcation timeout",
        };
-
+       struct tegra_pcie_info *pcie = arg;
        u32 code, signature;
 
-       code = afi_readl(AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
-       signature = afi_readl(AFI_INTR_SIGNATURE);
-       afi_writel(0, AFI_INTR_CODE);
+       code = afi_readl(pcie, AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
+       signature = afi_readl(pcie, AFI_INTR_SIGNATURE);
+       afi_writel(pcie, 0, AFI_INTR_CODE);
 
        if (code == AFI_INTR_LEGACY)
                return IRQ_NONE;
@@ -500,14 +495,16 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
         * happen a lot during enumeration
         */
        if (code == AFI_INTR_MASTER_ABORT)
-               pr_debug("PCIE: %s, signature: %08x\n", err_msg[code], 
signature);
+               dev_dbg(pcie->dev, "%s, signature: %08x\n", err_msg[code],
+                       signature);
        else
-               pr_err("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+               dev_err(pcie->dev, "%s, signature: %08x\n", err_msg[code],
+                       signature);
 
        return IRQ_HANDLED;
 }
 
-static void tegra_pcie_setup_translations(void)
+static void tegra_pcie_setup_translations(struct tegra_pcie_info *pcie)
 {
        u32 fpci_bar;
        u32 size;
@@ -517,120 +514,120 @@ static void tegra_pcie_setup_translations(void)
        fpci_bar = ((u32)0xfdff << 16);
        size = PCIE_CFG_SZ;
        axi_address = TEGRA_PCIE_BASE + PCIE_CFG_OFF;
-       afi_writel(axi_address, AFI_AXI_BAR0_START);
-       afi_writel(size >> 12, AFI_AXI_BAR0_SZ);
-       afi_writel(fpci_bar, AFI_FPCI_BAR0);
+       afi_writel(pcie, axi_address, AFI_AXI_BAR0_START);
+       afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
+       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR0);
 
        /* Bar 1: extended config Bar */
        fpci_bar = ((u32)0xfe1 << 20);
        size = PCIE_EXT_CFG_SZ;
        axi_address = TEGRA_PCIE_BASE + PCIE_EXT_CFG_OFF;
-       afi_writel(axi_address, AFI_AXI_BAR1_START);
-       afi_writel(size >> 12, AFI_AXI_BAR1_SZ);
-       afi_writel(fpci_bar, AFI_FPCI_BAR1);
+       afi_writel(pcie, axi_address, AFI_AXI_BAR1_START);
+       afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
+       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1);
 
        /* Bar 2: downstream IO bar */
        fpci_bar = ((__u32)0xfdfc << 16);
-       size = MMIO_SIZE;
-       axi_address = MMIO_BASE;
-       afi_writel(axi_address, AFI_AXI_BAR2_START);
-       afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
-       afi_writel(fpci_bar, AFI_FPCI_BAR2);
+       size = TEGRA_PCIE_MMIO_SIZE;
+       axi_address = TEGRA_PCIE_MMIO_BASE;
+       afi_writel(pcie, axi_address, AFI_AXI_BAR2_START);
+       afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
+       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR2);
 
        /* Bar 3: prefetchable memory BAR */
        fpci_bar = (((PREFETCH_MEM_BASE_0 >> 12) & 0x0fffffff) << 4) | 0x1;
        size =  PREFETCH_MEM_SIZE_0 +  PREFETCH_MEM_SIZE_1;
        axi_address = PREFETCH_MEM_BASE_0;
-       afi_writel(axi_address, AFI_AXI_BAR3_START);
-       afi_writel(size >> 12, AFI_AXI_BAR3_SZ);
-       afi_writel(fpci_bar, AFI_FPCI_BAR3);
+       afi_writel(pcie, axi_address, AFI_AXI_BAR3_START);
+       afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
+       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR3);
 
        /* Bar 4: non prefetchable memory BAR */
        fpci_bar = (((MEM_BASE_0 >> 12) & 0x0FFFFFFF) << 4) | 0x1;
        size = MEM_SIZE_0 + MEM_SIZE_1;
        axi_address = MEM_BASE_0;
-       afi_writel(axi_address, AFI_AXI_BAR4_START);
-       afi_writel(size >> 12, AFI_AXI_BAR4_SZ);
-       afi_writel(fpci_bar, AFI_FPCI_BAR4);
+       afi_writel(pcie, axi_address, AFI_AXI_BAR4_START);
+       afi_writel(pcie, size >> 12, AFI_AXI_BAR4_SZ);
+       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR4);
 
        /* Bar 5: NULL out the remaining BAR as it is not used */
        fpci_bar = 0;
        size = 0;
        axi_address = 0;
-       afi_writel(axi_address, AFI_AXI_BAR5_START);
-       afi_writel(size >> 12, AFI_AXI_BAR5_SZ);
-       afi_writel(fpci_bar, AFI_FPCI_BAR5);
+       afi_writel(pcie, axi_address, AFI_AXI_BAR5_START);
+       afi_writel(pcie, size >> 12, AFI_AXI_BAR5_SZ);
+       afi_writel(pcie, fpci_bar, AFI_FPCI_BAR5);
 
        /* map all upstream transactions as uncached */
-       afi_writel(PHYS_OFFSET, AFI_CACHE_BAR0_ST);
-       afi_writel(0, AFI_CACHE_BAR0_SZ);
-       afi_writel(0, AFI_CACHE_BAR1_ST);
-       afi_writel(0, AFI_CACHE_BAR1_SZ);
+       afi_writel(pcie, PHYS_OFFSET, AFI_CACHE_BAR0_ST);
+       afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ);
+       afi_writel(pcie, 0, AFI_CACHE_BAR1_ST);
+       afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ);
 
        /* No MSI */
-       afi_writel(0, AFI_MSI_FPCI_BAR_ST);
-       afi_writel(0, AFI_MSI_BAR_SZ);
-       afi_writel(0, AFI_MSI_AXI_BAR_ST);
-       afi_writel(0, AFI_MSI_BAR_SZ);
+       afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST);
+       afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
+       afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST);
+       afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
 }
 
-static int tegra_pcie_enable_controller(void)
+static int tegra_pcie_enable_controller(struct tegra_pcie_info *pcie)
 {
        u32 val, reg;
        int i, timeout;
 
        /* Enable slot clock and pulse the reset signals */
        for (i = 0, reg = AFI_PEX0_CTRL; i < 2; i++, reg += 0x8) {
-               val = afi_readl(reg) |  AFI_PEX_CTRL_REFCLK_EN;
-               afi_writel(val, reg);
+               val = afi_readl(pcie, reg) |  AFI_PEX_CTRL_REFCLK_EN;
+               afi_writel(pcie, val, reg);
                val &= ~AFI_PEX_CTRL_RST;
-               afi_writel(val, reg);
+               afi_writel(pcie, val, reg);
 
-               val = afi_readl(reg) | AFI_PEX_CTRL_RST;
-               afi_writel(val, reg);
+               val = afi_readl(pcie, reg) | AFI_PEX_CTRL_RST;
+               afi_writel(pcie, val, reg);
        }
 
        /* Enable dual controller and both ports */
-       val = afi_readl(AFI_PCIE_CONFIG);
+       val = afi_readl(pcie, AFI_PCIE_CONFIG);
        val &= ~(AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE |
                 AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE |
                 AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK);
        val |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
-       afi_writel(val, AFI_PCIE_CONFIG);
+       afi_writel(pcie, val, AFI_PCIE_CONFIG);
 
-       val = afi_readl(AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
-       afi_writel(val, AFI_FUSE);
+       val = afi_readl(pcie, AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+       afi_writel(pcie, val, AFI_FUSE);
 
        /* Initialze internal PHY, enable up to 16 PCIE lanes */
-       pads_writel(0x0, PADS_CTL_SEL);
+       pads_writel(pcie, 0x0, PADS_CTL_SEL);
 
        /* override IDDQ to 1 on all 4 lanes */
-       val = pads_readl(PADS_CTL) | PADS_CTL_IDDQ_1L;
-       pads_writel(val, PADS_CTL);
+       val = pads_readl(pcie, PADS_CTL) | PADS_CTL_IDDQ_1L;
+       pads_writel(pcie, val, PADS_CTL);
 
        /*
         * set up PHY PLL inputs select PLLE output as refclock,
         * set TX ref sel to div10 (not div5)
         */
-       val = pads_readl(PADS_PLL_CTL);
+       val = pads_readl(pcie, PADS_PLL_CTL);
        val &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
        val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
-       pads_writel(val, PADS_PLL_CTL);
+       pads_writel(pcie, val, PADS_PLL_CTL);
 
        /* take PLL out of reset  */
-       val = pads_readl(PADS_PLL_CTL) | PADS_PLL_CTL_RST_B4SM;
-       pads_writel(val, PADS_PLL_CTL);
+       val = pads_readl(pcie, PADS_PLL_CTL) | PADS_PLL_CTL_RST_B4SM;
+       pads_writel(pcie, val, PADS_PLL_CTL);
 
        /*
         * Hack, set the clock voltage to the DEFAULT provided by hw folks.
         * This doesn't exist in the documentation
         */
-       pads_writel(0xfa5cfa5c, 0xc8);
+       pads_writel(pcie, 0xfa5cfa5c, 0xc8);
 
        /* Wait for the PLL to lock */
        timeout = 300;
        do {
-               val = pads_readl(PADS_PLL_CTL);
+               val = pads_readl(pcie, PADS_PLL_CTL);
                usleep_range(1000, 1000);
                if (--timeout == 0) {
                        pr_err("Tegra PCIe error: timeout waiting for PLL\n");
@@ -639,188 +636,237 @@ static int tegra_pcie_enable_controller(void)
        } while (!(val & PADS_PLL_CTL_LOCKDET));
 
        /* turn off IDDQ override */
-       val = pads_readl(PADS_CTL) & ~PADS_CTL_IDDQ_1L;
-       pads_writel(val, PADS_CTL);
+       val = pads_readl(pcie, PADS_CTL) & ~PADS_CTL_IDDQ_1L;
+       pads_writel(pcie, val, PADS_CTL);
 
        /* enable TX/RX data */
-       val = pads_readl(PADS_CTL);
+       val = pads_readl(pcie, PADS_CTL);
        val |= (PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L);
-       pads_writel(val, PADS_CTL);
+       pads_writel(pcie, val, PADS_CTL);
 
        /* Take the PCIe interface module out of reset */
-       tegra_periph_reset_deassert(tegra_pcie.pcie_xclk);
+       tegra_periph_reset_deassert(pcie->pcie_xclk);
 
        /* Finally enable PCIe */
-       val = afi_readl(AFI_CONFIGURATION) | AFI_CONFIGURATION_EN_FPCI;
-       afi_writel(val, AFI_CONFIGURATION);
+       val = afi_readl(pcie, AFI_CONFIGURATION) | AFI_CONFIGURATION_EN_FPCI;
+       afi_writel(pcie, val, AFI_CONFIGURATION);
 
        val = (AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
               AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
               AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR);
-       afi_writel(val, AFI_AFI_INTR_ENABLE);
-       afi_writel(0xffffffff, AFI_SM_INTR_ENABLE);
+       afi_writel(pcie, val, AFI_AFI_INTR_ENABLE);
+       afi_writel(pcie, 0xffffffff, AFI_SM_INTR_ENABLE);
 
        /* FIXME: No MSI for now, only INT */
-       afi_writel(AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
+       afi_writel(pcie, AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
 
        /* Disable all execptions */
-       afi_writel(0, AFI_FPCI_ERROR_MASKS);
+       afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS);
 
        return 0;
 }
 
-static void tegra_pcie_power_off(void)
+static void tegra_pcie_power_off(struct tegra_pcie_info *pcie)
 {
-       tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
-       tegra_periph_reset_assert(tegra_pcie.afi_clk);
-       tegra_periph_reset_assert(tegra_pcie.pex_clk);
+       tegra_periph_reset_assert(pcie->pcie_xclk);
+       tegra_periph_reset_assert(pcie->afi_clk);
+       tegra_periph_reset_assert(pcie->pex_clk);
 
        tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
        tegra_pmc_pcie_xclk_clamp(true);
 }
 
-static int tegra_pcie_power_regate(void)
+static int tegra_pcie_power_regate(struct tegra_pcie_info *pcie)
 {
        int err;
 
-       tegra_pcie_power_off();
+       tegra_pcie_power_off(pcie);
 
        tegra_pmc_pcie_xclk_clamp(true);
 
-       tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
-       tegra_periph_reset_assert(tegra_pcie.afi_clk);
+       tegra_periph_reset_assert(pcie->pcie_xclk);
+       tegra_periph_reset_assert(pcie->afi_clk);
 
        err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
-                                               tegra_pcie.pex_clk);
+                                               pcie->pex_clk);
        if (err) {
-               pr_err("PCIE: powerup sequence failed: %d\n", err);
+               dev_err(pcie->dev, "powerup sequence failed: %d\n", err);
                return err;
        }
 
-       tegra_periph_reset_deassert(tegra_pcie.afi_clk);
+       tegra_periph_reset_deassert(pcie->afi_clk);
 
        tegra_pmc_pcie_xclk_clamp(false);
 
-       clk_enable(tegra_pcie.afi_clk);
-       clk_enable(tegra_pcie.pex_clk);
-       return clk_enable(tegra_pcie.pll_e);
+       clk_enable(pcie->afi_clk);
+       clk_enable(pcie->pex_clk);
+       return clk_enable(pcie->pll_e);
 }
 
-static int tegra_pcie_clocks_get(void)
+static int tegra_pcie_clocks_get(struct tegra_pcie_info *pcie)
 {
        int err;
 
-       tegra_pcie.pex_clk = clk_get(NULL, "pex");
-       if (IS_ERR(tegra_pcie.pex_clk))
-               return PTR_ERR(tegra_pcie.pex_clk);
+       pcie->pex_clk = clk_get(NULL, "pex");
+       if (IS_ERR(pcie->pex_clk))
+               return PTR_ERR(pcie->pex_clk);
 
-       tegra_pcie.afi_clk = clk_get(NULL, "afi");
-       if (IS_ERR(tegra_pcie.afi_clk)) {
-               err = PTR_ERR(tegra_pcie.afi_clk);
+       pcie->afi_clk = clk_get(NULL, "afi");
+       if (IS_ERR(pcie->afi_clk)) {
+               err = PTR_ERR(pcie->afi_clk);
                goto err_afi_clk;
        }
 
-       tegra_pcie.pcie_xclk = clk_get(NULL, "pcie_xclk");
-       if (IS_ERR(tegra_pcie.pcie_xclk)) {
-               err =  PTR_ERR(tegra_pcie.pcie_xclk);
+       pcie->pcie_xclk = clk_get(NULL, "pcie_xclk");
+       if (IS_ERR(pcie->pcie_xclk)) {
+               err = PTR_ERR(pcie->pcie_xclk);
                goto err_pcie_xclk;
        }
 
-       tegra_pcie.pll_e = clk_get_sys(NULL, "pll_e");
-       if (IS_ERR(tegra_pcie.pll_e)) {
-               err = PTR_ERR(tegra_pcie.pll_e);
+       pcie->pll_e = clk_get_sys(NULL, "pll_e");
+       if (IS_ERR(pcie->pll_e)) {
+               err = PTR_ERR(pcie->pll_e);
                goto err_pll_e;
        }
 
        return 0;
 
 err_pll_e:
-       clk_put(tegra_pcie.pcie_xclk);
+       clk_put(pcie->pcie_xclk);
 err_pcie_xclk:
-       clk_put(tegra_pcie.afi_clk);
+       clk_put(pcie->afi_clk);
 err_afi_clk:
-       clk_put(tegra_pcie.pex_clk);
+       clk_put(pcie->pex_clk);
 
        return err;
 }
 
-static void tegra_pcie_clocks_put(void)
+static void tegra_pcie_clocks_put(struct tegra_pcie_info *pcie)
 {
-       clk_put(tegra_pcie.pll_e);
-       clk_put(tegra_pcie.pcie_xclk);
-       clk_put(tegra_pcie.afi_clk);
-       clk_put(tegra_pcie.pex_clk);
+       clk_put(pcie->pll_e);
+       clk_put(pcie->pcie_xclk);
+       clk_put(pcie->afi_clk);
+       clk_put(pcie->pex_clk);
 }
 
-static int __init tegra_pcie_get_resources(void)
+static int __devinit tegra_pcie_get_resources(struct platform_device *pdev)
 {
-       struct resource *res_mmio = &tegra_pcie.res_mmio;
+       struct tegra_pcie_info *pcie = platform_get_drvdata(pdev);
+       struct resource *regs;
+       struct resource *mmio;
        int err;
 
-       err = tegra_pcie_clocks_get();
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mmio = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+       if (!regs || !mmio) {
+               dev_err(&pdev->dev, "failed to get I/O resources\n");
+               return -ENXIO;
+       }
+
+       err = tegra_pcie_clocks_get(pcie);
        if (err) {
-               pr_err("PCIE: failed to get clocks: %d\n", err);
+               dev_err(&pdev->dev, "failed to get clocks: %d\n", err);
                return err;
        }
 
-       err = tegra_pcie_power_regate();
+       err = tegra_pcie_power_regate(pcie);
        if (err) {
-               pr_err("PCIE: failed to power up: %d\n", err);
+               dev_err(&pdev->dev, "failed to power up: %d\n", err);
                goto err_pwr_on;
        }
 
-       tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
-       if (tegra_pcie.regs == NULL) {
-               pr_err("PCIE: Failed to map PCI/AFI registers\n");
+       regs = request_mem_region(regs->start, resource_size(regs), "PCI/AFI");
+       if (regs == NULL) {
+               dev_err(&pdev->dev, "failed to request PCI/AFI region: %d\n", 
err);
+               goto err_req_reg;
+       }
+
+       pcie->regs = ioremap_nocache(regs->start, resource_size(regs));
+       if (pcie->regs == NULL) {
+               dev_err(&pdev->dev, "failed to map PCI/AFI registers\n");
                err = -ENOMEM;
                goto err_map_reg;
        }
 
-       err = request_resource(&iomem_resource, res_mmio);
-       if (err) {
-               pr_err("PCIE: Failed to request resources: %d\n", err);
+       mmio = request_mem_region(mmio->start, resource_size(mmio), "PCI I/O");
+       if (mmio == NULL) {
+               dev_err(&pdev->dev, "failed to request PCI I/O region: %d\n", 
err);
                goto err_req_io;
        }
 
-       tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
-                                            resource_size(res_mmio));
-       if (tegra_pcie_io_base == NULL) {
-               pr_err("PCIE: Failed to map IO\n");
+       pcie->mmio = ioremap_nocache(mmio->start, resource_size(mmio));
+       if (pcie->mmio == NULL) {
+               dev_err(&pdev->dev, "failed to map PCI I/O region\n");
                err = -ENOMEM;
                goto err_map_io;
        }
 
-       err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
-                         IRQF_SHARED, "PCIE", &tegra_pcie);
+       tegra_pcie_io_base = pcie->mmio;
+
+       err = platform_get_irq(pdev, 0);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to get IRQ: %d\n", err);
+               goto err_irq;
+       }
+
+       pcie->irq = err;
+
+       err = request_irq(pcie->irq, tegra_pcie_isr, IRQF_SHARED, "PCIE",
+                         pcie);
        if (err) {
-               pr_err("PCIE: Failed to register IRQ: %d\n", err);
+               dev_err(&pdev->dev, "failed to register IRQ: %d\n", err);
                goto err_irq;
        }
-       set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
 
        return 0;
 
 err_irq:
-       iounmap(tegra_pcie_io_base);
+       iounmap(pcie->mmio);
 err_map_io:
-       release_resource(&tegra_pcie.res_mmio);
+       release_resource(mmio);
 err_req_io:
-       iounmap(tegra_pcie.regs);
+       iounmap(pcie->regs);
 err_map_reg:
-       tegra_pcie_power_off();
+       release_resource(regs);
+err_req_reg:
+       tegra_pcie_power_off(pcie);
 err_pwr_on:
-       tegra_pcie_clocks_put();
+       tegra_pcie_clocks_put(pcie);
 
        return err;
 }
 
+static int tegra_pcie_put_resources(struct platform_device *pdev)
+{
+       struct tegra_pcie_info *pcie = platform_get_drvdata(pdev);
+       struct resource *regs;
+       struct resource *mmio;
+
+       free_irq(pcie->irq, pcie);
+
+       iounmap(pcie->mmio);
+       mmio = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       release_resource(mmio);
+
+       iounmap(pcie->regs);
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_resource(regs);
+
+       tegra_pcie_power_off(pcie);
+       tegra_pcie_clocks_put(pcie);
+
+       return 0;
+}
+
 /*
  * FIXME: If there are no PCIe cards attached, then calling this function
  * can result in the increase of the bootup time as there are big timeout
  * loops.
  */
 #define TEGRA_PCIE_LINKUP_TIMEOUT      200     /* up to 1.2 seconds */
-static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
+static bool tegra_pcie_check_link(struct tegra_pcie_info *pcie,
+                                 struct tegra_pcie_port *pp, int idx,
                                  u32 reset_reg)
 {
        u32 reg;
@@ -840,7 +886,7 @@ static bool tegra_pcie_check_link(struct tegra_pcie_port 
*pp, int idx,
                }
 
                if (!timeout)  {
-                       pr_err("PCIE: port %d: link down, retrying\n", idx);
+                       dev_err(pcie->dev, "port %d: link down, retrying\n", 
idx);
                        goto retry;
                }
 
@@ -857,11 +903,11 @@ static bool tegra_pcie_check_link(struct tegra_pcie_port 
*pp, int idx,
 
 retry:
                /* Pulse the PEX reset */
-               reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
-               afi_writel(reg, reset_reg);
+               reg = afi_readl(pcie, reset_reg) | AFI_PEX_CTRL_RST;
+               afi_writel(pcie, reg, reset_reg);
                mdelay(1);
-               reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
-               afi_writel(reg, reset_reg);
+               reg = afi_readl(pcie, reset_reg) & ~AFI_PEX_CTRL_RST;
+               afi_writel(pcie, reg, reset_reg);
 
                retries--;
        } while (retries);
@@ -869,55 +915,117 @@ retry:
        return false;
 }
 
-static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
+static void __devinit tegra_pcie_add_port(struct tegra_pcie_info *pcie,
+                                         int index, u32 offset,
+                                         u32 reset_reg)
 {
        struct tegra_pcie_port *pp;
 
-       pp = tegra_pcie.port + tegra_pcie.num_ports;
+       pp = pcie->port + pcie->num_ports;
 
        pp->index = -1;
-       pp->base = tegra_pcie.regs + offset;
-       pp->link_up = tegra_pcie_check_link(pp, index, reset_reg);
+       pp->base = pcie->regs + offset;
+       pp->link_up = tegra_pcie_check_link(pcie, pp, index, reset_reg);
 
        if (!pp->link_up) {
                pp->base = NULL;
-               printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index);
+               dev_info(pcie->dev, "port %d: link down, ignoring\n", index);
                return;
        }
 
-       tegra_pcie.num_ports++;
+       pcie->num_ports++;
        pp->index = index;
        pp->root_bus_nr = -1;
        memset(pp->res, 0, sizeof(pp->res));
 }
 
-int __init tegra_pcie_init(bool init_port0, bool init_port1)
+static int __devinit tegra_pcie_probe(struct platform_device *pdev)
 {
+       struct tegra_pcie_pdata *pdata = pdev->dev.platform_data;
+       void *private_data[TEGRA_PCIE_MAX_PORTS];
+       struct tegra_pcie_info *pcie;
+       struct hw_pci hw;
        int err;
 
-       if (!(init_port0 || init_port1))
+       if (!pdata->enable_ports[0] && !pdata->enable_ports[1])
                return -ENODEV;
 
+       pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+       if (!pcie)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, pcie);
+       pcie->dev = &pdev->dev;
+
        pcibios_min_mem = 0;
 
-       err = tegra_pcie_get_resources();
-       if (err)
+       err = tegra_pcie_get_resources(pdev);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to request resources: %d\n", err);
                return err;
+       }
+
+       if (pdata->init) {
+               err = pdata->init(pdev);
+               if (err < 0) {
+                       tegra_pcie_put_resources(pdev);
+                       return err;
+               }
+       }
 
-       err = tegra_pcie_enable_controller();
+       err = tegra_pcie_enable_controller(pcie);
        if (err)
                return err;
 
        /* setup the AFI address translations */
-       tegra_pcie_setup_translations();
+       tegra_pcie_setup_translations(pcie);
 
-       if (init_port0)
-               tegra_pcie_add_port(0, RP0_OFFSET, AFI_PEX0_CTRL);
+       if (pdata->enable_ports[0]) {
+               tegra_pcie_add_port(pcie, 0, RP0_OFFSET, AFI_PEX0_CTRL);
+               private_data[0] = pcie;
+       }
+
+       if (pdata->enable_ports[1]) {
+               tegra_pcie_add_port(pcie, 1, RP1_OFFSET, AFI_PEX1_CTRL);
+               private_data[1] = pcie;
+       }
 
-       if (init_port1)
-               tegra_pcie_add_port(1, RP1_OFFSET, AFI_PEX1_CTRL);
+       memset(&hw, 0, sizeof(hw));
+       hw.nr_controllers = 2;
+       hw.private_data = private_data;
+       hw.setup = tegra_pcie_setup;
+       hw.scan = tegra_pcie_scan_bus;
+       hw.map_irq = tegra_pcie_map_irq;
 
-       pci_common_init(&tegra_pcie_hw);
+       pci_common_init(&hw);
 
        return 0;
 }
+
+static int __devexit tegra_pcie_remove(struct platform_device *pdev)
+{
+       struct tegra_pcie_pdata *pdata = pdev->dev.platform_data;
+       int err;
+
+       err = tegra_pcie_put_resources(pdev);
+       if (err < 0)
+               return err;
+
+       if (pdata->exit) {
+               err = pdata->exit(pdev);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static struct platform_driver tegra_pcie_driver = {
+       .driver = {
+               .name = "tegra-pcie",
+               .owner = THIS_MODULE,
+       },
+       .probe = tegra_pcie_probe,
+       .remove = __devexit_p(tegra_pcie_remove),
+};
+module_platform_driver(tegra_pcie_driver);
-- 
1.7.10.4

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

Reply via email to