xref: /openbmc/linux/Documentation/input/devices/rotary-encoder.rst (revision 5a94296bc02ac616336da7b5332b86d2ca8827f0)
1b08c118cSDmitry Torokhov============================================================
2b08c118cSDmitry Torokhovrotary-encoder - a generic driver for GPIO connected devices
3b08c118cSDmitry Torokhov============================================================
4b08c118cSDmitry Torokhov
5b08c118cSDmitry Torokhov:Author: Daniel Mack <daniel@caiaq.de>, Feb 2009
6b08c118cSDmitry Torokhov
7b08c118cSDmitry TorokhovFunction
8b08c118cSDmitry Torokhov--------
9b08c118cSDmitry Torokhov
10b08c118cSDmitry TorokhovRotary encoders are devices which are connected to the CPU or other
11b08c118cSDmitry Torokhovperipherals with two wires. The outputs are phase-shifted by 90 degrees
12b08c118cSDmitry Torokhovand by triggering on falling and rising edges, the turn direction can
13b08c118cSDmitry Torokhovbe determined.
14b08c118cSDmitry Torokhov
15b08c118cSDmitry TorokhovSome encoders have both outputs low in stable states, others also have
16b08c118cSDmitry Torokhova stable state with both outputs high (half-period mode) and some have
17b08c118cSDmitry Torokhova stable state in all steps (quarter-period mode).
18b08c118cSDmitry Torokhov
19b08c118cSDmitry TorokhovThe phase diagram of these two outputs look like this::
20b08c118cSDmitry Torokhov
21b08c118cSDmitry Torokhov                  _____       _____       _____
22b08c118cSDmitry Torokhov                 |     |     |     |     |     |
23b08c118cSDmitry Torokhov  Channel A  ____|     |_____|     |_____|     |____
24b08c118cSDmitry Torokhov
25b08c118cSDmitry Torokhov                 :  :  :  :  :  :  :  :  :  :  :  :
26b08c118cSDmitry Torokhov            __       _____       _____       _____
27b08c118cSDmitry Torokhov              |     |     |     |     |     |     |
28b08c118cSDmitry Torokhov  Channel B   |_____|     |_____|     |_____|     |__
29b08c118cSDmitry Torokhov
30b08c118cSDmitry Torokhov                 :  :  :  :  :  :  :  :  :  :  :  :
31b08c118cSDmitry Torokhov  Event          a  b  c  d  a  b  c  d  a  b  c  d
32b08c118cSDmitry Torokhov
33b08c118cSDmitry Torokhov                |<-------->|
34b08c118cSDmitry Torokhov	          one step
35b08c118cSDmitry Torokhov
36b08c118cSDmitry Torokhov                |<-->|
37b08c118cSDmitry Torokhov	          one step (half-period mode)
38b08c118cSDmitry Torokhov
39b08c118cSDmitry Torokhov                |<>|
40b08c118cSDmitry Torokhov	          one step (quarter-period mode)
41b08c118cSDmitry Torokhov
42b08c118cSDmitry TorokhovFor more information, please see
43b08c118cSDmitry Torokhov	https://en.wikipedia.org/wiki/Rotary_encoder
44b08c118cSDmitry Torokhov
45b08c118cSDmitry Torokhov
46b08c118cSDmitry TorokhovEvents / state machine
47b08c118cSDmitry Torokhov----------------------
48b08c118cSDmitry Torokhov
49b08c118cSDmitry TorokhovIn half-period mode, state a) and c) above are used to determine the
50b08c118cSDmitry Torokhovrotational direction based on the last stable state. Events are reported in
51b08c118cSDmitry Torokhovstates b) and d) given that the new stable state is different from the last
52b08c118cSDmitry Torokhov(i.e. the rotation was not reversed half-way).
53b08c118cSDmitry Torokhov
54b08c118cSDmitry TorokhovOtherwise, the following apply:
55b08c118cSDmitry Torokhov
56b08c118cSDmitry Torokhova) Rising edge on channel A, channel B in low state
57b08c118cSDmitry Torokhov	This state is used to recognize a clockwise turn
58b08c118cSDmitry Torokhov
59b08c118cSDmitry Torokhovb) Rising edge on channel B, channel A in high state
60b08c118cSDmitry Torokhov	When entering this state, the encoder is put into 'armed' state,
61b08c118cSDmitry Torokhov	meaning that there it has seen half the way of a one-step transition.
62b08c118cSDmitry Torokhov
63b08c118cSDmitry Torokhovc) Falling edge on channel A, channel B in high state
64b08c118cSDmitry Torokhov	This state is used to recognize a counter-clockwise turn
65b08c118cSDmitry Torokhov
66b08c118cSDmitry Torokhovd) Falling edge on channel B, channel A in low state
67b08c118cSDmitry Torokhov	Parking position. If the encoder enters this state, a full transition
68b08c118cSDmitry Torokhov	should have happened, unless it flipped back on half the way. The
69b08c118cSDmitry Torokhov	'armed' state tells us about that.
70b08c118cSDmitry Torokhov
71b08c118cSDmitry TorokhovPlatform requirements
72b08c118cSDmitry Torokhov---------------------
73b08c118cSDmitry Torokhov
74b08c118cSDmitry TorokhovAs there is no hardware dependent call in this driver, the platform it is
75b08c118cSDmitry Torokhovused with must support gpiolib. Another requirement is that IRQs must be
76b08c118cSDmitry Torokhovable to fire on both edges.
77b08c118cSDmitry Torokhov
78b08c118cSDmitry Torokhov
79b08c118cSDmitry TorokhovBoard integration
80b08c118cSDmitry Torokhov-----------------
81b08c118cSDmitry Torokhov
82b08c118cSDmitry TorokhovTo use this driver in your system, register a platform_device with the
83b08c118cSDmitry Torokhovname 'rotary-encoder' and associate the IRQs and some specific platform
84b08c118cSDmitry Torokhovdata with it. Because the driver uses generic device properties, this can
85b08c118cSDmitry Torokhovbe done either via device tree, ACPI, or using static board files, like in
86b08c118cSDmitry Torokhovexample below:
87b08c118cSDmitry Torokhov
88b08c118cSDmitry Torokhov::
89b08c118cSDmitry Torokhov
90b08c118cSDmitry Torokhov	/* board support file example */
91b08c118cSDmitry Torokhov
92b08c118cSDmitry Torokhov	#include <linux/input.h>
93b08c118cSDmitry Torokhov	#include <linux/gpio/machine.h>
94b08c118cSDmitry Torokhov	#include <linux/property.h>
95b08c118cSDmitry Torokhov
96b08c118cSDmitry Torokhov	#define GPIO_ROTARY_A 1
97b08c118cSDmitry Torokhov	#define GPIO_ROTARY_B 2
98b08c118cSDmitry Torokhov
99b08c118cSDmitry Torokhov	static struct gpiod_lookup_table rotary_encoder_gpios = {
100b08c118cSDmitry Torokhov		.dev_id = "rotary-encoder.0",
101b08c118cSDmitry Torokhov		.table = {
102b08c118cSDmitry Torokhov			GPIO_LOOKUP_IDX("gpio-0",
103b08c118cSDmitry Torokhov					GPIO_ROTARY_A, NULL, 0, GPIO_ACTIVE_LOW),
104b08c118cSDmitry Torokhov			GPIO_LOOKUP_IDX("gpio-0",
105b08c118cSDmitry Torokhov					GPIO_ROTARY_B, NULL, 1, GPIO_ACTIVE_HIGH),
106b08c118cSDmitry Torokhov			{ },
107b08c118cSDmitry Torokhov		},
108b08c118cSDmitry Torokhov	};
109b08c118cSDmitry Torokhov
110*6484e758SHeikki Krogerus	static const struct property_entry rotary_encoder_properties[] = {
111a4d5569eSAndy Shevchenko		PROPERTY_ENTRY_U32("rotary-encoder,steps-per-period", 24),
112a4d5569eSAndy Shevchenko		PROPERTY_ENTRY_U32("linux,axis",		      ABS_X),
113a4d5569eSAndy Shevchenko		PROPERTY_ENTRY_U32("rotary-encoder,relative_axis",    0),
114b08c118cSDmitry Torokhov		{ },
115b08c118cSDmitry Torokhov	};
116b08c118cSDmitry Torokhov
117*6484e758SHeikki Krogerus	static const struct software_node rotary_encoder_node = {
118*6484e758SHeikki Krogerus		.properties = rotary_encoder_properties,
119*6484e758SHeikki Krogerus	};
120*6484e758SHeikki Krogerus
121b08c118cSDmitry Torokhov	static struct platform_device rotary_encoder_device = {
122b08c118cSDmitry Torokhov		.name		= "rotary-encoder",
123b08c118cSDmitry Torokhov		.id		= 0,
124b08c118cSDmitry Torokhov	};
125b08c118cSDmitry Torokhov
126b08c118cSDmitry Torokhov	...
127b08c118cSDmitry Torokhov
128b08c118cSDmitry Torokhov	gpiod_add_lookup_table(&rotary_encoder_gpios);
129*6484e758SHeikki Krogerus	device_add_software_node(&rotary_encoder_device.dev, &rotary_encoder_node);
130b08c118cSDmitry Torokhov	platform_device_register(&rotary_encoder_device);
131b08c118cSDmitry Torokhov
132b08c118cSDmitry Torokhov	...
133b08c118cSDmitry Torokhov
134b08c118cSDmitry TorokhovPlease consult device tree binding documentation to see all properties
135b08c118cSDmitry Torokhovsupported by the driver.
136