From 27721a52d6c8e33327ec3cae9f730204be99d251 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Mon, 30 May 2011 10:24:47 +0900 Subject: gpio: Fix gpio-exynos4 build fails in mainline After the GPIO driver move, some symbols became selectable when they shouldn't be. Tighten the dependencies. Reported-by: Randy Dunlap Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4a7f63143455..317199796c5f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -88,29 +88,29 @@ config GPIO_IT8761E config GPIO_EXYNOS4 bool "Samsung Exynos4 GPIO library support" - default y if CPU_EXYNOS4210 - depends on ARM + default y + depends on ARM && CPU_EXYNOS4210 help Say yes here to support Samsung Exynos4 series SoCs GPIO library config GPIO_PLAT_SAMSUNG bool "Samsung SoCs GPIO library support" - default y if SAMSUNG_GPIOLIB_4BIT - depends on ARM + default y + depends on ARM && SAMSUNG_GPIOLIB_4BIT help Say yes here to support Samsung SoCs GPIO library config GPIO_S5PC100 bool "Samsung S5PC100 GPIO library support" - default y if CPU_S5PC100 - depends on ARM + default y + depends on ARM && CPU_S5PC100 help Say yes here to support Samsung S5PC100 SoCs GPIO library config GPIO_S5PV210 bool "Samsung S5PV210/S5PC110 GPIO library support" - default y if CPU_S5PV210 - depends on ARM + default y + depends on ARM && CPU_S5PV210 help Say yes here to support Samsung S5PV210/S5PC110 SoCs GPIO library -- cgit v1.2.3 From d52b31deffe1956ac62d0b81b915c9b52cffb814 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 27 May 2011 13:56:12 -0700 Subject: GPIO: OMAP: fix section mismatch warnings WARNING: arch/arm/plat-omap/built-in.o(.devinit.text+0x46c): Section mismatch in reference from the function omap_gpio_probe() to the function .init.text:omap_gpio_chip_init() The function __devinit omap_gpio_probe() references a function __init omap_gpio_chip_init(). If omap_gpio_chip_init is only used by omap_gpio_probe then annotate omap_gpio_chip_init with a matching annotation. Signed-off-by: Russell King Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 6c51191da567..76709b03572e 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1524,7 +1524,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank, int id) } } -static void __init omap_gpio_chip_init(struct gpio_bank *bank) +static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) { int j; static int gpio; -- cgit v1.2.3 From 0622b25bf071fd83c6eef6b61fb5f3f12a418528 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 6 Jun 2011 13:38:17 -0700 Subject: GPIO: OMAP: fix setting IRQWAKEN bits for OMAP4 Setting the IRQWAKEN bit was overwriting previous IRQWAKEN bits, causing only the last bit set to take effect, resulting in lost wakeups when the GPIO controller is in idle. Replace direct writes to IRQWAKEN with MOD_REG_BIT calls to perform a read-modify-write on the register. Signed-off-by: Colin Cross Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 76709b03572e..5ad827a1a3e8 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -432,7 +432,6 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, { void __iomem *base = bank->base; u32 gpio_bit = 1 << gpio; - u32 val; if (cpu_is_omap44xx()) { MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT0, gpio_bit, @@ -455,15 +454,8 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, } if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { if (cpu_is_omap44xx()) { - if (trigger != 0) - __raw_writel(1 << gpio, bank->base+ - OMAP4_GPIO_IRQWAKEN0); - else { - val = __raw_readl(bank->base + - OMAP4_GPIO_IRQWAKEN0); - __raw_writel(val & (~(1 << gpio)), bank->base + - OMAP4_GPIO_IRQWAKEN0); - } + MOD_REG_BIT(OMAP4_GPIO_IRQWAKEN0, gpio_bit, + trigger != 0); } else { /* * GPIO wakeup request can only be generated on edge -- cgit v1.2.3 From 85ec7b970553369e0c956fab1d7a6022f2a99369 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 6 Jun 2011 13:38:18 -0700 Subject: GPIO: OMAP: add locking around calls to _set_gpio_triggering _set_gpio_triggering uses read-modify-write on bank registers, lock bank->lock around all calls to it to prevent register corruption if two cpus access gpios in the same bank at the same time. Signed-off-by: Colin Cross Signed-off-by: Kevin Hilman --- drivers/gpio/gpio-omap.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 5ad827a1a3e8..01f74a8459d9 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1126,8 +1126,11 @@ static void gpio_irq_shutdown(struct irq_data *d) { unsigned int gpio = d->irq - IH_GPIO_BASE; struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned long flags; + spin_lock_irqsave(&bank->lock, flags); _reset_gpio(bank, gpio); + spin_unlock_irqrestore(&bank->lock, flags); } static void gpio_ack_irq(struct irq_data *d) @@ -1142,9 +1145,12 @@ static void gpio_mask_irq(struct irq_data *d) { unsigned int gpio = d->irq - IH_GPIO_BASE; struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned long flags; + spin_lock_irqsave(&bank->lock, flags); _set_gpio_irqenable(bank, gpio, 0); _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE); + spin_unlock_irqrestore(&bank->lock, flags); } static void gpio_unmask_irq(struct irq_data *d) @@ -1153,7 +1159,9 @@ static void gpio_unmask_irq(struct irq_data *d) struct gpio_bank *bank = irq_data_get_irq_chip_data(d); unsigned int irq_mask = 1 << get_gpio_index(gpio); u32 trigger = irqd_get_trigger_type(d); + unsigned long flags; + spin_lock_irqsave(&bank->lock, flags); if (trigger) _set_gpio_triggering(bank, get_gpio_index(gpio), trigger); @@ -1165,6 +1173,7 @@ static void gpio_unmask_irq(struct irq_data *d) } _set_gpio_irqenable(bank, gpio, 1); + spin_unlock_irqrestore(&bank->lock, flags); } static struct irq_chip gpio_irq_chip = { -- cgit v1.2.3 From 0bf8fa04e80a562641f687547053f98670f25cf9 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Tue, 7 Jun 2011 14:04:49 +0530 Subject: gpio/exynos4: Fix incorrect mapping of gpio pull-up macro to register setting The S3C_GPIO_PULL_UP macro value incorrectly maps to a reserved setting of GPIO pull up/down registers on Exynos4 platform. Fix this incorrect mapping by adding wrappers to the s3c_gpio_setpull_updown and s3c_gpio_getpull_updown functions. Signed-off-by: Thomas Abraham Acked-by: Kyungmin Park Signed-off-by: Grant Likely --- drivers/gpio/gpio-exynos4.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-exynos4.c b/drivers/gpio/gpio-exynos4.c index d54ca6adb660..9029835112e7 100644 --- a/drivers/gpio/gpio-exynos4.c +++ b/drivers/gpio/gpio-exynos4.c @@ -21,16 +21,37 @@ #include #include +int s3c_gpio_setpull_exynos4(struct s3c_gpio_chip *chip, + unsigned int off, s3c_gpio_pull_t pull) +{ + if (pull == S3C_GPIO_PULL_UP) + pull = 3; + + return s3c_gpio_setpull_updown(chip, off, pull); +} + +s3c_gpio_pull_t s3c_gpio_getpull_exynos4(struct s3c_gpio_chip *chip, + unsigned int off) +{ + s3c_gpio_pull_t pull; + + pull = s3c_gpio_getpull_updown(chip, off); + if (pull == 3) + pull = S3C_GPIO_PULL_UP; + + return pull; +} + static struct s3c_gpio_cfg gpio_cfg = { .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, + .set_pull = s3c_gpio_setpull_exynos4, + .get_pull = s3c_gpio_getpull_exynos4, }; static struct s3c_gpio_cfg gpio_cfg_noint = { .set_config = s3c_gpio_setcfg_s3c64xx_4bit, - .set_pull = s3c_gpio_setpull_updown, - .get_pull = s3c_gpio_getpull_updown, + .set_pull = s3c_gpio_setpull_exynos4, + .get_pull = s3c_gpio_getpull_exynos4, }; /* -- cgit v1.2.3 From 32919a28cc8470b1526f77b2f12cca8841b9ac62 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 7 Jun 2011 14:37:27 -0600 Subject: gpio/samsung: make Kconfig options def_bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Samsung GPIO drivers are always built-in when the relevant platform is selected.  Change the Kconfig symbol to def_bool y dependant on the platform. Signed-off-by: H Hartley Sweeten Acked-by: Kyungmin Park Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 317199796c5f..2967002a9f82 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -87,32 +87,20 @@ config GPIO_IT8761E Say yes here to support GPIO functionality of IT8761E super I/O chip. config GPIO_EXYNOS4 - bool "Samsung Exynos4 GPIO library support" - default y - depends on ARM && CPU_EXYNOS4210 - help - Say yes here to support Samsung Exynos4 series SoCs GPIO library + def_bool y + depends on CPU_EXYNOS4210 config GPIO_PLAT_SAMSUNG - bool "Samsung SoCs GPIO library support" - default y - depends on ARM && SAMSUNG_GPIOLIB_4BIT - help - Say yes here to support Samsung SoCs GPIO library + def_bool y + depends on SAMSUNG_GPIOLIB_4BIT config GPIO_S5PC100 - bool "Samsung S5PC100 GPIO library support" - default y - depends on ARM && CPU_S5PC100 - help - Say yes here to support Samsung S5PC100 SoCs GPIO library + def_bool y + depends on CPU_S5PC100 config GPIO_S5PV210 - bool "Samsung S5PV210/S5PC110 GPIO library support" - default y - depends on ARM && CPU_S5PV210 - help - Say yes here to support Samsung S5PV210/S5PC110 SoCs GPIO library + def_bool y + depends on CPU_S5PV210 config GPIO_PL061 bool "PrimeCell PL061 GPIO support" -- cgit v1.2.3 From 33d78647dc409784c18aa71995346e6955802fe0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 9 Jun 2011 11:08:47 +0200 Subject: gpio/nomadik: fix sleepmode for elder Nomadik The mach-nomadik machine did not compile properly due to bad ux500-specific functions being called. Introduce new state variables to fix this up. Reported-by: Axel Lin Cc: Alessandro Rubini Cc: Prafulla Wadaskar Signed-off-by: Linus Walleij Signed-off-by: Grant Likely --- arch/arm/mach-ux500/cpu-db8500.c | 3 +++ arch/arm/plat-nomadik/include/plat/gpio.h | 1 + drivers/gpio/gpio-nomadik.c | 40 ++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers/gpio') diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index c3c417656bd9..4598b06c8c55 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -159,6 +159,9 @@ static void __init db8500_add_gpios(void) /* No custom data yet */ }; + if (cpu_is_u8500v2()) + pdata.supports_sleepmode = true; + dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base), IRQ_DB8500_GPIO0, &pdata); } diff --git a/arch/arm/plat-nomadik/include/plat/gpio.h b/arch/arm/plat-nomadik/include/plat/gpio.h index ea19a5b2f227..d5d7e651269c 100644 --- a/arch/arm/plat-nomadik/include/plat/gpio.h +++ b/arch/arm/plat-nomadik/include/plat/gpio.h @@ -90,6 +90,7 @@ struct nmk_gpio_platform_data { int num_gpio; u32 (*get_secondary_status)(unsigned int bank); void (*set_ioforce)(bool enable); + bool supports_sleepmode; }; #endif /* __ASM_PLAT_GPIO_H */ diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c index 4961ef9bc153..2c212c732d76 100644 --- a/drivers/gpio/gpio-nomadik.c +++ b/drivers/gpio/gpio-nomadik.c @@ -4,6 +4,7 @@ * Copyright (C) 2008,2009 STMicroelectronics * Copyright (C) 2009 Alessandro Rubini * Rewritten based on work by Prafulla WADASKAR + * Copyright (C) 2011 Linus Walleij * * 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 @@ -49,6 +50,7 @@ struct nmk_gpio_chip { u32 (*get_secondary_status)(unsigned int bank); void (*set_ioforce)(bool enable); spinlock_t lock; + bool sleepmode; /* Keep track of configured edges */ u32 edge_rising; u32 edge_falling; @@ -393,14 +395,25 @@ EXPORT_SYMBOL(nmk_config_pins_sleep); * @gpio: pin number * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE, * - * Sets the sleep mode of a pin. If @mode is NMK_GPIO_SLPM_INPUT, the pin is - * changed to an input (with pullup/down enabled) in sleep and deep sleep. If - * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was - * configured even when in sleep and deep sleep. + * This register is actually in the pinmux layer, not the GPIO block itself. + * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP + * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code). + * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is + * HIGH, overriding the normal setting defined by GPIO_AFSELx registers. + * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit), + * the GPIOs return to the normal setting defined by GPIO_AFSELx registers. * - * On DB8500v2 onwards, this setting loses the previous meaning and instead - * indicates if wakeup detection is enabled on the pin. Note that - * enable_irq_wake() will automatically enable wakeup detection. + * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO + * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is + * entered) regardless of the altfunction selected. Also wake-up detection is + * ENABLED. + * + * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains + * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS + * (for altfunction GPIO) or respective on-chip peripherals (for other + * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED. + * + * Note that enable_irq_wake() will automatically enable wakeup detection. */ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode) { @@ -551,6 +564,12 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, int gpio, bool on) { + if (nmk_chip->sleepmode) { + __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, + on ? NMK_GPIO_SLPM_WAKEUP_ENABLE + : NMK_GPIO_SLPM_WAKEUP_DISABLE); + } + __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on); } @@ -901,7 +920,7 @@ void nmk_gpio_wakeups_suspend(void) writel(chip->fwimsc & chip->real_wake, chip->addr + NMK_GPIO_FWIMSC); - if (cpu_is_u8500v2()) { + if (chip->sleepmode) { chip->slpm = readl(chip->addr + NMK_GPIO_SLPC); /* 0 -> wakeup enable */ @@ -923,7 +942,7 @@ void nmk_gpio_wakeups_resume(void) writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC); writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC); - if (cpu_is_u8500v2()) + if (chip->sleepmode) writel(chip->slpm, chip->addr + NMK_GPIO_SLPC); } } @@ -1010,6 +1029,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) nmk_chip->secondary_parent_irq = secondary_irq; nmk_chip->get_secondary_status = pdata->get_secondary_status; nmk_chip->set_ioforce = pdata->set_ioforce; + nmk_chip->sleepmode = pdata->supports_sleepmode; spin_lock_init(&nmk_chip->lock); chip = &nmk_chip->chip; @@ -1065,5 +1085,3 @@ core_initcall(nmk_gpio_init); MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); MODULE_DESCRIPTION("Nomadik GPIO Driver"); MODULE_LICENSE("GPL"); - - -- cgit v1.2.3 From ea5a9607cb2a3c7e5e9fcb1b3d75b8f88eca5766 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 15 Jun 2011 14:52:43 -0600 Subject: gpio/tegra: Move Tegra gpio driver to drivers/gpio As part of the gpio driver consolidation, this patch moves the Tegra driver into drivers/gpio Signed-off-by: Grant Likely Acked-by: Olof Johansson Acked-by: Colin Cross --- arch/arm/mach-tegra/Makefile | 1 - arch/arm/mach-tegra/gpio.c | 431 ------------------------------------------- drivers/gpio/Makefile | 1 + drivers/gpio/gpio-tegra.c | 431 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 432 insertions(+), 432 deletions(-) delete mode 100644 arch/arm/mach-tegra/gpio.c create mode 100644 drivers/gpio/gpio-tegra.c (limited to 'drivers/gpio') diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 823c703e573c..ed58ef9019b5 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -4,7 +4,6 @@ obj-y += io.o obj-y += irq.o obj-y += clock.o obj-y += timer.o -obj-y += gpio.o obj-y += pinmux.o obj-y += powergate.o obj-y += fuse.o diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c deleted file mode 100644 index 919d63837736..000000000000 --- a/arch/arm/mach-tegra/gpio.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * arch/arm/mach-tegra/gpio.c - * - * Copyright (c) 2010 Google, Inc - * - * Author: - * Erik Gilling - * - * 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. - * - */ - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#define GPIO_BANK(x) ((x) >> 5) -#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_CNF(x) (GPIO_REG(x) + 0x00) -#define GPIO_OE(x) (GPIO_REG(x) + 0x10) -#define GPIO_OUT(x) (GPIO_REG(x) + 0X20) -#define GPIO_IN(x) (GPIO_REG(x) + 0x30) -#define GPIO_INT_STA(x) (GPIO_REG(x) + 0x40) -#define GPIO_INT_ENB(x) (GPIO_REG(x) + 0x50) -#define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60) -#define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70) - -#define GPIO_MSK_CNF(x) (GPIO_REG(x) + 0x800) -#define GPIO_MSK_OE(x) (GPIO_REG(x) + 0x810) -#define GPIO_MSK_OUT(x) (GPIO_REG(x) + 0X820) -#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + 0x840) -#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + 0x850) -#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + 0x860) - -#define GPIO_INT_LVL_MASK 0x010101 -#define GPIO_INT_LVL_EDGE_RISING 0x000101 -#define GPIO_INT_LVL_EDGE_FALLING 0x000100 -#define GPIO_INT_LVL_EDGE_BOTH 0x010100 -#define GPIO_INT_LVL_LEVEL_HIGH 0x000001 -#define GPIO_INT_LVL_LEVEL_LOW 0x000000 - -struct tegra_gpio_bank { - int bank; - int irq; - spinlock_t lvl_lock[4]; -#ifdef CONFIG_PM - u32 cnf[4]; - u32 out[4]; - u32 oe[4]; - u32 int_enb[4]; - u32 int_lvl[4]; -#endif -}; - - -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 int tegra_gpio_compose(int bank, int port, int bit) -{ - return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7); -} - -static void tegra_gpio_mask_write(u32 reg, int gpio, int value) -{ - u32 val; - - val = 0x100 << GPIO_BIT(gpio); - if (value) - val |= 1 << GPIO_BIT(gpio); - __raw_writel(val, reg); -} - -void tegra_gpio_enable(int gpio) -{ - tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); -} - -void tegra_gpio_disable(int gpio) -{ - tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); -} - -static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value); -} - -static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - return (__raw_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; -} - -static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0); - return 0; -} - -static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - tegra_gpio_set(chip, offset, value); - tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1); - return 0; -} - - - -static struct gpio_chip tegra_gpio_chip = { - .label = "tegra-gpio", - .direction_input = tegra_gpio_direction_input, - .get = tegra_gpio_get, - .direction_output = tegra_gpio_direction_output, - .set = tegra_gpio_set, - .base = 0, - .ngpio = TEGRA_NR_GPIOS, -}; - -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)); -} - -static void tegra_gpio_irq_mask(struct irq_data *d) -{ - int gpio = d->irq - INT_GPIO_BASE; - - tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); -} - -static void tegra_gpio_irq_unmask(struct irq_data *d) -{ - int gpio = d->irq - INT_GPIO_BASE; - - tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); -} - -static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) -{ - int gpio = d->irq - INT_GPIO_BASE; - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - int port = GPIO_PORT(gpio); - int lvl_type; - int val; - unsigned long flags; - - switch (type & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_EDGE_RISING: - lvl_type = GPIO_INT_LVL_EDGE_RISING; - break; - - case IRQ_TYPE_EDGE_FALLING: - lvl_type = GPIO_INT_LVL_EDGE_FALLING; - break; - - case IRQ_TYPE_EDGE_BOTH: - lvl_type = GPIO_INT_LVL_EDGE_BOTH; - break; - - case IRQ_TYPE_LEVEL_HIGH: - lvl_type = GPIO_INT_LVL_LEVEL_HIGH; - break; - - case IRQ_TYPE_LEVEL_LOW: - lvl_type = GPIO_INT_LVL_LEVEL_LOW; - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&bank->lvl_lock[port], flags); - - val = __raw_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)); - - spin_unlock_irqrestore(&bank->lvl_lock[port], flags); - - if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); - else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); - - return 0; -} - -static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - struct tegra_gpio_bank *bank; - int port; - int pin; - int unmasked = 0; - struct irq_chip *chip = irq_desc_get_chip(desc); - - chained_irq_enter(chip, desc); - - bank = irq_get_handler_data(irq); - - 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)); - - for_each_set_bit(pin, &sta, 8) { - __raw_writel(1 << pin, GPIO_INT_CLR(gpio)); - - /* if gpio is edge triggered, clear condition - * before executing the hander so that we don't - * miss edges - */ - if (lvl & (0x100 << pin)) { - unmasked = 1; - chained_irq_exit(chip, desc); - } - - generic_handle_irq(gpio_to_irq(gpio + pin)); - } - } - - if (!unmasked) - chained_irq_exit(chip, desc); - -} - -#ifdef CONFIG_PM -void tegra_gpio_resume(void) -{ - unsigned long flags; - int b; - int p; - - local_irq_save(flags); - - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { - struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; - - 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)); - } - } - - local_irq_restore(flags); -} - -void tegra_gpio_suspend(void) -{ - unsigned long flags; - int b; - int p; - - local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { - struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; - - 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)); - } - } - local_irq_restore(flags); -} - -static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) -{ - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - return irq_set_irq_wake(bank->irq, enable); -} -#endif - -static struct irq_chip tegra_gpio_irq_chip = { - .name = "GPIO", - .irq_ack = tegra_gpio_irq_ack, - .irq_mask = tegra_gpio_irq_mask, - .irq_unmask = tegra_gpio_irq_unmask, - .irq_set_type = tegra_gpio_irq_set_type, -#ifdef CONFIG_PM - .irq_set_wake = tegra_gpio_wake_enable, -#endif -}; - - -/* This lock class tells lockdep that GPIO irqs are in a different - * category than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; - -static int __init tegra_gpio_init(void) -{ - struct tegra_gpio_bank *bank; - int i; - int j; - - 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)); - } - } - - gpiochip_add(&tegra_gpio_chip); - - for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) { - bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))]; - - irq_set_lockdep_class(i, &gpio_lock_class); - irq_set_chip_data(i, bank); - irq_set_chip_and_handler(i, &tegra_gpio_irq_chip, - handle_simple_irq); - set_irq_flags(i, IRQF_VALID); - } - - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { - bank = &tegra_gpio_banks[i]; - - irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); - - for (j = 0; j < 4; j++) - spin_lock_init(&bank->lvl_lock[j]); - } - - return 0; -} - -postcore_initcall(tegra_gpio_init); - -void __init tegra_gpio_config(struct tegra_gpio_table *table, int num) -{ - int i; - - for (i = 0; i < num; i++) { - int gpio = table[i].gpio; - - if (table[i].enable) - tegra_gpio_enable(gpio); - else - tegra_gpio_disable(gpio); - } -} - -#ifdef CONFIG_DEBUG_FS - -#include -#include - -static int dbg_gpio_show(struct seq_file *s, void *unused) -{ - int i; - int j; - - for (i = 0; i < 7; i++) { - for (j = 0; j < 4; j++) { - int gpio = tegra_gpio_compose(i, j, 0); - 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))); - } - } - return 0; -} - -static int dbg_gpio_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_gpio_show, &inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = dbg_gpio_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init tegra_gpio_debuginit(void) -{ - (void) debugfs_create_file("tegra_gpio", S_IRUGO, - NULL, NULL, &debug_fops); - return 0; -} -late_initcall(tegra_gpio_debuginit); -#endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index b605f8ec6fbe..85d85a3f0a44 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_GPIO_PCH) += pch_gpio.o obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o obj-$(CONFIG_GPIO_TC3589X) += tc3589x-gpio.o +obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c new file mode 100644 index 000000000000..919d63837736 --- /dev/null +++ b/drivers/gpio/gpio-tegra.c @@ -0,0 +1,431 @@ +/* + * arch/arm/mach-tegra/gpio.c + * + * Copyright (c) 2010 Google, Inc + * + * Author: + * Erik Gilling + * + * 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. + * + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define GPIO_BANK(x) ((x) >> 5) +#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_CNF(x) (GPIO_REG(x) + 0x00) +#define GPIO_OE(x) (GPIO_REG(x) + 0x10) +#define GPIO_OUT(x) (GPIO_REG(x) + 0X20) +#define GPIO_IN(x) (GPIO_REG(x) + 0x30) +#define GPIO_INT_STA(x) (GPIO_REG(x) + 0x40) +#define GPIO_INT_ENB(x) (GPIO_REG(x) + 0x50) +#define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60) +#define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70) + +#define GPIO_MSK_CNF(x) (GPIO_REG(x) + 0x800) +#define GPIO_MSK_OE(x) (GPIO_REG(x) + 0x810) +#define GPIO_MSK_OUT(x) (GPIO_REG(x) + 0X820) +#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + 0x840) +#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + 0x850) +#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + 0x860) + +#define GPIO_INT_LVL_MASK 0x010101 +#define GPIO_INT_LVL_EDGE_RISING 0x000101 +#define GPIO_INT_LVL_EDGE_FALLING 0x000100 +#define GPIO_INT_LVL_EDGE_BOTH 0x010100 +#define GPIO_INT_LVL_LEVEL_HIGH 0x000001 +#define GPIO_INT_LVL_LEVEL_LOW 0x000000 + +struct tegra_gpio_bank { + int bank; + int irq; + spinlock_t lvl_lock[4]; +#ifdef CONFIG_PM + u32 cnf[4]; + u32 out[4]; + u32 oe[4]; + u32 int_enb[4]; + u32 int_lvl[4]; +#endif +}; + + +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 int tegra_gpio_compose(int bank, int port, int bit) +{ + return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7); +} + +static void tegra_gpio_mask_write(u32 reg, int gpio, int value) +{ + u32 val; + + val = 0x100 << GPIO_BIT(gpio); + if (value) + val |= 1 << GPIO_BIT(gpio); + __raw_writel(val, reg); +} + +void tegra_gpio_enable(int gpio) +{ + tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); +} + +void tegra_gpio_disable(int gpio) +{ + tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); +} + +static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value); +} + +static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + return (__raw_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; +} + +static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0); + return 0; +} + +static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + tegra_gpio_set(chip, offset, value); + tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1); + return 0; +} + + + +static struct gpio_chip tegra_gpio_chip = { + .label = "tegra-gpio", + .direction_input = tegra_gpio_direction_input, + .get = tegra_gpio_get, + .direction_output = tegra_gpio_direction_output, + .set = tegra_gpio_set, + .base = 0, + .ngpio = TEGRA_NR_GPIOS, +}; + +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)); +} + +static void tegra_gpio_irq_mask(struct irq_data *d) +{ + int gpio = d->irq - INT_GPIO_BASE; + + tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); +} + +static void tegra_gpio_irq_unmask(struct irq_data *d) +{ + int gpio = d->irq - INT_GPIO_BASE; + + tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); +} + +static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + int gpio = d->irq - INT_GPIO_BASE; + struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + int port = GPIO_PORT(gpio); + int lvl_type; + int val; + unsigned long flags; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + lvl_type = GPIO_INT_LVL_EDGE_RISING; + break; + + case IRQ_TYPE_EDGE_FALLING: + lvl_type = GPIO_INT_LVL_EDGE_FALLING; + break; + + case IRQ_TYPE_EDGE_BOTH: + lvl_type = GPIO_INT_LVL_EDGE_BOTH; + break; + + case IRQ_TYPE_LEVEL_HIGH: + lvl_type = GPIO_INT_LVL_LEVEL_HIGH; + break; + + case IRQ_TYPE_LEVEL_LOW: + lvl_type = GPIO_INT_LVL_LEVEL_LOW; + break; + + default: + return -EINVAL; + } + + spin_lock_irqsave(&bank->lvl_lock[port], flags); + + val = __raw_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)); + + spin_unlock_irqrestore(&bank->lvl_lock[port], flags); + + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + __irq_set_handler_locked(d->irq, handle_level_irq); + else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + __irq_set_handler_locked(d->irq, handle_edge_irq); + + return 0; +} + +static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct tegra_gpio_bank *bank; + int port; + int pin; + int unmasked = 0; + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + bank = irq_get_handler_data(irq); + + 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)); + + for_each_set_bit(pin, &sta, 8) { + __raw_writel(1 << pin, GPIO_INT_CLR(gpio)); + + /* if gpio is edge triggered, clear condition + * before executing the hander so that we don't + * miss edges + */ + if (lvl & (0x100 << pin)) { + unmasked = 1; + chained_irq_exit(chip, desc); + } + + generic_handle_irq(gpio_to_irq(gpio + pin)); + } + } + + if (!unmasked) + chained_irq_exit(chip, desc); + +} + +#ifdef CONFIG_PM +void tegra_gpio_resume(void) +{ + unsigned long flags; + int b; + int p; + + local_irq_save(flags); + + for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; + + 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)); + } + } + + local_irq_restore(flags); +} + +void tegra_gpio_suspend(void) +{ + unsigned long flags; + int b; + int p; + + local_irq_save(flags); + for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; + + 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)); + } + } + local_irq_restore(flags); +} + +static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) +{ + struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + return irq_set_irq_wake(bank->irq, enable); +} +#endif + +static struct irq_chip tegra_gpio_irq_chip = { + .name = "GPIO", + .irq_ack = tegra_gpio_irq_ack, + .irq_mask = tegra_gpio_irq_mask, + .irq_unmask = tegra_gpio_irq_unmask, + .irq_set_type = tegra_gpio_irq_set_type, +#ifdef CONFIG_PM + .irq_set_wake = tegra_gpio_wake_enable, +#endif +}; + + +/* This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +static int __init tegra_gpio_init(void) +{ + struct tegra_gpio_bank *bank; + int i; + int j; + + 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)); + } + } + + gpiochip_add(&tegra_gpio_chip); + + for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) { + bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))]; + + irq_set_lockdep_class(i, &gpio_lock_class); + irq_set_chip_data(i, bank); + irq_set_chip_and_handler(i, &tegra_gpio_irq_chip, + handle_simple_irq); + set_irq_flags(i, IRQF_VALID); + } + + for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + bank = &tegra_gpio_banks[i]; + + irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); + irq_set_handler_data(bank->irq, bank); + + for (j = 0; j < 4; j++) + spin_lock_init(&bank->lvl_lock[j]); + } + + return 0; +} + +postcore_initcall(tegra_gpio_init); + +void __init tegra_gpio_config(struct tegra_gpio_table *table, int num) +{ + int i; + + for (i = 0; i < num; i++) { + int gpio = table[i].gpio; + + if (table[i].enable) + tegra_gpio_enable(gpio); + else + tegra_gpio_disable(gpio); + } +} + +#ifdef CONFIG_DEBUG_FS + +#include +#include + +static int dbg_gpio_show(struct seq_file *s, void *unused) +{ + int i; + int j; + + for (i = 0; i < 7; i++) { + for (j = 0; j < 4; j++) { + int gpio = tegra_gpio_compose(i, j, 0); + 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))); + } + } + return 0; +} + +static int dbg_gpio_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_gpio_show, &inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = dbg_gpio_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init tegra_gpio_debuginit(void) +{ + (void) debugfs_create_file("tegra_gpio", S_IRUGO, + NULL, NULL, &debug_fops); + return 0; +} +late_initcall(tegra_gpio_debuginit); +#endif -- cgit v1.2.3 From df2212270ce94f12e9caed6ca04c7077672d588e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 15 Jun 2011 14:54:14 -0600 Subject: gpio/tegra: add devicetree support Add support for decoding gpios from the device tree Signed-off-by: Grant Likely Acked-by: Olof Johansson --- Documentation/devicetree/bindings/gpio/gpio_nvidia.txt | 7 +++++++ drivers/gpio/gpio-tegra.c | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio_nvidia.txt (limited to 'drivers/gpio') diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt new file mode 100644 index 000000000000..afb3ff3134c8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt @@ -0,0 +1,7 @@ +NVIDIA Tegra 2 GPIO controller + +Required properties: +- compatible : "nvidia,tegra250-gpio" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). +- gpio-controller : Marks the device node as a GPIO controller. diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 919d63837736..13afb881ffc3 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -23,6 +23,7 @@ #include #include +#include #include @@ -340,6 +341,15 @@ static int __init tegra_gpio_init(void) } } +#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,tegra250-gpio"); +#endif /* CONFIG_OF_GPIO */ + gpiochip_add(&tegra_gpio_chip); for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) { -- cgit v1.2.3