summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/pcie.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/pcie.c')
-rw-r--r--arch/arm/mach-tegra/pcie.c58
1 files changed, 56 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 80a9a121f193..68e0fda385ae 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -36,6 +36,8 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
#include <asm/sizes.h>
#include <asm/mach/pci.h>
@@ -308,6 +310,7 @@ struct tegra_pcie_port {
char mem_space_name[16];
char prefetch_space_name[20];
struct resource res[3];
+ struct pci_bus* bus;
};
struct tegra_pcie_info {
@@ -319,6 +322,7 @@ struct tegra_pcie_info {
struct resource res_mmio;
int power_rails_enabled;
int pcie_power_enabled;
+ struct work_struct hotplug_detect;
struct regulator *regulator_hvdd;
struct regulator *regulator_pexio;
@@ -333,8 +337,6 @@ struct tegra_pcie_info {
#define pmc_readl(reg) \
__raw_readl((u32)reg_pmc_base + (reg))
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
static struct tegra_pcie_info tegra_pcie = {
.res_mmio = {
.name = "PCI IO",
@@ -620,6 +622,31 @@ static struct hw_pci tegra_pcie_hw = {
.map_irq = tegra_pcie_map_irq,
};
+static void work_hotplug_handler(struct work_struct *work)
+{
+ struct tegra_pcie_info *pcie_driver =
+ container_of(work, struct tegra_pcie_info, hotplug_detect);
+ int val;
+
+ if (pcie_driver->plat_data->gpio == -1)
+ return;
+ val = gpio_get_value(pcie_driver->plat_data->gpio);
+ if (val == 0) {
+ pr_info("Pcie Dock Connected but hotplug functionality not supported yet\n");
+ } else {
+ struct pci_dev *dev = NULL;
+
+ pr_info("Pcie Dock DisConnected\n");
+ for_each_pci_dev(dev)
+ pci_stop_bus_device(dev);
+ }
+}
+
+static irqreturn_t gpio_pcie_detect_isr(int irq, void *arg)
+{
+ schedule_work(&tegra_pcie.hotplug_detect);
+ return IRQ_HANDLED;
+}
static irqreturn_t tegra_pcie_isr(int irq, void *arg)
{
@@ -1169,6 +1196,8 @@ static int tegra_pcie_init(void)
pcibios_min_mem = 0x03000000ul;
pcibios_min_io = 0x10000000ul;
#endif
+
+ INIT_WORK(&tegra_pcie.hotplug_detect, work_hotplug_handler);
err = tegra_pcie_get_resources();
if (err)
return err;
@@ -1184,11 +1213,36 @@ static int tegra_pcie_init(void)
}
tegra_pcie.pcie_power_enabled = 1;
+ if (tegra_pcie.plat_data->use_dock_detect) {
+ unsigned int irq;
+
+ pr_info("acquiring dock_detect = %d\n",
+ tegra_pcie.plat_data->gpio);
+ gpio_request(tegra_pcie.plat_data->gpio, "pcie_dock_detect");
+ gpio_direction_input(tegra_pcie.plat_data->gpio);
+ irq = gpio_to_irq(tegra_pcie.plat_data->gpio);
+ if (irq < 0) {
+ pr_err("Unable to get irq number for dock_detect\n");
+ goto err_irq;
+ }
+ err = request_irq(irq,
+ gpio_pcie_detect_isr,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "pcie_dock_detect",
+ (void *)tegra_pcie.plat_data);
+ if (err < 0) {
+ pr_err("Unable to claim irq number for dock_detect\n");
+ goto err_irq;
+ }
+ }
+
if (tegra_pcie.num_ports)
pci_common_init(&tegra_pcie_hw);
else
err = tegra_pcie_power_off();
+err_irq:
+
return err;
}