18c2ecf20Sopenharmony_ci============================================================
28c2ecf20Sopenharmony_cirotary-encoder - a generic driver for GPIO connected devices
38c2ecf20Sopenharmony_ci============================================================
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci:Author: Daniel Mack <daniel@caiaq.de>, Feb 2009
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ciFunction
88c2ecf20Sopenharmony_ci--------
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciRotary encoders are devices which are connected to the CPU or other
118c2ecf20Sopenharmony_ciperipherals with two wires. The outputs are phase-shifted by 90 degrees
128c2ecf20Sopenharmony_ciand by triggering on falling and rising edges, the turn direction can
138c2ecf20Sopenharmony_cibe determined.
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciSome encoders have both outputs low in stable states, others also have
168c2ecf20Sopenharmony_cia stable state with both outputs high (half-period mode) and some have
178c2ecf20Sopenharmony_cia stable state in all steps (quarter-period mode).
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciThe phase diagram of these two outputs look like this::
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci                  _____       _____       _____
228c2ecf20Sopenharmony_ci                 |     |     |     |     |     |
238c2ecf20Sopenharmony_ci  Channel A  ____|     |_____|     |_____|     |____
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci                 :  :  :  :  :  :  :  :  :  :  :  :
268c2ecf20Sopenharmony_ci            __       _____       _____       _____
278c2ecf20Sopenharmony_ci              |     |     |     |     |     |     |
288c2ecf20Sopenharmony_ci  Channel B   |_____|     |_____|     |_____|     |__
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci                 :  :  :  :  :  :  :  :  :  :  :  :
318c2ecf20Sopenharmony_ci  Event          a  b  c  d  a  b  c  d  a  b  c  d
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci                |<-------->|
348c2ecf20Sopenharmony_ci	          one step
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci                |<-->|
378c2ecf20Sopenharmony_ci	          one step (half-period mode)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci                |<>|
408c2ecf20Sopenharmony_ci	          one step (quarter-period mode)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciFor more information, please see
438c2ecf20Sopenharmony_ci	https://en.wikipedia.org/wiki/Rotary_encoder
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciEvents / state machine
478c2ecf20Sopenharmony_ci----------------------
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciIn half-period mode, state a) and c) above are used to determine the
508c2ecf20Sopenharmony_cirotational direction based on the last stable state. Events are reported in
518c2ecf20Sopenharmony_cistates b) and d) given that the new stable state is different from the last
528c2ecf20Sopenharmony_ci(i.e. the rotation was not reversed half-way).
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciOtherwise, the following apply:
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cia) Rising edge on channel A, channel B in low state
578c2ecf20Sopenharmony_ci	This state is used to recognize a clockwise turn
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cib) Rising edge on channel B, channel A in high state
608c2ecf20Sopenharmony_ci	When entering this state, the encoder is put into 'armed' state,
618c2ecf20Sopenharmony_ci	meaning that there it has seen half the way of a one-step transition.
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cic) Falling edge on channel A, channel B in high state
648c2ecf20Sopenharmony_ci	This state is used to recognize a counter-clockwise turn
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cid) Falling edge on channel B, channel A in low state
678c2ecf20Sopenharmony_ci	Parking position. If the encoder enters this state, a full transition
688c2ecf20Sopenharmony_ci	should have happened, unless it flipped back on half the way. The
698c2ecf20Sopenharmony_ci	'armed' state tells us about that.
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciPlatform requirements
728c2ecf20Sopenharmony_ci---------------------
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciAs there is no hardware dependent call in this driver, the platform it is
758c2ecf20Sopenharmony_ciused with must support gpiolib. Another requirement is that IRQs must be
768c2ecf20Sopenharmony_ciable to fire on both edges.
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ciBoard integration
808c2ecf20Sopenharmony_ci-----------------
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciTo use this driver in your system, register a platform_device with the
838c2ecf20Sopenharmony_ciname 'rotary-encoder' and associate the IRQs and some specific platform
848c2ecf20Sopenharmony_cidata with it. Because the driver uses generic device properties, this can
858c2ecf20Sopenharmony_cibe done either via device tree, ACPI, or using static board files, like in
868c2ecf20Sopenharmony_ciexample below:
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci::
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	/* board support file example */
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	#include <linux/input.h>
938c2ecf20Sopenharmony_ci	#include <linux/gpio/machine.h>
948c2ecf20Sopenharmony_ci	#include <linux/property.h>
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	#define GPIO_ROTARY_A 1
978c2ecf20Sopenharmony_ci	#define GPIO_ROTARY_B 2
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	static struct gpiod_lookup_table rotary_encoder_gpios = {
1008c2ecf20Sopenharmony_ci		.dev_id = "rotary-encoder.0",
1018c2ecf20Sopenharmony_ci		.table = {
1028c2ecf20Sopenharmony_ci			GPIO_LOOKUP_IDX("gpio-0",
1038c2ecf20Sopenharmony_ci					GPIO_ROTARY_A, NULL, 0, GPIO_ACTIVE_LOW),
1048c2ecf20Sopenharmony_ci			GPIO_LOOKUP_IDX("gpio-0",
1058c2ecf20Sopenharmony_ci					GPIO_ROTARY_B, NULL, 1, GPIO_ACTIVE_HIGH),
1068c2ecf20Sopenharmony_ci			{ },
1078c2ecf20Sopenharmony_ci		},
1088c2ecf20Sopenharmony_ci	};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	static const struct property_entry rotary_encoder_properties[] __initconst = {
1118c2ecf20Sopenharmony_ci		PROPERTY_ENTRY_U32("rotary-encoder,steps-per-period", 24),
1128c2ecf20Sopenharmony_ci		PROPERTY_ENTRY_U32("linux,axis",		      ABS_X),
1138c2ecf20Sopenharmony_ci		PROPERTY_ENTRY_U32("rotary-encoder,relative_axis",    0),
1148c2ecf20Sopenharmony_ci		{ },
1158c2ecf20Sopenharmony_ci	};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	static struct platform_device rotary_encoder_device = {
1188c2ecf20Sopenharmony_ci		.name		= "rotary-encoder",
1198c2ecf20Sopenharmony_ci		.id		= 0,
1208c2ecf20Sopenharmony_ci	};
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	...
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	gpiod_add_lookup_table(&rotary_encoder_gpios);
1258c2ecf20Sopenharmony_ci	device_add_properties(&rotary_encoder_device, rotary_encoder_properties);
1268c2ecf20Sopenharmony_ci	platform_device_register(&rotary_encoder_device);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	...
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciPlease consult device tree binding documentation to see all properties
1318c2ecf20Sopenharmony_cisupported by the driver.
132