📄 gpio.c
字号:
/* * linux/arch/arm/plat-omap/gpio.c * * Support functions for OMAP GPIO * * Copyright (C) 2003-2005 Nokia Corporation * Written by Juha Yrjölä <juha.yrjola@nokia.com> * * 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. */#include <linux/init.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/sysdev.h>#include <linux/err.h>#include <linux/clk.h>#include <asm/hardware.h>#include <asm/irq.h>#include <asm/arch/irqs.h>#include <asm/arch/gpio.h>#include <asm/mach/irq.h>#include <asm/io.h>/* * OMAP1510 GPIO registers */#define OMAP1510_GPIO_BASE (void __iomem *)0xfffce000#define OMAP1510_GPIO_DATA_INPUT 0x00#define OMAP1510_GPIO_DATA_OUTPUT 0x04#define OMAP1510_GPIO_DIR_CONTROL 0x08#define OMAP1510_GPIO_INT_CONTROL 0x0c#define OMAP1510_GPIO_INT_MASK 0x10#define OMAP1510_GPIO_INT_STATUS 0x14#define OMAP1510_GPIO_PIN_CONTROL 0x18#define OMAP1510_IH_GPIO_BASE 64/* * 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_GPIO_REVISION 0x0000#define OMAP1610_GPIO_SYSCONFIG 0x0010#define OMAP1610_GPIO_SYSSTATUS 0x0014#define OMAP1610_GPIO_IRQSTATUS1 0x0018#define OMAP1610_GPIO_IRQENABLE1 0x001c#define OMAP1610_GPIO_WAKEUPENABLE 0x0028#define OMAP1610_GPIO_DATAIN 0x002c#define OMAP1610_GPIO_DATAOUT 0x0030#define OMAP1610_GPIO_DIRECTION 0x0034#define OMAP1610_GPIO_EDGE_CTRL1 0x0038#define OMAP1610_GPIO_EDGE_CTRL2 0x003c#define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c#define OMAP1610_GPIO_CLEAR_WAKEUPENA 0x00a8#define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0#define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc#define OMAP1610_GPIO_SET_WAKEUPENA 0x00e8#define OMAP1610_GPIO_SET_DATAOUT 0x00f0/* * OMAP730 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/* * 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 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 OMAP24XX_GPIO_REVISION 0x0000#define OMAP24XX_GPIO_SYSCONFIG 0x0010#define OMAP24XX_GPIO_SYSSTATUS 0x0014#define OMAP24XX_GPIO_IRQSTATUS1 0x0018#define OMAP24XX_GPIO_IRQSTATUS2 0x0028#define OMAP24XX_GPIO_IRQENABLE2 0x002c#define OMAP24XX_GPIO_IRQENABLE1 0x001c#define OMAP24XX_GPIO_CTRL 0x0030#define OMAP24XX_GPIO_OE 0x0034#define OMAP24XX_GPIO_DATAIN 0x0038#define OMAP24XX_GPIO_DATAOUT 0x003c#define OMAP24XX_GPIO_LEVELDETECT0 0x0040#define OMAP24XX_GPIO_LEVELDETECT1 0x0044#define OMAP24XX_GPIO_RISINGDETECT 0x0048#define OMAP24XX_GPIO_FALLINGDETECT 0x004c#define OMAP24XX_GPIO_CLEARIRQENABLE1 0x0060#define OMAP24XX_GPIO_SETIRQENABLE1 0x0064#define OMAP24XX_GPIO_CLEARWKUENA 0x0080#define OMAP24XX_GPIO_SETWKUENA 0x0084#define OMAP24XX_GPIO_CLEARDATAOUT 0x0090#define OMAP24XX_GPIO_SETDATAOUT 0x0094struct gpio_bank { void __iomem *base; u16 irq; u16 virtual_irq_start; int method; u32 reserved_map;#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX) u32 suspend_wakeup; u32 saved_wakeup;#endif#ifdef CONFIG_ARCH_OMAP24XX u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; u32 saved_datain; u32 saved_fallingdetect; u32 saved_risingdetect;#endif spinlock_t lock;};#define METHOD_MPUIO 0#define METHOD_GPIO_1510 1#define METHOD_GPIO_1610 2#define METHOD_GPIO_730 3#define METHOD_GPIO_24XX 4#ifdef CONFIG_ARCH_OMAP16XXstatic 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 },};#endif#ifdef CONFIG_ARCH_OMAP15XXstatic 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 }};#endif#ifdef CONFIG_ARCH_OMAP730static 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 },};#endif#ifdef CONFIG_ARCH_OMAP24XXstatic 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 },};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 },};#endifstatic struct gpio_bank *gpio_bank;static int gpio_bank_count;static inline struct gpio_bank *get_gpio_bank(int gpio){#ifdef CONFIG_ARCH_OMAP15XX if (cpu_is_omap15xx()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1]; }#endif#if defined(CONFIG_ARCH_OMAP16XX) if (cpu_is_omap16xx()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1 + (gpio >> 4)]; }#endif#ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1 + (gpio >> 5)]; }#endif#ifdef CONFIG_ARCH_OMAP24XX if (cpu_is_omap24xx()) return &gpio_bank[gpio >> 5];#endif}static inline int get_gpio_index(int gpio){#ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) return gpio & 0x1f;#endif#ifdef CONFIG_ARCH_OMAP24XX if (cpu_is_omap24xx()) return gpio & 0x1f;#endif return gpio & 0x0f;}static inline int gpio_valid(int gpio){ if (gpio < 0) return -1;#ifndef CONFIG_ARCH_OMAP24XX if (OMAP_GPIO_IS_MPUIO(gpio)) { if (gpio >= OMAP_MAX_GPIO_LINES + 16) return -1; return 0; }#endif#ifdef CONFIG_ARCH_OMAP15XX if (cpu_is_omap15xx() && gpio < 16) return 0;#endif#if defined(CONFIG_ARCH_OMAP16XX) if ((cpu_is_omap16xx()) && gpio < 64) return 0;#endif#ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730() && gpio < 192) return 0;#endif#ifdef CONFIG_ARCH_OMAP24XX if (cpu_is_omap24xx() && gpio < 128) return 0;#endif return -1;}static int check_gpio(int gpio){ if (unlikely(gpio_valid(gpio)) < 0) { printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio); dump_stack(); return -1; } return 0;}static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input){ void __iomem *reg = bank->base; u32 l; switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_IO_CNTL; break;#endif#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_DIR_CONTROL; break;#endif#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_DIRECTION; break;#endif#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_DIR_CONTROL; break;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_OE; break;#endif default: WARN_ON(1); return; } l = __raw_readl(reg); if (is_input) l |= 1 << gpio; else l &= ~(1 << gpio); __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; u32 l = 0; switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_OUTPUT; l = __raw_readl(reg); if (enable) l |= 1 << gpio; else l &= ~(1 << gpio); break;#endif#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_DATA_OUTPUT; l = __raw_readl(reg); if (enable) l |= 1 << gpio; else l &= ~(1 << gpio); break;#endif#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: if (enable) reg += OMAP1610_GPIO_SET_DATAOUT; else reg += OMAP1610_GPIO_CLEAR_DATAOUT; l = 1 << gpio; break;#endif#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_DATA_OUTPUT; l = __raw_readl(reg); if (enable) l |= 1 << gpio; else l &= ~(1 << gpio); break;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETDATAOUT; else reg += OMAP24XX_GPIO_CLEARDATAOUT; l = 1 << gpio; break;#endif default: WARN_ON(1); return; } __raw_writel(l, reg);}void omap_set_gpio_dataout(int gpio, int enable){ 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 case METHOD_MPUIO: reg += OMAP_MPUIO_INPUT_LATCH; break;#endif#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_DATA_INPUT; break;#endif#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_DATAIN; break;#endif#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_DATA_INPUT; break;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAIN; 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); \ if (set) l |= bit_mask; \ else l &= ~bit_mask; \ __raw_writel(l, base + reg); \} while(0)#ifdef CONFIG_ARCH_OMAP24XXstatic 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); 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); } 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. */}#endifstatic int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger){ void __iomem *reg = bank->base; u32 l = 0; switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_INT_EDGE; l = __raw_readl(reg); if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; break;#endif#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; l = __raw_readl(reg); if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; break;#endif#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: if (gpio & 0x08) reg += OMAP1610_GPIO_EDGE_CTRL2; else reg += OMAP1610_GPIO_EDGE_CTRL1; gpio &= 0x07; l = __raw_readl(reg); l &= ~(3 << (gpio << 1)); if (trigger & __IRQT_RISEDGE) l |= 2 << (gpio << 1); if (trigger & __IRQT_FALEDGE) l |= 1 << (gpio << 1); if (trigger) /* Enable wake-up during idle for dynamic tick */ __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA); else __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; l = __raw_readl(reg); if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; break;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: set_24xx_gpio_triggering(bank, gpio, trigger); break;#endif default: goto bad; } __raw_writel(l, reg); return 0;bad: return -EINVAL;}static int gpio_irq_type(unsigned irq, unsigned type){ struct gpio_bank *bank; unsigned gpio; int retval; if (!cpu_is_omap24xx() && irq > IH_MPUIO_BASE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -