From patchwork Fri Feb 5 12:08:21 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= X-Patchwork-Id: 579466 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3A2941409A0 for ; Fri, 5 Feb 2016 23:11:56 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aRfD5-00028d-4P; Fri, 05 Feb 2016 12:09:59 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aRfCL-0001eY-DJ for linux-arm-kernel@lists.infradead.org; Fri, 05 Feb 2016 12:09:17 +0000 Received: from ptx.hi.pengutronix.de ([2001:67c:670:100:1d::c0] ident=Debian-exim) by metis.ext.pengutronix.de with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from ) id 1aRfBz-00085y-8N; Fri, 05 Feb 2016 13:08:51 +0100 Received: from ukl by ptx.hi.pengutronix.de with local (Exim 4.84) (envelope-from ) id 1aRfBy-0001ji-VA; Fri, 05 Feb 2016 13:08:51 +0100 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: Ezequiel Garcia , Dmitry Torokhov , Sylvain Rochet , Johan Hovold , Daniel Mack , Haojian Zhuang , Robert Jarzmik Subject: [PATCH v3 3/3] Input: rotary-encoder - support more than 2 gpios as input Date: Fri, 5 Feb 2016 13:08:21 +0100 Message-Id: <1454674101-1194-4-git-send-email-u.kleine-koenig@pengutronix.de> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1454674101-1194-1-git-send-email-u.kleine-koenig@pengutronix.de> References: <1454674101-1194-1-git-send-email-u.kleine-koenig@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::c0 X-SA-Exim-Mail-From: ukl@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-arm-kernel@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160205_040913_716121_2543C5A4 X-CRM114-Status: GOOD ( 27.06 ) X-Spam-Score: -2.4 (--) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-2.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.5 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kernel@pengutronix.de, linux-input@vger.kernel.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org This changes how the used gpios are stored (i.e. a struct gpio_descs instead of two struct gpio_desc) and as with >2 gpios the states are numbered differently the function rotary_encoder_get_state returns unencoded numbers instead of grey encoded numbers before. The latter has some implications on how the returned value is used and so the change is bigger than one might expect at first. Acked-by: Rob Herring Signed-off-by: Uwe Kleine-König --- .../devicetree/bindings/input/rotary-encoder.txt | 2 +- drivers/input/misc/rotary_encoder.c | 156 +++++++++------------ 2 files changed, 65 insertions(+), 93 deletions(-) diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt index de99cbbbf6da..6c9f0c8a846c 100644 --- a/Documentation/devicetree/bindings/input/rotary-encoder.txt +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt @@ -1,7 +1,7 @@ Rotary encoder DT bindings Required properties: -- gpios: a spec for two GPIOs to be used +- gpios: a spec for at least two GPIOs to be used, most significant first Optional properties: - linux,axis: the input subsystem axis to map to this rotary encoder. diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 5a4e1d69c4af..09f6de77d1af 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -40,35 +40,42 @@ struct rotary_encoder { unsigned int pos; - struct gpio_desc *gpio_a; - struct gpio_desc *gpio_b; + struct gpio_descs *gpios; - unsigned int irq_a; - unsigned int irq_b; + unsigned int *irq; bool armed; - unsigned char dir; /* 0 - clockwise, 1 - CCW */ + signed char dir; /* 1 - clockwise, -1 - CCW */ - char last_stable; + unsigned last_stable; }; -static int rotary_encoder_get_state(struct rotary_encoder *encoder) +static unsigned rotary_encoder_get_state(struct rotary_encoder *encoder) { - int a = !!gpiod_get_value_cansleep(encoder->gpio_a); - int b = !!gpiod_get_value_cansleep(encoder->gpio_b); + int i; + unsigned ret = 0; - return ((a << 1) | b); + for (i = 0; i < encoder->gpios->ndescs; ++i) { + int val = gpiod_get_value(encoder->gpios->desc[i]); + /* convert from gray encoding to normal */ + if (ret & 1) + val = !val; + + ret = ret << 1 | val; + } + + return ret & 3; } static void rotary_encoder_report_event(struct rotary_encoder *encoder) { if (encoder->relative_axis) { input_report_rel(encoder->input, - encoder->axis, encoder->dir ? -1 : 1); + encoder->axis, encoder->dir); } else { unsigned int pos = encoder->pos; - if (encoder->dir) { + if (encoder->dir < 0) { /* turning counter-clockwise */ if (encoder->rollover) pos += encoder->steps; @@ -93,7 +100,7 @@ static void rotary_encoder_report_event(struct rotary_encoder *encoder) static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) { struct rotary_encoder *encoder = dev_id; - int state; + unsigned state; mutex_lock(&encoder->access_mutex); @@ -108,12 +115,12 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) break; case 0x1: - case 0x2: + case 0x3: if (encoder->armed) - encoder->dir = state - 1; + encoder->dir = 2 - state; break; - case 0x3: + case 0x2: encoder->armed = true; break; } @@ -126,25 +133,19 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) { struct rotary_encoder *encoder = dev_id; - int state; + unsigned int state; mutex_lock(&encoder->access_mutex); state = rotary_encoder_get_state(encoder); - switch (state) { - case 0x00: - case 0x03: + if (state & 1) { + encoder->dir = ((encoder->last_stable - state + 1) % 4) - 1; + } else { if (state != encoder->last_stable) { rotary_encoder_report_event(encoder); encoder->last_stable = state; } - break; - - case 0x01: - case 0x02: - encoder->dir = (encoder->last_stable + state) & 0x01; - break; } mutex_unlock(&encoder->access_mutex); @@ -155,46 +156,18 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) { struct rotary_encoder *encoder = dev_id; - unsigned char sum; - int state; + unsigned int state; mutex_lock(&encoder->access_mutex); state = rotary_encoder_get_state(encoder); - /* - * We encode the previous and the current state using a byte. - * The previous state in the MSB nibble, the current state in the LSB - * nibble. Then use a table to decide the direction of the turn. - */ - sum = (encoder->last_stable << 4) + state; - switch (sum) { - case 0x31: - case 0x10: - case 0x02: - case 0x23: - encoder->dir = 0; /* clockwise */ - break; - - case 0x13: - case 0x01: - case 0x20: - case 0x32: - encoder->dir = 1; /* counter-clockwise */ - break; - - default: - /* - * Ignore all other values. This covers the case when the - * state didn't change (a spurious interrupt) and the - * cases where the state changed by two steps, making it - * impossible to tell the direction. - * - * In either case, don't report any event and save the - * state for later. - */ + if ((encoder->last_stable + 1) % 4 == state) + encoder->dir = 1; + else if (encoder->last_stable == (state + 1) % 4) + encoder->dir = -1; + else goto out; - } rotary_encoder_report_event(encoder); @@ -213,6 +186,7 @@ static int rotary_encoder_probe(struct platform_device *pdev) irq_handler_t handler; u32 steps_per_period; int err; + unsigned i; encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL); if (!encoder) @@ -243,24 +217,16 @@ static int rotary_encoder_probe(struct platform_device *pdev) encoder->relative_axis = device_property_read_bool(dev, "rotary-encoder,relative-axis"); - encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN); - if (IS_ERR(encoder->gpio_a)) { - err = PTR_ERR(encoder->gpio_a); - dev_err(dev, "unable to get GPIO at index 0: %d\n", err); - return err; + encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); + if (IS_ERR(encoder->gpios)) { + dev_err(dev, "unable to get gpios\n"); + return PTR_ERR(encoder->gpios); } - - encoder->irq_a = gpiod_to_irq(encoder->gpio_a); - - encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN); - if (IS_ERR(encoder->gpio_b)) { - err = PTR_ERR(encoder->gpio_b); - dev_err(dev, "unable to get GPIO at index 1: %d\n", err); - return err; + if (encoder->gpios->ndescs < 2) { + dev_err(dev, "not enough gpios found\n"); + return -EINVAL; } - encoder->irq_b = gpiod_to_irq(encoder->gpio_b); - input = devm_input_allocate_device(dev); if (!input) return -ENOMEM; @@ -277,7 +243,7 @@ static int rotary_encoder_probe(struct platform_device *pdev) input_set_abs_params(input, encoder->axis, 0, encoder->steps, 0, 1); - switch (steps_per_period) { + switch (steps_per_period >> (encoder->gpios->ndescs - 2)) { case 4: handler = &rotary_encoder_quarter_period_irq; encoder->last_stable = rotary_encoder_get_state(encoder); @@ -295,22 +261,26 @@ static int rotary_encoder_probe(struct platform_device *pdev) return -EINVAL; } - err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - DRV_NAME, encoder); - if (err) { - dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); - return err; - } + encoder->irq = + devm_kzalloc(dev, + sizeof(*encoder->irq) * encoder->gpios->ndescs, + GFP_KERNEL); + if (!encoder->irq) + return -ENOMEM; - err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler, + for (i = 0; i < encoder->gpios->ndescs; ++i) { + encoder->irq[i] = gpiod_to_irq(encoder->gpios->desc[i]); + + err = devm_request_threaded_irq(dev, encoder->irq[i], + NULL, handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, DRV_NAME, encoder); - if (err) { - dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); - return err; + if (err) { + dev_err(dev, "unable to request IRQ %d (gpio#%d)\n", + encoder->irq[i], i); + return err; + } } err = input_register_device(input); @@ -332,8 +302,9 @@ static int __maybe_unused rotary_encoder_suspend(struct device *dev) struct rotary_encoder *encoder = dev_get_drvdata(dev); if (device_may_wakeup(dev)) { - enable_irq_wake(encoder->irq_a); - enable_irq_wake(encoder->irq_b); + unsigned int i; + for (i = 0; i < encoder->gpios->ndescs; ++i) + enable_irq_wake(encoder->irq[i]); } return 0; @@ -344,8 +315,9 @@ static int __maybe_unused rotary_encoder_resume(struct device *dev) struct rotary_encoder *encoder = dev_get_drvdata(dev); if (device_may_wakeup(dev)) { - disable_irq_wake(encoder->irq_a); - disable_irq_wake(encoder->irq_b); + unsigned int i; + for (i = 0; i < encoder->gpios->ndescs; ++i) + disable_irq_wake(encoder->irq[i]); } return 0;