📄 gpio.c
字号:
gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); else gpio = irq - IH_GPIO_BASE; if (check_gpio(gpio) < 0) return -EINVAL; if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; /* OMAP1 allows only only edge triggering */ if (!cpu_is_omap24xx() && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) return -EINVAL; bank = get_irq_chip_data(irq); spin_lock(&bank->lock); 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); return retval;}static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask){ void __iomem *reg = bank->base; switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: /* MPUIO irqstatus is reset by reading the status register, * so do nothing here */ return;#endif#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_STATUS; break;#endif#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_IRQSTATUS1; break;#endif#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_STATUS; break;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQSTATUS1; break;#endif default: WARN_ON(1); return; } __raw_writel(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ if (cpu_is_omap2420()) __raw_writel(gpio_mask, bank->base + OMAP24XX_GPIO_IRQSTATUS2);}static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio){ _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio));}static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank){ void __iomem *reg = bank->base; int inv = 0; u32 l; u32 mask; switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_MASKIT; mask = 0xffff; inv = 1; break;#endif#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_MASK; mask = 0xffff; inv = 1; break;#endif#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_IRQENABLE1; mask = 0xffff; break;#endif#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_MASK; mask = 0xffffffff; inv = 1; break;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQENABLE1; mask = 0xffffffff; break;#endif default: WARN_ON(1); return 0; } l = __raw_readl(reg); if (inv) l = ~l; l &= mask; return l;}static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable){ void __iomem *reg = bank->base; u32 l; switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_MASKIT; l = __raw_readl(reg); if (enable) l &= ~(gpio_mask); else l |= gpio_mask; break;#endif#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_MASK; l = __raw_readl(reg); if (enable) l &= ~(gpio_mask); else l |= gpio_mask; break;#endif#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: if (enable) reg += OMAP1610_GPIO_SET_IRQENABLE1; else reg += OMAP1610_GPIO_CLEAR_IRQENABLE1; l = gpio_mask; break;#endif#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_MASK; l = __raw_readl(reg); if (enable) l &= ~(gpio_mask); else l |= gpio_mask; break;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETIRQENABLE1; else reg += OMAP24XX_GPIO_CLEARIRQENABLE1; l = gpio_mask; break;#endif default: WARN_ON(1); return; } __raw_writel(l, reg);}static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable){ _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);}/* * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register. * 1510 does not seem to have a wake-up register. If JTAG is connected * to the target, system will wake up always on GPIO events. While * system is running all registered GPIO interrupts need to have wake-up * enabled. When system is suspended, only selected GPIO interrupts need * to have wake-up enabled. */static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable){ switch (bank->method) {#ifdef CONFIG_ARCH_OMAP16XX case METHOD_MPUIO: case METHOD_GPIO_1610: spin_lock(&bank->lock); if (enable) { bank->suspend_wakeup |= (1 << gpio); enable_irq_wake(bank->irq); } else { disable_irq_wake(bank->irq); bank->suspend_wakeup &= ~(1 << gpio); } spin_unlock(&bank->lock); return 0;#endif#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: 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) { bank->suspend_wakeup |= (1 << gpio); enable_irq_wake(bank->irq); } else { disable_irq_wake(bank->irq); bank->suspend_wakeup &= ~(1 << gpio); } spin_unlock(&bank->lock); return 0;#endif default: printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n", bank->method); return -EINVAL; }}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);}/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */static int gpio_wake_enable(unsigned int irq, unsigned int enable){ unsigned int gpio = irq - IH_GPIO_BASE; struct gpio_bank *bank; int retval; if (check_gpio(gpio) < 0) return -ENODEV; bank = get_irq_chip_data(irq); retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable); return retval;}int omap_request_gpio(int gpio){ struct gpio_bank *bank; 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)); /* 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);#ifdef CONFIG_ARCH_OMAP15XX if (bank->method == METHOD_GPIO_1510) { void __iomem *reg; /* Claim the pin for MPU */ reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg); }#endif spin_unlock(&bank->lock); return 0;}void omap_free_gpio(int gpio){ struct gpio_bank *bank; 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; }#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); }#endif#ifdef CONFIG_ARCH_OMAP24XX if (bank->method == METHOD_GPIO_24XX) { /* Disable wake-up during idle for dynamic tick */ void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA; __raw_writel(1 << get_gpio_index(gpio), reg); }#endif bank->reserved_map &= ~(1 << get_gpio_index(gpio)); _reset_gpio(bank, gpio); spin_unlock(&bank->lock);}/* * We need to unmask the GPIO bank interrupt as soon as possible to * avoid missing GPIO interrupts for other lines in the bank. * Then we need to mask-read-clear-unmask the triggered GPIO lines * in the bank to avoid missing nested interrupts for a GPIO line. * If we wait to unmask individual GPIO lines in the bank after the * line's interrupt handler has been run, we may miss some nested * interrupts. */static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc){ void __iomem *isr_reg = NULL; u32 isr; unsigned int gpio_irq; struct gpio_bank *bank; u32 retrigger = 0; int unmasked = 0; desc->chip->ack(irq); bank = get_irq_data(irq);#ifdef CONFIG_ARCH_OMAP1 if (bank->method == METHOD_MPUIO) isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;#endif#ifdef CONFIG_ARCH_OMAP15XX if (bank->method == METHOD_GPIO_1510) isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;#endif#if defined(CONFIG_ARCH_OMAP16XX) 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;#endif#ifdef CONFIG_ARCH_OMAP24XX if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;#endif while(1) { u32 isr_saved, level_mask = 0; u32 enabled; enabled = _get_gpio_irqbank_mask(bank); isr_saved = isr = __raw_readl(isr_reg) & enabled; if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) isr &= 0x0000ffff; if (cpu_is_omap24xx()) { level_mask = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) | __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); level_mask &= enabled; } /* clear edge sensitive interrupts before handler(s) are called so that we don't miss any interrupt occurred while executing them */ _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); /* if there is only edge sensitive GPIO pin interrupts configured, we could unmask GPIO bank interrupt immediately */ if (!level_mask && !unmasked) { unmasked = 1; desc->chip->unmask(irq); } isr |= retrigger; retrigger = 0; if (!isr) break; gpio_irq = bank->virtual_irq_start; for (; isr != 0; isr >>= 1, gpio_irq++) { struct irq_desc *d; int irq_mask; 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; } } if (cpu_is_omap24xx()) { /* 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); } } /* if bank has any level sensitive GPIO pin interrupt configured, we must unmask the bank interrupt only after handler(s) are executed in order to avoid spurious bank interrupt */ if (!unmasked) desc->chip->unmask(irq);}static void gpio_irq_shutdown(unsigned int irq){ unsigned int gpio = irq - IH_GPIO_BASE; struct gpio_bank *bank = get_irq_chip_data(irq); _reset_gpio(bank, gpio);}static void gpio_ack_irq(unsigned int irq){ unsigned int gpio = irq - IH_GPIO_BASE; struct gpio_bank *bank = get_irq_chip_data(irq); _clear_gpio_irqstatus(bank, gpio);}static void gpio_mask_irq(unsigned int irq){ unsigned int gpio = irq - IH_GPIO_BASE; struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio, 0);}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); _set_gpio_irqenable(bank, gpio_idx, 1);}static struct irq_chip gpio_irq_chip = { .name = "GPIO", .shutdown = gpio_irq_shutdown, .ack = gpio_ack_irq, .mask = gpio_mask_irq, .unmask = gpio_unmask_irq, .set_type = gpio_irq_type, .set_wake = gpio_wake_enable,};/*---------------------------------------------------------------------*/#ifdef CONFIG_ARCH_OMAP1/* MPUIO uses the always-on 32k clock */static void mpuio_ack_irq(unsigned int irq){ /* The ISR is reset automatically, so do nothing here. */}static void mpuio_mask_irq(unsigned int irq){ unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio, 0);}static void mpuio_unmask_irq(unsigned int irq){ unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio, 1);}static struct irq_chip mpuio_irq_chip = { .name = "MPUIO", .ack = mpuio_ack_irq, .mask = mpuio_mask_irq, .unmask = mpuio_unmask_irq, .set_type = gpio_irq_type,#ifdef CONFIG_ARCH_OMAP16XX /* REVISIT: assuming only 16xx supports MPUIO wake events */ .set_wake = gpio_wake_enable,#endif};#define bank_is_mpuio(bank) ((bank)->method == METHOD_MPUIO)#ifdef CONFIG_ARCH_OMAP16XX#include <linux/platform_device.h>static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg){ struct gpio_bank *bank = platform_get_drvdata(pdev); void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT; spin_lock(&bank->lock); bank->saved_wakeup = __raw_readl(mask_reg); __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -