All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Input: rotary_encoder - Fixups for Dmitry's rework and support for >2 gpios
@ 2016-02-05 12:08 ` Uwe Kleine-König
  0 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: Ezequiel Garcia, Dmitry Torokhov, Sylvain Rochet, Johan Hovold,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-input-u79uwXL29TY76Z2rM5mHXA

Hello,

This bases on top of

	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input rotary-encoder

(currently at 557a30f2f046).

Dmitry, I assume you will squash the two fixups accordingly, otherwise
just tell me, then I create proper patches.

Also let me note that with threaded irqs I'm able to rotate my device
quicker than irq handling happens. So a quick counterclockwise rotation
might be detected as single step clockwise rotation.

Best regards
Uwe

Uwe Kleine-König (3):
  fixup! Input: rotary_encoder - convert to use gpiod API
  fixup! Input: rotary_encoder - use threaded irqs
  Input: rotary-encoder - support more than 2 gpios as input

 .../devicetree/bindings/input/rotary-encoder.txt   |   2 +-
 arch/arm/mach-pxa/raumfeld.c                       |   2 +-
 drivers/input/misc/rotary_encoder.c                | 158 +++++++++------------
 3 files changed, 68 insertions(+), 94 deletions(-)

-- 
2.7.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 0/3] Input: rotary_encoder - Fixups for Dmitry's rework and support for >2 gpios
@ 2016-02-05 12:08 ` Uwe Kleine-König
  0 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

This bases on top of

	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input rotary-encoder

(currently at 557a30f2f046).

Dmitry, I assume you will squash the two fixups accordingly, otherwise
just tell me, then I create proper patches.

Also let me note that with threaded irqs I'm able to rotate my device
quicker than irq handling happens. So a quick counterclockwise rotation
might be detected as single step clockwise rotation.

Best regards
Uwe

Uwe Kleine-K?nig (3):
  fixup! Input: rotary_encoder - convert to use gpiod API
  fixup! Input: rotary_encoder - use threaded irqs
  Input: rotary-encoder - support more than 2 gpios as input

 .../devicetree/bindings/input/rotary-encoder.txt   |   2 +-
 arch/arm/mach-pxa/raumfeld.c                       |   2 +-
 drivers/input/misc/rotary_encoder.c                | 158 +++++++++------------
 3 files changed, 68 insertions(+), 94 deletions(-)

-- 
2.7.0

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 1/3] fixup! Input: rotary_encoder - convert to use gpiod API
  2016-02-05 12:08 ` Uwe Kleine-König
@ 2016-02-05 12:08     ` Uwe Kleine-König
  -1 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: Ezequiel Garcia, Dmitry Torokhov, Sylvain Rochet, Johan Hovold,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-input-u79uwXL29TY76Z2rM5mHXA

---
 arch/arm/mach-pxa/raumfeld.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index c559114431eb..77e412cd2766 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -368,7 +368,7 @@ static struct pxaohci_platform_data raumfeld_ohci_info = {
  */
 
 static struct gpiod_lookup_table raumfeld_rotary_gpios_table = {
-	.dev_id = "rotary-encoder",
+	.dev_id = "rotary-encoder.0",
 	.table = {
 		GPIO_LOOKUP_IDX("gpio-0",
 				GPIO_VOLENC_A, NULL, 0, GPIO_ACTIVE_LOW),
-- 
2.7.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 1/3] fixup! Input: rotary_encoder - convert to use gpiod API
@ 2016-02-05 12:08     ` Uwe Kleine-König
  0 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

---
 arch/arm/mach-pxa/raumfeld.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index c559114431eb..77e412cd2766 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -368,7 +368,7 @@ static struct pxaohci_platform_data raumfeld_ohci_info = {
  */
 
 static struct gpiod_lookup_table raumfeld_rotary_gpios_table = {
-	.dev_id = "rotary-encoder",
+	.dev_id = "rotary-encoder.0",
 	.table = {
 		GPIO_LOOKUP_IDX("gpio-0",
 				GPIO_VOLENC_A, NULL, 0, GPIO_ACTIVE_LOW),
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/3] fixup! Input: rotary_encoder - use threaded irqs
  2016-02-05 12:08 ` Uwe Kleine-König
@ 2016-02-05 12:08   ` Uwe Kleine-König
  -1 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: Ezequiel Garcia, Dmitry Torokhov, Sylvain Rochet, Johan Hovold,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik
  Cc: devicetree, kernel, linux-arm-kernel, linux-input

request_threaed_irq fails if handler == NULL and ONESHOT not in flags.
---
 drivers/input/misc/rotary_encoder.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 309612a6d9f5..5a4e1d69c4af 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -296,7 +296,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	}
 
 	err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+				IRQF_ONESHOT,
 				DRV_NAME, encoder);
 	if (err) {
 		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
@@ -304,7 +305,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	}
 
 	err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+				IRQF_ONESHOT,
 				DRV_NAME, encoder);
 	if (err) {
 		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 2/3] fixup! Input: rotary_encoder - use threaded irqs
@ 2016-02-05 12:08   ` Uwe Kleine-König
  0 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

request_threaed_irq fails if handler == NULL and ONESHOT not in flags.
---
 drivers/input/misc/rotary_encoder.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 309612a6d9f5..5a4e1d69c4af 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -296,7 +296,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	}
 
 	err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+				IRQF_ONESHOT,
 				DRV_NAME, encoder);
 	if (err) {
 		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
@@ -304,7 +305,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	}
 
 	err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+				IRQF_ONESHOT,
 				DRV_NAME, encoder);
 	if (err) {
 		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 3/3] Input: rotary-encoder - support more than 2 gpios as input
  2016-02-05 12:08 ` Uwe Kleine-König
@ 2016-02-05 12:08     ` Uwe Kleine-König
  -1 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: Ezequiel Garcia, Dmitry Torokhov, Sylvain Rochet, Johan Hovold,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-input-u79uwXL29TY76Z2rM5mHXA

This changes how the used gpios are stored (i.e. a struct gpio_descs
instead of two struct gpio_desc) and as with >2 gpios the states are
numbered differently the function rotary_encoder_get_state returns
unencoded numbers instead of grey encoded numbers before. The latter has
some implications on how the returned value is used and so the change is
bigger than one might expect at first.

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 .../devicetree/bindings/input/rotary-encoder.txt   |   2 +-
 drivers/input/misc/rotary_encoder.c                | 156 +++++++++------------
 2 files changed, 65 insertions(+), 93 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt
index de99cbbbf6da..6c9f0c8a846c 100644
--- a/Documentation/devicetree/bindings/input/rotary-encoder.txt
+++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt
@@ -1,7 +1,7 @@
 Rotary encoder DT bindings
 
 Required properties:
-- gpios: a spec for two GPIOs to be used
+- gpios: a spec for at least two GPIOs to be used, most significant first
 
 Optional properties:
 - linux,axis: the input subsystem axis to map to this rotary encoder.
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 5a4e1d69c4af..09f6de77d1af 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -40,35 +40,42 @@ struct rotary_encoder {
 
 	unsigned int pos;
 
-	struct gpio_desc *gpio_a;
-	struct gpio_desc *gpio_b;
+	struct gpio_descs *gpios;
 
-	unsigned int irq_a;
-	unsigned int irq_b;
+	unsigned int *irq;
 
 	bool armed;
-	unsigned char dir;	/* 0 - clockwise, 1 - CCW */
+	signed char dir;	/* 1 - clockwise, -1 - CCW */
 
-	char last_stable;
+	unsigned last_stable;
 };
 
