Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Input driver for resistor ladder connected on ADC
  4 *
  5 * Copyright (c) 2016 Alexandre Belloni
  6 */
  7
  8#include <linux/err.h>
  9#include <linux/iio/consumer.h>
 10#include <linux/iio/types.h>
 11#include <linux/input.h>
 12#include <linux/input-polldev.h>
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/of.h>
 16#include <linux/platform_device.h>
 17#include <linux/property.h>
 18#include <linux/slab.h>
 19
 20struct adc_keys_button {
 21	u32 voltage;
 22	u32 keycode;
 23};
 24
 25struct adc_keys_state {
 26	struct iio_channel *channel;
 27	u32 num_keys;
 28	u32 last_key;
 29	u32 keyup_voltage;
 30	const struct adc_keys_button *map;
 31};
 32
 33static void adc_keys_poll(struct input_polled_dev *dev)
 34{
 35	struct adc_keys_state *st = dev->private;
 36	int i, value, ret;
 37	u32 diff, closest = 0xffffffff;
 38	int keycode = 0;
 39
 40	ret = iio_read_channel_processed(st->channel, &value);
 41	if (unlikely(ret < 0)) {
 42		/* Forcibly release key if any was pressed */
 43		value = st->keyup_voltage;
 44	} else {
 45		for (i = 0; i < st->num_keys; i++) {
 46			diff = abs(st->map[i].voltage - value);
 47			if (diff < closest) {
 48				closest = diff;
 49				keycode = st->map[i].keycode;
 50			}
 51		}
 52	}
 53
 54	if (abs(st->keyup_voltage - value) < closest)
 55		keycode = 0;
 56
 57	if (st->last_key && st->last_key != keycode)
 58		input_report_key(dev->input, st->last_key, 0);
 59
 60	if (keycode)
 61		input_report_key(dev->input, keycode, 1);
 62
 63	input_sync(dev->input);
 64	st->last_key = keycode;
 65}
 66
 67static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
 68{
 69	struct adc_keys_button *map;
 70	struct fwnode_handle *child;
 71	int i;
 72
 73	st->num_keys = device_get_child_node_count(dev);
 74	if (st->num_keys == 0) {
 75		dev_err(dev, "keymap is missing\n");
 76		return -EINVAL;
 77	}
 78
 79	map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL);
 80	if (!map)
 81		return -ENOMEM;
 82
 83	i = 0;
 84	device_for_each_child_node(dev, child) {
 85		if (fwnode_property_read_u32(child, "press-threshold-microvolt",
 86					     &map[i].voltage)) {
 87			dev_err(dev, "Key with invalid or missing voltage\n");
 88			fwnode_handle_put(child);
 89			return -EINVAL;
 90		}
 91		map[i].voltage /= 1000;
 92
 93		if (fwnode_property_read_u32(child, "linux,code",
 94					     &map[i].keycode)) {
 95			dev_err(dev, "Key with invalid or missing linux,code\n");
 96			fwnode_handle_put(child);
 97			return -EINVAL;
 98		}
 99
100		i++;
101	}
102
103	st->map = map;
104	return 0;
105}
106
107static int adc_keys_probe(struct platform_device *pdev)
108{
109	struct device *dev = &pdev->dev;
110	struct adc_keys_state *st;
111	struct input_polled_dev *poll_dev;
112	struct input_dev *input;
113	enum iio_chan_type type;
114	int i, value;
115	int error;
116
117	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
118	if (!st)
119		return -ENOMEM;
120
121	st->channel = devm_iio_channel_get(dev, "buttons");
122	if (IS_ERR(st->channel))
123		return PTR_ERR(st->channel);
124
125	if (!st->channel->indio_dev)
126		return -ENXIO;
127
128	error = iio_get_channel_type(st->channel, &type);
129	if (error < 0)
130		return error;
131
132	if (type != IIO_VOLTAGE) {
133		dev_err(dev, "Incompatible channel type %d\n", type);
134		return -EINVAL;
135	}
136
137	if (device_property_read_u32(dev, "keyup-threshold-microvolt",
138				     &st->keyup_voltage)) {
139		dev_err(dev, "Invalid or missing keyup voltage\n");
140		return -EINVAL;
141	}
142	st->keyup_voltage /= 1000;
143
144	error = adc_keys_load_keymap(dev, st);
145	if (error)
146		return error;
147
148	poll_dev = devm_input_allocate_polled_device(dev);
149	if (!poll_dev) {
150		dev_err(dev, "failed to allocate input device\n");
151		return -ENOMEM;
152	}
153
154	if (!device_property_read_u32(dev, "poll-interval", &value))
155		poll_dev->poll_interval = value;
156
157	poll_dev->poll = adc_keys_poll;
158	poll_dev->private = st;
159
160	input = poll_dev->input;
161
162	input->name = pdev->name;
163	input->phys = "adc-keys/input0";
164
165	input->id.bustype = BUS_HOST;
166	input->id.vendor = 0x0001;
167	input->id.product = 0x0001;
168	input->id.version = 0x0100;
169
170	__set_bit(EV_KEY, input->evbit);
171	for (i = 0; i < st->num_keys; i++)
172		__set_bit(st->map[i].keycode, input->keybit);
173
174	if (device_property_read_bool(dev, "autorepeat"))
175		__set_bit(EV_REP, input->evbit);
176
177	error = input_register_polled_device(poll_dev);
178	if (error) {
179		dev_err(dev, "Unable to register input device: %d\n", error);
180		return error;
181	}
182
183	return 0;
184}
185
186#ifdef CONFIG_OF
187static const struct of_device_id adc_keys_of_match[] = {
188	{ .compatible = "adc-keys", },
189	{ }
190};
191MODULE_DEVICE_TABLE(of, adc_keys_of_match);
192#endif
193
194static struct platform_driver __refdata adc_keys_driver = {
195	.driver = {
196		.name = "adc_keys",
197		.of_match_table = of_match_ptr(adc_keys_of_match),
198	},
199	.probe = adc_keys_probe,
200};
201module_platform_driver(adc_keys_driver);
202
203MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
204MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC");
205MODULE_LICENSE("GPL v2");