diff options
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
| -rw-r--r-- | drivers/gpio/gpio-omap.c | 608 |
1 files changed, 357 insertions, 251 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f1fbedb2a6f..00f29aa1fb9 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -24,12 +24,11 @@ #include <linux/pm.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> #include <linux/gpio.h> +#include <linux/bitops.h> #include <linux/platform_data/gpio-omap.h> -#include <asm/mach/irq.h> - #define OFF_MODE 1 static LIST_HEAD(omap_gpio_list); @@ -53,8 +52,6 @@ struct gpio_bank { struct list_head node; void __iomem *base; u16 irq; - int irq_base; - struct irq_domain *domain; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; @@ -65,12 +62,14 @@ struct gpio_bank { struct gpio_chip chip; struct clk *dbck; u32 mod_usage; + u32 irq_usage; u32 dbck_enable_mask; bool dbck_enabled; struct device *dev; bool is_mpuio; bool dbck_flag; bool loses_context; + bool context_valid; int stride; u32 width; int context_loss_count; @@ -84,12 +83,21 @@ struct gpio_bank { }; #define GPIO_INDEX(bank, gpio) (gpio % bank->width) -#define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio)) +#define GPIO_BIT(bank, gpio) (BIT(GPIO_INDEX(bank, gpio))) #define GPIO_MOD_CTRL_BIT BIT(0) +#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage) +#define LINE_USED(line, offset) (line & (BIT(offset))) + static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) { - return gpio_irq - bank->irq_base + bank->chip.base; + return bank->chip.base + gpio_irq; +} + +static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + return container_of(chip, struct gpio_bank, chip); } static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) @@ -98,12 +106,12 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) u32 l; reg += bank->regs->direction; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (is_input) - l |= 1 << gpio; + l |= BIT(gpio); else - l &= ~(1 << gpio); - __raw_writel(l, reg); + l &= ~(BIT(gpio)); + writel_relaxed(l, reg); bank->context.oe = l; } @@ -122,7 +130,7 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable) bank->context.dataout &= ~l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } /* set data out value using mask register */ @@ -132,12 +140,12 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) u32 gpio_bit = GPIO_BIT(bank, gpio); u32 l; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (enable) l |= gpio_bit; else l &= ~gpio_bit; - __raw_writel(l, reg); + writel_relaxed(l, reg); bank->context.dataout = l; } @@ -145,35 +153,35 @@ static int _get_gpio_datain(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->datain; - return (__raw_readl(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (BIT(offset))) != 0; } static int _get_gpio_dataout(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->dataout; - return (__raw_readl(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (BIT(offset))) != 0; } static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) { - int l = __raw_readl(base + reg); + int l = readl_relaxed(base + reg); if (set) l |= mask; else l &= ~mask; - __raw_writel(l, base + reg); + writel_relaxed(l, base + reg); } static inline void _gpio_dbck_enable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && !bank->dbck_enabled) { - clk_enable(bank->dbck); + clk_prepare_enable(bank->dbck); bank->dbck_enabled = true; - __raw_writel(bank->dbck_enable_mask, + writel_relaxed(bank->dbck_enable_mask, bank->base + bank->regs->debounce_en); } } @@ -186,9 +194,9 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank) * enabled but the clock is not, GPIO module seems to be unable * to detect events and generate interrupts at least on OMAP3. */ - __raw_writel(0, bank->base + bank->regs->debounce_en); + writel_relaxed(0, bank->base + bank->regs->debounce_en); - clk_disable(bank->dbck); + clk_disable_unprepare(bank->dbck); bank->dbck_enabled = false; } } @@ -221,12 +229,12 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, l = GPIO_BIT(bank, gpio); - clk_enable(bank->dbck); + clk_prepare_enable(bank->dbck); reg = bank->base + bank->regs->debounce; - __raw_writel(debounce, reg); + writel_relaxed(debounce, reg); reg = bank->base + bank->regs->debounce_en; - val = __raw_readl(reg); + val = readl_relaxed(reg); if (debounce) val |= l; @@ -234,8 +242,8 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, val &= ~l; bank->dbck_enable_mask = val; - __raw_writel(val, reg); - clk_disable(bank->dbck); + writel_relaxed(val, reg); + clk_disable_unprepare(bank->dbck); /* * Enable debounce clock per module. * This call is mandatory because in omap_gpio_request() when @@ -273,14 +281,14 @@ static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) bank->dbck_enable_mask &= ~gpio_bit; bank->context.debounce_en &= ~gpio_bit; - __raw_writel(bank->context.debounce_en, + writel_relaxed(bank->context.debounce_en, bank->base + bank->regs->debounce_en); if (!bank->dbck_enable_mask) { bank->context.debounce = 0; - __raw_writel(bank->context.debounce, bank->base + + writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - clk_disable(bank->dbck); + clk_disable_unprepare(bank->dbck); bank->dbck_enabled = false; } } @@ -289,7 +297,7 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, unsigned trigger) { void __iomem *base = bank->base; - u32 gpio_bit = 1 << gpio; + u32 gpio_bit = BIT(gpio); _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, trigger & IRQ_TYPE_LEVEL_LOW); @@ -301,18 +309,18 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, trigger & IRQ_TYPE_EDGE_FALLING); bank->context.leveldetect0 = - __raw_readl(bank->base + bank->regs->leveldetect0); + readl_relaxed(bank->base + bank->regs->leveldetect0); bank->context.leveldetect1 = - __raw_readl(bank->base + bank->regs->leveldetect1); + readl_relaxed(bank->base + bank->regs->leveldetect1); bank->context.risingdetect = - __raw_readl(bank->base + bank->regs->risingdetect); + readl_relaxed(bank->base + bank->regs->risingdetect); bank->context.fallingdetect = - __raw_readl(bank->base + bank->regs->fallingdetect); + readl_relaxed(bank->base + bank->regs->fallingdetect); if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); + readl_relaxed(bank->base + bank->regs->wkup_en); } /* This part needs to be executed always for OMAP{34xx, 44xx} */ @@ -337,8 +345,8 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, exit: bank->level_mask = - __raw_readl(bank->base + bank->regs->leveldetect0) | - __raw_readl(bank->base + bank->regs->leveldetect1); + readl_relaxed(bank->base + bank->regs->leveldetect0) | + readl_relaxed(bank->base + bank->regs->leveldetect1); } #ifdef CONFIG_ARCH_OMAP1 @@ -356,13 +364,13 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) reg += bank->regs->irqctrl; - l = __raw_readl(reg); + l = readl_relaxed(reg); if ((l >> gpio) & 1) - l &= ~(1 << gpio); + l &= ~(BIT(gpio)); else - l |= 1 << gpio; + l |= BIT(gpio); - __raw_writel(l, reg); + writel_relaxed(l, reg); } #else static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} @@ -380,17 +388,17 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, } else if (bank->regs->irqctrl) { reg += bank->regs->irqctrl; - l = __raw_readl(reg); + l = readl_relaxed(reg); if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) - bank->toggle_mask |= 1 << gpio; + bank->toggle_mask |= BIT(gpio); if (trigger & IRQ_TYPE_EDGE_RISING) - l |= 1 << gpio; + l |= BIT(gpio); else if (trigger & IRQ_TYPE_EDGE_FALLING) - l &= ~(1 << gpio); + l &= ~(BIT(gpio)); else return -EINVAL; - __raw_writel(l, reg); + writel_relaxed(l, reg); } else if (bank->regs->edgectrl1) { if (gpio & 0x08) reg += bank->regs->edgectrl2; @@ -398,28 +406,85 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, reg += bank->regs->edgectrl1; gpio &= 0x07; - l = __raw_readl(reg); + l = readl_relaxed(reg); l &= ~(3 << (gpio << 1)); if (trigger & IRQ_TYPE_EDGE_RISING) l |= 2 << (gpio << 1); if (trigger & IRQ_TYPE_EDGE_FALLING) - l |= 1 << (gpio << 1); + l |= BIT(gpio << 1); /* Enable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger); + _gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); - __raw_writel(l, reg); + readl_relaxed(bank->base + bank->regs->wkup_en); + writel_relaxed(l, reg); } return 0; } +static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset) +{ + if (bank->regs->pinctrl) { + void __iomem *reg = bank->base + bank->regs->pinctrl; + + /* Claim the pin for MPU */ + writel_relaxed(readl_relaxed(reg) | (BIT(offset)), reg); + } + + if (bank->regs->ctrl && !BANK_USED(bank)) { + void __iomem *reg = bank->base + bank->regs->ctrl; + u32 ctrl; + + ctrl = readl_relaxed(reg); + /* Module is enabled, clocks are not gated */ + ctrl &= ~GPIO_MOD_CTRL_BIT; + writel_relaxed(ctrl, reg); + bank->context.ctrl = ctrl; + } +} + +static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset) +{ + void __iomem *base = bank->base; + + if (bank->regs->wkup_en && + !LINE_USED(bank->mod_usage, offset) && + !LINE_USED(bank->irq_usage, offset)) { + /* Disable wake-up during idle for dynamic tick */ + _gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0); + bank->context.wake_en = + readl_relaxed(bank->base + bank->regs->wkup_en); + } + + if (bank->regs->ctrl && !BANK_USED(bank)) { + void __iomem *reg = bank->base + bank->regs->ctrl; + u32 ctrl; + + ctrl = readl_relaxed(reg); + /* Module is disabled, clocks are gated */ + ctrl |= GPIO_MOD_CTRL_BIT; + writel_relaxed(ctrl, reg); + bank->context.ctrl = ctrl; + } +} + +static int gpio_is_input(struct gpio_bank *bank, int mask) +{ + void __iomem *reg = bank->base + bank->regs->direction; + + return readl_relaxed(reg) & mask; +} + static int gpio_irq_type(struct irq_data *d, unsigned type) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned gpio = 0; int retval; unsigned long flags; + unsigned offset; + + if (!BANK_USED(bank)) + pm_runtime_get_sync(bank->dev); #ifdef CONFIG_ARCH_OMAP1 if (d->irq > IH_MPUIO_BASE) @@ -427,7 +492,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) #endif if (!gpio) - gpio = irq_to_gpio(bank, d->irq); + gpio = irq_to_gpio(bank, d->hwirq); if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -437,7 +502,17 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) return -EINVAL; spin_lock_irqsave(&bank->lock, flags); - retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type); + offset = GPIO_INDEX(bank, gpio); + retval = _set_gpio_triggering(bank, offset, type); + if (!LINE_USED(bank->mod_usage, offset)) { + _enable_gpio_module(bank, offset); + _set_gpio_direction(bank, offset, 1); + } else if (!gpio_is_input(bank, BIT(offset))) { + spin_unlock_irqrestore(&bank->lock, flags); + return -EINVAL; + } + + bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio)); spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) @@ -453,16 +528,16 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) void __iomem *reg = bank->base; reg += bank->regs->irqstatus; - __raw_writel(gpio_mask, reg); + writel_relaxed(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ if (bank->regs->irqstatus2) { reg = bank->base + bank->regs->irqstatus2; - __raw_writel(gpio_mask, reg); + writel_relaxed(gpio_mask, reg); } /* Flush posted write for the irq status to avoid spurious interrupts */ - __raw_readl(reg); + readl_relaxed(reg); } static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) @@ -474,10 +549,10 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) { void __iomem *reg = bank->base; u32 l; - u32 mask = (1 << bank->width) - 1; + u32 mask = (BIT(bank->width)) - 1; reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l = ~l; l &= mask; @@ -495,7 +570,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 |= gpio_mask; } else { reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l &= ~gpio_mask; else @@ -503,7 +578,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 = l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) @@ -517,7 +592,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 &= ~gpio_mask; } else { reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l |= gpio_mask; else @@ -525,7 +600,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 = l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) @@ -561,7 +636,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) else bank->context.wake_en &= ~gpio_bit; - __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en); + writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -579,8 +654,8 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int gpio_wake_enable(struct irq_data *d, unsigned int enable) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + struct gpio_bank *bank = _irq_data_get_bank(d); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); return _set_gpio_wakeup(bank, gpio, enable); } @@ -594,35 +669,19 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) * If this is the first gpio_request for the bank, * enable the bank module. */ - if (!bank->mod_usage) + if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); spin_lock_irqsave(&bank->lock, flags); /* Set trigger to none. You need to enable the desired trigger with - * request_irq() or set_irq_type(). + * request_irq() or set_irq_type(). Only do this if the IRQ line has + * not already been requested. */ - _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - - if (bank->regs->pinctrl) { - void __iomem *reg = bank->base + bank->regs->pinctrl; - - /* Claim the pin for MPU */ - __raw_writel(__raw_readl(reg) | (1 << offset), reg); + if (!LINE_USED(bank->irq_usage, offset)) { + _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + _enable_gpio_module(bank, offset); } - - if (bank->regs->ctrl && !bank->mod_usage) { - void __iomem *reg = bank->base + bank->regs->ctrl; - u32 ctrl; - - ctrl = __raw_readl(reg); - /* Module is enabled, clocks are not gated */ - ctrl &= ~GPIO_MOD_CTRL_BIT; - __raw_writel(ctrl, reg); - bank->context.ctrl = ctrl; - } - - bank->mod_usage |= 1 << offset; - + bank->mod_usage |= BIT(offset); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -631,31 +690,11 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); - void __iomem *base = bank->base; unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - - if (bank->regs->wkup_en) { - /* Disable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); - bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); - } - - bank->mod_usage &= ~(1 << offset); - - if (bank->regs->ctrl && !bank->mod_usage) { - void __iomem *reg = bank->base + bank->regs->ctrl; - u32 ctrl; - - ctrl = __raw_readl(reg); - /* Module is disabled, clocks are gated */ - ctrl |= GPIO_MOD_CTRL_BIT; - __raw_writel(ctrl, reg); - bank->context.ctrl = ctrl; - } - + bank->mod_usage &= ~(BIT(offset)); + _disable_gpio_module(bank, offset); _reset_gpio(bank, bank->chip.base + offset); spin_unlock_irqrestore(&bank->lock, flags); @@ -663,7 +702,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) * If this is the last gpio to be freed in the bank, * disable the bank module. */ - if (!bank->mod_usage) + if (!BANK_USED(bank)) pm_runtime_put(bank->dev); } @@ -680,26 +719,27 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *isr_reg = NULL; u32 isr; - unsigned int gpio_irq, gpio_index; + unsigned int bit; struct gpio_bank *bank; int unmasked = 0; - struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_get_handler_data(irq); - chained_irq_enter(chip, desc); + chained_irq_enter(irqchip, desc); - bank = irq_get_handler_data(irq); + bank = container_of(chip, struct gpio_bank, chip); isr_reg = bank->base + bank->regs->irqstatus; pm_runtime_get_sync(bank->dev); if (WARN_ON(!isr_reg)) goto exit; - while(1) { + while (1) { u32 isr_saved, level_mask = 0; u32 enabled; enabled = _get_gpio_irqbank_mask(bank); - isr_saved = isr = __raw_readl(isr_reg) & enabled; + isr_saved = isr = readl_relaxed(isr_reg) & enabled; if (bank->level_mask) level_mask = bank->level_mask & enabled; @@ -715,20 +755,15 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) configured, we could unmask GPIO bank interrupt immediately */ if (!level_mask && !unmasked) { unmasked = 1; - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); } if (!isr) break; - gpio_irq = bank->irq_base; - for (; isr != 0; isr >>= 1, gpio_irq++) { - int gpio = irq_to_gpio(bank, gpio_irq); - - if (!(isr & 1)) - continue; - - gpio_index = GPIO_INDEX(bank, gpio); + while (isr) { + bit = __ffs(isr); + isr &= ~(BIT(bit)); /* * Some chips can't respond to both rising and falling @@ -737,10 +772,11 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) * 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); + if (bank->toggle_mask & (BIT(bit))) + _toggle_gpio_edge_triggering(bank, bit); - generic_handle_irq(gpio_irq); + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, + bit)); } } /* if bank has any level sensitive GPIO pin interrupt @@ -749,33 +785,44 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) interrupt */ exit: if (!unmasked) - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); pm_runtime_put(bank->dev); } static void gpio_irq_shutdown(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + struct gpio_bank *bank = _irq_data_get_bank(d); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; + unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); + gpio_unlock_as_irq(&bank->chip, offset); + bank->irq_usage &= ~(BIT(offset)); + _disable_gpio_module(bank, offset); _reset_gpio(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); + + /* + * If this is the last IRQ to be freed in the bank, + * disable the bank module. + */ + if (!BANK_USED(bank)) + pm_runtime_put(bank->dev); } static void gpio_ack_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + struct gpio_bank *bank = _irq_data_get_bank(d); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); _clear_gpio_irqstatus(bank, gpio); } static void gpio_mask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + struct gpio_bank *bank = _irq_data_get_bank(d); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; spin_lock_irqsave(&bank->lock, flags); @@ -786,8 +833,8 @@ static void gpio_mask_irq(struct irq_data *d) static void gpio_unmask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); - unsigned int gpio = irq_to_gpio(bank, d->irq); + struct gpio_bank *bank = _irq_data_get_bank(d); + unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned int irq_mask = GPIO_BIT(bank, gpio); u32 trigger = irqd_get_trigger_type(d); unsigned long flags; @@ -828,7 +875,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(0xffff & ~bank->context.wake_en, mask_reg); + writel_relaxed(0xffff & ~bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -843,7 +890,7 @@ static int omap_mpuio_resume_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(bank->context.wake_en, mask_reg); + writel_relaxed(bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -881,23 +928,31 @@ static inline void mpuio_init(struct gpio_bank *bank) /*---------------------------------------------------------------------*/ -static int gpio_input(struct gpio_chip *chip, unsigned offset) +static int gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; unsigned long flags; + void __iomem *reg; + int dir; bank = container_of(chip, struct gpio_bank, chip); + reg = bank->base + bank->regs->direction; spin_lock_irqsave(&bank->lock, flags); - _set_gpio_direction(bank, offset, 1); + dir = !!(readl_relaxed(reg) & BIT(offset)); spin_unlock_irqrestore(&bank->lock, flags); - return 0; + return dir; } -static int gpio_is_input(struct gpio_bank *bank, int mask) +static int gpio_input(struct gpio_chip *chip, unsigned offset) { - void __iomem *reg = bank->base + bank->regs->direction; + struct gpio_bank *bank; + unsigned long flags; - return __raw_readl(reg) & mask; + 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_get(struct gpio_chip *chip, unsigned offset) @@ -906,7 +961,7 @@ static int gpio_get(struct gpio_chip *chip, unsigned offset) u32 mask; bank = container_of(chip, struct gpio_bank, chip); - mask = (1 << offset); + mask = (BIT(offset)); if (gpio_is_input(bank, mask)) return _get_gpio_datain(bank, offset); @@ -953,14 +1008,6 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int 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->irq_base + offset; -} - /*---------------------------------------------------------------------*/ static void __init omap_gpio_show_rev(struct gpio_bank *bank) @@ -971,7 +1018,7 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank) if (called || bank->regs->revision == USHRT_MAX) return; - rev = __raw_readw(bank->base + bank->regs->revision); + rev = readw_relaxed(bank->base + bank->regs->revision); pr_info("OMAP GPIO hardware version %d.%d\n", (rev >> 4) & 0x0f, rev & 0x0f); @@ -992,20 +1039,20 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) l = 0xffff; if (bank->is_mpuio) { - __raw_writel(l, bank->base + bank->regs->irqenable); + writel_relaxed(l, bank->base + bank->regs->irqenable); return; } _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv); _gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv); if (bank->regs->debounce_en) - __raw_writel(0, base + bank->regs->debounce_en); + writel_relaxed(0, base + bank->regs->debounce_en); /* Save OE default value (0xffffffff) in the context */ - bank->context.oe = __raw_readl(bank->base + bank->regs->direction); + bank->context.oe = readl_relaxed(bank->base + bank->regs->direction); /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl) - __raw_writel(0, base + bank->regs->ctrl); + writel_relaxed(0, base + bank->regs->ctrl); bank->dbck = clk_get(bank->dev, "dbclk"); if (IS_ERR(bank->dbck)) @@ -1034,17 +1081,19 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, ct->chip.irq_set_type = gpio_irq_type; if (bank->regs->wkup_en) - ct->chip.irq_set_wake = gpio_wake_enable, + ct->chip.irq_set_wake = gpio_wake_enable; ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static void omap_gpio_chip_init(struct gpio_bank *bank) +static int omap_gpio_chip_init(struct gpio_bank *bank) { int j; static int gpio; + int irq_base = 0; + int ret; /* * REVISIT eventually switch from OMAP-specific gpio structs @@ -1052,12 +1101,12 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) */ bank->chip.request = omap_gpio_request; bank->chip.free = omap_gpio_free; + bank->chip.get_direction = gpio_get_direction; bank->chip.direction_input = gpio_input; bank->chip.get = gpio_get; bank->chip.direction_output = gpio_output; bank->chip.set_debounce = gpio_debounce; bank->chip.set = gpio_set; - bank->chip.to_irq = gpio_2irq; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1070,21 +1119,48 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) } bank->chip.ngpio = bank->width; - gpiochip_add(&bank->chip); + ret = gpiochip_add(&bank->chip); + if (ret) { + dev_err(bank->dev, "Could not register gpio chip %d\n", ret); + return ret; + } + +#ifdef CONFIG_ARCH_OMAP1 + /* + * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop + * irq_alloc_descs() since a base IRQ offset will no longer be needed. + */ + irq_base = irq_alloc_descs(-1, 0, bank->width, 0); + if (irq_base < 0) { + dev_err(bank->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } +#endif + + ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip, + irq_base, gpio_irq_handler, + IRQ_TYPE_NONE); + + if (ret) { + dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret); + ret = gpiochip_remove(&bank->chip); + return -ENODEV; + } + + gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip, + bank->irq, gpio_irq_handler); - for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) { - irq_set_lockdep_class(j, &gpio_lock_class); - irq_set_chip_data(j, bank); + for (j = 0; j < bank->width; j++) { + int irq = irq_find_mapping(bank->chip.irqdomain, j); + irq_set_lockdep_class(irq, &gpio_lock_class); if (bank->is_mpuio) { - omap_mpuio_alloc_gc(bank, j, bank->width); - } else { - irq_set_chip(j, &gpio_irq_chip); - irq_set_handler(j, handle_simple_irq); - set_irq_flags(j, IRQF_VALID); + omap_mpuio_alloc_gc(bank, irq, bank->width); + irq_set_chip_and_handler(irq, NULL, NULL); + set_irq_flags(irq, 0); } } - irq_set_chained_handler(bank->irq, gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); + + return 0; } static const struct of_device_id omap_gpio_match[]; @@ -1097,11 +1173,11 @@ static int omap_gpio_probe(struct platform_device *pdev) const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; - int ret = 0; + int ret; match = of_match_device(of_match_ptr(omap_gpio_match), dev); - pdata = match ? match->data : dev->platform_data; + pdata = match ? match->data : dev_get_platdata(dev); if (!pdata) return -EINVAL; @@ -1119,26 +1195,27 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->irq = res->start; bank->dev = dev; + bank->chip.dev = dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; bank->is_mpuio = pdata->is_mpuio; bank->non_wakeup_gpios = pdata->non_wakeup_gpios; - bank->loses_context = pdata->loses_context; bank->regs = pdata->regs; #ifdef CONFIG_OF_GPIO bank->chip.of_node = of_node_get(node); #endif + if (node) { + if (!of_property_read_bool(node, "ti,gpio-always-on")) + bank->loses_context = true; + } else { + bank->loses_context = pdata->loses_context; - bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0); - if (bank->irq_base < 0) { - dev_err(dev, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; + if (bank->loses_context) + bank->get_context_loss_count = + pdata->get_context_loss_count; } - bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base, - 0, &irq_domain_simple_ops, NULL); - if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = _set_gpio_dataout_reg; else @@ -1148,21 +1225,10 @@ static int omap_gpio_probe(struct platform_device *pdev) /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!res)) { - dev_err(dev, "Invalid mem resource\n"); - return -ENODEV; - } - - if (!devm_request_mem_region(dev, res->start, resource_size(res), - pdev->name)) { - dev_err(dev, "Region already claimed\n"); - return -EBUSY; - } - - bank->base = devm_ioremap(dev, res->start, resource_size(res)); - if (!bank->base) { - dev_err(dev, "Could not ioremap\n"); - return -ENOMEM; + bank->base = devm_ioremap_resource(dev, res); + if (IS_ERR(bank->base)) { + irq_domain_remove(bank->chip.irqdomain); + return PTR_ERR(bank->base); } platform_set_drvdata(pdev, bank); @@ -1175,17 +1241,18 @@ static int omap_gpio_probe(struct platform_device *pdev) mpuio_init(bank); omap_gpio_mod_init(bank); - omap_gpio_chip_init(bank); - omap_gpio_show_rev(bank); - if (bank->loses_context) - bank->get_context_loss_count = pdata->get_context_loss_count; + ret = omap_gpio_chip_init(bank); + if (ret) + return ret; + + omap_gpio_show_rev(bank); pm_runtime_put(bank->dev); list_add_tail(&bank->node, &omap_gpio_list); - return ret; + return 0; } #ifdef CONFIG_ARCH_OMAP2PLUS @@ -1216,11 +1283,11 @@ static int omap_gpio_runtime_suspend(struct device *dev) */ wake_low = bank->context.leveldetect0 & bank->context.wake_en; if (wake_low) - __raw_writel(wake_low | bank->context.fallingdetect, + writel_relaxed(wake_low | bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); wake_hi = bank->context.leveldetect1 & bank->context.wake_en; if (wake_hi) - __raw_writel(wake_hi | bank->context.risingdetect, + writel_relaxed(wake_hi | bank->context.risingdetect, bank->base + bank->regs->risingdetect); if (!bank->enabled_non_wakeup_gpios) @@ -1235,7 +1302,7 @@ static int omap_gpio_runtime_suspend(struct device *dev) * non-wakeup GPIOs. Otherwise spurious IRQs will be * generated. See OMAP2420 Errata item 1.101. */ - bank->saved_datain = __raw_readl(bank->base + + bank->saved_datain = readl_relaxed(bank->base + bank->regs->datain); l1 = bank->context.fallingdetect; l2 = bank->context.risingdetect; @@ -1243,8 +1310,8 @@ static int omap_gpio_runtime_suspend(struct device *dev) l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; - __raw_writel(l1, bank->base + bank->regs->fallingdetect); - __raw_writel(l2, bank->base + bank->regs->risingdetect); + writel_relaxed(l1, bank->base + bank->regs->fallingdetect); + writel_relaxed(l2, bank->base + bank->regs->risingdetect); bank->workaround_enabled = true; @@ -1259,15 +1326,31 @@ update_gpio_context_count: return 0; } +static void omap_gpio_init_context(struct gpio_bank *p); + static int omap_gpio_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct gpio_bank *bank = platform_get_drvdata(pdev); - int context_lost_cnt_after; u32 l = 0, gen, gen0, gen1; unsigned long flags; + int c; spin_lock_irqsave(&bank->lock, flags); + + /* + * On the first resume during the probe, the context has not + * been initialised and so initialise it now. Also initialise + * the context loss count. + */ + if (bank->loses_context && !bank->context_valid) { + omap_gpio_init_context(bank); + + if (bank->get_context_loss_count) + bank->context_loss_count = + bank->get_context_loss_count(bank->dev); + } + _gpio_dbck_enable(bank); /* @@ -1276,19 +1359,22 @@ static int omap_gpio_runtime_resume(struct device *dev) * generate a PRCM wakeup. Here we restore the * pre-runtime_suspend() values for edge triggering. */ - __raw_writel(bank->context.fallingdetect, + writel_relaxed(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); - __raw_writel(bank->context.risingdetect, + writel_relaxed(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - if (bank->get_context_loss_count) { - context_lost_cnt_after = - bank->get_context_loss_count(bank->dev); - if (context_lost_cnt_after != bank->context_loss_count) { + if (bank->loses_context) { + if (!bank->get_context_loss_count) { omap_gpio_restore_context(bank); } else { - spin_unlock_irqrestore(&bank->lock, flags); - return 0; + c = bank->get_context_loss_count(bank->dev); + if (c != bank->context_loss_count) { + omap_gpio_restore_context(bank); + } else { + spin_unlock_irqrestore(&bank->lock, flags); + return 0; + } } } @@ -1297,11 +1383,7 @@ static int omap_gpio_runtime_resume(struct device *dev) return 0; } - __raw_writel(bank->context.fallingdetect, - bank->base + bank->regs->fallingdetect); - __raw_writel(bank->context.risingdetect, - bank->base + bank->regs->risingdetect); - l = __raw_readl(bank->base + bank->regs->datain); + l = readl_relaxed(bank->base + bank->regs->datain); /* * Check if any of the non-wakeup interrupt GPIOs have changed @@ -1331,24 +1413,24 @@ static int omap_gpio_runtime_resume(struct device *dev) if (gen) { u32 old0, old1; - old0 = __raw_readl(bank->base + bank->regs->leveldetect0); - old1 = __raw_readl(bank->base + bank->regs->leveldetect1); + old0 = readl_relaxed(bank->base + bank->regs->leveldetect0); + old1 = readl_relaxed(bank->base + bank->regs->leveldetect1); if (!bank->regs->irqstatus_raw0) { - __raw_writel(old0 | gen, bank->base + + writel_relaxed(old0 | gen, bank->base + bank->regs->leveldetect0); - __raw_writel(old1 | gen, bank->base + + writel_relaxed(old1 | gen, bank->base + bank->regs->leveldetect1); } if (bank->regs->irqstatus_raw0) { - __raw_writel(old0 | l, bank->base + + writel_relaxed(old0 | l, bank->base + bank->regs->leveldetect0); - __raw_writel(old1 | l, bank->base + + writel_relaxed(old1 | l, bank->base + bank->regs->leveldetect1); } - __raw_writel(old0, bank->base + bank->regs->leveldetect0); - __raw_writel(old1, bank->base + bank->regs->leveldetect1); + writel_relaxed(old0, bank->base + bank->regs->leveldetect0); + writel_relaxed(old1, bank->base + bank->regs->leveldetect1); } bank->workaround_enabled = false; @@ -1363,7 +1445,7 @@ void omap2_gpio_prepare_for_idle(int pwr_mode) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { - if (!bank->mod_usage || !bank->loses_context) + if (!BANK_USED(bank) || !bank->loses_context) continue; bank->power_mode = pwr_mode; @@ -1377,7 +1459,7 @@ void omap2_gpio_resume_after_idle(void) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { - if (!bank->mod_usage || !bank->loses_context) + if (!BANK_USED(bank) || !bank->loses_context) continue; pm_runtime_get_sync(bank->dev); @@ -1385,43 +1467,67 @@ void omap2_gpio_resume_after_idle(void) } #if defined(CONFIG_PM_RUNTIME) +static void omap_gpio_init_context(struct gpio_bank *p) +{ + struct omap_gpio_reg_offs *regs = p->regs; + void __iomem *base = p->base; + + p->context.ctrl = readl_relaxed(base + regs->ctrl); + p->context.oe = readl_relaxed(base + regs->direction); + p->context.wake_en = readl_relaxed(base + regs->wkup_en); + p->context.leveldetect0 = readl_relaxed(base + regs->leveldetect0); + p->context.leveldetect1 = readl_relaxed(base + regs->leveldetect1); + p->context.risingdetect = readl_relaxed(base + regs->risingdetect); + p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect); + p->context.irqenable1 = readl_relaxed(base + regs->irqenable); + p->context.irqenable2 = readl_relaxed(base + regs->irqenable2); + + if (regs->set_dataout && p->regs->clr_dataout) + p->context.dataout = readl_relaxed(base + regs->set_dataout); + else + p->context.dataout = readl_relaxed(base + regs->dataout); + + p->context_valid = true; +} + static void omap_gpio_restore_context(struct gpio_bank *bank) { - __raw_writel(bank->context.wake_en, + writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); - __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl); - __raw_writel(bank->context.leveldetect0, + writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl); + writel_relaxed(bank->context.leveldetect0, bank->base + bank->regs->leveldetect0); - __raw_writel(bank->context.leveldetect1, + writel_relaxed(bank->context.leveldetect1, bank->base + bank->regs->leveldetect1); - __raw_writel(bank->context.risingdetect, + writel_relaxed(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - __raw_writel(bank->context.fallingdetect, + writel_relaxed(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); if (bank->regs->set_dataout && bank->regs->clr_dataout) - __raw_writel(bank->context.dataout, + writel_relaxed(bank->context.dataout, bank->base + bank->regs->set_dataout); else - __raw_writel(bank->context.dataout, + writel_relaxed(bank->context.dataout, bank->base + bank->regs->dataout); - __raw_writel(bank->context.oe, bank->base + bank->regs->direction); + writel_relaxed(bank->context.oe, bank->base + bank->regs->direction); if (bank->dbck_enable_mask) { - __raw_writel(bank->context.debounce, bank->base + + writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - __raw_writel(bank->context.debounce_en, + writel_relaxed(bank->context.debounce_en, bank->base + bank->regs->debounce_en); } - __raw_writel(bank->context.irqenable1, + writel_relaxed(bank->context.irqenable1, bank->base + bank->regs->irqenable); - __raw_writel(bank->context.irqenable2, + writel_relaxed(bank->context.irqenable2, bank->base + bank->regs->irqenable2); } #endif /* CONFIG_PM_RUNTIME */ #else #define omap_gpio_runtime_suspend NULL #define omap_gpio_runtime_resume NULL +static inline void omap_gpio_init_context(struct gpio_bank *p) {} #endif static const struct dev_pm_ops gpio_pm_ops = { @@ -1476,19 +1582,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .fallingdetect = OMAP4_GPIO_FALLINGDETECT, }; -const static struct omap_gpio_platform_data omap2_pdata = { +static const struct omap_gpio_platform_data omap2_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = false, }; -const static struct omap_gpio_platform_data omap3_pdata = { +static const struct omap_gpio_platform_data omap3_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = true, }; -const static struct omap_gpio_platform_data omap4_pdata = { +static const struct omap_gpio_platform_data omap4_pdata = { .regs = &omap4_gpio_regs, .bank_width = 32, .dbck_flag = true, |