-static int rotary_encoder_get_state(struct rotary_encoder *encoder)
+static unsigned rotary_encoder_get_state(struct rotary_encoder *encoder)
 {
-	int a = !!gpiod_get_value_cansleep(encoder->gpio_a);
-	int b = !!gpiod_get_value_cansleep(encoder->gpio_b);
+	int i;
+	unsigned ret = 0;
 
-	return ((a << 1) | b);
+	for (i = 0; i < encoder->gpios->ndescs; ++i) {
+		int val = gpiod_get_value(encoder->gpios->desc[i]);
+		/* convert from gray encoding to normal */
+		if (ret & 1)
+			val = !val;
+
+		ret = ret << 1 | val;
+	}
+
+	return ret & 3;
 }
 
 static void rotary_encoder_report_event(struct rotary_encoder *encoder)
 {
 	if (encoder->relative_axis) {
 		input_report_rel(encoder->input,
-				 encoder->axis, encoder->dir ? -1 : 1);
+				 encoder->axis, encoder->dir);
 	} else {
 		unsigned int pos = encoder->pos;
 
-		if (encoder->dir) {
+		if (encoder->dir < 0) {
 			/* turning counter-clockwise */
 			if (encoder->rollover)
 				pos += encoder->steps;
@@ -93,7 +100,7 @@ static void rotary_encoder_report_event(struct rotary_encoder *encoder)
 static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
 {
 	struct rotary_encoder *encoder = dev_id;
-	int state;
+	unsigned state;
 
 	mutex_lock(&encoder->access_mutex);
 
@@ -108,12 +115,12 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
 		break;
 
 	case 0x1:
-	case 0x2:
+	case 0x3:
 		if (encoder->armed)
-			encoder->dir = state - 1;
+			encoder->dir = 2 - state;
 		break;
 
-	case 0x3:
+	case 0x2:
 		encoder->armed = true;
 		break;
 	}
@@ -126,25 +133,19 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
 static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
 {
 	struct rotary_encoder *encoder = dev_id;
-	int state;
+	unsigned int state;
 
 	mutex_lock(&encoder->access_mutex);
 
 	state = rotary_encoder_get_state(encoder);
 
-	switch (state) {
-	case 0x00:
-	case 0x03:
+	if (state & 1) {
+		encoder->dir = ((encoder->last_stable - state + 1) % 4) - 1;
+	} else {
 		if (state != encoder->last_stable) {
 			rotary_encoder_report_event(encoder);
 			encoder->last_stable = state;
 		}
-		break;
-
-	case 0x01:
-	case 0x02:
-		encoder->dir = (encoder->last_stable + state) & 0x01;
-		break;
 	}
 
 	mutex_unlock(&encoder->access_mutex);
@@ -155,46 +156,18 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
 static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
 {
 	struct rotary_encoder *encoder = dev_id;
-	unsigned char sum;
-	int state;
+	unsigned int state;
 
 	mutex_lock(&encoder->access_mutex);
 
 	state = rotary_encoder_get_state(encoder);
 
-	/*
-	 * 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.
-		 */
+	if ((encoder->last_stable + 1) % 4 == state)
+		encoder->dir = 1;
+	else if (encoder->last_stable == (state + 1) % 4)
+		encoder->dir = -1;
+	else
 		goto out;
-	}
 
 	rotary_encoder_report_event(encoder);
 
@@ -213,6 +186,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	irq_handler_t handler;
 	u32 steps_per_period;
 	int err;
+	unsigned i;
 
 	encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL);
 	if (!encoder)
@@ -243,24 +217,16 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	encoder->relative_axis =
 		device_property_read_bool(dev, "rotary-encoder,relative-axis");
 
-	encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN);
-	if (IS_ERR(encoder->gpio_a)) {
-		err = PTR_ERR(encoder->gpio_a);
-		dev_err(dev, "unable to get GPIO at index 0: %d\n", err);
-		return err;
+	encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
+	if (IS_ERR(encoder->gpios)) {
+		dev_err(dev, "unable to get gpios\n");
+		return PTR_ERR(encoder->gpios);
 	}
-
-	encoder->irq_a = gpiod_to_irq(encoder->gpio_a);
-
-	encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN);
-	if (IS_ERR(encoder->gpio_b)) {
-		err = PTR_ERR(encoder->gpio_b);
-		dev_err(dev, "unable to get GPIO at index 1: %d\n", err);
-		return err;
+	if (encoder->gpios->ndescs < 2) {
+		dev_err(dev, "not enough gpios found\n");
+		return -EINVAL;
 	}
 
-	encoder->irq_b = gpiod_to_irq(encoder->gpio_b);
-
 	input = devm_input_allocate_device(dev);
 	if (!input)
 		return -ENOMEM;
@@ -277,7 +243,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 		input_set_abs_params(input,
 				     encoder->axis, 0, encoder->steps, 0, 1);
 
-	switch (steps_per_period) {
+	switch (steps_per_period >> (encoder->gpios->ndescs - 2)) {
 	case 4:
 		handler = &rotary_encoder_quarter_period_irq;
 		encoder->last_stable = rotary_encoder_get_state(encoder);
@@ -295,22 +261,26 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-				IRQF_ONESHOT,
-				DRV_NAME, encoder);
-	if (err) {
-		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
-		return err;
-	}
+	encoder->irq =
+		devm_kzalloc(dev,
+			     sizeof(*encoder->irq) * encoder->gpios->ndescs,
+			     GFP_KERNEL);
+	if (!encoder->irq)
+		return -ENOMEM;
 
-	err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler,
+	for (i = 0; i < encoder->gpios->ndescs; ++i) {
+		encoder->irq[i] = gpiod_to_irq(encoder->gpios->desc[i]);
+
+		err = devm_request_threaded_irq(dev, encoder->irq[i],
+				NULL, handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
 				IRQF_ONESHOT,
 				DRV_NAME, encoder);
-	if (err) {
-		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
-		return err;
+		if (err) {
+			dev_err(dev, "unable to request IRQ %d (gpio#%d)\n",
+				encoder->irq[i], i);
+			return err;
+		}
 	}
 
 	err = input_register_device(input);
@@ -332,8 +302,9 @@ static int __maybe_unused rotary_encoder_suspend(struct device *dev)
 	struct rotary_encoder *encoder = dev_get_drvdata(dev);
 
 	if (device_may_wakeup(dev)) {
-		enable_irq_wake(encoder->irq_a);
-		enable_irq_wake(encoder->irq_b);
+		unsigned int i;
+		for (i = 0; i < encoder->gpios->ndescs; ++i)
+			enable_irq_wake(encoder->irq[i]);
 	}
 
 	return 0;
@@ -344,8 +315,9 @@ static int __maybe_unused rotary_encoder_resume(struct device *dev)
 	struct rotary_encoder *encoder = dev_get_drvdata(dev);
 
 	if (device_may_wakeup(dev)) {
-		disable_irq_wake(encoder->irq_a);
-		disable_irq_wake(encoder->irq_b);
+		unsigned int i;
+		for (i = 0; i < encoder->gpios->ndescs; ++i)
+			disable_irq_wake(encoder->irq[i]);
 	}
 
 	return 0;
-- 
2.7.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3 3/3] Input: rotary-encoder - support more than 2 gpios as input
@ 2016-02-05 12:08     ` Uwe Kleine-König
  0 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-05 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

This changes how the used gpios are stored (i.e. a struct gpio_descs
instead of two struct gpio_desc) and as with >2 gpios the states are
numbered differently the function rotary_encoder_get_state returns
unencoded numbers instead of grey encoded numbers before. The latter has
some implications on how the returned value is used and so the change is
bigger than one might expect at first.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
 .../devicetree/bindings/input/rotary-encoder.txt   |   2 +-
 drivers/input/misc/rotary_encoder.c                | 156 +++++++++------------
 2 files changed, 65 insertions(+), 93 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt
index de99cbbbf6da..6c9f0c8a846c 100644
--- a/Documentation/devicetree/bindings/input/rotary-encoder.txt
+++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt
@@ -1,7 +1,7 @@
 Rotary encoder DT bindings
 
 Required properties:
-- gpios: a spec for two GPIOs to be used
+- gpios: a spec for at least two GPIOs to be used, most significant first
 
 Optional properties:
 - linux,axis: the input subsystem axis to map to this rotary encoder.
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 5a4e1d69c4af..09f6de77d1af 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -40,35 +40,42 @@ struct rotary_encoder {
 
 	unsigned int pos;
 
-	struct gpio_desc *gpio_a;
-	struct gpio_desc *gpio_b;
+	struct gpio_descs *gpios;
 
-	unsigned int irq_a;
-	unsigned int irq_b;
+	unsigned int *irq;
 
 	bool armed;
-	unsigned char dir;	/* 0 - clockwise, 1 - CCW */
+	signed char dir;	/* 1 - clockwise, -1 - CCW */
 
-	char last_stable;
+	unsigned last_stable;
 };
 
-static int rotary_encoder_get_state(struct rotary_encoder *encoder)
+static unsigned rotary_encoder_get_state(struct rotary_encoder *encoder)
 {
-	int a = !!gpiod_get_value_cansleep(encoder->gpio_a);
-	int b = !!gpiod_get_value_cansleep(encoder->gpio_b);
+	int i;
+	unsigned ret = 0;
 
-	return ((a << 1) | b);
+	for (i = 0; i < encoder->gpios->ndescs; ++i) {
+		int val = gpiod_get_value(encoder->gpios->desc[i]);
+		/* convert from gray encoding to normal */
+		if (ret & 1)
+			val = !val;
+
+		ret = ret << 1 | val;
+	}
+
+	return ret & 3;
 }
 
 static void rotary_encoder_report_event(struct rotary_encoder *encoder)
 {
 	if (encoder->relative_axis) {
 		input_report_rel(encoder->input,
-				 encoder->axis, encoder->dir ? -1 : 1);
+				 encoder->axis, encoder->dir);
 	} else {
 		unsigned int pos = encoder->pos;
 
-		if (encoder->dir) {
+		if (encoder->dir < 0) {
 			/* turning counter-clockwise */
 			if (encoder->rollover)
 				pos += encoder->steps;
@@ -93,7 +100,7 @@ static void rotary_encoder_report_event(struct rotary_encoder *encoder)
 static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
 {
 	struct rotary_encoder *encoder = dev_id;
-	int state;
+	unsigned state;
 
 	mutex_lock(&encoder->access_mutex);
 
@@ -108,12 +115,12 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
 		break;
 
 	case 0x1:
-	case 0x2:
+	case 0x3:
 		if (encoder->armed)
-			encoder->dir = state - 1;
+			encoder->dir = 2 - state;
 		break;
 
-	case 0x3:
+	case 0x2:
 		encoder->armed = true;
 		break;
 	}
@@ -126,25 +133,19 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
 static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
 {
 	struct rotary_encoder *encoder = dev_id;
-	int state;
+	unsigned int state;
 
 	mutex_lock(&encoder->access_mutex);
 
 	state = rotary_encoder_get_state(encoder);
 
-	switch (state) {
-	case 0x00:
-	case 0x03:
+	if (state & 1) {
+		encoder->dir = ((encoder->last_stable - state + 1) % 4) - 1;
+	} else {
 		if (state != encoder->last_stable) {
 			rotary_encoder_report_event(encoder);
 			encoder->last_stable = state;
 		}
-		break;
-
-	case 0x01:
-	case 0x02:
-		encoder->dir = (encoder->last_stable + state) & 0x01;
-		break;
 	}
 
 	mutex_unlock(&encoder->access_mutex);
@@ -155,46 +156,18 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
 static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
 {
 	struct rotary_encoder *encoder = dev_id;
-	unsigned char sum;
-	int state;
+	unsigned int state;
 
 	mutex_lock(&encoder->access_mutex);
 
 	state = rotary_encoder_get_state(encoder);
 
-	/*
-	 * 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.
-		 */
+	if ((encoder->last_stable + 1) % 4 == state)
+		encoder->dir = 1;
+	else if (encoder->last_stable == (state + 1) % 4)
+		encoder->dir = -1;
+	else
 		goto out;
-	}
 
 	rotary_encoder_report_event(encoder);
 
@@ -213,6 +186,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	irq_handler_t handler;
 	u32 steps_per_period;
 	int err;
+	unsigned i;
 
 	encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL);
 	if (!encoder)
@@ -243,24 +217,16 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 	encoder->relative_axis =
 		device_property_read_bool(dev, "rotary-encoder,relative-axis");
 
-	encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN);
-	if (IS_ERR(encoder->gpio_a)) {
-		err = PTR_ERR(encoder->gpio_a);
-		dev_err(dev, "unable to get GPIO at index 0: %d\n", err);
-		return err;
+	encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
+	if (IS_ERR(encoder->gpios)) {
+		dev_err(dev, "unable to get gpios\n");
+		return PTR_ERR(encoder->gpios);
 	}
-
-	encoder->irq_a = gpiod_to_irq(encoder->gpio_a);
-
-	encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN);
-	if (IS_ERR(encoder->gpio_b)) {
-		err = PTR_ERR(encoder->gpio_b);
-		dev_err(dev, "unable to get GPIO at index 1: %d\n", err);
-		return err;
+	if (encoder->gpios->ndescs < 2) {
+		dev_err(dev, "not enough gpios found\n");
+		return -EINVAL;
 	}
 
-	encoder->irq_b = gpiod_to_irq(encoder->gpio_b);
-
 	input = devm_input_allocate_device(dev);
 	if (!input)
 		return -ENOMEM;
@@ -277,7 +243,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 		input_set_abs_params(input,
 				     encoder->axis, 0, encoder->steps, 0, 1);
 
-	switch (steps_per_period) {
+	switch (steps_per_period >> (encoder->gpios->ndescs - 2)) {
 	case 4:
 		handler = &rotary_encoder_quarter_period_irq;
 		encoder->last_stable = rotary_encoder_get_state(encoder);
@@ -295,22 +261,26 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-				IRQF_ONESHOT,
-				DRV_NAME, encoder);
-	if (err) {
-		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
-		return err;
-	}
+	encoder->irq =
+		devm_kzalloc(dev,
+			     sizeof(*encoder->irq) * encoder->gpios->ndescs,
+			     GFP_KERNEL);
+	if (!encoder->irq)
+		return -ENOMEM;
 
-	err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler,
+	for (i = 0; i < encoder->gpios->ndescs; ++i) {
+		encoder->irq[i] = gpiod_to_irq(encoder->gpios->desc[i]);
+
+		err = devm_request_threaded_irq(dev, encoder->irq[i],
+				NULL, handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
 				IRQF_ONESHOT,
 				DRV_NAME, encoder);
-	if (err) {
-		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
-		return err;
+		if (err) {
+			dev_err(dev, "unable to request IRQ %d (gpio#%d)\n",
+				encoder->irq[i], i);
+			return err;
+		}
 	}
 
 	err = input_register_device(input);
@@ -332,8 +302,9 @@ static int __maybe_unused rotary_encoder_suspend(struct device *dev)
 	struct rotary_encoder *encoder = dev_get_drvdata(dev);
 
 	if (device_may_wakeup(dev)) {
-		enable_irq_wake(encoder->irq_a);
-		enable_irq_wake(encoder->irq_b);
+		unsigned int i;
+		for (i = 0; i < encoder->gpios->ndescs; ++i)
+			enable_irq_wake(encoder->irq[i]);
 	}
 
 	return 0;
@@ -344,8 +315,9 @@ static int __maybe_unused rotary_encoder_resume(struct device *dev)
 	struct rotary_encoder *encoder = dev_get_drvdata(dev);
 
 	if (device_may_wakeup(dev)) {
-		disable_irq_wake(encoder->irq_a);
-		disable_irq_wake(encoder->irq_b);
+		unsigned int i;
+		for (i = 0; i < encoder->gpios->ndescs; ++i)
+			disable_irq_wake(encoder->irq[i]);
 	}
 
 	return 0;
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v3 0/3] Input: rotary_encoder - Fixups for Dmitry's rework and support for >2 gpios
  2016-02-05 12:08 ` Uwe Kleine-König
@ 2016-02-16  7:33   ` Uwe Kleine-König
  -1 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-16  7:33 UTC (permalink / raw)
  To: Ezequiel Garcia, Dmitry Torokhov, Sylvain Rochet, Johan Hovold,
	Daniel Mack, Haojian Zhuang, Robert Jarzmik
  Cc: devicetree, linux-arm-kernel, kernel, linux-input

Hello Dmitry,

On Fri, Feb 05, 2016 at 01:08:18PM +0100, Uwe Kleine-König wrote:
> Hello,
> 
> This bases on top of
> 
> 	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input rotary-encoder
> 
> (currently at 557a30f2f046).
> 
> Dmitry, I assume you will squash the two fixups accordingly, otherwise
> just tell me, then I create proper patches.
> 
> Also let me note that with threaded irqs I'm able to rotate my device
> quicker than irq handling happens. So a quick counterclockwise rotation
> might be detected as single step clockwise rotation.

gentle ping!

Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3 0/3] Input: rotary_encoder - Fixups for Dmitry's rework and support for >2 gpios
@ 2016-02-16  7:33   ` Uwe Kleine-König
  0 siblings, 0 replies; 10+ messages in thread
From: Uwe Kleine-König @ 2016-02-16  7:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Dmitry,

On Fri, Feb 05, 2016 at 01:08:18PM +0100, Uwe Kleine-K?nig wrote:
> Hello,
> 
> This bases on top of
> 
> 	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input rotary-encoder
> 
> (currently at 557a30f2f046).
> 
> Dmitry, I assume you will squash the two fixups accordingly, otherwise
> just tell me, then I create proper patches.
> 
> Also let me note that with threaded irqs I'm able to rotate my device
> quicker than irq handling happens. So a quick counterclockwise rotation
> might be detected as single step clockwise rotation.

gentle ping!

Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-02-16  7:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-05 12:08 [PATCH v3 0/3] Input: rotary_encoder - Fixups for Dmitry's rework and support for >2 gpios Uwe Kleine-König
2016-02-05 12:08 ` Uwe Kleine-König
2016-02-05 12:08 ` [PATCH v3 2/3] fixup! Input: rotary_encoder - use threaded irqs Uwe Kleine-König
2016-02-05 12:08   ` Uwe Kleine-König
     [not found] ` <1454674101-1194-1-git-send-email-u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2016-02-05 12:08   ` [PATCH v3 1/3] fixup! Input: rotary_encoder - convert to use gpiod API Uwe Kleine-König
2016-02-05 12:08     ` Uwe Kleine-König
2016-02-05 12:08   ` [PATCH v3 3/3] Input: rotary-encoder - support more than 2 gpios as input Uwe Kleine-König
2016-02-05 12:08     ` Uwe Kleine-König
2016-02-16  7:33 ` [PATCH v3 0/3] Input: rotary_encoder - Fixups for Dmitry's rework and support for >2 gpios Uwe Kleine-König
2016-02-16  7:33   ` Uwe Kleine-König

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.