From patchwork Tue Jan 14 14:52:21 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas KANDAGATLA X-Patchwork-Id: 3486151 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 652799F169 for ; Tue, 14 Jan 2014 14:59:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3FB1220237 for ; Tue, 14 Jan 2014 14:59:08 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EA6EE20225 for ; Tue, 14 Jan 2014 14:59:06 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W35S3-00013y-W0; Tue, 14 Jan 2014 14:58:48 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1W35Rz-0006WV-Sc; Tue, 14 Jan 2014 14:58:43 +0000 Received: from eu1sys200aog106.obsmtp.com ([207.126.144.121]) by merlin.infradead.org with smtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W35Rk-0006TO-My for linux-arm-kernel@lists.infradead.org; Tue, 14 Jan 2014 14:58:30 +0000 Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob106.postini.com ([207.126.147.11]) with SMTP ID DSNKUtVQcYFD57b0XFBBjFssTvaAiIRZ2O95@postini.com; Tue, 14 Jan 2014 14:58:28 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 64DFE173; Tue, 14 Jan 2014 14:57:06 +0000 (GMT) Received: from Webmail-eu.st.com (Safex1hubcas23.st.com [10.75.90.46]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 13A48168BD; Tue, 14 Jan 2014 14:44:05 +0000 (GMT) Received: from localhost (10.65.51.147) by webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.123.3; Tue, 14 Jan 2014 15:57:52 +0100 From: To: Linus Walleij Subject: [PATCH v1 3/5] pinctrl: st: Add software edge trigger interrupt support. Date: Tue, 14 Jan 2014 14:52:21 +0000 Message-ID: <1389711141-21090-1-git-send-email-srinivas.kandagatla@st.com> X-Mailer: git-send-email 1.7.6.5 In-Reply-To: <1389711077-20949-1-git-send-email-srinivas.kandagatla@st.com> References: <1389711077-20949-1-git-send-email-srinivas.kandagatla@st.com> MIME-Version: 1.0 X-Originating-IP: [10.65.51.147] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140114_095829_064270_33D78CB8 X-CRM114-Status: GOOD ( 18.76 ) X-Spam-Score: -4.2 (----) Cc: Mark Rutland , devicetree@vger.kernel.org, Russell King , Pawel Moll , Ian Campbell , srinivas.kandagatla@st.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Rob Herring , Rob Landley , Kumar Gala , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Srinivas Kandagatla ST pin controller does not have hardware support for detecting edge triggered interrupts, It only has level triggering support. This patch attempts to fake up edge triggers from hw level trigger support in software. With this facility now the gpios can be easily used for keypads, otherwise it would be difficult for drivers like keypads to work with level trigger interrupts. Signed-off-by: Srinivas Kandagatla --- drivers/pinctrl/pinctrl-st.c | 66 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 03c0cfd..7d2780e 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -271,6 +271,24 @@ struct st_pctl_group { struct st_pinconf *pin_conf; }; +#define ST_IRQ_EDGE_CONF_BITS_PER_PIN 4 +#define ST_IRQ_EDGE_MASK 0xf +#define ST_IRQ_EDGE_FALLING BIT(0) +#define ST_IRQ_EDGE_RISING BIT(1) +#define ST_IRQ_EDGE_BOTH (BIT(0) | BIT(1)) + +#define ST_IRQ_RISING_EDGE_CONF(pin) \ + (ST_IRQ_EDGE_RISING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)) + +#define ST_IRQ_FALLING_EDGE_CONF(pin) \ + (ST_IRQ_EDGE_FALLING << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)) + +#define ST_IRQ_BOTH_EDGE_CONF(pin) \ + (ST_IRQ_EDGE_BOTH << (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)) + +#define ST_IRQ_EDGE_CONF(conf, pin) \ + (conf >> (pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN) & ST_IRQ_EDGE_MASK) + struct st_gpio_bank { struct gpio_chip gpio_chip; struct pinctrl_gpio_range range; @@ -278,6 +296,8 @@ struct st_gpio_bank { struct st_pio_control pc; struct irq_domain *domain; int gpio_irq; + unsigned long irq_edge_conf; + spinlock_t lock; }; struct st_pinctrl { @@ -1241,20 +1261,40 @@ static void st_gpio_irq_enable(struct irq_data *d) static int st_gpio_irq_set_type(struct irq_data *d, unsigned type) { struct st_gpio_bank *bank = irq_data_get_irq_chip_data(d); + unsigned long flags; int comp, pin = d->hwirq; u32 val; + u32 pin_edge_conf = 0; switch (type) { case IRQ_TYPE_LEVEL_HIGH: comp = 0; break; + case IRQ_TYPE_EDGE_FALLING: + comp = 0; + pin_edge_conf = ST_IRQ_FALLING_EDGE_CONF(pin); + break; case IRQ_TYPE_LEVEL_LOW: comp = 1; break; + case IRQ_TYPE_EDGE_RISING: + comp = 1; + pin_edge_conf = ST_IRQ_RISING_EDGE_CONF(pin); + break; + case IRQ_TYPE_EDGE_BOTH: + comp = st_gpio_get(&bank->gpio_chip, pin); + pin_edge_conf = ST_IRQ_BOTH_EDGE_CONF(pin); + break; default: return -EINVAL; } + spin_lock_irqsave(&bank->lock, flags); + bank->irq_edge_conf &= ~(ST_IRQ_EDGE_MASK << ( + pin * ST_IRQ_EDGE_CONF_BITS_PER_PIN)); + bank->irq_edge_conf |= pin_edge_conf; + spin_unlock_irqrestore(&bank->lock, flags); + val = readl(bank->base + REG_PIO_PCOMP); val &= ~BIT(pin); val |= (comp << pin); @@ -1266,7 +1306,12 @@ static int st_gpio_irq_set_type(struct irq_data *d, unsigned type) static void __gpio_irq_handler(struct st_gpio_bank *bank) { unsigned long port_in, port_mask, port_comp, port_active; - int n; + unsigned long bank_edge_mask, flags; + int n, val, pin_edge_cfg; + + spin_lock_irqsave(&bank->lock, flags); + bank_edge_mask = bank->irq_edge_conf; + spin_unlock_irqrestore(&bank->lock, flags); port_in = readl(bank->base + REG_PIO_PIN); port_comp = readl(bank->base + REG_PIO_PCOMP); @@ -1275,6 +1320,22 @@ static void __gpio_irq_handler(struct st_gpio_bank *bank) port_active = (port_in ^ port_comp) & port_mask; for_each_set_bit(n, &port_active, BITS_PER_LONG) { + /* check if we are detecting fake edges ... */ + pin_edge_cfg = ST_IRQ_EDGE_CONF(bank_edge_mask, n); + + if (pin_edge_cfg) { + /* edge detection. */ + val = st_gpio_get(&bank->gpio_chip, n); + if (val) + writel(BIT(n), bank->base + REG_PIO_SET_PCOMP); + else + writel(BIT(n), bank->base + REG_PIO_CLR_PCOMP); + + if (pin_edge_cfg != ST_IRQ_EDGE_BOTH && + !((pin_edge_cfg & ST_IRQ_EDGE_FALLING) ^ val)) + continue; + } + generic_handle_irq(irq_find_mapping(bank->domain, n)); } } @@ -1334,7 +1395,7 @@ static int st_gpio_irq_domain_map(struct irq_domain *h, struct st_gpio_bank *bank = h->host_data; irq_set_chip(virq, &st_gpio_irqchip); - irq_set_handler(virq, handle_level_irq); + irq_set_handler(virq, handle_simple_irq); set_irq_flags(virq, IRQF_VALID); irq_set_chip_data(virq, bank); @@ -1392,6 +1453,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info, bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK; bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK; bank->gpio_chip.of_node = np; + spin_lock_init(&bank->lock); of_property_read_string(np, "st,bank-name", &range->name); bank->gpio_chip.label = range->name;