|
@@ -20,10 +20,11 @@
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/irq.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
-
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/of.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
+#include <linux/module.h>
|
|
|
|
|
|
#include <asm/mach/irq.h>
|
|
|
|
|
@@ -34,9 +35,7 @@
|
|
|
#define GPIO_PORT(x) (((x) >> 3) & 0x3)
|
|
|
#define GPIO_BIT(x) ((x) & 0x7)
|
|
|
|
|
|
-#define GPIO_REG(x) (IO_TO_VIRT(TEGRA_GPIO_BASE) + \
|
|
|
- GPIO_BANK(x) * 0x80 + \
|
|
|
- GPIO_PORT(x) * 4)
|
|
|
+#define GPIO_REG(x) (GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4)
|
|
|
|
|
|
#define GPIO_CNF(x) (GPIO_REG(x) + 0x00)
|
|
|
#define GPIO_OE(x) (GPIO_REG(x) + 0x10)
|
|
@@ -75,15 +74,18 @@ struct tegra_gpio_bank {
|
|
|
};
|
|
|
|
|
|
|
|
|
-static struct tegra_gpio_bank tegra_gpio_banks[] = {
|
|
|
- {.bank = 0, .irq = INT_GPIO1},
|
|
|
- {.bank = 1, .irq = INT_GPIO2},
|
|
|
- {.bank = 2, .irq = INT_GPIO3},
|
|
|
- {.bank = 3, .irq = INT_GPIO4},
|
|
|
- {.bank = 4, .irq = INT_GPIO5},
|
|
|
- {.bank = 5, .irq = INT_GPIO6},
|
|
|
- {.bank = 6, .irq = INT_GPIO7},
|
|
|
-};
|
|
|
+static void __iomem *regs;
|
|
|
+static struct tegra_gpio_bank tegra_gpio_banks[7];
|
|
|
+
|
|
|
+static inline void tegra_gpio_writel(u32 val, u32 reg)
|
|
|
+{
|
|
|
+ __raw_writel(val, regs + reg);
|
|
|
+}
|
|
|
+
|
|
|
+static inline u32 tegra_gpio_readl(u32 reg)
|
|
|
+{
|
|
|
+ return __raw_readl(regs + reg);
|
|
|
+}
|
|
|
|
|
|
static int tegra_gpio_compose(int bank, int port, int bit)
|
|
|
{
|
|
@@ -97,7 +99,7 @@ static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
|
|
|
val = 0x100 << GPIO_BIT(gpio);
|
|
|
if (value)
|
|
|
val |= 1 << GPIO_BIT(gpio);
|
|
|
- __raw_writel(val, reg);
|
|
|
+ tegra_gpio_writel(val, reg);
|
|
|
}
|
|
|
|
|
|
void tegra_gpio_enable(int gpio)
|
|
@@ -117,7 +119,7 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
|
|
|
|
static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
|
{
|
|
|
- return (__raw_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
|
|
|
+ return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
|
|
|
}
|
|
|
|
|
|
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|
@@ -150,7 +152,7 @@ static void tegra_gpio_irq_ack(struct irq_data *d)
|
|
|
{
|
|
|
int gpio = d->irq - INT_GPIO_BASE;
|
|
|
|
|
|
- __raw_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
|
|
|
+ tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
|
|
|
}
|
|
|
|
|
|
static void tegra_gpio_irq_mask(struct irq_data *d)
|
|
@@ -203,10 +205,10 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|
|
|
|
|
spin_lock_irqsave(&bank->lvl_lock[port], flags);
|
|
|
|
|
|
- val = __raw_readl(GPIO_INT_LVL(gpio));
|
|
|
+ val = tegra_gpio_readl(GPIO_INT_LVL(gpio));
|
|
|
val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
|
|
|
val |= lvl_type << GPIO_BIT(gpio);
|
|
|
- __raw_writel(val, GPIO_INT_LVL(gpio));
|
|
|
+ tegra_gpio_writel(val, GPIO_INT_LVL(gpio));
|
|
|
|
|
|
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
|
|
|
|
|
@@ -232,12 +234,12 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|
|
|
|
|
for (port = 0; port < 4; port++) {
|
|
|
int gpio = tegra_gpio_compose(bank->bank, port, 0);
|
|
|
- unsigned long sta = __raw_readl(GPIO_INT_STA(gpio)) &
|
|
|
- __raw_readl(GPIO_INT_ENB(gpio));
|
|
|
- u32 lvl = __raw_readl(GPIO_INT_LVL(gpio));
|
|
|
+ unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) &
|
|
|
+ tegra_gpio_readl(GPIO_INT_ENB(gpio));
|
|
|
+ u32 lvl = tegra_gpio_readl(GPIO_INT_LVL(gpio));
|
|
|
|
|
|
for_each_set_bit(pin, &sta, 8) {
|
|
|
- __raw_writel(1 << pin, GPIO_INT_CLR(gpio));
|
|
|
+ tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
|
|
|
|
|
|
/* if gpio is edge triggered, clear condition
|
|
|
* before executing the hander so that we don't
|
|
@@ -271,11 +273,11 @@ void tegra_gpio_resume(void)
|
|
|
|
|
|
for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
|
|
|
unsigned int gpio = (b<<5) | (p<<3);
|
|
|
- __raw_writel(bank->cnf[p], GPIO_CNF(gpio));
|
|
|
- __raw_writel(bank->out[p], GPIO_OUT(gpio));
|
|
|
- __raw_writel(bank->oe[p], GPIO_OE(gpio));
|
|
|
- __raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
|
|
|
- __raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
|
|
|
+ tegra_gpio_writel(bank->cnf[p], GPIO_CNF(gpio));
|
|
|
+ tegra_gpio_writel(bank->out[p], GPIO_OUT(gpio));
|
|
|
+ tegra_gpio_writel(bank->oe[p], GPIO_OE(gpio));
|
|
|
+ tegra_gpio_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
|
|
|
+ tegra_gpio_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -294,11 +296,11 @@ void tegra_gpio_suspend(void)
|
|
|
|
|
|
for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
|
|
|
unsigned int gpio = (b<<5) | (p<<3);
|
|
|
- bank->cnf[p] = __raw_readl(GPIO_CNF(gpio));
|
|
|
- bank->out[p] = __raw_readl(GPIO_OUT(gpio));
|
|
|
- bank->oe[p] = __raw_readl(GPIO_OE(gpio));
|
|
|
- bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio));
|
|
|
- bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio));
|
|
|
+ bank->cnf[p] = tegra_gpio_readl(GPIO_CNF(gpio));
|
|
|
+ bank->out[p] = tegra_gpio_readl(GPIO_OUT(gpio));
|
|
|
+ bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
|
|
|
+ bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
|
|
|
+ bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
|
|
|
}
|
|
|
}
|
|
|
local_irq_restore(flags);
|
|
@@ -328,27 +330,54 @@ static struct irq_chip tegra_gpio_irq_chip = {
|
|
|
*/
|
|
|
static struct lock_class_key gpio_lock_class;
|
|
|
|
|
|
-static int __init tegra_gpio_init(void)
|
|
|
+static int __devinit tegra_gpio_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
+ struct resource *res;
|
|
|
struct tegra_gpio_bank *bank;
|
|
|
int i;
|
|
|
int j;
|
|
|
|
|
|
+ for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
|
|
|
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
|
|
|
+ if (!res) {
|
|
|
+ dev_err(&pdev->dev, "Missing IRQ resource\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ bank = &tegra_gpio_banks[i];
|
|
|
+ bank->bank = i;
|
|
|
+ bank->irq = res->start;
|
|
|
+ }
|
|
|
+
|
|
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
+ if (!res) {
|
|
|
+ dev_err(&pdev->dev, "Missing MEM resource\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!devm_request_mem_region(&pdev->dev, res->start,
|
|
|
+ resource_size(res),
|
|
|
+ dev_name(&pdev->dev))) {
|
|
|
+ dev_err(&pdev->dev, "Couldn't request MEM resource\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
|
|
+ if (!regs) {
|
|
|
+ dev_err(&pdev->dev, "Couldn't ioremap regs\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
for (i = 0; i < 7; i++) {
|
|
|
for (j = 0; j < 4; j++) {
|
|
|
int gpio = tegra_gpio_compose(i, j, 0);
|
|
|
- __raw_writel(0x00, GPIO_INT_ENB(gpio));
|
|
|
+ tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_OF_GPIO
|
|
|
- /*
|
|
|
- * This isn't ideal, but it gets things hooked up until this
|
|
|
- * driver is converted into a platform_device
|
|
|
- */
|
|
|
- tegra_gpio_chip.of_node = of_find_compatible_node(NULL, NULL,
|
|
|
- "nvidia,tegra20-gpio");
|
|
|
-#endif /* CONFIG_OF_GPIO */
|
|
|
+ tegra_gpio_chip.of_node = pdev->dev.of_node;
|
|
|
+#endif
|
|
|
|
|
|
gpiochip_add(&tegra_gpio_chip);
|
|
|
|
|
@@ -375,6 +404,24 @@ static int __init tegra_gpio_init(void)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static struct of_device_id tegra_gpio_of_match[] __devinitdata = {
|
|
|
+ { .compatible = "nvidia,tegra20-gpio", },
|
|
|
+ { },
|
|
|
+};
|
|
|
+
|
|
|
+static struct platform_driver tegra_gpio_driver = {
|
|
|
+ .driver = {
|
|
|
+ .name = "tegra-gpio",
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .of_match_table = tegra_gpio_of_match,
|
|
|
+ },
|
|
|
+ .probe = tegra_gpio_probe,
|
|
|
+};
|
|
|
+
|
|
|
+static int __init tegra_gpio_init(void)
|
|
|
+{
|
|
|
+ return platform_driver_register(&tegra_gpio_driver);
|
|
|
+}
|
|
|
postcore_initcall(tegra_gpio_init);
|
|
|
|
|
|
void __init tegra_gpio_config(struct tegra_gpio_table *table, int num)
|
|
@@ -407,13 +454,13 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
|
|
|
seq_printf(s,
|
|
|
"%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
|
|
|
i, j,
|
|
|
- __raw_readl(GPIO_CNF(gpio)),
|
|
|
- __raw_readl(GPIO_OE(gpio)),
|
|
|
- __raw_readl(GPIO_OUT(gpio)),
|
|
|
- __raw_readl(GPIO_IN(gpio)),
|
|
|
- __raw_readl(GPIO_INT_STA(gpio)),
|
|
|
- __raw_readl(GPIO_INT_ENB(gpio)),
|
|
|
- __raw_readl(GPIO_INT_LVL(gpio)));
|
|
|
+ tegra_gpio_readl(GPIO_CNF(gpio)),
|
|
|
+ tegra_gpio_readl(GPIO_OE(gpio)),
|
|
|
+ tegra_gpio_readl(GPIO_OUT(gpio)),
|
|
|
+ tegra_gpio_readl(GPIO_IN(gpio)),
|
|
|
+ tegra_gpio_readl(GPIO_INT_STA(gpio)),
|
|
|
+ tegra_gpio_readl(GPIO_INT_ENB(gpio)),
|
|
|
+ tegra_gpio_readl(GPIO_INT_LVL(gpio)));
|
|
|
}
|
|
|
}
|
|
|
return 0;
|