X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=arch%2Farm%2Fplat-omap%2Fgpio.c;h=45a225d09125ca0b7c774d5eebeb4aa022b0fecb;hb=3374cd1abd478f767aaedf2c21d109596ff0fe72;hp=c233ebd7639abac22977855054b57f00432ff56e;hpb=d11ac9791b87efb24506b6391a965b789385157c;p=safe%2Fjmp%2Flinux-2.6 diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index c233ebd..45a225d 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -6,6 +6,9 @@ * Copyright (C) 2003-2005 Nokia Corporation * Written by Juha Yrjölä * + * Copyright (C) 2009 Texas Instruments + * Added OMAP4 support - Santosh Shilimkar + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -17,19 +20,18 @@ #include #include #include +#include -#include +#include #include -#include -#include +#include +#include #include -#include - /* * OMAP1510 GPIO registers */ -#define OMAP1510_GPIO_BASE (void __iomem *)0xfffce000 +#define OMAP1510_GPIO_BASE 0xfffce000 #define OMAP1510_GPIO_DATA_INPUT 0x00 #define OMAP1510_GPIO_DATA_OUTPUT 0x04 #define OMAP1510_GPIO_DIR_CONTROL 0x08 @@ -43,10 +45,10 @@ /* * OMAP1610 specific GPIO registers */ -#define OMAP1610_GPIO1_BASE (void __iomem *)0xfffbe400 -#define OMAP1610_GPIO2_BASE (void __iomem *)0xfffbec00 -#define OMAP1610_GPIO3_BASE (void __iomem *)0xfffbb400 -#define OMAP1610_GPIO4_BASE (void __iomem *)0xfffbbc00 +#define OMAP1610_GPIO1_BASE 0xfffbe400 +#define OMAP1610_GPIO2_BASE 0xfffbec00 +#define OMAP1610_GPIO3_BASE 0xfffbb400 +#define OMAP1610_GPIO4_BASE 0xfffbbc00 #define OMAP1610_GPIO_REVISION 0x0000 #define OMAP1610_GPIO_SYSCONFIG 0x0010 #define OMAP1610_GPIO_SYSSTATUS 0x0014 @@ -66,34 +68,36 @@ #define OMAP1610_GPIO_SET_DATAOUT 0x00f0 /* - * OMAP730 specific GPIO registers + * OMAP7XX specific GPIO registers */ -#define OMAP730_GPIO1_BASE (void __iomem *)0xfffbc000 -#define OMAP730_GPIO2_BASE (void __iomem *)0xfffbc800 -#define OMAP730_GPIO3_BASE (void __iomem *)0xfffbd000 -#define OMAP730_GPIO4_BASE (void __iomem *)0xfffbd800 -#define OMAP730_GPIO5_BASE (void __iomem *)0xfffbe000 -#define OMAP730_GPIO6_BASE (void __iomem *)0xfffbe800 -#define OMAP730_GPIO_DATA_INPUT 0x00 -#define OMAP730_GPIO_DATA_OUTPUT 0x04 -#define OMAP730_GPIO_DIR_CONTROL 0x08 -#define OMAP730_GPIO_INT_CONTROL 0x0c -#define OMAP730_GPIO_INT_MASK 0x10 -#define OMAP730_GPIO_INT_STATUS 0x14 +#define OMAP7XX_GPIO1_BASE 0xfffbc000 +#define OMAP7XX_GPIO2_BASE 0xfffbc800 +#define OMAP7XX_GPIO3_BASE 0xfffbd000 +#define OMAP7XX_GPIO4_BASE 0xfffbd800 +#define OMAP7XX_GPIO5_BASE 0xfffbe000 +#define OMAP7XX_GPIO6_BASE 0xfffbe800 +#define OMAP7XX_GPIO_DATA_INPUT 0x00 +#define OMAP7XX_GPIO_DATA_OUTPUT 0x04 +#define OMAP7XX_GPIO_DIR_CONTROL 0x08 +#define OMAP7XX_GPIO_INT_CONTROL 0x0c +#define OMAP7XX_GPIO_INT_MASK 0x10 +#define OMAP7XX_GPIO_INT_STATUS 0x14 + +#define OMAP1_MPUIO_VBASE OMAP1_MPUIO_BASE /* * omap24xx specific GPIO registers */ -#define OMAP242X_GPIO1_BASE (void __iomem *)0x48018000 -#define OMAP242X_GPIO2_BASE (void __iomem *)0x4801a000 -#define OMAP242X_GPIO3_BASE (void __iomem *)0x4801c000 -#define OMAP242X_GPIO4_BASE (void __iomem *)0x4801e000 +#define OMAP242X_GPIO1_BASE 0x48018000 +#define OMAP242X_GPIO2_BASE 0x4801a000 +#define OMAP242X_GPIO3_BASE 0x4801c000 +#define OMAP242X_GPIO4_BASE 0x4801e000 -#define OMAP243X_GPIO1_BASE (void __iomem *)0x4900C000 -#define OMAP243X_GPIO2_BASE (void __iomem *)0x4900E000 -#define OMAP243X_GPIO3_BASE (void __iomem *)0x49010000 -#define OMAP243X_GPIO4_BASE (void __iomem *)0x49012000 -#define OMAP243X_GPIO5_BASE (void __iomem *)0x480B6000 +#define OMAP243X_GPIO1_BASE 0x4900C000 +#define OMAP243X_GPIO2_BASE 0x4900E000 +#define OMAP243X_GPIO3_BASE 0x49010000 +#define OMAP243X_GPIO4_BASE 0x49012000 +#define OMAP243X_GPIO5_BASE 0x480B6000 #define OMAP24XX_GPIO_REVISION 0x0000 #define OMAP24XX_GPIO_SYSCONFIG 0x0010 @@ -102,6 +106,7 @@ #define OMAP24XX_GPIO_IRQSTATUS2 0x0028 #define OMAP24XX_GPIO_IRQENABLE2 0x002c #define OMAP24XX_GPIO_IRQENABLE1 0x001c +#define OMAP24XX_GPIO_WAKE_EN 0x0020 #define OMAP24XX_GPIO_CTRL 0x0030 #define OMAP24XX_GPIO_OE 0x0034 #define OMAP24XX_GPIO_DATAIN 0x0038 @@ -110,6 +115,8 @@ #define OMAP24XX_GPIO_LEVELDETECT1 0x0044 #define OMAP24XX_GPIO_RISINGDETECT 0x0048 #define OMAP24XX_GPIO_FALLINGDETECT 0x004c +#define OMAP24XX_GPIO_DEBOUNCE_EN 0x0050 +#define OMAP24XX_GPIO_DEBOUNCE_VAL 0x0054 #define OMAP24XX_GPIO_CLEARIRQENABLE1 0x0060 #define OMAP24XX_GPIO_SETIRQENABLE1 0x0064 #define OMAP24XX_GPIO_CLEARWKUENA 0x0080 @@ -117,29 +124,64 @@ #define OMAP24XX_GPIO_CLEARDATAOUT 0x0090 #define OMAP24XX_GPIO_SETDATAOUT 0x0094 +#define OMAP4_GPIO_REVISION 0x0000 +#define OMAP4_GPIO_SYSCONFIG 0x0010 +#define OMAP4_GPIO_EOI 0x0020 +#define OMAP4_GPIO_IRQSTATUSRAW0 0x0024 +#define OMAP4_GPIO_IRQSTATUSRAW1 0x0028 +#define OMAP4_GPIO_IRQSTATUS0 0x002c +#define OMAP4_GPIO_IRQSTATUS1 0x0030 +#define OMAP4_GPIO_IRQSTATUSSET0 0x0034 +#define OMAP4_GPIO_IRQSTATUSSET1 0x0038 +#define OMAP4_GPIO_IRQSTATUSCLR0 0x003c +#define OMAP4_GPIO_IRQSTATUSCLR1 0x0040 +#define OMAP4_GPIO_IRQWAKEN0 0x0044 +#define OMAP4_GPIO_IRQWAKEN1 0x0048 +#define OMAP4_GPIO_SYSSTATUS 0x0104 +#define OMAP4_GPIO_CTRL 0x0130 +#define OMAP4_GPIO_OE 0x0134 +#define OMAP4_GPIO_DATAIN 0x0138 +#define OMAP4_GPIO_DATAOUT 0x013c +#define OMAP4_GPIO_LEVELDETECT0 0x0140 +#define OMAP4_GPIO_LEVELDETECT1 0x0144 +#define OMAP4_GPIO_RISINGDETECT 0x0148 +#define OMAP4_GPIO_FALLINGDETECT 0x014c +#define OMAP4_GPIO_DEBOUNCENABLE 0x0150 +#define OMAP4_GPIO_DEBOUNCINGTIME 0x0154 +#define OMAP4_GPIO_CLEARDATAOUT 0x0190 +#define OMAP4_GPIO_SETDATAOUT 0x0194 /* * omap34xx specific GPIO registers */ -#define OMAP34XX_GPIO1_BASE (void __iomem *)0x48310000 -#define OMAP34XX_GPIO2_BASE (void __iomem *)0x49050000 -#define OMAP34XX_GPIO3_BASE (void __iomem *)0x49052000 -#define OMAP34XX_GPIO4_BASE (void __iomem *)0x49054000 -#define OMAP34XX_GPIO5_BASE (void __iomem *)0x49056000 -#define OMAP34XX_GPIO6_BASE (void __iomem *)0x49058000 +#define OMAP34XX_GPIO1_BASE 0x48310000 +#define OMAP34XX_GPIO2_BASE 0x49050000 +#define OMAP34XX_GPIO3_BASE 0x49052000 +#define OMAP34XX_GPIO4_BASE 0x49054000 +#define OMAP34XX_GPIO5_BASE 0x49056000 +#define OMAP34XX_GPIO6_BASE 0x49058000 +/* + * OMAP44XX specific GPIO registers + */ +#define OMAP44XX_GPIO1_BASE 0x4a310000 +#define OMAP44XX_GPIO2_BASE 0x48055000 +#define OMAP44XX_GPIO3_BASE 0x48057000 +#define OMAP44XX_GPIO4_BASE 0x48059000 +#define OMAP44XX_GPIO5_BASE 0x4805B000 +#define OMAP44XX_GPIO6_BASE 0x4805D000 struct gpio_bank { + unsigned long pbase; void __iomem *base; u16 irq; u16 virtual_irq_start; int method; - u32 reserved_map; -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) u32 suspend_wakeup; u32 saved_wakeup; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#ifdef CONFIG_ARCH_OMAP2PLUS u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; @@ -147,71 +189,141 @@ struct gpio_bank { u32 saved_fallingdetect; u32 saved_risingdetect; #endif + u32 level_mask; + u32 toggle_mask; spinlock_t lock; + struct gpio_chip chip; + struct clk *dbck; + u32 mod_usage; }; #define METHOD_MPUIO 0 #define METHOD_GPIO_1510 1 #define METHOD_GPIO_1610 2 -#define METHOD_GPIO_730 3 -#define METHOD_GPIO_24XX 4 +#define METHOD_GPIO_7XX 3 +#define METHOD_GPIO_24XX 5 +#define METHOD_GPIO_44XX 6 #ifdef CONFIG_ARCH_OMAP16XX static struct gpio_bank gpio_bank_1610[5] = { - { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO}, - { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 }, - { OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 }, - { OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 }, - { OMAP1610_GPIO4_BASE, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, METHOD_GPIO_1610 }, + { OMAP1_MPUIO_VBASE, NULL, INT_MPUIO, IH_MPUIO_BASE, + METHOD_MPUIO }, + { OMAP1610_GPIO1_BASE, NULL, INT_GPIO_BANK1, IH_GPIO_BASE, + METHOD_GPIO_1610 }, + { OMAP1610_GPIO2_BASE, NULL, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, + METHOD_GPIO_1610 }, + { OMAP1610_GPIO3_BASE, NULL, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, + METHOD_GPIO_1610 }, + { OMAP1610_GPIO4_BASE, NULL, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, + METHOD_GPIO_1610 }, }; #endif #ifdef CONFIG_ARCH_OMAP15XX static struct gpio_bank gpio_bank_1510[2] = { - { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, - { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1510 } + { OMAP1_MPUIO_VBASE, NULL, INT_MPUIO, IH_MPUIO_BASE, + METHOD_MPUIO }, + { OMAP1510_GPIO_BASE, NULL, INT_GPIO_BANK1, IH_GPIO_BASE, + METHOD_GPIO_1510 } }; #endif -#ifdef CONFIG_ARCH_OMAP730 -static struct gpio_bank gpio_bank_730[7] = { - { OMAP_MPUIO_BASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO }, - { OMAP730_GPIO1_BASE, INT_730_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 }, - { OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 }, - { OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 }, - { OMAP730_GPIO4_BASE, INT_730_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_730 }, - { OMAP730_GPIO5_BASE, INT_730_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_730 }, - { OMAP730_GPIO6_BASE, INT_730_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_730 }, +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) +static struct gpio_bank gpio_bank_7xx[7] = { + { OMAP1_MPUIO_VBASE, NULL, INT_7XX_MPUIO, IH_MPUIO_BASE, + METHOD_MPUIO }, + { OMAP7XX_GPIO1_BASE, NULL, INT_7XX_GPIO_BANK1, IH_GPIO_BASE, + METHOD_GPIO_7XX }, + { OMAP7XX_GPIO2_BASE, NULL, INT_7XX_GPIO_BANK2, IH_GPIO_BASE + 32, + METHOD_GPIO_7XX }, + { OMAP7XX_GPIO3_BASE, NULL, INT_7XX_GPIO_BANK3, IH_GPIO_BASE + 64, + METHOD_GPIO_7XX }, + { OMAP7XX_GPIO4_BASE, NULL, INT_7XX_GPIO_BANK4, IH_GPIO_BASE + 96, + METHOD_GPIO_7XX }, + { OMAP7XX_GPIO5_BASE, NULL, INT_7XX_GPIO_BANK5, IH_GPIO_BASE + 128, + METHOD_GPIO_7XX }, + { OMAP7XX_GPIO6_BASE, NULL, INT_7XX_GPIO_BANK6, IH_GPIO_BASE + 160, + METHOD_GPIO_7XX }, }; #endif -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 static struct gpio_bank gpio_bank_242x[4] = { - { OMAP242X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, - { OMAP242X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX }, - { OMAP242X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX }, - { OMAP242X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX }, + { OMAP242X_GPIO1_BASE, NULL, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, + METHOD_GPIO_24XX }, + { OMAP242X_GPIO2_BASE, NULL, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, + METHOD_GPIO_24XX }, + { OMAP242X_GPIO3_BASE, NULL, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, + METHOD_GPIO_24XX }, + { OMAP242X_GPIO4_BASE, NULL, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, + METHOD_GPIO_24XX }, }; static struct gpio_bank gpio_bank_243x[5] = { - { OMAP243X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, - { OMAP243X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX }, - { OMAP243X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX }, - { OMAP243X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX }, - { OMAP243X_GPIO5_BASE, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX }, + { OMAP243X_GPIO1_BASE, NULL, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, + METHOD_GPIO_24XX }, + { OMAP243X_GPIO2_BASE, NULL, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, + METHOD_GPIO_24XX }, + { OMAP243X_GPIO3_BASE, NULL, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, + METHOD_GPIO_24XX }, + { OMAP243X_GPIO4_BASE, NULL, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, + METHOD_GPIO_24XX }, + { OMAP243X_GPIO5_BASE, NULL, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, + METHOD_GPIO_24XX }, }; #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 static struct gpio_bank gpio_bank_34xx[6] = { - { OMAP34XX_GPIO1_BASE, INT_34XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, - { OMAP34XX_GPIO2_BASE, INT_34XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX }, - { OMAP34XX_GPIO3_BASE, INT_34XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX }, - { OMAP34XX_GPIO4_BASE, INT_34XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX }, - { OMAP34XX_GPIO5_BASE, INT_34XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX }, - { OMAP34XX_GPIO6_BASE, INT_34XX_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_24XX }, + { OMAP34XX_GPIO1_BASE, NULL, INT_34XX_GPIO_BANK1, IH_GPIO_BASE, + METHOD_GPIO_24XX }, + { OMAP34XX_GPIO2_BASE, NULL, INT_34XX_GPIO_BANK2, IH_GPIO_BASE + 32, + METHOD_GPIO_24XX }, + { OMAP34XX_GPIO3_BASE, NULL, INT_34XX_GPIO_BANK3, IH_GPIO_BASE + 64, + METHOD_GPIO_24XX }, + { OMAP34XX_GPIO4_BASE, NULL, INT_34XX_GPIO_BANK4, IH_GPIO_BASE + 96, + METHOD_GPIO_24XX }, + { OMAP34XX_GPIO5_BASE, NULL, INT_34XX_GPIO_BANK5, IH_GPIO_BASE + 128, + METHOD_GPIO_24XX }, + { OMAP34XX_GPIO6_BASE, NULL, INT_34XX_GPIO_BANK6, IH_GPIO_BASE + 160, + METHOD_GPIO_24XX }, +}; + +struct omap3_gpio_regs { + u32 sysconfig; + u32 irqenable1; + u32 irqenable2; + u32 wake_en; + u32 ctrl; + u32 oe; + u32 leveldetect0; + u32 leveldetect1; + u32 risingdetect; + u32 fallingdetect; + u32 dataout; + u32 setwkuena; + u32 setdataout; +}; + +static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS]; +#endif + +#ifdef CONFIG_ARCH_OMAP4 +static struct gpio_bank gpio_bank_44xx[6] = { + { OMAP44XX_GPIO1_BASE, NULL, OMAP44XX_IRQ_GPIO1, IH_GPIO_BASE, + METHOD_GPIO_44XX }, + { OMAP44XX_GPIO2_BASE, NULL, OMAP44XX_IRQ_GPIO2, IH_GPIO_BASE + 32, + METHOD_GPIO_44XX }, + { OMAP44XX_GPIO3_BASE, NULL, OMAP44XX_IRQ_GPIO3, IH_GPIO_BASE + 64, + METHOD_GPIO_44XX }, + { OMAP44XX_GPIO4_BASE, NULL, OMAP44XX_IRQ_GPIO4, IH_GPIO_BASE + 96, + METHOD_GPIO_44XX }, + { OMAP44XX_GPIO5_BASE, NULL, OMAP44XX_IRQ_GPIO5, IH_GPIO_BASE + 128, + METHOD_GPIO_44XX }, + { OMAP44XX_GPIO6_BASE, NULL, OMAP44XX_IRQ_GPIO6, IH_GPIO_BASE + 160, + METHOD_GPIO_44XX }, }; #endif @@ -231,24 +343,26 @@ static inline struct gpio_bank *get_gpio_bank(int gpio) return &gpio_bank[0]; return &gpio_bank[1 + (gpio >> 4)]; } - if (cpu_is_omap730()) { + if (cpu_is_omap7xx()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1 + (gpio >> 5)]; } if (cpu_is_omap24xx()) return &gpio_bank[gpio >> 5]; - if (cpu_is_omap34xx()) + if (cpu_is_omap34xx() || cpu_is_omap44xx()) return &gpio_bank[gpio >> 5]; + BUG(); + return NULL; } static inline int get_gpio_index(int gpio) { - if (cpu_is_omap730()) + if (cpu_is_omap7xx()) return gpio & 0x1f; if (cpu_is_omap24xx()) return gpio & 0x1f; - if (cpu_is_omap34xx()) + if (cpu_is_omap34xx() || cpu_is_omap44xx()) return gpio & 0x1f; return gpio & 0x0f; } @@ -266,18 +380,18 @@ static inline int gpio_valid(int gpio) return 0; if ((cpu_is_omap16xx()) && gpio < 64) return 0; - if (cpu_is_omap730() && gpio < 192) + if (cpu_is_omap7xx() && gpio < 192) return 0; if (cpu_is_omap24xx() && gpio < 128) return 0; - if (cpu_is_omap34xx() && gpio < 160) + if ((cpu_is_omap34xx() || cpu_is_omap44xx()) && gpio < 192) return 0; return -1; } static int check_gpio(int gpio) { - if (unlikely(gpio_valid(gpio)) < 0) { + if (unlikely(gpio_valid(gpio) < 0)) { printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio); dump_stack(); return -1; @@ -306,16 +420,21 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) reg += OMAP1610_GPIO_DIRECTION; break; #endif -#ifdef CONFIG_ARCH_OMAP730 - case METHOD_GPIO_730: - reg += OMAP730_GPIO_DIR_CONTROL; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DIR_CONTROL; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_OE; break; #endif +#if defined(CONFIG_ARCH_OMAP4) + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_OE; + break; +#endif default: WARN_ON(1); return; @@ -328,18 +447,6 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) __raw_writel(l, reg); } -void omap_set_gpio_direction(int gpio, int is_input) -{ - struct gpio_bank *bank; - - if (check_gpio(gpio) < 0) - return; - bank = get_gpio_bank(gpio); - spin_lock(&bank->lock); - _set_gpio_direction(bank, get_gpio_index(gpio), is_input); - spin_unlock(&bank->lock); -} - static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) { void __iomem *reg = bank->base; @@ -375,9 +482,9 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) l = 1 << gpio; break; #endif -#ifdef CONFIG_ARCH_OMAP730 - case METHOD_GPIO_730: - reg += OMAP730_GPIO_DATA_OUTPUT; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DATA_OUTPUT; l = __raw_readl(reg); if (enable) l |= 1 << gpio; @@ -385,7 +492,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) l &= ~(1 << gpio); break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETDATAOUT; @@ -394,6 +501,15 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) l = 1 << gpio; break; #endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + if (enable) + reg += OMAP4_GPIO_SETDATAOUT; + else + reg += OMAP4_GPIO_CLEARDATAOUT; + l = 1 << gpio; + break; +#endif default: WARN_ON(1); return; @@ -401,26 +517,12 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) __raw_writel(l, reg); } -void omap_set_gpio_dataout(int gpio, int enable) +static int _get_gpio_datain(struct gpio_bank *bank, int gpio) { - struct gpio_bank *bank; - - if (check_gpio(gpio) < 0) - return; - bank = get_gpio_bank(gpio); - spin_lock(&bank->lock); - _set_gpio_dataout(bank, get_gpio_index(gpio), enable); - spin_unlock(&bank->lock); -} - -int omap_get_gpio_datain(int gpio) -{ - struct gpio_bank *bank; void __iomem *reg; if (check_gpio(gpio) < 0) return -EINVAL; - bank = get_gpio_bank(gpio); reg = bank->base; switch (bank->method) { #ifdef CONFIG_ARCH_OMAP1 @@ -438,16 +540,21 @@ int omap_get_gpio_datain(int gpio) reg += OMAP1610_GPIO_DATAIN; break; #endif -#ifdef CONFIG_ARCH_OMAP730 - case METHOD_GPIO_730: - reg += OMAP730_GPIO_DATA_INPUT; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DATA_INPUT; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAIN; break; #endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_DATAIN; + break; +#endif default: return -EINVAL; } @@ -455,6 +562,48 @@ int omap_get_gpio_datain(int gpio) & (1 << get_gpio_index(gpio))) != 0; } +static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) +{ + void __iomem *reg; + + if (check_gpio(gpio) < 0) + return -EINVAL; + reg = bank->base; + + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_OUTPUT; + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DATA_OUTPUT; + break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DATAOUT; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DATA_OUTPUT; + break; +#endif +#ifdef CONFIG_ARCH_OMAP2PLUS + case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: + reg += OMAP24XX_GPIO_DATAOUT; + break; +#endif + default: + return -EINVAL; + } + + return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0; +} + #define MOD_REG_BIT(reg, bit_mask, set) \ do { \ int l = __raw_readl(base + reg); \ @@ -463,33 +612,179 @@ do { \ __raw_writel(l, base + reg); \ } while(0) -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) -static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) +void omap_set_gpio_debounce(int gpio, int enable) +{ + struct gpio_bank *bank; + void __iomem *reg; + unsigned long flags; + u32 val, l = 1 << get_gpio_index(gpio); + + if (cpu_class_is_omap1()) + return; + + bank = get_gpio_bank(gpio); + reg = bank->base; + + if (cpu_is_omap44xx()) + reg += OMAP4_GPIO_DEBOUNCENABLE; + else + reg += OMAP24XX_GPIO_DEBOUNCE_EN; + + if (!(bank->mod_usage & l)) { + printk(KERN_ERR "GPIO %d not requested\n", gpio); + return; + } + + spin_lock_irqsave(&bank->lock, flags); + val = __raw_readl(reg); + + if (enable && !(val & l)) + val |= l; + else if (!enable && (val & l)) + val &= ~l; + else + goto done; + + if (cpu_is_omap34xx() || cpu_is_omap44xx()) { + if (enable) + clk_enable(bank->dbck); + else + clk_disable(bank->dbck); + } + + __raw_writel(val, reg); +done: + spin_unlock_irqrestore(&bank->lock, flags); +} +EXPORT_SYMBOL(omap_set_gpio_debounce); + +void omap_set_gpio_debounce_time(int gpio, int enc_time) +{ + struct gpio_bank *bank; + void __iomem *reg; + + if (cpu_class_is_omap1()) + return; + + bank = get_gpio_bank(gpio); + reg = bank->base; + + if (!bank->mod_usage) { + printk(KERN_ERR "GPIO not requested\n"); + return; + } + + enc_time &= 0xff; + + if (cpu_is_omap44xx()) + reg += OMAP4_GPIO_DEBOUNCINGTIME; + else + reg += OMAP24XX_GPIO_DEBOUNCE_VAL; + + __raw_writel(enc_time, reg); +} +EXPORT_SYMBOL(omap_set_gpio_debounce_time); + +#ifdef CONFIG_ARCH_OMAP2PLUS +static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, + int trigger) { void __iomem *base = bank->base; u32 gpio_bit = 1 << gpio; - - MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, - trigger & __IRQT_LOWLVL); - MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, - trigger & __IRQT_HIGHLVL); - MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit, - trigger & __IRQT_RISEDGE); - MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, - trigger & __IRQT_FALEDGE); + u32 val; + + if (cpu_is_omap44xx()) { + MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT0, gpio_bit, + trigger & IRQ_TYPE_LEVEL_LOW); + MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT1, gpio_bit, + trigger & IRQ_TYPE_LEVEL_HIGH); + MOD_REG_BIT(OMAP4_GPIO_RISINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_RISING); + MOD_REG_BIT(OMAP4_GPIO_FALLINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_FALLING); + } else { + MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, + trigger & IRQ_TYPE_LEVEL_LOW); + MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, + trigger & IRQ_TYPE_LEVEL_HIGH); + MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_RISING); + MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_FALLING); + } if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - if (trigger != 0) - __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_SETWKUENA); - else - __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_CLEARWKUENA); + 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); + } + } else { + if (trigger != 0) + __raw_writel(1 << gpio, bank->base + + OMAP24XX_GPIO_SETWKUENA); + else + __raw_writel(1 << gpio, bank->base + + OMAP24XX_GPIO_CLEARWKUENA); + } } else { if (trigger != 0) bank->enabled_non_wakeup_gpios |= gpio_bit; else bank->enabled_non_wakeup_gpios &= ~gpio_bit; } - /* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only level - * triggering requested. */ + + if (cpu_is_omap44xx()) { + bank->level_mask = + __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT0) | + __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT1); + } else { + bank->level_mask = + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) | + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + } +} +#endif + +#ifdef CONFIG_ARCH_OMAP1 +/* + * This only applies to chips that can't do both rising and falling edge + * detection at once. For all other chips, this function is a noop. + */ +static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) +{ + void __iomem *reg = bank->base; + u32 l = 0; + + switch (bank->method) { + case METHOD_MPUIO: + reg += OMAP_MPUIO_GPIO_INT_EDGE; + break; +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_INT_CONTROL; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_CONTROL; + break; +#endif + default: + return; + } + + l = __raw_readl(reg); + if ((l >> gpio) & 1) + l &= ~(1 << gpio); + else + l |= 1 << gpio; + + __raw_writel(l, reg); } #endif @@ -503,9 +798,11 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_INT_EDGE; l = __raw_readl(reg); - if (trigger & __IRQT_RISEDGE) + if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) + bank->toggle_mask |= 1 << gpio; + if (trigger & IRQ_TYPE_EDGE_RISING) l |= 1 << gpio; - else if (trigger & __IRQT_FALEDGE) + else if (trigger & IRQ_TYPE_EDGE_FALLING) l &= ~(1 << gpio); else goto bad; @@ -515,9 +812,11 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger & __IRQT_RISEDGE) + if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) + bank->toggle_mask |= 1 << gpio; + if (trigger & IRQ_TYPE_EDGE_RISING) l |= 1 << gpio; - else if (trigger & __IRQT_FALEDGE) + else if (trigger & IRQ_TYPE_EDGE_FALLING) l &= ~(1 << gpio); else goto bad; @@ -532,9 +831,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) gpio &= 0x07; l = __raw_readl(reg); l &= ~(3 << (gpio << 1)); - if (trigger & __IRQT_RISEDGE) + if (trigger & IRQ_TYPE_EDGE_RISING) l |= 2 << (gpio << 1); - if (trigger & __IRQT_FALEDGE) + if (trigger & IRQ_TYPE_EDGE_FALLING) l |= 1 << (gpio << 1); if (trigger) /* Enable wake-up during idle for dynamic tick */ @@ -543,20 +842,23 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA); break; #endif -#ifdef CONFIG_ARCH_OMAP730 - case METHOD_GPIO_730: - reg += OMAP730_GPIO_INT_CONTROL; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger & __IRQT_RISEDGE) + if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) + bank->toggle_mask |= 1 << gpio; + if (trigger & IRQ_TYPE_EDGE_RISING) l |= 1 << gpio; - else if (trigger & __IRQT_FALEDGE) + else if (trigger & IRQ_TYPE_EDGE_FALLING) l &= ~(1 << gpio); else goto bad; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: set_24xx_gpio_triggering(bank, gpio, trigger); break; #endif @@ -574,6 +876,7 @@ static int gpio_irq_type(unsigned irq, unsigned type) struct gpio_bank *bank; unsigned gpio; int retval; + unsigned long flags; if (!cpu_class_is_omap2() && irq > IH_MPUIO_BASE) gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); @@ -592,13 +895,19 @@ static int gpio_irq_type(unsigned irq, unsigned type) return -EINVAL; bank = get_irq_chip_data(irq); - spin_lock(&bank->lock); + spin_lock_irqsave(&bank->lock, flags); retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type); if (retval == 0) { irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; irq_desc[irq].status |= type; } - spin_unlock(&bank->lock); + spin_unlock_irqrestore(&bank->lock, flags); + + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + __set_irq_handler_unlocked(irq, handle_level_irq); + else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + __set_irq_handler_unlocked(irq, handle_edge_irq); + return retval; } @@ -623,16 +932,21 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) reg += OMAP1610_GPIO_IRQSTATUS1; break; #endif -#ifdef CONFIG_ARCH_OMAP730 - case METHOD_GPIO_730: - reg += OMAP730_GPIO_INT_STATUS; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_STATUS; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQSTATUS1; break; #endif +#if defined(CONFIG_ARCH_OMAP4) + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_IRQSTATUS0; + break; +#endif default: WARN_ON(1); return; @@ -640,10 +954,17 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) __raw_writel(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) if (cpu_is_omap24xx() || cpu_is_omap34xx()) - __raw_writel(gpio_mask, bank->base + OMAP24XX_GPIO_IRQSTATUS2); -#endif + reg = bank->base + OMAP24XX_GPIO_IRQSTATUS2; + else if (cpu_is_omap44xx()) + reg = bank->base + OMAP4_GPIO_IRQSTATUS1; + + if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap44xx()) { + __raw_writel(gpio_mask, reg); + + /* Flush posted write for the irq status to avoid spurious interrupts */ + __raw_readl(reg); + } } static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) @@ -679,19 +1000,25 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) mask = 0xffff; break; #endif -#ifdef CONFIG_ARCH_OMAP730 - case METHOD_GPIO_730: - reg += OMAP730_GPIO_INT_MASK; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_MASK; mask = 0xffffffff; inv = 1; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQENABLE1; mask = 0xffffffff; break; #endif +#if defined(CONFIG_ARCH_OMAP4) + case METHOD_GPIO_44XX: + reg += OMAP4_GPIO_IRQSTATUSSET0; + mask = 0xffffffff; + break; +#endif default: WARN_ON(1); return 0; @@ -739,9 +1066,9 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab l = gpio_mask; break; #endif -#ifdef CONFIG_ARCH_OMAP730 - case METHOD_GPIO_730: - reg += OMAP730_GPIO_INT_MASK; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_MASK; l = __raw_readl(reg); if (enable) l &= ~(gpio_mask); @@ -749,7 +1076,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab l |= gpio_mask; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETIRQENABLE1; @@ -758,6 +1085,15 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab l = gpio_mask; break; #endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + if (enable) + reg += OMAP4_GPIO_IRQSTATUSSET0; + else + reg += OMAP4_GPIO_IRQSTATUSCLR0; + l = gpio_mask; + break; +#endif default: WARN_ON(1); return; @@ -780,38 +1116,35 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena */ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) { + unsigned long uninitialized_var(flags); + switch (bank->method) { #ifdef CONFIG_ARCH_OMAP16XX case METHOD_MPUIO: case METHOD_GPIO_1610: - spin_lock(&bank->lock); - if (enable) { + spin_lock_irqsave(&bank->lock, flags); + if (enable) bank->suspend_wakeup |= (1 << gpio); - enable_irq_wake(bank->irq); - } else { - disable_irq_wake(bank->irq); + else bank->suspend_wakeup &= ~(1 << gpio); - } - spin_unlock(&bank->lock); + spin_unlock_irqrestore(&bank->lock, flags); return 0; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#ifdef CONFIG_ARCH_OMAP2PLUS case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: if (bank->non_wakeup_gpios & (1 << gpio)) { printk(KERN_ERR "Unable to modify wakeup on " "non-wakeup GPIO%d\n", (bank - gpio_bank) * 32 + gpio); return -EINVAL; } - spin_lock(&bank->lock); - if (enable) { + spin_lock_irqsave(&bank->lock, flags); + if (enable) bank->suspend_wakeup |= (1 << gpio); - enable_irq_wake(bank->irq); - } else { - disable_irq_wake(bank->irq); + else bank->suspend_wakeup &= ~(1 << gpio); - } - spin_unlock(&bank->lock); + spin_unlock_irqrestore(&bank->lock, flags); return 0; #endif default: @@ -826,7 +1159,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) _set_gpio_direction(bank, get_gpio_index(gpio), 1); _set_gpio_irqenable(bank, gpio, 0); _clear_gpio_irqstatus(bank, gpio); - _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE); + _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ @@ -844,27 +1177,17 @@ static int gpio_wake_enable(unsigned int irq, unsigned int enable) return retval; } -int omap_request_gpio(int gpio) +static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) { - struct gpio_bank *bank; + struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); + unsigned long flags; - if (check_gpio(gpio) < 0) - return -EINVAL; - - bank = get_gpio_bank(gpio); - spin_lock(&bank->lock); - if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) { - printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio); - dump_stack(); - spin_unlock(&bank->lock); - return -1; - } - bank->reserved_map |= (1 << get_gpio_index(gpio)); + spin_lock_irqsave(&bank->lock, flags); /* Set trigger to none. You need to enable the desired trigger with * request_irq() or set_irq_type(). */ - _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE); + _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); #ifdef CONFIG_ARCH_OMAP15XX if (bank->method == METHOD_GPIO_1510) { @@ -872,45 +1195,57 @@ int omap_request_gpio(int gpio) /* Claim the pin for MPU */ reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; - __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg); + __raw_writel(__raw_readl(reg) | (1 << offset), reg); } #endif - spin_unlock(&bank->lock); + if (!cpu_class_is_omap1()) { + if (!bank->mod_usage) { + u32 ctrl; + ctrl = __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); + ctrl &= 0xFFFFFFFE; + /* Module is enabled, clocks are not gated */ + __raw_writel(ctrl, bank->base + OMAP24XX_GPIO_CTRL); + } + bank->mod_usage |= 1 << offset; + } + spin_unlock_irqrestore(&bank->lock, flags); return 0; } -void omap_free_gpio(int gpio) +static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) { - struct gpio_bank *bank; + struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); + unsigned long flags; - if (check_gpio(gpio) < 0) - return; - bank = get_gpio_bank(gpio); - spin_lock(&bank->lock); - if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) { - printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio); - dump_stack(); - spin_unlock(&bank->lock); - return; - } + spin_lock_irqsave(&bank->lock, flags); #ifdef CONFIG_ARCH_OMAP16XX if (bank->method == METHOD_GPIO_1610) { /* Disable wake-up during idle for dynamic tick */ void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; - __raw_writel(1 << get_gpio_index(gpio), reg); + __raw_writel(1 << offset, reg); } #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) - if (bank->method == METHOD_GPIO_24XX) { +#ifdef CONFIG_ARCH_OMAP2PLUS + if ((bank->method == METHOD_GPIO_24XX) || + (bank->method == METHOD_GPIO_44XX)) { /* Disable wake-up during idle for dynamic tick */ void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA; - __raw_writel(1 << get_gpio_index(gpio), reg); + __raw_writel(1 << offset, reg); } #endif - bank->reserved_map &= ~(1 << get_gpio_index(gpio)); - _reset_gpio(bank, gpio); - spin_unlock(&bank->lock); + if (!cpu_class_is_omap1()) { + bank->mod_usage &= ~(1 << offset); + if (!bank->mod_usage) { + u32 ctrl; + ctrl = __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); + /* Module is disabled, clocks are gated */ + ctrl |= 1; + __raw_writel(ctrl, bank->base + OMAP24XX_GPIO_CTRL); + } + } + _reset_gpio(bank, bank->chip.base + offset); + spin_unlock_irqrestore(&bank->lock, flags); } /* @@ -926,7 +1261,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *isr_reg = NULL; u32 isr; - unsigned int gpio_irq; + unsigned int gpio_irq, gpio_index; struct gpio_bank *bank; u32 retrigger = 0; int unmasked = 0; @@ -946,14 +1281,18 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (bank->method == METHOD_GPIO_1610) isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1; #endif -#ifdef CONFIG_ARCH_OMAP730 - if (bank->method == METHOD_GPIO_730) - isr_reg = bank->base + OMAP730_GPIO_INT_STATUS; +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + if (bank->method == METHOD_GPIO_7XX) + isr_reg = bank->base + OMAP7XX_GPIO_INT_STATUS; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; #endif +#if defined(CONFIG_ARCH_OMAP4) + if (bank->method == METHOD_GPIO_44XX) + isr_reg = bank->base + OMAP4_GPIO_IRQSTATUS0; +#endif while(1) { u32 isr_saved, level_mask = 0; u32 enabled; @@ -965,12 +1304,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) isr &= 0x0000ffff; if (cpu_class_is_omap2()) { - level_mask = - __raw_readl(bank->base + - OMAP24XX_GPIO_LEVELDETECT0) | - __raw_readl(bank->base + - OMAP24XX_GPIO_LEVELDETECT1); - level_mask &= enabled; + level_mask = bank->level_mask & enabled; } /* clear edge sensitive interrupts before handler(s) are @@ -994,52 +1328,25 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) gpio_irq = bank->virtual_irq_start; for (; isr != 0; isr >>= 1, gpio_irq++) { - struct irq_desc *d; - int irq_mask; + gpio_index = get_gpio_index(irq_to_gpio(gpio_irq)); + if (!(isr & 1)) continue; - d = irq_desc + gpio_irq; - /* Don't run the handler if it's already running - * or was disabled lazely. - */ - if (unlikely((d->depth || - (d->status & IRQ_INPROGRESS)))) { - irq_mask = 1 << - (gpio_irq - bank->virtual_irq_start); - /* The unmasking will be done by - * enable_irq in case it is disabled or - * after returning from the handler if - * it's already running. - */ - _enable_gpio_irqbank(bank, irq_mask, 0); - if (!d->depth) { - /* Level triggered interrupts - * won't ever be reentered - */ - BUG_ON(level_mask & irq_mask); - d->status |= IRQ_PENDING; - } - continue; - } - - desc_handle_irq(gpio_irq, d); - if (unlikely((d->status & IRQ_PENDING) && !d->depth)) { - irq_mask = 1 << - (gpio_irq - bank->virtual_irq_start); - d->status &= ~IRQ_PENDING; - _enable_gpio_irqbank(bank, irq_mask, 1); - retrigger |= irq_mask; - } - } +#ifdef CONFIG_ARCH_OMAP1 + /* + * Some chips can't respond to both rising and falling + * at the same time. If this irq was requested with + * both flags, we need to flip the ICR data for the IRQ + * to respond to the IRQ for the opposite direction. + * This will be indicated in the bank toggle_mask. + */ + if (bank->toggle_mask & (1 << gpio_index)) + _toggle_gpio_edge_triggering(bank, gpio_index); +#endif - if (cpu_class_is_omap2()) { - /* clear level sensitive interrupts after handler(s) */ - _enable_gpio_irqbank(bank, isr_saved & level_mask, 0); - _clear_gpio_irqbank(bank, isr_saved & level_mask); - _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); + generic_handle_irq(gpio_irq); } - } /* if bank has any level sensitive GPIO pin interrupt configured, we must unmask the bank interrupt only after @@ -1072,15 +1379,28 @@ static void gpio_mask_irq(unsigned int irq) struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio, 0); + _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE); } static void gpio_unmask_irq(unsigned int irq) { unsigned int gpio = irq - IH_GPIO_BASE; - unsigned int gpio_idx = get_gpio_index(gpio); struct gpio_bank *bank = get_irq_chip_data(irq); + unsigned int irq_mask = 1 << get_gpio_index(gpio); + struct irq_desc *desc = irq_to_desc(irq); + u32 trigger = desc->status & IRQ_TYPE_SENSE_MASK; + + if (trigger) + _set_gpio_triggering(bank, get_gpio_index(gpio), trigger); + + /* For level-triggered GPIOs, the clearing must be done after + * the HW source is cleared, thus after the handler has run */ + if (bank->level_mask & irq_mask) { + _set_gpio_irqenable(bank, gpio, 0); + _clear_gpio_irqstatus(bank, gpio); + } - _set_gpio_irqenable(bank, gpio_idx, 1); + _set_gpio_irqenable(bank, gpio, 1); } static struct irq_chip gpio_irq_chip = { @@ -1140,39 +1460,47 @@ static struct irq_chip mpuio_irq_chip = { #include -static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg) +static int omap_mpuio_suspend_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct gpio_bank *bank = platform_get_drvdata(pdev); void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT; + unsigned long flags; - spin_lock(&bank->lock); + spin_lock_irqsave(&bank->lock, flags); bank->saved_wakeup = __raw_readl(mask_reg); __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg); - spin_unlock(&bank->lock); + spin_unlock_irqrestore(&bank->lock, flags); return 0; } -static int omap_mpuio_resume_early(struct platform_device *pdev) +static int omap_mpuio_resume_noirq(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct gpio_bank *bank = platform_get_drvdata(pdev); void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT; + unsigned long flags; - spin_lock(&bank->lock); + spin_lock_irqsave(&bank->lock, flags); __raw_writel(bank->saved_wakeup, mask_reg); - spin_unlock(&bank->lock); + spin_unlock_irqrestore(&bank->lock, flags); return 0; } +static const struct dev_pm_ops omap_mpuio_dev_pm_ops = { + .suspend_noirq = omap_mpuio_suspend_noirq, + .resume_noirq = omap_mpuio_resume_noirq, +}; + /* use platform_driver for this, now that there's no longer any * point to sys_device (other than not disturbing old code). */ static struct platform_driver omap_mpuio_driver = { - .suspend_late = omap_mpuio_suspend_late, - .resume_early = omap_mpuio_resume_early, .driver = { .name = "mpuio", + .pm = &omap_mpuio_dev_pm_ops, }, }; @@ -1208,8 +1536,101 @@ static inline void mpuio_init(void) {} /*---------------------------------------------------------------------*/ +/* REVISIT these are stupid implementations! replace by ones that + * don't switch on METHOD_* and which mostly avoid spinlocks + */ + +static int gpio_input(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank; + unsigned long flags; + + bank = container_of(chip, struct gpio_bank, chip); + spin_lock_irqsave(&bank->lock, flags); + _set_gpio_direction(bank, offset, 1); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +} + +static int gpio_is_input(struct gpio_bank *bank, int mask) +{ + void __iomem *reg = bank->base; + + switch (bank->method) { + case METHOD_MPUIO: + reg += OMAP_MPUIO_IO_CNTL; + break; + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DIRECTION; + break; + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_24XX: + case METHOD_GPIO_44XX: + reg += OMAP24XX_GPIO_OE; + break; + } + return __raw_readl(reg) & mask; +} + +static int gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank; + void __iomem *reg; + int gpio; + u32 mask; + + gpio = chip->base + offset; + bank = get_gpio_bank(gpio); + reg = bank->base; + mask = 1 << get_gpio_index(gpio); + + if (gpio_is_input(bank, mask)) + return _get_gpio_datain(bank, gpio); + else + return _get_gpio_dataout(bank, gpio); +} + +static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) +{ + struct gpio_bank *bank; + unsigned long flags; + + bank = container_of(chip, struct gpio_bank, chip); + spin_lock_irqsave(&bank->lock, flags); + _set_gpio_dataout(bank, offset, value); + _set_gpio_direction(bank, offset, 0); + spin_unlock_irqrestore(&bank->lock, flags); + return 0; +} + +static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct gpio_bank *bank; + unsigned long flags; + + bank = container_of(chip, struct gpio_bank, chip); + spin_lock_irqsave(&bank->lock, flags); + _set_gpio_dataout(bank, offset, value); + spin_unlock_irqrestore(&bank->lock, flags); +} + +static int gpio_2irq(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank; + + bank = container_of(chip, struct gpio_bank, chip); + return bank->virtual_irq_start + offset; +} + +/*---------------------------------------------------------------------*/ + static int initialized; -#if !defined(CONFIG_ARCH_OMAP3) +#if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2) static struct clk * gpio_ick; #endif @@ -1222,18 +1643,39 @@ static struct clk * gpio5_ick; static struct clk * gpio5_fck; #endif -#if defined(CONFIG_ARCH_OMAP3) -static struct clk *gpio_fclks[OMAP34XX_NR_GPIOS]; +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) static struct clk *gpio_iclks[OMAP34XX_NR_GPIOS]; #endif +static void __init omap_gpio_show_rev(void) +{ + u32 rev; + + if (cpu_is_omap16xx()) + rev = __raw_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION); + else if (cpu_is_omap24xx() || cpu_is_omap34xx()) + rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION); + else if (cpu_is_omap44xx()) + rev = __raw_readl(gpio_bank[0].base + OMAP4_GPIO_REVISION); + else + return; + + printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n", + (rev >> 4) & 0x0f, rev & 0x0f); +} + +/* 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 _omap_gpio_init(void) { int i; + int gpio = 0; struct gpio_bank *bank; -#if defined(CONFIG_ARCH_OMAP3) + int bank_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */ char clk_name[11]; -#endif initialized = 1; @@ -1279,8 +1721,8 @@ static int __init _omap_gpio_init(void) } #endif -#if defined(CONFIG_ARCH_OMAP3) - if (cpu_is_omap34xx()) { +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) + if (cpu_is_omap34xx() || cpu_is_omap44xx()) { for (i = 0; i < OMAP34XX_NR_GPIOS; i++) { sprintf(clk_name, "gpio%d_ick", i + 1); gpio_iclks[i] = clk_get(NULL, clk_name); @@ -1288,12 +1730,6 @@ static int __init _omap_gpio_init(void) printk(KERN_ERR "Could not get %s\n", clk_name); else clk_enable(gpio_iclks[i]); - sprintf(clk_name, "gpio%d_fck", i + 1); - gpio_fclks[i] = clk_get(NULL, clk_name); - if (IS_ERR(gpio_fclks[i])) - printk(KERN_ERR "Could not get %s\n", clk_name); - else - clk_enable(gpio_fclks[i]); } } #endif @@ -1301,70 +1737,62 @@ static int __init _omap_gpio_init(void) #ifdef CONFIG_ARCH_OMAP15XX if (cpu_is_omap15xx()) { - printk(KERN_INFO "OMAP1510 GPIO hardware\n"); gpio_bank_count = 2; gpio_bank = gpio_bank_1510; + bank_size = SZ_2K; } #endif #if defined(CONFIG_ARCH_OMAP16XX) if (cpu_is_omap16xx()) { - u32 rev; - gpio_bank_count = 5; gpio_bank = gpio_bank_1610; - rev = omap_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION); - printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n", - (rev >> 4) & 0x0f, rev & 0x0f); + bank_size = SZ_2K; } #endif -#ifdef CONFIG_ARCH_OMAP730 - if (cpu_is_omap730()) { - printk(KERN_INFO "OMAP730 GPIO hardware\n"); +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + if (cpu_is_omap7xx()) { gpio_bank_count = 7; - gpio_bank = gpio_bank_730; + gpio_bank = gpio_bank_7xx; + bank_size = SZ_2K; } #endif - -#ifdef CONFIG_ARCH_OMAP24XX +#ifdef CONFIG_ARCH_OMAP2 if (cpu_is_omap242x()) { - int rev; - gpio_bank_count = 4; gpio_bank = gpio_bank_242x; - rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION); - printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n", - (rev >> 4) & 0x0f, rev & 0x0f); } if (cpu_is_omap243x()) { - int rev; - gpio_bank_count = 5; gpio_bank = gpio_bank_243x; - rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION); - printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n", - (rev >> 4) & 0x0f, rev & 0x0f); } #endif -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 if (cpu_is_omap34xx()) { - int rev; - gpio_bank_count = OMAP34XX_NR_GPIOS; gpio_bank = gpio_bank_34xx; - rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION); - printk(KERN_INFO "OMAP34xx GPIO hardware version %d.%d\n", - (rev >> 4) & 0x0f, rev & 0x0f); + } +#endif +#ifdef CONFIG_ARCH_OMAP4 + if (cpu_is_omap44xx()) { + gpio_bank_count = OMAP34XX_NR_GPIOS; + gpio_bank = gpio_bank_44xx; } #endif for (i = 0; i < gpio_bank_count; i++) { int j, gpio_count = 16; bank = &gpio_bank[i]; - bank->reserved_map = 0; - bank->base = IO_ADDRESS(bank->base); spin_lock_init(&bank->lock); + + /* Static mapping, never released */ + bank->base = ioremap(bank->pbase, bank_size); + if (!bank->base) { + printk(KERN_ERR "Could not ioremap gpio bank%i\n", i); + continue; + } + if (bank_is_mpuio(bank)) - omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT); + __raw_writew(0xffff, bank->base + OMAP_MPUIO_GPIO_MASKIT); if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) { __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS); @@ -1374,32 +1802,84 @@ static int __init _omap_gpio_init(void) __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); __raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG); } - if (cpu_is_omap730() && bank->method == METHOD_GPIO_730) { - __raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK); - __raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS); + if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) { + __raw_writel(0xffffffff, bank->base + OMAP7XX_GPIO_INT_MASK); + __raw_writel(0x00000000, bank->base + OMAP7XX_GPIO_INT_STATUS); - gpio_count = 32; /* 730 has 32-bit GPIOs */ + gpio_count = 32; /* 7xx has 32-bit GPIOs */ } -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) - if (bank->method == METHOD_GPIO_24XX) { +#ifdef CONFIG_ARCH_OMAP2PLUS + if ((bank->method == METHOD_GPIO_24XX) || + (bank->method == METHOD_GPIO_44XX)) { static const u32 non_wakeup_gpios[] = { 0xe203ffc0, 0x08700040 }; - __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1); - __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1); - __raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG); - - /* Initialize interface clock ungated, module enabled */ - __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL); + if (cpu_is_omap44xx()) { + __raw_writel(0xffffffff, bank->base + + OMAP4_GPIO_IRQSTATUSCLR0); + __raw_writew(0x0015, bank->base + + OMAP4_GPIO_SYSCONFIG); + __raw_writel(0x00000000, bank->base + + OMAP4_GPIO_DEBOUNCENABLE); + /* + * Initialize interface clock ungated, + * module enabled + */ + __raw_writel(0, bank->base + OMAP4_GPIO_CTRL); + } else { + __raw_writel(0x00000000, bank->base + + OMAP24XX_GPIO_IRQENABLE1); + __raw_writel(0xffffffff, bank->base + + OMAP24XX_GPIO_IRQSTATUS1); + __raw_writew(0x0015, bank->base + + OMAP24XX_GPIO_SYSCONFIG); + __raw_writel(0x00000000, bank->base + + OMAP24XX_GPIO_DEBOUNCE_EN); + + /* + * Initialize interface clock ungated, + * module enabled + */ + __raw_writel(0, bank->base + + OMAP24XX_GPIO_CTRL); + } if (i < ARRAY_SIZE(non_wakeup_gpios)) bank->non_wakeup_gpios = non_wakeup_gpios[i]; gpio_count = 32; } #endif + + bank->mod_usage = 0; + /* REVISIT eventually switch from OMAP-specific gpio structs + * over to the generic ones + */ + bank->chip.request = omap_gpio_request; + bank->chip.free = omap_gpio_free; + bank->chip.direction_input = gpio_input; + bank->chip.get = gpio_get; + bank->chip.direction_output = gpio_output; + bank->chip.set = gpio_set; + bank->chip.to_irq = gpio_2irq; + if (bank_is_mpuio(bank)) { + bank->chip.label = "mpuio"; +#ifdef CONFIG_ARCH_OMAP16XX + bank->chip.dev = &omap_mpuio_device.dev; +#endif + bank->chip.base = OMAP_MPUIO(0); + } else { + bank->chip.label = "gpio"; + bank->chip.base = gpio; + gpio += gpio_count; + } + bank->chip.ngpio = gpio_count; + + gpiochip_add(&bank->chip); + for (j = bank->virtual_irq_start; j < bank->virtual_irq_start + gpio_count; j++) { + lockdep_set_class(&irq_desc[j].lock, &gpio_lock_class); set_irq_chip_data(j, bank); if (bank_is_mpuio(bank)) set_irq_chip(j, &mpuio_irq_chip); @@ -1410,6 +1890,13 @@ static int __init _omap_gpio_init(void) } set_irq_chained_handler(bank->irq, gpio_irq_handler); set_irq_data(bank->irq, bank); + + if (cpu_is_omap34xx() || cpu_is_omap44xx()) { + sprintf(clk_name, "gpio%d_dbck", i + 1); + bank->dbck = clk_get(NULL, clk_name); + if (IS_ERR(bank->dbck)) + printk(KERN_ERR "Could not get %s\n", clk_name); + } } /* Enable system clock for GPIO module. @@ -1423,10 +1910,12 @@ static int __init _omap_gpio_init(void) if (cpu_is_omap34xx()) omap_writel(1 << 0, 0x48306814); + omap_gpio_show_rev(); + return 0; } -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) { int i; @@ -1439,6 +1928,7 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) void __iomem *wake_status; void __iomem *wake_clear; void __iomem *wake_set; + unsigned long flags; switch (bank->method) { #ifdef CONFIG_ARCH_OMAP16XX @@ -1448,22 +1938,29 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: - wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA; + wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN; wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; break; #endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + wake_status = bank->base + OMAP4_GPIO_IRQWAKEN0; + wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; + wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; + break; +#endif default: continue; } - spin_lock(&bank->lock); + spin_lock_irqsave(&bank->lock, flags); bank->saved_wakeup = __raw_readl(wake_status); __raw_writel(0xffffffff, wake_clear); __raw_writel(bank->suspend_wakeup, wake_set); - spin_unlock(&bank->lock); + spin_unlock_irqrestore(&bank->lock, flags); } return 0; @@ -1473,13 +1970,14 @@ static int omap_gpio_resume(struct sys_device *dev) { int i; - if (!cpu_is_omap24xx() && !cpu_is_omap16xx()) + if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) return 0; for (i = 0; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; void __iomem *wake_clear; void __iomem *wake_set; + unsigned long flags; switch (bank->method) { #ifdef CONFIG_ARCH_OMAP16XX @@ -1488,20 +1986,26 @@ static int omap_gpio_resume(struct sys_device *dev) wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) case METHOD_GPIO_24XX: wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; break; #endif +#ifdef CONFIG_ARCH_OMAP4 + case METHOD_GPIO_44XX: + wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0; + wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0; + break; +#endif default: continue; } - spin_lock(&bank->lock); + spin_lock_irqsave(&bank->lock, flags); __raw_writel(0xffffffff, wake_clear); __raw_writel(bank->saved_wakeup, wake_set); - spin_unlock(&bank->lock); + spin_unlock_irqrestore(&bank->lock, flags); } return 0; @@ -1520,7 +2024,7 @@ static struct sys_device omap_gpio_device = { #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#ifdef CONFIG_ARCH_OMAP2PLUS static int workaround_enabled; @@ -1536,19 +2040,42 @@ void omap2_gpio_prepare_for_retention(void) if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) - bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); - l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); - l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); -#endif + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + bank->saved_datain = __raw_readl(bank->base + + OMAP24XX_GPIO_DATAIN); + l1 = __raw_readl(bank->base + + OMAP24XX_GPIO_FALLINGDETECT); + l2 = __raw_readl(bank->base + + OMAP24XX_GPIO_RISINGDETECT); + } + + if (cpu_is_omap44xx()) { + bank->saved_datain = __raw_readl(bank->base + + OMAP4_GPIO_DATAIN); + l1 = __raw_readl(bank->base + + OMAP4_GPIO_FALLINGDETECT); + l2 = __raw_readl(bank->base + + OMAP4_GPIO_RISINGDETECT); + } + bank->saved_fallingdetect = l1; bank->saved_risingdetect = l2; l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) - __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT); -#endif + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + __raw_writel(l1, bank->base + + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(l2, bank->base + + OMAP24XX_GPIO_RISINGDETECT); + } + + if (cpu_is_omap44xx()) { + __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); + __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); + } + c++; } if (!c) { @@ -1566,35 +2093,82 @@ void omap2_gpio_resume_after_retention(void) return; for (i = 0; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; - u32 l; + u32 l, gen, gen0, gen1; if (!(bank->enabled_non_wakeup_gpios)) continue; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) - __raw_writel(bank->saved_fallingdetect, + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + __raw_writel(bank->saved_fallingdetect, bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(bank->saved_risingdetect, + __raw_writel(bank->saved_risingdetect, bank->base + OMAP24XX_GPIO_RISINGDETECT); -#endif + l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); + } + + if (cpu_is_omap44xx()) { + __raw_writel(bank->saved_fallingdetect, + bank->base + OMAP4_GPIO_FALLINGDETECT); + __raw_writel(bank->saved_risingdetect, + bank->base + OMAP4_GPIO_RISINGDETECT); + l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN); + } + /* Check if any of the non-wakeup interrupt GPIOs have changed * state. If so, generate an IRQ by software. This is * horribly racy, but it's the best we can do to work around * this silicon bug. */ -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) - l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); -#endif l ^= bank->saved_datain; l &= bank->non_wakeup_gpios; - if (l) { + + /* + * No need to generate IRQs for the rising edge for gpio IRQs + * configured with falling edge only; and vice versa. + */ + gen0 = l & bank->saved_fallingdetect; + gen0 &= bank->saved_datain; + + gen1 = l & bank->saved_risingdetect; + gen1 &= ~(bank->saved_datain); + + /* FIXME: Consider GPIO IRQs with level detections properly! */ + gen = l & (~(bank->saved_fallingdetect) & + ~(bank->saved_risingdetect)); + /* Consider all GPIO IRQs needed to be updated */ + gen |= gen0 | gen1; + + if (gen) { u32 old0, old1; -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) - old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); - old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(old1 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT1); - __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0); - __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1); -#endif + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + old0 = __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT0); + old1 = __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT1); + __raw_writel(old0 | gen, bank->base + + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(old1 | gen, bank->base + + OMAP24XX_GPIO_LEVELDETECT1); + __raw_writel(old0, bank->base + + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(old1, bank->base + + OMAP24XX_GPIO_LEVELDETECT1); + } + + if (cpu_is_omap44xx()) { + old0 = __raw_readl(bank->base + + OMAP4_GPIO_LEVELDETECT0); + old1 = __raw_readl(bank->base + + OMAP4_GPIO_LEVELDETECT1); + __raw_writel(old0 | l, bank->base + + OMAP4_GPIO_LEVELDETECT0); + __raw_writel(old1 | l, bank->base + + OMAP4_GPIO_LEVELDETECT1); + __raw_writel(old0, bank->base + + OMAP4_GPIO_LEVELDETECT0); + __raw_writel(old1, bank->base + + OMAP4_GPIO_LEVELDETECT1); + } } } @@ -1602,6 +2176,81 @@ void omap2_gpio_resume_after_retention(void) #endif +#ifdef CONFIG_ARCH_OMAP3 +/* save the registers of bank 2-6 */ +void omap_gpio_save_context(void) +{ + int i; + + /* saving banks from 2-6 only since GPIO1 is in WKUP */ + for (i = 1; i < gpio_bank_count; i++) { + struct gpio_bank *bank = &gpio_bank[i]; + gpio_context[i].sysconfig = + __raw_readl(bank->base + OMAP24XX_GPIO_SYSCONFIG); + gpio_context[i].irqenable1 = + __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1); + gpio_context[i].irqenable2 = + __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2); + gpio_context[i].wake_en = + __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN); + gpio_context[i].ctrl = + __raw_readl(bank->base + OMAP24XX_GPIO_CTRL); + gpio_context[i].oe = + __raw_readl(bank->base + OMAP24XX_GPIO_OE); + gpio_context[i].leveldetect0 = + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); + gpio_context[i].leveldetect1 = + __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + gpio_context[i].risingdetect = + __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); + gpio_context[i].fallingdetect = + __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); + gpio_context[i].dataout = + __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT); + gpio_context[i].setwkuena = + __raw_readl(bank->base + OMAP24XX_GPIO_SETWKUENA); + gpio_context[i].setdataout = + __raw_readl(bank->base + OMAP24XX_GPIO_SETDATAOUT); + } +} + +/* restore the required registers of bank 2-6 */ +void omap_gpio_restore_context(void) +{ + int i; + + for (i = 1; i < gpio_bank_count; i++) { + struct gpio_bank *bank = &gpio_bank[i]; + __raw_writel(gpio_context[i].sysconfig, + bank->base + OMAP24XX_GPIO_SYSCONFIG); + __raw_writel(gpio_context[i].irqenable1, + bank->base + OMAP24XX_GPIO_IRQENABLE1); + __raw_writel(gpio_context[i].irqenable2, + bank->base + OMAP24XX_GPIO_IRQENABLE2); + __raw_writel(gpio_context[i].wake_en, + bank->base + OMAP24XX_GPIO_WAKE_EN); + __raw_writel(gpio_context[i].ctrl, + bank->base + OMAP24XX_GPIO_CTRL); + __raw_writel(gpio_context[i].oe, + bank->base + OMAP24XX_GPIO_OE); + __raw_writel(gpio_context[i].leveldetect0, + bank->base + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(gpio_context[i].leveldetect1, + bank->base + OMAP24XX_GPIO_LEVELDETECT1); + __raw_writel(gpio_context[i].risingdetect, + bank->base + OMAP24XX_GPIO_RISINGDETECT); + __raw_writel(gpio_context[i].fallingdetect, + bank->base + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(gpio_context[i].dataout, + bank->base + OMAP24XX_GPIO_DATAOUT); + __raw_writel(gpio_context[i].setwkuena, + bank->base + OMAP24XX_GPIO_SETWKUENA); + __raw_writel(gpio_context[i].setdataout, + bank->base + OMAP24XX_GPIO_SETDATAOUT); + } +} +#endif + /* * This may get called early from board specific init * for boards that have interrupts routed via FPGA. @@ -1623,7 +2272,7 @@ static int __init omap_gpio_sysinit(void) mpuio_init(); -#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) if (cpu_is_omap16xx() || cpu_class_is_omap2()) { if (ret == 0) { ret = sysdev_class_register(&omap_gpio_sysclass); @@ -1636,12 +2285,6 @@ static int __init omap_gpio_sysinit(void) return ret; } -EXPORT_SYMBOL(omap_request_gpio); -EXPORT_SYMBOL(omap_free_gpio); -EXPORT_SYMBOL(omap_set_gpio_direction); -EXPORT_SYMBOL(omap_set_gpio_dataout); -EXPORT_SYMBOL(omap_get_gpio_datain); - arch_initcall(omap_gpio_sysinit); @@ -1650,31 +2293,6 @@ arch_initcall(omap_gpio_sysinit); #include #include -static int gpio_is_input(struct gpio_bank *bank, int mask) -{ - void __iomem *reg = bank->base; - - switch (bank->method) { - case METHOD_MPUIO: - reg += OMAP_MPUIO_IO_CNTL; - break; - case METHOD_GPIO_1510: - reg += OMAP1510_GPIO_DIR_CONTROL; - break; - case METHOD_GPIO_1610: - reg += OMAP1610_GPIO_DIRECTION; - break; - case METHOD_GPIO_730: - reg += OMAP730_GPIO_DIR_CONTROL; - break; - case METHOD_GPIO_24XX: - reg += OMAP24XX_GPIO_OE; - break; - } - return __raw_readl(reg) & mask; -} - - static int dbg_gpio_show(struct seq_file *s, void *unused) { unsigned i, j, gpio; @@ -1686,28 +2304,34 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) if (bank_is_mpuio(bank)) gpio = OMAP_MPUIO(0); - else if (cpu_class_is_omap2() || cpu_is_omap730()) + else if (cpu_class_is_omap2() || cpu_is_omap7xx()) bankwidth = 32; for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) { unsigned irq, value, is_in, irqstat; + const char *label; - if (!(bank->reserved_map & mask)) + label = gpiochip_is_requested(&bank->chip, j); + if (!label) continue; irq = bank->virtual_irq_start + j; - value = omap_get_gpio_datain(gpio); + value = gpio_get_value(gpio); is_in = gpio_is_input(bank, mask); if (bank_is_mpuio(bank)) - seq_printf(s, "MPUIO %2d: ", j); + seq_printf(s, "MPUIO %2d ", j); else - seq_printf(s, "GPIO %3d: ", gpio); - seq_printf(s, "%s %s", + seq_printf(s, "GPIO %3d ", gpio); + seq_printf(s, "(%-20.20s): %s %s", + label, is_in ? "in " : "out", value ? "hi" : "lo"); +/* FIXME for at least omap2, show pullup/pulldown state */ + irqstat = irq_desc[irq].status; +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) if (is_in && ((bank->suspend_wakeup & mask) || irqstat & IRQ_TYPE_SENSE_MASK)) { char *trigger = NULL; @@ -1729,14 +2353,15 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) trigger = "high"; break; case IRQ_TYPE_NONE: - trigger = "(unspecified)"; + trigger = "(?)"; break; } - seq_printf(s, ", irq-%d %s%s", + seq_printf(s, ", irq-%d %-8s%s", irq, trigger, (bank->suspend_wakeup & mask) ? " wakeup" : ""); } +#endif seq_printf(s, "\n"); }