1/* 2 * rotary_encoder.c 3 * 4 * (c) 2009 Daniel Mack <daniel@caiaq.de> 5 * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com> 6 * 7 * state machine code inspired by code from Tim Ruetz 8 * 9 * A generic driver for rotary encoders connected to GPIO lines. 10 * See file:Documentation/input/rotary-encoder.txt for more information 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License version 2 as 14 * published by the Free Software Foundation. 15 */ 16 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/interrupt.h> 20#include <linux/input.h> 21#include <linux/device.h> 22#include <linux/platform_device.h> 23#include <linux/gpio.h> 24#include <linux/rotary_encoder.h> 25#include <linux/slab.h> 26#include <linux/of.h> 27#include <linux/of_platform.h> 28#include <linux/of_gpio.h> 29 30#define DRV_NAME "rotary-encoder" 31 32struct rotary_encoder { 33 struct input_dev *input; 34 const struct rotary_encoder_platform_data *pdata; 35 36 unsigned int axis; 37 unsigned int pos; 38 39 unsigned int irq_a; 40 unsigned int irq_b; 41 42 bool armed; 43 unsigned char dir; /* 0 - clockwise, 1 - CCW */ 44 45 char last_stable; 46}; 47 48static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata) 49{ 50 int a = !!gpio_get_value(pdata->gpio_a); 51 int b = !!gpio_get_value(pdata->gpio_b); 52 53 a ^= pdata->inverted_a; 54 b ^= pdata->inverted_b; 55 56 return ((a << 1) | b); 57} 58 59static void rotary_encoder_report_event(struct rotary_encoder *encoder) 60{ 61 const struct rotary_encoder_platform_data *pdata = encoder->pdata; 62 63 if (pdata->relative_axis) { 64 input_report_rel(encoder->input, 65 pdata->axis, encoder->dir ? -1 : 1); 66 } else { 67 unsigned int pos = encoder->pos; 68 69 if (encoder->dir) { 70 /* turning counter-clockwise */ 71 if (pdata->rollover) 72 pos += pdata->steps; 73 if (pos) 74 pos--; 75 } else { 76 /* turning clockwise */ 77 if (pdata->rollover || pos < pdata->steps) 78 pos++; 79 } 80 81 if (pdata->rollover) 82 pos %= pdata->steps; 83 84 encoder->pos = pos; 85 input_report_abs(encoder->input, pdata->axis, encoder->pos); 86 } 87 88 input_sync(encoder->input); 89} 90 91static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) 92{ 93 struct rotary_encoder *encoder = dev_id; 94 int state; 95 96 state = rotary_encoder_get_state(encoder->pdata); 97 98 switch (state) { 99 case 0x0: 100 if (encoder->armed) { 101 rotary_encoder_report_event(encoder); 102 encoder->armed = false; 103 } 104 break; 105 106 case 0x1: 107 case 0x2: 108 if (encoder->armed) 109 encoder->dir = state - 1; 110 break; 111 112 case 0x3: 113 encoder->armed = true; 114 break; 115 } 116 117 return IRQ_HANDLED; 118} 119 120static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) 121{ 122 struct rotary_encoder *encoder = dev_id; 123 int state; 124 125 state = rotary_encoder_get_state(encoder->pdata); 126 127 switch (state) { 128 case 0x00: 129 case 0x03: 130 if (state != encoder->last_stable) { 131 rotary_encoder_report_event(encoder); 132 encoder->last_stable = state; 133 } 134 break; 135 136 case 0x01: 137 case 0x02: 138 encoder->dir = (encoder->last_stable + state) & 0x01; 139 break; 140 } 141 142 return IRQ_HANDLED; 143} 144 145#ifdef CONFIG_OF 146static const struct of_device_id rotary_encoder_of_match[] = { 147 { .compatible = "rotary-encoder", }, 148 { }, 149}; 150MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); 151 152static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct device *dev) 153{ 154 const struct of_device_id *of_id = 155 of_match_device(rotary_encoder_of_match, dev); 156 struct device_node *np = dev->of_node; 157 struct rotary_encoder_platform_data *pdata; 158 enum of_gpio_flags flags; 159 160 if (!of_id || !np) 161 return NULL; 162 163 pdata = kzalloc(sizeof(struct rotary_encoder_platform_data), 164 GFP_KERNEL); 165 if (!pdata) 166 return ERR_PTR(-ENOMEM); 167 168 of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps); 169 of_property_read_u32(np, "linux,axis", &pdata->axis); 170 171 pdata->gpio_a = of_get_gpio_flags(np, 0, &flags); 172 pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW; 173 174 pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); 175 pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; 176 177 pdata->relative_axis = !!of_get_property(np, 178 "rotary-encoder,relative-axis", NULL); 179 pdata->rollover = !!of_get_property(np, 180 "rotary-encoder,rollover", NULL); 181 pdata->half_period = !!of_get_property(np, 182 "rotary-encoder,half-period", NULL); 183 184 return pdata; 185} 186#else 187static inline struct rotary_encoder_platform_data * 188rotary_encoder_parse_dt(struct device *dev) 189{ 190 return NULL; 191} 192#endif 193 194static int rotary_encoder_probe(struct platform_device *pdev) 195{ 196 struct device *dev = &pdev->dev; 197 const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev); 198 struct rotary_encoder *encoder; 199 struct input_dev *input; 200 irq_handler_t handler; 201 int err; 202 203 if (!pdata) { 204 pdata = rotary_encoder_parse_dt(dev); 205 if (IS_ERR(pdata)) 206 return PTR_ERR(pdata); 207 208 if (!pdata) { 209 dev_err(dev, "missing platform data\n"); 210 return -EINVAL; 211 } 212 } 213 214 encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); 215 input = input_allocate_device(); 216 if (!encoder || !input) { 217 err = -ENOMEM; 218 goto exit_free_mem; 219 } 220 221 encoder->input = input; 222 encoder->pdata = pdata; 223 224 input->name = pdev->name; 225 input->id.bustype = BUS_HOST; 226 input->dev.parent = dev; 227 228 if (pdata->relative_axis) { 229 input->evbit[0] = BIT_MASK(EV_REL); 230 input->relbit[0] = BIT_MASK(pdata->axis); 231 } else { 232 input->evbit[0] = BIT_MASK(EV_ABS); 233 input_set_abs_params(encoder->input, 234 pdata->axis, 0, pdata->steps, 0, 1); 235 } 236 237 /* request the GPIOs */ 238 err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); 239 if (err) { 240 dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); 241 goto exit_free_mem; 242 } 243 244 err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); 245 if (err) { 246 dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b); 247 goto exit_free_gpio_a; 248 } 249 250 encoder->irq_a = gpio_to_irq(pdata->gpio_a); 251 encoder->irq_b = gpio_to_irq(pdata->gpio_b); 252 253 /* request the IRQs */ 254 if (pdata->half_period) { 255 handler = &rotary_encoder_half_period_irq; 256 encoder->last_stable = rotary_encoder_get_state(pdata); 257 } else { 258 handler = &rotary_encoder_irq; 259 } 260 261 err = request_irq(encoder->irq_a, handler, 262 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 263 DRV_NAME, encoder); 264 if (err) { 265 dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); 266 goto exit_free_gpio_b; 267 } 268 269 err = request_irq(encoder->irq_b, handler, 270 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 271 DRV_NAME, encoder); 272 if (err) { 273 dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); 274 goto exit_free_irq_a; 275 } 276 277 err = input_register_device(input); 278 if (err) { 279 dev_err(dev, "failed to register input device\n"); 280 goto exit_free_irq_b; 281 } 282 283 platform_set_drvdata(pdev, encoder); 284 285 return 0; 286 287exit_free_irq_b: 288 free_irq(encoder->irq_b, encoder); 289exit_free_irq_a: 290 free_irq(encoder->irq_a, encoder); 291exit_free_gpio_b: 292 gpio_free(pdata->gpio_b); 293exit_free_gpio_a: 294 gpio_free(pdata->gpio_a); 295exit_free_mem: 296 input_free_device(input); 297 kfree(encoder); 298 if (!dev_get_platdata(&pdev->dev)) 299 kfree(pdata); 300 301 return err; 302} 303 304static int rotary_encoder_remove(struct platform_device *pdev) 305{ 306 struct rotary_encoder *encoder = platform_get_drvdata(pdev); 307 const struct rotary_encoder_platform_data *pdata = encoder->pdata; 308 309 free_irq(encoder->irq_a, encoder); 310 free_irq(encoder->irq_b, encoder); 311 gpio_free(pdata->gpio_a); 312 gpio_free(pdata->gpio_b); 313 314 input_unregister_device(encoder->input); 315 kfree(encoder); 316 317 if (!dev_get_platdata(&pdev->dev)) 318 kfree(pdata); 319 320 return 0; 321} 322 323static struct platform_driver rotary_encoder_driver = { 324 .probe = rotary_encoder_probe, 325 .remove = rotary_encoder_remove, 326 .driver = { 327 .name = DRV_NAME, 328 .of_match_table = of_match_ptr(rotary_encoder_of_match), 329 } 330}; 331module_platform_driver(rotary_encoder_driver); 332 333MODULE_ALIAS("platform:" DRV_NAME); 334MODULE_DESCRIPTION("GPIO rotary encoder driver"); 335MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold"); 336MODULE_LICENSE("GPL v2"); 337