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 REL_* axes

The rotary encoder driver only supports returning input events
for ABS_* axes, this adds support for REL_* axes. The relative
axis input event is reported as -1 for each counter-clockwise
step and +1 for each clockwise step.

The ability to clamp the position of ABS_* axes between 0 and
a maximum of "steps" has also been added.

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

H Hartley Sweeten and committed by
Dmitry Torokhov
bd3ce655 3f3e7c6e

+51 -21
+8 -1
Documentation/input/rotary-encoder.txt
··· 67 67 struct rotary_encoder_platform_data is declared in 68 68 include/linux/rotary-encoder.h and needs to be filled with the number of 69 69 steps the encoder has and can carry information about externally inverted 70 - signals (because of used invertig buffer or other reasons). 70 + signals (because of an inverting buffer or other reasons). The encoder 71 + can be set up to deliver input information as either an absolute or relative 72 + axes. For relative axes the input event returns +/-1 for each step. For 73 + absolute axes the position of the encoder can either roll over between zero 74 + and the number of steps or will clamp at the maximum and zero depending on 75 + the configuration. 71 76 72 77 Because GPIO to IRQ mapping is platform specific, this information must 73 78 be given in seperately to the driver. See the example below. ··· 90 85 static struct rotary_encoder_platform_data my_rotary_encoder_info = { 91 86 .steps = 24, 92 87 .axis = ABS_X, 88 + .relative_axis = false, 89 + .rollover = false, 93 90 .gpio_a = GPIO_ROTARY_A, 94 91 .gpio_b = GPIO_ROTARY_B, 95 92 .inverted_a = 0,
+41 -20
drivers/input/misc/rotary_encoder.c
··· 26 26 #define DRV_NAME "rotary-encoder" 27 27 28 28 struct rotary_encoder { 29 - unsigned int irq_a; 30 - unsigned int irq_b; 31 - unsigned int pos; 32 - unsigned int armed; 33 - unsigned int dir; 34 29 struct input_dev *input; 35 30 struct rotary_encoder_platform_data *pdata; 31 + 32 + unsigned int axis; 33 + unsigned int pos; 34 + 35 + unsigned int irq_a; 36 + unsigned int irq_b; 37 + 38 + bool armed; 39 + unsigned char dir; /* 0 - clockwise, 1 - CCW */ 36 40 }; 37 41 38 42 static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) ··· 57 53 if (!encoder->armed) 58 54 break; 59 55 60 - if (encoder->dir) { 61 - /* turning counter-clockwise */ 62 - encoder->pos += pdata->steps; 63 - encoder->pos--; 64 - encoder->pos %= pdata->steps; 56 + if (pdata->relative_axis) { 57 + input_report_rel(encoder->input, pdata->axis, 58 + encoder->dir ? -1 : 1); 65 59 } else { 66 - /* turning clockwise */ 67 - encoder->pos++; 68 - encoder->pos %= pdata->steps; 69 - } 60 + unsigned int pos = encoder->pos; 70 61 71 - input_report_abs(encoder->input, pdata->axis, encoder->pos); 62 + if (encoder->dir) { 63 + /* turning counter-clockwise */ 64 + if (pdata->rollover) 65 + pos += pdata->steps; 66 + if (pos) 67 + pos--; 68 + } else { 69 + /* turning clockwise */ 70 + if (pdata->rollover || pos < pdata->steps) 71 + pos++; 72 + } 73 + if (pdata->rollover) 74 + pos %= pdata->steps; 75 + encoder->pos = pos; 76 + input_report_abs(encoder->input, pdata->axis, 77 + encoder->pos); 78 + } 72 79 input_sync(encoder->input); 73 80 74 - encoder->armed = 0; 81 + encoder->armed = false; 75 82 break; 76 83 77 84 case 0x1: ··· 92 77 break; 93 78 94 79 case 0x3: 95 - encoder->armed = 1; 80 + encoder->armed = true; 96 81 break; 97 82 } 98 83 ··· 128 113 input->name = pdev->name; 129 114 input->id.bustype = BUS_HOST; 130 115 input->dev.parent = &pdev->dev; 131 - input->evbit[0] = BIT_MASK(EV_ABS); 132 - input_set_abs_params(encoder->input, 133 - pdata->axis, 0, pdata->steps, 0, 1); 116 + 117 + if (pdata->relative_axis) { 118 + input->evbit[0] = BIT_MASK(EV_REL); 119 + input->relbit[0] = BIT_MASK(pdata->axis); 120 + } else { 121 + input->evbit[0] = BIT_MASK(EV_ABS); 122 + input_set_abs_params(encoder->input, 123 + pdata->axis, 0, pdata->steps, 0, 1); 124 + } 134 125 135 126 err = input_register_device(input); 136 127 if (err) {
+2
include/linux/rotary_encoder.h
··· 8 8 unsigned int gpio_b; 9 9 unsigned int inverted_a; 10 10 unsigned int inverted_b; 11 + bool relative_axis; 12 + bool rollover; 11 13 }; 12 14 13 15 #endif /* __ROTARY_ENCODER_H__ */