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