rotary_encoder.c 7.7 KB
Newer Older
1 2 3 4
/*
 * rotary_encoder.c
 *
 * (c) 2009 Daniel Mack <daniel@caiaq.de>
5
 * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
6 7 8 9
 *
 * state machine code inspired by code from Tim Ruetz
 *
 * A generic driver for rotary encoders connected to GPIO lines.
P
Paul Bolle 已提交
10
 * See file:Documentation/input/rotary-encoder.txt for more information
11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/rotary_encoder.h>
25
#include <linux/slab.h>
26
#include <linux/of.h>
27 28
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
29 30 31 32 33

#define DRV_NAME "rotary-encoder"

struct rotary_encoder {
	struct input_dev *input;
34
	const struct rotary_encoder_platform_data *pdata;
35 36 37 38 39 40 41 42 43

	unsigned int axis;
	unsigned int pos;

	unsigned int irq_a;
	unsigned int irq_b;

	bool armed;
	unsigned char dir;	/* 0 - clockwise, 1 - CCW */
44 45

	char last_stable;
46 47
};

48
static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata)
49 50 51 52 53 54 55
{
	int a = !!gpio_get_value(pdata->gpio_a);
	int b = !!gpio_get_value(pdata->gpio_b);

	a ^= pdata->inverted_a;
	b ^= pdata->inverted_b;

56 57
	return ((a << 1) | b);
}
58

59 60
static void rotary_encoder_report_event(struct rotary_encoder *encoder)
{
61
	const struct rotary_encoder_platform_data *pdata = encoder->pdata;
62

63 64 65 66 67 68 69 70
	if (pdata->relative_axis) {
		input_report_rel(encoder->input,
				 pdata->axis, encoder->dir ? -1 : 1);
	} else {
		unsigned int pos = encoder->pos;

		if (encoder->dir) {
			/* turning counter-clockwise */
71
			if (pdata->rollover)
72 73 74 75 76 77 78
				pos += pdata->steps;
			if (pos)
				pos--;
		} else {
			/* turning clockwise */
			if (pdata->rollover || pos < pdata->steps)
				pos++;
79 80
		}

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
		if (pdata->rollover)
			pos %= pdata->steps;

		encoder->pos = pos;
		input_report_abs(encoder->input, pdata->axis, encoder->pos);
	}

	input_sync(encoder->input);
}

static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
{
	struct rotary_encoder *encoder = dev_id;
	int state;

	state = rotary_encoder_get_state(encoder->pdata);

	switch (state) {
	case 0x0:
		if (encoder->armed) {
			rotary_encoder_report_event(encoder);
			encoder->armed = false;
		}
104 105 106 107 108 109 110 111 112
		break;

	case 0x1:
	case 0x2:
		if (encoder->armed)
			encoder->dir = state - 1;
		break;

	case 0x3:
113
		encoder->armed = true;
114 115 116 117 118 119
		break;
	}

	return IRQ_HANDLED;
}

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
{
	struct rotary_encoder *encoder = dev_id;
	int state;

	state = rotary_encoder_get_state(encoder->pdata);

	switch (state) {
	case 0x00:
	case 0x03:
		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;
	}

	return IRQ_HANDLED;
}

145
#ifdef CONFIG_OF
146
static const struct of_device_id rotary_encoder_of_match[] = {
147 148 149 150 151
	{ .compatible = "rotary-encoder", },
	{ },
};
MODULE_DEVICE_TABLE(of, rotary_encoder_of_match);

B
Bill Pemberton 已提交
152
static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct device *dev)
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
{
	const struct of_device_id *of_id =
				of_match_device(rotary_encoder_of_match, dev);
	struct device_node *np = dev->of_node;
	struct rotary_encoder_platform_data *pdata;
	enum of_gpio_flags flags;

	if (!of_id || !np)
		return NULL;

	pdata = kzalloc(sizeof(struct rotary_encoder_platform_data),
			GFP_KERNEL);
	if (!pdata)
		return ERR_PTR(-ENOMEM);

	of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps);
	of_property_read_u32(np, "linux,axis", &pdata->axis);

	pdata->gpio_a = of_get_gpio_flags(np, 0, &flags);
	pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW;

	pdata->gpio_b = of_get_gpio_flags(np, 1, &flags);
	pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW;

	pdata->relative_axis = !!of_get_property(np,
					"rotary-encoder,relative-axis", NULL);
	pdata->rollover = !!of_get_property(np,
					"rotary-encoder,rollover", NULL);
	pdata->half_period = !!of_get_property(np,
					"rotary-encoder,half-period", NULL);

	return pdata;
}
#else
static inline struct rotary_encoder_platform_data *
rotary_encoder_parse_dt(struct device *dev)
{
	return NULL;
}
#endif

