Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: rotary-encoder - add support for half-period encoders

Add support for encoders that have two detents per input signal period.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Acked-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Johan Hovold and committed by
Dmitry Torokhov
e70bdd41 521a8f5c

+53 -3
+13
Documentation/input/rotary-encoder.txt
··· 9 9 and by triggering on falling and rising edges, the turn direction can 10 10 be determined. 11 11 12 + Some encoders have both outputs low in stable states, whereas others also have 13 + a stable state with both outputs high (half-period mode). 14 + 12 15 The phase diagram of these two outputs look like this: 13 16 14 17 _____ _____ _____ ··· 29 26 |<-------->| 30 27 one step 31 28 29 + |<-->| 30 + one step (half-period mode) 32 31 33 32 For more information, please see 34 33 http://en.wikipedia.org/wiki/Rotary_encoder ··· 38 33 39 34 1. Events / state machine 40 35 ------------------------- 36 + 37 + In half-period mode, state a) and c) above are used to determine the 38 + rotational direction based on the last stable state. Events are reported in 39 + states b) and d) given that the new stable state is different from the last 40 + (i.e. the rotation was not reversed half-way). 41 + 42 + Otherwise, the following apply: 41 43 42 44 a) Rising edge on channel A, channel B in low state 43 45 This state is used to recognize a clockwise turn ··· 108 96 .gpio_b = GPIO_ROTARY_B, 109 97 .inverted_a = 0, 110 98 .inverted_b = 0, 99 + .half_period = false, 111 100 }; 112 101 113 102 static struct platform_device rotary_encoder_device = {
+39 -3
drivers/input/misc/rotary_encoder.c
··· 2 2 * rotary_encoder.c 3 3 * 4 4 * (c) 2009 Daniel Mack <daniel@caiaq.de> 5 + * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com> 5 6 * 6 7 * state machine code inspired by code from Tim Ruetz 7 8 * ··· 39 38 40 39 bool armed; 41 40 unsigned char dir; /* 0 - clockwise, 1 - CCW */ 41 + 42 + char last_stable; 42 43 }; 43 44 44 45 static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) ··· 115 112 return IRQ_HANDLED; 116 113 } 117 114 115 + static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) 116 + { 117 + struct rotary_encoder *encoder = dev_id; 118 + int state; 119 + 120 + state = rotary_encoder_get_state(encoder->pdata); 121 + 122 + switch (state) { 123 + case 0x00: 124 + case 0x03: 125 + if (state != encoder->last_stable) { 126 + rotary_encoder_report_event(encoder); 127 + encoder->last_stable = state; 128 + } 129 + break; 130 + 131 + case 0x01: 132 + case 0x02: 133 + encoder->dir = (encoder->last_stable + state) & 0x01; 134 + break; 135 + } 136 + 137 + return IRQ_HANDLED; 138 + } 139 + 118 140 static int __devinit rotary_encoder_probe(struct platform_device *pdev) 119 141 { 120 142 struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; 121 143 struct rotary_encoder *encoder; 122 144 struct input_dev *input; 145 + irq_handler_t handler; 123 146 int err; 124 147 125 148 if (!pdata) { ··· 216 187 } 217 188 218 189 /* request the IRQs */ 219 - err = request_irq(encoder->irq_a, &rotary_encoder_irq, 190 + if (pdata->half_period) { 191 + handler = &rotary_encoder_half_period_irq; 192 + encoder->last_stable = rotary_encoder_get_state(pdata); 193 + } else { 194 + handler = &rotary_encoder_irq; 195 + } 196 + 197 + err = request_irq(encoder->irq_a, handler, 220 198 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 221 199 DRV_NAME, encoder); 222 200 if (err) { ··· 232 196 goto exit_free_gpio_b; 233 197 } 234 198 235 - err = request_irq(encoder->irq_b, &rotary_encoder_irq, 199 + err = request_irq(encoder->irq_b, handler, 236 200 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 237 201 DRV_NAME, encoder); 238 202 if (err) { ··· 300 264 301 265 MODULE_ALIAS("platform:" DRV_NAME); 302 266 MODULE_DESCRIPTION("GPIO rotary encoder driver"); 303 - MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 267 + MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold"); 304 268 MODULE_LICENSE("GPL v2");
+1
include/linux/rotary_encoder.h
··· 10 10 unsigned int inverted_b; 11 11 bool relative_axis; 12 12 bool rollover; 13 + bool half_period; 13 14 }; 14 15 15 16 #endif /* __ROTARY_ENCODER_H__ */