Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3913300imu; Mon, 14 Jan 2019 11:17:45 -0800 (PST) X-Google-Smtp-Source: ALg8bN7l+hDIJRi5Z8yF606HtlP/piOLlvQwh0Aa3kB2HB+7K5MALZuiMrCxrtQBz8tl889autEs X-Received: by 2002:a62:c21c:: with SMTP id l28mr27350pfg.74.1547493465746; Mon, 14 Jan 2019 11:17:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1547493465; cv=none; d=google.com; s=arc-20160816; b=l0BL0EWneU8EUn7mXpLK2xAIN1bQLNLG5k8OGjZ0xJwEIhfABjYlkMGXmVdWpoHK0J hb9B3bY+anD2XCVJHI48kQyg6NnujgrvEYqu5YL2hLSiitClJGBp5cGZ6Tk/dAWm2wNc x7DJiDnEHyFndyrfLdMPw1oIubUSM0VEEtyypsOhX4LQBxMr6EwA2bHbPAuJOKESe2RV ZEzC2QJrOnJtaBEL1iMyGmCx8fJDfoW1kJwhumlDbhfWwM6UZU8IvhJlNt6ovsfyYjhm g4ByvcX089cnXICFstWbJvTKiE4caDa6cOSdR8xQJUbybicYO6c1r/vTLU7iDC1isZt7 Q0Fw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=Rt1oOD/no5MPEa9SHIJJf+HNUtIFkv1tL3ImbVPC4fY=; b=l5O3fPx+9lBJGm/cT8oKI129xQm34VietX2dVuEeDibXfxzERF7I04AVywfMotlGtl oRB55q/kGzHRlDs125kc0RGaP5HaMEDRthT9/PkNb8i4EvJNgz/LmoAMpqm9FhgdJTk0 nODcjluU/sEmBhHunROKSoK5udGNoUuJ7Q3OmPqFqAp/ev6qJnUiYggjVAAlBHNYXyPJ TLKHuEscC6erZYlZqmYWSCtZ8EbdU7ARaX2Ybi9Qm/gsbI0bL85RBm4Vse9lAODwQb9E WCe6Vx7nQ0FALmsqdiHxzToj+C+GBrXdQkZF4OH00+ficWBhrEhU0LfsO5A6ZxHmENUt SHfg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q15si965259pgm.420.2019.01.14.11.17.30; Mon, 14 Jan 2019 11:17:45 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726910AbfANTPM (ORCPT + 99 others); Mon, 14 Jan 2019 14:15:12 -0500 Received: from mout.gmx.net ([212.227.17.21]:38791 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726728AbfANTPK (ORCPT ); Mon, 14 Jan 2019 14:15:10 -0500 Received: from longitude ([109.90.232.48]) by mail.gmx.com (mrgmx101 [212.227.17.168]) with ESMTPSA (Nemesis) id 0LeiJ8-1h2EgU1QMA-00qTQn; Mon, 14 Jan 2019 20:15:08 +0100 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= To: linux-gpio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Linus Walleij , Bartosz Golaszewski , =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Subject: [PATCH v2 2/2] gpio: hlwd: Implement edge trigger emulation Date: Mon, 14 Jan 2019 20:14:50 +0100 Message-Id: <20190114191450.11597-3-j.neuschaefer@gmx.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190114191450.11597-1-j.neuschaefer@gmx.net> References: <20190114191450.11597-1-j.neuschaefer@gmx.net> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Provags-ID: V03:K1:mP8bCeC010qffF5qftc4yIN0iStt1NP0xDOUSSNG2lPoC9EV22X 58Aj6+5Rl3GGZ0zd6jftZ2VKkgAWoesdzyDKzNG/uyXZgf1eRlMLfjfQqCZHYXpjSpLXUkl F0+eCgBgZwJ4UfODytQIrQ7lnZkokvkfJc8Bl5u66mDiQIzalvnRJ9CkKZ3iVtpip8DBJI9 Xzf9U2ETvvKPu23NAPg2g== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:ojxmK40wKwk=:N9afsRF1zy4LDGPowC26Wo Pa2xWt4KkLLmJHuDoa06QV/OqgA/GBWkO3GfpHSVxI1T+B+3rqxQj9Xs3v2tzvX8tr6txcMqk 5aMaIjCv91zdD6ylx2NAM/8hxA2tyxrsfRcXcmxGK51GVsQGKzWvwPF8vu8lqZZtoomSvLSan qyv9+/E52JxYG7ko06psteWn87haDYOjCGNIE8gxbngx3OXElPiYOTTbDjwoozhM7gLRXU2dU JR93wxOkPWF55D5nkpQqonaO0JKAM9EndVdINYaJMx+F+m3uyzBznHVskXofkVrl2s91D1AUk VRjOcaqkZFE6PGyuFQJHtt1dneAr5bIxJF2594F6BvG924CSUiFV9X6/OgWqIitLAx52cfZBm VKclQAfXyGAXGhBSKRJkfPTwCJz6ZKX6DNF3mhxERCrcMVvaVX/4ZzpMeVxmzGQNmSaLXv3GJ uIIlF6hcivQkaGUKBaiDhiE+AkziQ6EFGgdFRVmSuTHb1SzHFED9nAwmFtRWYeqwX5m+V7jTK e+3zT7rXtB2yT4WOoTV9RtG1ATE3VxLzgcONGpQDZUENzB68HnEqAR5xeRlaxvYC9NQSehu9b G6byhWEJcBrIbyoZot/DnFlnSmy8qsd4E2rXfZUImqeYaHLgu39Qynd7fxqslRR580xYS253L 5dYiAUQuTCh3vjIdK9c7rGQc9VBeCp9b8/ezEUYKNlLHbhVHtI5hOull9ZReTsu3hHhuN9io8 XWT1rzGjZVAuFMKHwS4DvrKlyMpO3SZ2yv0TUNKRt+fWymJQpQl2d6Ojb7zLjG8FFZu7z/ZW2 9eUXNdVIIEeckkYHOD/6cYX1zdEDc3bmaZvbKAo4SGeSxD+xRNN4rVaSY6SqtHQlX63N9XrnA owJj/oFF5Fk4dFyOKX0ko/Z0epgKH+zpeprAo8QkblTlyMqZGHuVzpqx5hByE7etww86AfukN dtboGKO28nA== Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Like the Spreadtrum EIC driver[1], this driver needs to emulate edge triggered interrupts to support the generic gpio-keys driver. [1]: https://www.spinics.net/lists/kernel/msg2764576.html Signed-off-by: Jonathan Neuschäfer --- v2: - Changed register addresses to io{read,write}32be() instead of hlwd->gpioc.{read,write}_reg, as suggested by Linus Walleij. v1: https://lore.kernel.org/lkml/20190113135844.13109-3-j.neuschaefer@gmx.net/ --- drivers/gpio/gpio-hlwd.c | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c index 61983c115856..a7b17897356e 100644 --- a/drivers/gpio/gpio-hlwd.c +++ b/drivers/gpio/gpio-hlwd.c @@ -51,6 +51,8 @@ struct hlwd_gpio { struct irq_chip irqc; void __iomem *regs; int irq; + u32 edge_emulation; + u32 rising_edge, falling_edge; }; static void hlwd_gpio_irqhandler(struct irq_desc *desc) @@ -61,10 +63,36 @@ static void hlwd_gpio_irqhandler(struct irq_desc *desc) unsigned long flags; unsigned long pending; int hwirq; + u32 emulated_pending; spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); pending = ioread32be(hlwd->regs + HW_GPIOB_INTFLAG); pending &= ioread32be(hlwd->regs + HW_GPIOB_INTMASK); + + /* Treat interrupts due to edge trigger emulation separately */ + emulated_pending = hlwd->edge_emulation & pending; + pending &= ~emulated_pending; + if (emulated_pending) { + u32 level, rising, falling; + + level = ioread32be(hlwd->regs + HW_GPIOB_INTLVL); + rising = level & emulated_pending; + falling = ~level & emulated_pending; + + /* Invert the levels */ + iowrite32be(level ^ emulated_pending, + hlwd->regs + HW_GPIOB_INTLVL); + + /* Ack all emulated-edge interrupts */ + iowrite32be(emulated_pending, hlwd->regs + HW_GPIOB_INTFLAG); + + /* Signal interrupts only on the correct edge */ + rising &= hlwd->rising_edge; + falling &= hlwd->falling_edge; + + /* Mark emulated interrupts as pending */ + pending |= rising | falling; + } spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); chained_irq_enter(chip, desc); @@ -120,6 +148,27 @@ static void hlwd_gpio_irq_enable(struct irq_data *data) hlwd_gpio_irq_unmask(data); } +static void hlwd_gpio_irq_setup_emulation(struct hlwd_gpio *hlwd, int hwirq, + unsigned int flow_type) +{ + u32 level, state; + + /* Set the trigger level to the inactive level */ + level = ioread32be(hlwd->regs + HW_GPIOB_INTLVL); + state = ioread32be(hlwd->regs + HW_GPIOB_IN) & BIT(hwirq); + level &= ~BIT(hwirq); + level |= state ^ BIT(hwirq); + iowrite32be(level, hlwd->regs + HW_GPIOB_INTLVL); + + hlwd->edge_emulation |= BIT(hwirq); + hlwd->rising_edge &= ~BIT(hwirq); + hlwd->falling_edge &= ~BIT(hwirq); + if (flow_type & IRQ_TYPE_EDGE_RISING) + hlwd->rising_edge |= BIT(hwirq); + if (flow_type & IRQ_TYPE_EDGE_FALLING) + hlwd->falling_edge |= BIT(hwirq); +} + static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) { struct hlwd_gpio *hlwd = @@ -129,6 +178,8 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) spin_lock_irqsave(&hlwd->gpioc.bgpio_lock, flags); + hlwd->edge_emulation &= ~BIT(data->hwirq); + switch (flow_type) { case IRQ_TYPE_LEVEL_HIGH: level = ioread32be(hlwd->regs + HW_GPIOB_INTLVL); @@ -140,6 +191,11 @@ static int hlwd_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) level &= ~BIT(data->hwirq); iowrite32be(level, hlwd->regs + HW_GPIOB_INTLVL); break; + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_EDGE_BOTH: + hlwd_gpio_irq_setup_emulation(hlwd, data->hwirq, flow_type); + break; default: spin_unlock_irqrestore(&hlwd->gpioc.bgpio_lock, flags); return -EINVAL; -- 2.20.1