From patchwork Tue Apr 5 19:46:18 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johan Hovold X-Patchwork-Id: 688701 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p35JkFTf012228 for ; Tue, 5 Apr 2011 19:46:53 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753739Ab1DETqw (ORCPT ); Tue, 5 Apr 2011 15:46:52 -0400 Received: from mail-ey0-f174.google.com ([209.85.215.174]:36316 "EHLO mail-ey0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752954Ab1DETqw (ORCPT ); Tue, 5 Apr 2011 15:46:52 -0400 Received: by eyx24 with SMTP id 24so229756eyx.19 for ; Tue, 05 Apr 2011 12:46:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=z+Jx53KMqnbr4qIy90CfuEGtqAsDdF6JtxPIKQaloMc=; b=HdQVAkP2LV0zOyn5viuDww33/CnmrcFQpBGBxIZpvrwnH8V+yUpFGw/KaOdM/tGwg3 iYvNa7qFfmfmt6Z5iDUyqxKvbuctYmldNLChiujAO3HoMNrj4mlpBaJ/vcyVCASswcBv ivD2VXGaHqofMWWfETgk4L9N0fh9NBlKAfpwo= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=Lz+AxOJDAGKIxN5XIB9Yu8aZy9OBuwVECV3NPm+RYBBUUD8bTUpBtZ8eNBwmY+PAl1 qshpSQnuBagPDc+vlcFEnoBtGZz15XurPua/r8SzoCoM4wJTxBbnjv+9tnIsWn3HrCoP TKcODO7EwA3AKPODW+d8zeTP52wV3fMkgTTxM= Received: by 10.213.4.135 with SMTP id 7mr401168ebr.81.1302032810866; Tue, 05 Apr 2011 12:46:50 -0700 (PDT) Received: from xi ([83.249.240.82]) by mx.google.com with ESMTPS id x14sm4197148eeh.13.2011.04.05.12.46.49 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 05 Apr 2011 12:46:50 -0700 (PDT) Received: from johan by xi with local (Exim 4.74) (envelope-from ) id 1Q7CDA-0008JE-4m; Tue, 05 Apr 2011 21:46:48 +0200 From: Johan Hovold To: Dmitry Torokhov Cc: Daniel Mack , linux-input@vger.kernel.org, Johan Hovold Subject: [PATCH 2/2 v3] input: rotary-encoder: add support for half-period encoders Date: Tue, 5 Apr 2011 21:46:18 +0200 Message-Id: <1302032778-31868-1-git-send-email-jhovold@gmail.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1302032381-31453-1-git-send-email-jhovold@gmail.com> References: <1302032381-31453-1-git-send-email-jhovold@gmail.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 05 Apr 2011 19:46:59 +0000 (UTC) Add support for encoders that have two detents per input signal period. Signed-off-by: Johan Hovold --- v2: fix typo in documentation (s/inputs/outputs/) v3: fix typo in documentation (s/ouputs/outputs/) Documentation/input/rotary-encoder.txt | 13 ++++++++++ drivers/input/misc/rotary_encoder.c | 41 +++++++++++++++++++++++++++++-- include/linux/rotary_encoder.h | 1 + 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt index 8b4129d..2ac5c60 100644 --- a/Documentation/input/rotary-encoder.txt +++ b/Documentation/input/rotary-encoder.txt @@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees and by triggering on falling and rising edges, the turn direction can be determined. +Some encoders have both outputs low in stable states, whereas others also have +a stable state with both outputs high (half-period mode). + The phase diagram of these two outputs look like this: _____ _____ _____ @@ -26,6 +29,8 @@ The phase diagram of these two outputs look like this: |<-------->| one step + |<-->| + one step (half-period mode) For more information, please see http://en.wikipedia.org/wiki/Rotary_encoder @@ -34,6 +39,13 @@ For more information, please see 1. Events / state machine ------------------------- +In half-period mode, state a) and c) above are used to determine the +rotational direction based on the last stable state. Events are reported in +states b) and d) given that the new stable state is different from the last +(i.e. the rotation was not reversed half-way). + +Otherwise, the following apply: + a) Rising edge on channel A, channel B in low state This state is used to recognize a clockwise turn @@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = { .gpio_b = GPIO_ROTARY_B, .inverted_a = 0, .inverted_b = 0, + .half_period = false, }; static struct platform_device rotary_encoder_device = { diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 253e502..ce329a6 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -2,6 +2,7 @@ * rotary_encoder.c * * (c) 2009 Daniel Mack + * Copyright (C) 2011 Johan Hovold * * state machine code inspired by code from Tim Ruetz * @@ -38,6 +39,8 @@ struct rotary_encoder { bool armed; unsigned char dir; /* 0 - clockwise, 1 - CCW */ + + char last_stable; }; static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) @@ -116,11 +119,36 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) +{ + struct rotary_encoder *encoder = dev_id; + int state; + + state = rotary_encoder_get_state(encoder->pdata); + + switch (state) { + case 0x00: + case 0x03: + if (state == encoder->last_stable) + break; + rotary_encoder_report_event(encoder); + encoder->last_stable = state; + break; + case 0x01: + case 0x02: + encoder->dir = (encoder->last_stable + state) & 0x01; + break; + } + + return IRQ_HANDLED; +} + static int __devinit rotary_encoder_probe(struct platform_device *pdev) { struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; struct rotary_encoder *encoder; struct input_dev *input; + irq_handler_t handler; int err; if (!pdata) { @@ -191,7 +219,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) } /* request the IRQs */ - err = request_irq(encoder->irq_a, &rotary_encoder_irq, + if (pdata->half_period) { + handler = &rotary_encoder_half_period_irq; + encoder->last_stable = rotary_encoder_get_state(pdata); + } else { + handler = &rotary_encoder_irq; + } + + err = request_irq(encoder->irq_a, handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, DRV_NAME, encoder); if (err) { @@ -200,7 +235,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) goto exit_free_gpio_b; } - err = request_irq(encoder->irq_b, &rotary_encoder_irq, + err = request_irq(encoder->irq_b, handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, DRV_NAME, encoder); if (err) { @@ -268,5 +303,5 @@ module_exit(rotary_encoder_exit); MODULE_ALIAS("platform:" DRV_NAME); MODULE_DESCRIPTION("GPIO rotary encoder driver"); -MODULE_AUTHOR("Daniel Mack "); +MODULE_AUTHOR("Daniel Mack , Johan Hovold"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index 215278b..3f594dc 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h @@ -10,6 +10,7 @@ struct rotary_encoder_platform_data { unsigned int inverted_b; bool relative_axis; bool rollover; + bool half_period; }; #endif /* __ROTARY_ENCODER_H__ */