From patchwork Sat Dec 12 01:25:53 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cory Maccarrone X-Patchwork-Id: 66896 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nBC1QGJu014964 for ; Sat, 12 Dec 2009 01:26:16 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1762353AbZLLB0B (ORCPT ); Fri, 11 Dec 2009 20:26:01 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1761661AbZLLB0B (ORCPT ); Fri, 11 Dec 2009 20:26:01 -0500 Received: from mail-pw0-f42.google.com ([209.85.160.42]:43949 "EHLO mail-pw0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1761500AbZLLB0A (ORCPT ); Fri, 11 Dec 2009 20:26:00 -0500 Received: by pwj9 with SMTP id 9so926485pwj.21 for ; Fri, 11 Dec 2009 17:26:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=ZDP+hbt1H8qP/YeF2B8A9tDlwUtvPaneDW2T20ypg2c=; b=rfKt5ZnfyAR8FBlOF1hR4mHy4HSczugT8xd3O1FJ3uu+Wnyg7O45n7pxhWMsy237x0 805cOhgGgCBF7KKR7hl9tygg23txGaHlNQHuFYewaqMxRy1V9nexqNtYIkDEHc3mcuOH YIkQXG2LLEZrlIMaGOBcSwxEaDCsXiUUQFVVw= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=mdm8vg45UR9fVDUQHFqQxokcTCqZJWjauKaCDqbkoe+WD9dlMtyRG1vUIBSZR9UFt3 Mf3JKN0kkbnE9+pZwiQ1JfqfEk3ZokwUVwOONLbMNP8JsMiYjZfz6ZXB4BlRqm/pUx+i nVUhqHlN8xxkOvTzTplyekb3/wkVfJHwDPS3Q= Received: by 10.142.248.38 with SMTP id v38mr1220102wfh.280.1260581167501; Fri, 11 Dec 2009 17:26:07 -0800 (PST) Received: from localhost (97-126-116-159.tukw.qwest.net [97.126.116.159]) by mx.google.com with ESMTPS id 23sm2216486pzk.12.2009.12.11.17.26.06 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 11 Dec 2009 17:26:06 -0800 (PST) From: Cory Maccarrone To: linux-omap@vger.kernel.org Cc: Cory Maccarrone Subject: [PATCH v2] [OMAP] gpio: Simultaneously requested rising and falling edge Date: Fri, 11 Dec 2009 17:25:53 -0800 Message-Id: <1260581153-4472-1-git-send-email-darkstar6262@gmail.com> X-Mailer: git-send-email 1.6.3.3 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 055160e..a05c83d 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -192,6 +192,7 @@ struct gpio_bank { u32 saved_risingdetect; #endif u32 level_mask; + u32 flip_mask; spinlock_t lock; struct gpio_chip chip; struct clk *dbck; @@ -749,6 +750,44 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, } #endif +/* + * This only applies to chips that can't do both rising and falling edge + * detection at once. For all other chips, this function is a noop. + */ +static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) +{ + void __iomem *reg = bank->base; + u32 l = 0; + + switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 + case METHOD_MPUIO: + reg += OMAP_MPUIO_GPIO_INT_EDGE; + break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_INT_CONTROL; + break; +#endif +#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) + case METHOD_GPIO_7XX: + reg += OMAP7XX_GPIO_INT_CONTROL; + break; +#endif + default: + return; + } + + l = __raw_readl(reg); + if ((l >> gpio) & 1) + l &= ~(1 << gpio); + else + l |= 1 << gpio; + + __raw_writel(l, reg); +} + static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) { void __iomem *reg = bank->base; @@ -759,6 +798,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_INT_EDGE; l = __raw_readl(reg); + if (trigger & IRQ_TYPE_EDGE_RISING && trigger & IRQ_TYPE_EDGE_FALLING) + bank->flip_mask |= 1 << gpio; if (trigger & IRQ_TYPE_EDGE_RISING) l |= 1 << gpio; else if (trigger & IRQ_TYPE_EDGE_FALLING) @@ -771,6 +812,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; l = __raw_readl(reg); + if (trigger & IRQ_TYPE_EDGE_RISING && trigger & IRQ_TYPE_EDGE_FALLING) + bank->flip_mask |= 1 << gpio; if (trigger & IRQ_TYPE_EDGE_RISING) l |= 1 << gpio; else if (trigger & IRQ_TYPE_EDGE_FALLING) @@ -803,6 +846,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_GPIO_7XX: reg += OMAP7XX_GPIO_INT_CONTROL; l = __raw_readl(reg); + if (trigger & IRQ_TYPE_EDGE_RISING && trigger & IRQ_TYPE_EDGE_FALLING) + bank->flip_mask |= 1 << gpio; if (trigger & IRQ_TYPE_EDGE_RISING) l |= 1 << gpio; else if (trigger & IRQ_TYPE_EDGE_FALLING) @@ -1217,7 +1262,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { void __iomem *isr_reg = NULL; u32 isr; - unsigned int gpio_irq; + unsigned int gpio_irq, gpio_index; struct gpio_bank *bank; u32 retrigger = 0; int unmasked = 0; @@ -1284,9 +1329,21 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) gpio_irq = bank->virtual_irq_start; for (; isr != 0; isr >>= 1, gpio_irq++) { + gpio_index = get_gpio_index(irq_to_gpio(gpio_irq)); + if (!(isr & 1)) continue; + /* + * Some chips can't respond to both rising and falling at the + * same time. If this irq was requested with both flags, we + * need to flip the ICR data for the IRQ to respond to the + * IRQ for the opposite direction. This will be indicated in + * the bank flip_mask. + */ + if ((bank->flip_mask >> gpio_index) & 1) + _toggle_gpio_edge_triggering(bank, gpio_index); + generic_handle_irq(gpio_irq); } }