From patchwork Mon Apr 18 15:06:56 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: charu@ti.com X-Patchwork-Id: 715771 X-Patchwork-Delegate: tony@atomide.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3IF3oFh015163 for ; Mon, 18 Apr 2011 15:03:52 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753440Ab1DRPDw (ORCPT ); Mon, 18 Apr 2011 11:03:52 -0400 Received: from bear.ext.ti.com ([192.94.94.41]:47469 "EHLO bear.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753346Ab1DRPDt (ORCPT ); Mon, 18 Apr 2011 11:03:49 -0400 Received: from dbdp20.itg.ti.com ([172.24.170.38]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id p3IF3ZBh009856 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 18 Apr 2011 10:03:37 -0500 Received: from dbde71.ent.ti.com (localhost [127.0.0.1]) by dbdp20.itg.ti.com (8.13.8/8.13.8) with ESMTP id p3IF3WR7008856; Mon, 18 Apr 2011 20:33:34 +0530 (IST) Received: from dbdp31.itg.ti.com (172.24.170.98) by DBDE71.ent.ti.com (172.24.170.149) with Microsoft SMTP Server id 8.3.106.1; Mon, 18 Apr 2011 20:33:17 +0530 Received: from ucmsshproxy.india.ext.ti.com (dbdp20.itg.ti.com [172.24.170.38]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with SMTP id p3IF3XLZ023179; Mon, 18 Apr 2011 20:33:33 +0530 (IST) Received: from x0084895-pc (unknown [10.24.244.78]) by ucmsshproxy.india.ext.ti.com (Postfix) with ESMTP id 6BEB2158004; Mon, 18 Apr 2011 20:33:32 +0530 (IST) From: "Varadarajan, Charulatha" To: , CC: , , , Charulatha V Subject: [PATCH 6/7] OMAP: GPIO: Cleanup prepare_for_idle/resume Date: Mon, 18 Apr 2011 20:36:56 +0530 Message-ID: <1303139217-10285-7-git-send-email-charu@ti.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 18 Apr 2011 15:03:53 +0000 (UTC) From: Charulatha V Use a function named gpio_bank_handle_idle() in omap_gpio_prepare_for_idle() to do the following: * debounce clock disable * if the next powerdomain state for the bank is off-mode: - remove triggering for all non-wakeup GPIOs (this is handled by a new function named omap_gpio_idle_handle_errata_i468()) - save context Also handle omap_gpio_resume_after_idle() in a similar way, using a function gpio_bank_handle_resume(). This would be helpful while modifying OMAP GPIO driver to use PM runtime framework. Signed-off-by: Charulatha V --- arch/arm/plat-omap/gpio.c | 350 ++++++++++++++++++++++++--------------------- 1 files changed, 187 insertions(+), 163 deletions(-) diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 5933c98..7660c06 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -1747,6 +1747,187 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) return 0; } +#ifdef CONFIG_ARCH_OMAP2PLUS +static int is_pwrdm_nxt_state_off; + +static inline void omap_gpio_idle_handle_errata_i468(struct gpio_bank *bank) +{ + u32 l1 = 0, l2 = 0; + + /* + * 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)) + return; + + if (bank->method == METHOD_GPIO_24XX) { + 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); + } else if (bank->method == METHOD_GPIO_44XX) { + 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 (bank->method == METHOD_GPIO_24XX) { + __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT); + } else if (bank->method == METHOD_GPIO_44XX) { + __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); + __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); + } + + bank->off_mode_wkup_wa_enabled = true; +} + +static inline void omap_gpio_resume_handle_errata_i468(struct gpio_bank *bank) +{ + u32 l = 0, gen, gen0, gen1; + + if (!bank->off_mode_wkup_wa_enabled) + return; + + bank->off_mode_wkup_wa_enabled = false; + + if (!(bank->enabled_non_wakeup_gpios)) + return; + + if (bank->method == METHOD_GPIO_24XX) { + __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); + } else if (bank->method == METHOD_GPIO_44XX) { + __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 (bank->method == METHOD_GPIO_24XX) { + 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); + } else if (bank->method == METHOD_GPIO_44XX) { + 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); + } + } +} + +static int gpio_bank_handle_idle(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = &gpio_bank[pdev->id]; + int j; + + /* If the gpio bank is not used, do nothing */ + if (!bank->mod_usage || !bank->looses_context) + return 0; + + for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) + clk_disable(bank->dbck); + + /* Save the context lost count */ + bank->ctx_lost_cnt_before = + omap_device_get_context_loss_count(pdev); + + if (is_pwrdm_nxt_state_off) { + omap_gpio_idle_handle_errata_i468(bank); + omap_gpio_save_context(bank); + } + + return 0; +} + +static int gpio_bank_handle_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct gpio_bank *bank = &gpio_bank[pdev->id]; + u32 ctx_lost_cnt_after; + int j; + + /* If the gpio bank is not used, do nothing */ + if (!bank->mod_usage || !bank->looses_context) + return 0; + + for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) + clk_enable(bank->dbck); + + pdev = to_platform_device(bank->dev); + ctx_lost_cnt_after = omap_device_get_context_loss_count(pdev); + + if (ctx_lost_cnt_after != bank->ctx_lost_cnt_before) { + omap_gpio_resume_handle_errata_i468(bank); + omap_gpio_restore_context(bank); + } + + return 0; +} +#endif + #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) { @@ -1864,183 +2045,26 @@ void omap2_gpio_prepare_for_idle(int off_mode) { int i; + is_pwrdm_nxt_state_off = off_mode; + for (i = 0; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; - struct platform_device *pdev; - u32 l1 = 0, l2 = 0; - int j; - - /* If the gpio bank is not used, do nothing */ - if (!bank->mod_usage) - continue; - - if (!bank->looses_context) - 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)) - goto save_gpio_ctx; - - if (bank->method == METHOD_GPIO_24XX) { - 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); - } else if (bank->method == METHOD_GPIO_44XX) { - 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 (bank->method == METHOD_GPIO_24XX) { - __raw_writel(l1, bank->base + - OMAP24XX_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + - OMAP24XX_GPIO_RISINGDETECT); - } else if (bank->method == METHOD_GPIO_44XX) { - __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT); - __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT); - } - - bank->off_mode_wkup_wa_enabled = true; -save_gpio_ctx: - pdev = to_platform_device(bank->dev); - bank->ctx_lost_cnt_before = - omap_device_get_context_loss_count(pdev); - omap_gpio_save_context(bank); + gpio_bank_handle_idle(bank->dev); } } void omap2_gpio_resume_after_idle(void) { int i; - u32 ctx_lost_cnt_after; + + is_pwrdm_nxt_state_off = 0; for (i = 0; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; - struct platform_device *pdev; - u32 l = 0, gen, gen0, gen1; - int j; - - /* If the gpio bank is not used, do nothing */ - if (!bank->mod_usage) - continue; - - if (!bank->looses_context) - continue; - - for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++) - clk_enable(bank->dbck); - - pdev = to_platform_device(bank->dev); - ctx_lost_cnt_after = omap_device_get_context_loss_count(pdev); - - if (ctx_lost_cnt_after == bank->ctx_lost_cnt_before) - continue; - - if (!bank->off_mode_wkup_wa_enabled) - goto restore_gpio_ctx; - - if (!(bank->enabled_non_wakeup_gpios)) - goto restore_gpio_ctx; - - if (bank->method == METHOD_GPIO_24XX) { - __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); - } else if (bank->method == METHOD_GPIO_44XX) { - __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 (bank->method == METHOD_GPIO_24XX) { - 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); - } else if (bank->method == METHOD_GPIO_44XX) { - 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); - } - } - -restore_gpio_ctx: - bank->off_mode_wkup_wa_enabled = false; - omap_gpio_restore_context(bank); + gpio_bank_handle_resume(bank->dev); } - } void omap_gpio_save_context(struct gpio_bank *bank)