B
Bill Pemberton 已提交
194
static int rotary_encoder_probe(struct platform_device *pdev)
195
{
196 197
	struct device *dev = &pdev->dev;
	const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev);
198 199
	struct rotary_encoder *encoder;
	struct input_dev *input;
200
	irq_handler_t handler;
201 202
	int err;

203
	if (!pdata) {
204 205 206 207 208 209 210 211
		pdata = rotary_encoder_parse_dt(dev);
		if (IS_ERR(pdata))
			return PTR_ERR(pdata);

		if (!pdata) {
			dev_err(dev, "missing platform data\n");
			return -EINVAL;
		}
212 213 214 215 216 217 218 219 220 221 222 223 224 225
	}

	encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL);
	input = input_allocate_device();
	if (!encoder || !input) {
		err = -ENOMEM;
		goto exit_free_mem;
	}

	encoder->input = input;
	encoder->pdata = pdata;

	input->name = pdev->name;
	input->id.bustype = BUS_HOST;
226
	input->dev.parent = dev;
227 228 229 230 231 232 233 234 235

	if (pdata->relative_axis) {
		input->evbit[0] = BIT_MASK(EV_REL);
		input->relbit[0] = BIT_MASK(pdata->axis);
	} else {
		input->evbit[0] = BIT_MASK(EV_ABS);
		input_set_abs_params(encoder->input,
				     pdata->axis, 0, pdata->steps, 0, 1);
	}
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 248 249
		goto exit_free_gpio_a;
	}

250 251 252
	encoder->irq_a = gpio_to_irq(pdata->gpio_a);
	encoder->irq_b = gpio_to_irq(pdata->gpio_b);

253
	/* request the IRQs */
254 255 256 257 258 259 260 261
	if (pdata->half_period) {
		handler = &rotary_encoder_half_period_irq;
		encoder->last_stable = rotary_encoder_get_state(pdata);
	} else {
		handler = &rotary_encoder_irq;
	}

	err = request_irq(encoder->irq_a, handler,
262
			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
263 264
			  DRV_NAME, encoder);
	if (err) {
265
		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
266 267 268
		goto exit_free_gpio_b;
	}

269
	err = request_irq(encoder->irq_b, handler,
270
			  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
271 272
			  DRV_NAME, encoder);
	if (err) {
273
		dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
274 275 276
		goto exit_free_irq_a;
	}

277 278 279 280 281 282
	err = input_register_device(input);
	if (err) {
		dev_err(dev, "failed to register input device\n");
		goto exit_free_irq_b;
	}

283 284 285 286
	platform_set_drvdata(pdev, encoder);

	return 0;

287 288
exit_free_irq_b:
	free_irq(encoder->irq_b, encoder);
289 290 291 292 293 294 295 296 297
exit_free_irq_a:
	free_irq(encoder->irq_a, encoder);
exit_free_gpio_b:
	gpio_free(pdata->gpio_b);
exit_free_gpio_a:
	gpio_free(pdata->gpio_a);
exit_free_mem:
	input_free_device(input);
	kfree(encoder);
298 299 300
	if (!dev_get_platdata(&pdev->dev))
		kfree(pdata);

301 302 303
	return err;
}

B
Bill Pemberton 已提交
304
static 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 310 311 312

	free_irq(encoder->irq_a, encoder);
	free_irq(encoder->irq_b, encoder);
	gpio_free(pdata->gpio_a);
	gpio_free(pdata->gpio_b);
313

314 315 316
	input_unregister_device(encoder->input);
	kfree(encoder);

317 318 319
	if (!dev_get_platdata(&pdev->dev))
		kfree(pdata);

320 321 322 323 324
	return 0;
}

static struct platform_driver rotary_encoder_driver = {
	.probe		= rotary_encoder_probe,
B
Bill Pemberton 已提交
325
	.remove		= rotary_encoder_remove,
326 327
	.driver		= {
		.name	= DRV_NAME,
328
		.of_match_table = of_match_ptr(rotary_encoder_of_match),
329 330
	}
};
331
module_platform_driver(rotary_encoder_driver);
332 333 334

MODULE_ALIAS("platform:" DRV_NAME);
MODULE_DESCRIPTION("GPIO rotary encoder driver");
335
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
336
MODULE_LICENSE("GPL v2");