From patchwork Tue May 14 20:54:26 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andreas Fenkart X-Patchwork-Id: 2568541 Return-Path: X-Original-To: patchwork-linux-omap@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 91437DF24C for ; Tue, 14 May 2013 20:54:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758059Ab3ENUyn (ORCPT ); Tue, 14 May 2013 16:54:43 -0400 Received: from mout.gmx.net ([212.227.15.15]:63476 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757791Ab3ENUym (ORCPT ); Tue, 14 May 2013 16:54:42 -0400 Received: from mailout-de.gmx.net ([10.1.76.33]) by mrigmx.server.lan (mrigmx001) with ESMTP (Nemesis) id 0MDjlo-1UjUr904PW-00H5i2 for ; Tue, 14 May 2013 22:54:41 +0200 Received: (qmail invoked by alias); 14 May 2013 20:54:40 -0000 Received: from ip-89-176-190-209.net.upcbroadband.cz (EHLO localhost) [89.176.190.209] by mail.gmx.net (mp033) with SMTP; 14 May 2013 22:54:40 +0200 X-Authenticated: #20192376 X-Provags-ID: V01U2FsdGVkX1/cgkwPr0HcXoA2o3XWTE4lc/BMfD6cA2ulD9w1Rb z4kcSlYYCWNcPY From: Andreas Fenkart To: santosh.shilimkar@ti.com Cc: khilman@deeprootsystems.com, grant.likely@secretlab.ca, linus.walleij@linaro.org, balbi@ti.com, linux-omap@vger.kernel.org, daniel@zonque.org, jon-hunter@ti.com, Andreas Fenkart Subject: [PATCH v3 2/3] gpio/omap: modify wake-up register with interrupt enable. Date: Tue, 14 May 2013 22:54:26 +0200 Message-Id: <1368564867-11142-2-git-send-email-andreas.fenkart@streamunlimited.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1368564867-11142-1-git-send-email-andreas.fenkart@streamunlimited.com> References: <1368564867-11142-1-git-send-email-andreas.fenkart@streamunlimited.com> MIME-Version: 1.0 X-Y-GMX-Trusted: 0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org OMAP4430 TRM chap. 25.4.5.2 To reduce dynamic consumption, an efficient idle scheme is based on the following: • An efficient local autoclock gating for each module • The implementation of control sideband signals between the PRCM module and each module This enhanced idle control allows clocks to be activated and deactivated safely without requiring complex software management. The idle mode request, idle acknowledge, and wake-up request are sideband signals between the PRCM module and the general-purpose interface OMAP4430 TRM chap. 25.4.6.2 There must be a correlation between the wake-up enable and interrupt enable register. If a GPIO pin has a wake-up configured on it, it must also have the corresponding interrupt enabled. Otherwise, it is possible there is a wake-up event, but after exiting the IDLE state, no interrupt is generated; the corresponding bit from the interrupt status register is not cleared, and the module does not acknowledge a future idle request. Up to now _set_gpio_triggering() is also handling the wake-up enable register. According the TRM this should be in sync with the interrupt enable. Wakeup is still enabled by default, since the module would not wake from idle otherwise. The enabled_wakeup_gpios was introduced to remember an explicit _set_gpio_wakeup beyond a mask/unmask cycle. Calling the flag flag disabled_wakeup_gpios would spare the problem of initializing it, but feels very unnatural to read. Wakeup functionality is completely untested, since the AM335x lacks a IRQWAKEN register. Signed-off-by: Andreas Fenkart Acked-by: Santosh Shilimkar --- drivers/gpio/gpio-omap.c | 68 ++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 082919e..44a93be 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -57,6 +57,7 @@ struct gpio_bank { struct irq_domain *domain; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; + u32 enabled_wakeup_gpios; struct gpio_regs context; u32 saved_datain; u32 level_mask; @@ -287,12 +288,6 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, _gpio_rmw(base, bank->regs->fallingdetect, gpio_bit, trigger & IRQ_TYPE_EDGE_FALLING); - if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { - bank->context.wake_en = - _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, - trigger != 0); - } - /* This part needs to be executed always for OMAP{34xx, 44xx} */ if (!bank->regs->irqctrl) { /* On omap24xx proceed only when valid GPIO bit is set */ @@ -350,12 +345,13 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, unsigned trigger) { void __iomem *reg = bank->base; - void __iomem *base = bank->base; u32 l = 0; - if (bank->regs->leveldetect0 && bank->regs->wkup_en) { + if (bank->regs->leveldetect0) { + /* edge both flanks simultaneously / plus level */ set_gpio_trigger(bank, gpio, trigger); } else if (bank->regs->irqctrl) { + /* edge single flank */ reg += bank->regs->irqctrl; l = __raw_readl(reg); @@ -370,6 +366,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, __raw_writel(l, reg); } else if (bank->regs->edgectrl1) { + /* edge both flanks simultaneously */ if (gpio & 0x08) reg += bank->regs->edgectrl2; else @@ -382,11 +379,6 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, l |= 2 << (gpio << 1); if (trigger & IRQ_TYPE_EDGE_FALLING) l |= 1 << (gpio << 1); - - /* Enable wake-up during idle for dynamic tick */ - bank->context.wake_en = - _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, - trigger); __raw_writel(l, reg); } return 0; @@ -485,10 +477,19 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) { + u32 gpio_bit = GPIO_BIT(bank, gpio); + void __iomem *base = bank->base; + if (enable) - _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + _enable_gpio_irqbank(bank, gpio_bit); else - _disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio)); + _disable_gpio_irqbank(bank, gpio_bit); + + if (bank->enabled_wakeup_gpios & gpio_bit) { + /* Enable wake-up during idle for dynamic tick */ + bank->context.wake_en = + _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, enable); + } } /* @@ -511,8 +512,27 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) } spin_lock_irqsave(&bank->lock, flags); - bank->context.wake_en = _gpio_rmw(bank->base, bank->regs->wkup_en, - gpio_bit, enable); + + if (enable) + bank->enabled_wakeup_gpios |= gpio_bit; + else + bank->enabled_wakeup_gpios &= ~gpio_bit; + + /* + * OMAP4430 TRM, 25.4.6.2 + * If there is a wake-up event, but after exiting the IDLE + * state, no interrupt is generated; the corresponding bit from + * the interrupt status register is not cleared, and the + * module does not acknowledge a future idle request. + */ + if (enable && !(bank->context.irqenable1 & gpio_bit)) + dev_warn(bank->dev, "Wake-up/IRQ enable mismatch for GPIO%d\n", + gpio); + else + bank->context.wake_en = _gpio_rmw(bank->base, + bank->regs->wkup_en, + gpio_bit, enable); + spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -525,6 +545,10 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) _clear_gpio_irqstatus(bank, gpio); _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE); _clear_gpio_debounce(bank, gpio); + + /* wakeup enabled by default */ + if (!(bank->non_wakeup_gpios & GPIO_BIT(bank, gpio))) + bank->enabled_wakeup_gpios |= GPIO_BIT(bank, gpio); } /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ @@ -554,6 +578,10 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) */ _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); + /* wakeup enabled by default */ + if (!(bank->non_wakeup_gpios & (1 << offset))) + bank->enabled_wakeup_gpios |= 1 << offset; + if (bank->regs->pinctrl) { /* Claim the pin for MPU */ _gpio_rmw(bank->base, bank->regs->pinctrl, 1 << offset, 1); @@ -580,12 +608,6 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&bank->lock, flags); - if (bank->regs->wkup_en) { - /* Disable wake-up during idle for dynamic tick */ - bank->context.wake_en = - _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); - } - bank->mod_usage &= ~(1 << offset); if (bank->regs->ctrl && !bank->mod_usage) {