gpio_set_debounce(), gpio_prepare_for_idle() and gpio_resume_after_idle() are specific to OMAP2PLUS CPUs. These functions rely on "dbck_enable_mask" which is part of GPIO bank structure. The above mentioned functions are moved to mach-omap2/gpio.c and the required information is passed from the OMAP GPIO driver. Signed-off-by: Charulatha V <charu@xxxxxx> --- arch/arm/mach-omap2/gpio.c | 201 ++++++++++++++++++++++++++++- arch/arm/plat-omap/gpio.c | 223 +++----------------------------- arch/arm/plat-omap/include/plat/gpio.h | 6 + 3 files changed, 222 insertions(+), 208 deletions(-) diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c index a46f4a5..a0edaeb 100644 --- a/arch/arm/mach-omap2/gpio.c +++ b/arch/arm/mach-omap2/gpio.c @@ -21,13 +21,31 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/clk.h> #include <plat/omap_hwmod.h> #include <plat/omap_device.h> #define OMAP2_GPIO_INDEX_MASK 0x1f #define OMAP2_GPIO_IRQENA_MASK 0xffffffff +#define OMAP2_GPIO_DEBOUNCE_MIN_CHK 32 +#define OMAP2_GPIO_DEBOUNCE_MAX_CHK 7936 +#define OMAP2_GPIO_DEBOUNCE_MIN_VAL 0x01 +#define OMAP2_GPIO_DEBOUNCE_MAX_VAL 0xff +#define OMAP2_GPIO_DEBOUNCE_VAL_DIV 0x1f +struct gpio_state { + struct list_head node; + u32 saved_datain; + u32 saved_fallingdetect; + u32 saved_risingdetect; + u32 dbck_enable_mask; + struct clk *dbck; + u16 id; +}; + +static int workaround_enabled; +static LIST_HEAD(omap_gpio_ctx_list); int gpio_bank_count; int bank_width; static u16 *reg_map; @@ -172,6 +190,161 @@ static void gpio_enable_irq(void __iomem *base, int gpio_mask, int enable) } } +static void gpio_debounce_set(void __iomem *base, unsigned gpio, + unsigned debounce, u16 id) +{ + u32 val; + u32 l = 0; + struct gpio_state *gpio_dev_state; + + if (debounce < OMAP2_GPIO_DEBOUNCE_MIN_CHK) + debounce = OMAP2_GPIO_DEBOUNCE_MIN_VAL; + else if (debounce > OMAP2_GPIO_DEBOUNCE_MAX_CHK) + debounce = OMAP2_GPIO_DEBOUNCE_MAX_VAL; + else + debounce = (debounce / OMAP2_GPIO_DEBOUNCE_VAL_DIV) - 1; + + gpio_write(debounce, base, DEBOUNCE_VAL); + + val = gpio_read(base, DEBOUNCE_EN); + l = 1 << get_gpio_index(gpio); + + list_for_each_entry(gpio_dev_state, &omap_gpio_ctx_list, node) { + if (gpio_dev_state->id == id) { + if (debounce) { + val |= l; + clk_enable(gpio_dev_state->dbck); + } else { + val &= ~l; + clk_disable(gpio_dev_state->dbck); + } + gpio_dev_state->dbck_enable_mask = val; + gpio_write(val, base, DEBOUNCE_EN); + } + } +} + +static void gpio_prepare_for_idle(u32 enabled_non_wakeup_gpios, u16 id, + void __iomem *base, int off_mode) +{ + int c = 0; + struct gpio_state *gpio_dev_state; + + list_for_each_entry(gpio_dev_state, &omap_gpio_ctx_list, node) { + u32 l1 = 0, l2 = 0; + int j; + + if (!gpio_dev_state->id == id) + continue; + + if ((cpu_is_omap34xx()) && (id == 0)) + continue; + + for (j = 0; j < hweight_long(gpio_dev_state->dbck_enable_mask); + j++) + clk_disable(gpio_dev_state->dbck); + + if (!off_mode) + continue; + + /* + * If going to OFF, remove triggering for all + * non-wakeup GPIOs. Otherwise spurious IRQs will be + * generated. See OMAP2420 Errata item 1.101. + */ + if (!enabled_non_wakeup_gpios) + continue; + + gpio_dev_state->saved_datain = gpio_read(base, DATAIN); + l1 = gpio_read(base, FALLINGDETECT); + l2 = gpio_read(base, RISINGDETECT); + + gpio_dev_state->saved_fallingdetect = l1; + gpio_dev_state->saved_risingdetect = l2; + l1 &= ~enabled_non_wakeup_gpios; + l2 &= ~enabled_non_wakeup_gpios; + + gpio_write(l1, base, FALLINGDETECT); + gpio_write(l2, base, RISINGDETECT); + + c++; + } + if (!c) { + workaround_enabled = 0; + return; + } + workaround_enabled = 1; +} + +static void gpio_resume_after_idle(u32 enabled_non_wakeup_gpios, u16 id, + void __iomem *base) +{ + struct gpio_state *gpio_dev_state; + + list_for_each_entry(gpio_dev_state, &omap_gpio_ctx_list, node) { + u32 l = 0, gen, gen0, gen1; + int j; + + if (!gpio_dev_state->id == id) + continue; + + if ((cpu_is_omap34xx()) && (id == 0)) + continue; + + for (j = 0; j < hweight_long(gpio_dev_state->dbck_enable_mask); + j++) + clk_enable(gpio_dev_state->dbck); + + if (!workaround_enabled) + continue; + + if (!enabled_non_wakeup_gpios) + continue; + + gpio_write(gpio_dev_state->saved_fallingdetect, base, + FALLINGDETECT); + gpio_write(gpio_dev_state->saved_risingdetect, base, + RISINGDETECT); + + l = gpio_read(base, 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. + */ + l ^= gpio_dev_state->saved_datain; + l &= enabled_non_wakeup_gpios; + + /* + * No need to generate IRQs for the rising edge for gpio IRQs + * configured with falling edge only; and vice versa. + */ + gen0 = l & gpio_dev_state->saved_fallingdetect; + gen0 &= gpio_dev_state->saved_datain; + + gen1 = l & gpio_dev_state->saved_risingdetect; + gen1 &= ~(gpio_dev_state->saved_datain); + + /* FIXME: Consider GPIO IRQs with level detections properly! */ + gen = l & (~(gpio_dev_state->saved_fallingdetect) & + ~(gpio_dev_state->saved_risingdetect)); + /* Consider all GPIO IRQs needed to be updated */ + gen |= gen0 | gen1; + + if (gen) { + u32 old0, old1; + + old0 = gpio_read(base, LEVELDETECT0); + old1 = gpio_read(base, LEVELDETECT1); + gpio_write(old0 | gen, base, LEVELDETECT0); + gpio_write(old1 | gen, base, LEVELDETECT1); + gpio_write(old0, base, LEVELDETECT0); + gpio_write(old1, base, LEVELDETECT1); + } + } +} + static struct omap_gpio_func gpio_fn = { .get_index = get_gpio_index, .gpio_valid = gpio_valid, @@ -180,6 +353,9 @@ static struct omap_gpio_func gpio_fn = { .gpio_set_trigger = gpio_set_trigger, .gpio_is_irqena = gpio_is_irqena, .gpio_enable_irq = gpio_enable_irq, + .gpio_debounce_set = gpio_debounce_set, + .gpio_idle = gpio_prepare_for_idle, + .gpio_resume_after_idle = gpio_resume_after_idle, }; static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) @@ -189,6 +365,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) struct omap_gpio_dev_attr *dev_attr; char *name = "omap_gpio"; int id; + struct gpio_state *gpio_dev_state; /* * extract the device id from name field available in the @@ -229,19 +406,39 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) return -EINVAL; } + gpio_dev_state = kzalloc(sizeof(struct gpio_state), GFP_KERNEL); + if (!gpio_dev_state) { + pr_err("%s:, Memory alloc failed for gpio_dev_state\n", + __func__); + kfree(pdata); + return -ENOMEM; + } + + gpio_dev_state->id = id - 1; + list_add_tail(&gpio_dev_state->node, &omap_gpio_ctx_list); + od = omap_device_build(name, id - 1, oh, pdata, sizeof(*pdata), omap_gpio_latency, ARRAY_SIZE(omap_gpio_latency), false); - kfree(pdata); - if (IS_ERR(od)) { WARN(1, "Can't build omap_device for %s:%s.\n", name, oh->name); + kfree(gpio_dev_state); + kfree(pdata); return PTR_ERR(od); } gpio_bank_count++; + if (pdata->dbck_flag) { + gpio_dev_state->dbck = clk_get(&od->pdev.dev, "dbclk"); + if (IS_ERR(gpio_dev_state->dbck)) + dev_err(&od->pdev.dev, "Could not get gpio%d dbck\n", + id); + } + + kfree(pdata); + return 0; } diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index f2cd2dd..55115df 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -150,16 +150,11 @@ struct gpio_bank { u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; u16 id; - u32 saved_datain; - u32 saved_fallingdetect; - u32 saved_risingdetect; u32 level_mask; u32 toggle_mask; spinlock_t lock; struct gpio_chip chip; - struct clk *dbck; u32 mod_usage; - u32 dbck_enable_mask; struct device *dev; bool dbck_flag; int stride; @@ -331,47 +326,12 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, unsigned debounce) { - void __iomem *reg = bank->base; - u32 val; - u32 l; - if (!bank->dbck_flag) return; - if (debounce < 32) - debounce = 0x01; - else if (debounce > 7936) - debounce = 0xff; - else - debounce = (debounce / 0x1f) - 1; - - l = 1 << gpio_fn.get_index(gpio); - - if (bank->method == METHOD_GPIO_44XX) - reg += OMAP4_GPIO_DEBOUNCINGTIME; - else - reg += OMAP24XX_GPIO_DEBOUNCE_VAL; - - __raw_writel(debounce, reg); - - reg = bank->base; - if (bank->method == METHOD_GPIO_44XX) - reg += OMAP4_GPIO_DEBOUNCENABLE; - else - reg += OMAP24XX_GPIO_DEBOUNCE_EN; - - val = __raw_readl(reg); - - if (debounce) { - val |= l; - clk_enable(bank->dbck); - } else { - val &= ~l; - clk_disable(bank->dbck); - } - bank->dbck_enable_mask = val; - - __raw_writel(val, reg); + if (!gpio_fn.gpio_debounce_set) + gpio_fn.gpio_debounce_set(bank->base, gpio, debounce, + bank->id); } /* @@ -1083,12 +1043,6 @@ static int gpio_debounce(struct gpio_chip *chip, unsigned offset, bank = container_of(chip, struct gpio_bank, chip); - if (!bank->dbck) { - bank->dbck = clk_get(bank->dev, "dbclk"); - if (IS_ERR(bank->dbck)) - dev_err(bank->dev, "Could not get gpio dbck\n"); - } - spin_lock_irqsave(&bank->lock, flags); _set_gpio_debounce(bank, offset, debounce); spin_unlock_irqrestore(&bank->lock, flags); @@ -1320,6 +1274,10 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) gpio_fn.gpio_set_trigger = pdata->gpio_fn->gpio_set_trigger; gpio_fn.gpio_is_irqena = pdata->gpio_fn->gpio_is_irqena; gpio_fn.gpio_enable_irq = pdata->gpio_fn->gpio_enable_irq; + gpio_fn.gpio_debounce_set = pdata->gpio_fn->gpio_debounce_set; + gpio_fn.gpio_idle = pdata->gpio_fn->gpio_idle; + gpio_fn.gpio_resume_after_idle = + pdata->gpio_fn->gpio_resume_after_idle; gpio_init_done = 1; } @@ -1401,179 +1359,32 @@ static struct sys_device omap_gpio_device = { .cls = &omap_gpio_sysclass, }; - -#ifdef CONFIG_ARCH_OMAP2PLUS - -static int workaround_enabled; - void omap2_gpio_prepare_for_idle(int off_mode) { - int c = 0; struct gpio_bank *bank; - list_for_each_entry(bank, &omap_gpio_list, node) { - u32 l1 = 0, l2 = 0; - int j; - - /* TODO: Do not use cpu_is_omap34xx */ - if ((cpu_is_omap34xx()) && (bank->id == 0)) - continue; - - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_disable(bank->dbck); - - if (!off_mode) - continue; - - /* If going to OFF, remove triggering for all - * non-wakeup GPIOs. Otherwise spurious IRQs will be - * generated. See OMAP2420 Errata item 1.101. */ - if (!(bank->enabled_non_wakeup_gpios)) - continue; - - 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 (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) { - workaround_enabled = 0; + if (!gpio_fn.gpio_idle) return; + + list_for_each_entry(bank, &omap_gpio_list, node) { + gpio_fn.gpio_idle(bank->enabled_non_wakeup_gpios, + bank->id, bank->base, off_mode); } - workaround_enabled = 1; } void omap2_gpio_resume_after_idle(void) { struct gpio_bank *bank; - list_for_each_entry(bank, &omap_gpio_list, node) { - u32 l = 0, gen, gen0, gen1; - int j; - - /* TODO: Do not use cpu_is_omap34xx */ - if ((cpu_is_omap34xx()) && (bank->id == 0)) - continue; - - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_enable(bank->dbck); - - if (!workaround_enabled) - continue; - - if (!(bank->enabled_non_wakeup_gpios)) - continue; - - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { - __raw_writel(bank->saved_fallingdetect, - bank->base + OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(bank->saved_risingdetect, - bank->base + OMAP24XX_GPIO_RISINGDETECT); - 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. */ - l ^= bank->saved_datain; - l &= bank->enabled_non_wakeup_gpios; - - /* - * 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 (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 (!gpio_fn.gpio_resume_after_idle) + return; - 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); - } - } + list_for_each_entry(bank, &omap_gpio_list, node) { + gpio_fn.gpio_resume_after_idle(bank->enabled_non_wakeup_gpios, + bank->id, bank->base); } - } -#endif - #ifdef CONFIG_ARCH_OMAP3 /* save the registers of bank 2-6 */ void omap_gpio_save_context(void) diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h index 331ee4c..bfd5b6c 100644 --- a/arch/arm/plat-omap/include/plat/gpio.h +++ b/arch/arm/plat-omap/include/plat/gpio.h @@ -116,6 +116,12 @@ struct omap_gpio_func { int (*gpio_set_trigger)(void __iomem *base, int gpio, int trigger); u32 (*gpio_is_irqena)(void __iomem *base); void (*gpio_enable_irq)(void __iomem *base, int gpio_mask, int enable); + void (*gpio_debounce_set)(void __iomem *base, unsigned gpio, + unsigned debounce, u16 id); + void (*gpio_idle)(u32 enabled_non_wakeup_gpios, u16 id, + void __iomem *base, int offmode); + void (*gpio_resume_after_idle)(u32 enabled_non_wakeup_gpios, u16 id, + void __iomem *base); }; struct omap_gpio_platform_data { -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html