As per the recent devicetree binding changes, this commit adds the support for the new 'steps-per-period' property. Legacy properties to specify the rotary behavior, are now deprecated and instead the new 'steps-per-period' is supported. The default behavior is retained. This allows to support rotary-encoder devices with detents wich are capable of producing a stable event on each step. Signed-off-by: Guido Martínez <guido@xxxxxxxxxxxxxxxxxxxx> Signed-off-by: Ezequiel Garcia <ezequiel@xxxxxxxxxxxxxxxxxxxx> --- drivers/input/misc/rotary_encoder.c | 87 +++++++++++++++++++++++++++++++++++-- include/linux/rotary_encoder.h | 2 +- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 15a4cc670a3f..e021615dd3c0 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -142,6 +142,55 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) +{ + struct rotary_encoder *encoder = dev_id; + unsigned char sum; + int state; + + state = rotary_encoder_get_state(encoder->pdata); + + /* + * 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. + */ + goto out; + } + + rotary_encoder_report_event(encoder); + +out: + encoder->last_stable = state; + return IRQ_HANDLED; +} + #ifdef CONFIG_OF static const struct of_device_id rotary_encoder_of_match[] = { { .compatible = "rotary-encoder", }, @@ -176,7 +225,26 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic pdata->relative_axis = of_property_read_bool(np, "rotary-encoder,relative-axis"); pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover"); - pdata->half_period = of_property_read_bool(np, "rotary-encoder,half-period"); + + if (!of_get_property(np, "rotary-encoder,steps-per-period", NULL)) { + /* + * Fallback to a one step per period behavior if the + * 'steps-per-period' is not set. + */ + pdata->steps_per_period = 1; + } else { + of_property_read_u32(np, "rotary-encoder,steps-per-period", + &pdata->steps_per_period); + } + + /* + * The 'half-period' property has been deprecated, you must use + * 'steps-per-period' and set an appropriate value. + */ + if (of_get_property(np, "rotary-encoder,half-period", NULL)) { + pr_warn(FW_WARN "\"rotary-encoder,half-period\" is deprecated\n"); + pdata->steps_per_period = 2; + } return pdata; } @@ -247,12 +315,23 @@ static int rotary_encoder_probe(struct platform_device *pdev) encoder->irq_a = gpio_to_irq(pdata->gpio_a); encoder->irq_b = gpio_to_irq(pdata->gpio_b); - /* request the IRQs */ - if (pdata->half_period) { + switch (pdata->steps_per_period) { + case 4: + handler = &rotary_encoder_quarter_period_irq; + encoder->last_stable = rotary_encoder_get_state(pdata); + break; + case 2: handler = &rotary_encoder_half_period_irq; encoder->last_stable = rotary_encoder_get_state(pdata); - } else { + break; + case 1: handler = &rotary_encoder_irq; + break; + default: + dev_err(dev, "'%d' is not a valid steps-per-period value\n", + pdata->steps_per_period); + err = -EINVAL; + goto exit_free_gpio_b; } err = request_irq(encoder->irq_a, handler, diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index 3f594dce5716..0bebba31908c 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h @@ -10,7 +10,7 @@ struct rotary_encoder_platform_data { unsigned int inverted_b; bool relative_axis; bool rollover; - bool half_period; + unsigned int steps_per_period; }; #endif /* __ROTARY_ENCODER_H__ */ -- 2.5.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html