Input: rotary_encoder - add support for REL_* axes
authorH Hartley Sweeten <hartleys@visionengravers.com>
Sat, 18 Apr 2009 03:12:35 +0000 (20:12 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Sat, 18 Apr 2009 03:37:21 +0000 (20:37 -0700)
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>
Documentation/input/rotary-encoder.txt
drivers/input/misc/rotary_encoder.c
include/linux/rotary_encoder.h

index 435102a26d9602fdd6bdce5f34296021ab43243d..3a6aec40c0b0518b6f4f8246ac61ad19a46d8812 100644 (file)
@@ -67,7 +67,12 @@ data with it.
 struct rotary_encoder_platform_data is declared in
 include/linux/rotary-encoder.h and needs to be filled with the number of
 steps the encoder has and can carry information about externally inverted
 struct rotary_encoder_platform_data is declared in
 include/linux/rotary-encoder.h and needs to be filled with the number of
 steps the encoder has and can carry information about externally inverted
-signals (because of used invertig buffer or other reasons).
+signals (because of an inverting buffer or other reasons). The encoder
+can be set up to deliver input information as either an absolute or relative
+axes. For relative axes the input event returns +/-1 for each step. For
+absolute axes the position of the encoder can either roll over between zero
+and the number of steps or will clamp at the maximum and zero depending on
+the configuration.
 
 Because GPIO to IRQ mapping is platform specific, this information must
 be given in seperately to the driver. See the example below.
 
 Because GPIO to IRQ mapping is platform specific, this information must
 be given in seperately to the driver. See the example below.
@@ -85,6 +90,8 @@ be given in seperately to the driver. See the example below.
 static struct rotary_encoder_platform_data my_rotary_encoder_info = {
        .steps          = 24,
        .axis           = ABS_X,
 static struct rotary_encoder_platform_data my_rotary_encoder_info = {
        .steps          = 24,
        .axis           = ABS_X,
+       .relative_axis  = false,
+       .rollover       = false,
        .gpio_a         = GPIO_ROTARY_A,
        .gpio_b         = GPIO_ROTARY_B,
        .inverted_a     = 0,
        .gpio_a         = GPIO_ROTARY_A,
        .gpio_b         = GPIO_ROTARY_B,
        .inverted_a     = 0,
index 5bb3ab51b8c67b7d0dfe2b18be91777ed94a8c4e..c806fbf1e1741ae68a542bc402e8236776c01f7c 100644 (file)
 #define DRV_NAME "rotary-encoder"
 
 struct rotary_encoder {
 #define DRV_NAME "rotary-encoder"
 
 struct rotary_encoder {
-       unsigned int irq_a;
-       unsigned int irq_b;
-       unsigned int pos;
-       unsigned int armed;
-       unsigned int dir;
        struct input_dev *input;
        struct rotary_encoder_platform_data *pdata;
        struct input_dev *input;
        struct rotary_encoder_platform_data *pdata;
+
+       unsigned int axis;
+       unsigned int pos;
+
+       unsigned int irq_a;
+       unsigned int irq_b;
+
+       bool armed;
+       unsigned char dir;      /* 0 - clockwise, 1 - CCW */
 };
 
 static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
 };
 
 static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
@@ -53,21 +57,32 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
                if (!encoder->armed)
                        break;
 
                if (!encoder->armed)
                        break;
 
-               if (encoder->dir) {
-                       /* turning counter-clockwise */
-                       encoder->pos += pdata->steps;
-                       encoder->pos--;
-                       encoder->pos %= pdata->steps;
+               if (pdata->relative_axis) {
+                       input_report_rel(encoder->input, pdata->axis,
+                                        encoder->dir ? -1 : 1);
                } else {
                } else {
-                       /* turning clockwise */
-                       encoder->pos++;
-                       encoder->pos %= pdata->steps;
+                       unsigned int pos = encoder->pos;
+
+                       if (encoder->dir) {
+                               /* turning counter-clockwise */
+                               if (pdata->rollover)
+                                       pos += pdata->steps;
+                               if (pos)
+                                       pos--;
+                       } else {
+                               /* turning clockwise */
+                               if (pdata->rollover || pos < pdata->steps)
+                                       pos++;
+                       }
+                       if (pdata->rollover)
+                               pos %= pdata->steps;
+                       encoder->pos = pos;
+                       input_report_abs(encoder->input, pdata->axis,
+                                        encoder->pos);
                }
                }
-
-               input_report_abs(encoder->input, pdata->axis, encoder->pos);
                input_sync(encoder->input);
 
                input_sync(encoder->input);
 
-               encoder->armed = 0;
+               encoder->armed = false;
                break;
 
        case 0x1:
                break;
 
        case 0x1:
@@ -77,7 +92,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
                break;
 
        case 0x3:
                break;
 
        case 0x3:
-               encoder->armed = 1;
+               encoder->armed = true;
                break;
        }
 
                break;
        }
 
@@ -113,9 +128,15 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
        input->name = pdev->name;
        input->id.bustype = BUS_HOST;
        input->dev.parent = &pdev->dev;
        input->name = pdev->name;
        input->id.bustype = BUS_HOST;
        input->dev.parent = &pdev->dev;
-       input->evbit[0] = BIT_MASK(EV_ABS);
-       input_set_abs_params(encoder->input,
-                            pdata->axis, 0, pdata->steps, 0, 1);
+
+       if (pdata->relative_axis) {
+               input->evbit[0] = BIT_MASK(EV_REL);
+               input->relbit[0] = BIT_MASK(pdata->axis);
+       } else {
+               input->evbit[0] = BIT_MASK(EV_ABS);
+               input_set_abs_params(encoder->input,
+                                    pdata->axis, 0, pdata->steps, 0, 1);
+       }
 
        err = input_register_device(input);
        if (err) {
 
        err = input_register_device(input);
        if (err) {
index 12d63a30c34736e3567321c2924c51999c9fa98e..215278b8df2aba5ca56f5eef120ef7b782523da6 100644 (file)
@@ -8,6 +8,8 @@ struct rotary_encoder_platform_data {
        unsigned int gpio_b;
        unsigned int inverted_a;
        unsigned int inverted_b;
        unsigned int gpio_b;
        unsigned int inverted_a;
        unsigned int inverted_b;
+       bool relative_axis;
+       bool rollover;
 };
 
 #endif /* __ROTARY_ENCODER_H__ */
 };
 
 #endif /* __ROTARY_ENCODER_H__ */