WIP FPC-III support
[linux/fpc-iii.git] / drivers / input / joystick / adc-joystick.c
blob78ebca7d400ae4de45c3f6dbf0c91963238eeb36
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Input driver for joysticks connected over ADC.
4 * Copyright (c) 2019-2020 Artur Rojek <contact@artur-rojek.eu>
5 */
6 #include <linux/ctype.h>
7 #include <linux/input.h>
8 #include <linux/iio/iio.h>
9 #include <linux/iio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/property.h>
14 #include <asm/unaligned.h>
16 struct adc_joystick_axis {
17 u32 code;
18 s32 range[2];
19 s32 fuzz;
20 s32 flat;
23 struct adc_joystick {
24 struct input_dev *input;
25 struct iio_cb_buffer *buffer;
26 struct adc_joystick_axis *axes;
27 struct iio_channel *chans;
28 int num_chans;
31 static int adc_joystick_handle(const void *data, void *private)
33 struct adc_joystick *joy = private;
34 enum iio_endian endianness;
35 int bytes, msb, val, idx, i;
36 const u16 *data_u16;
37 bool sign;
39 bytes = joy->chans[0].channel->scan_type.storagebits >> 3;
41 for (i = 0; i < joy->num_chans; ++i) {
42 idx = joy->chans[i].channel->scan_index;
43 endianness = joy->chans[i].channel->scan_type.endianness;
44 msb = joy->chans[i].channel->scan_type.realbits - 1;
45 sign = tolower(joy->chans[i].channel->scan_type.sign) == 's';
47 switch (bytes) {
48 case 1:
49 val = ((const u8 *)data)[idx];
50 break;
51 case 2:
52 data_u16 = (const u16 *)data + idx;
55 * Data is aligned to the sample size by IIO core.
56 * Call `get_unaligned_xe16` to hide type casting.
58 if (endianness == IIO_BE)
59 val = get_unaligned_be16(data_u16);
60 else if (endianness == IIO_LE)
61 val = get_unaligned_le16(data_u16);
62 else /* IIO_CPU */
63 val = *data_u16;
64 break;
65 default:
66 return -EINVAL;
69 val >>= joy->chans[i].channel->scan_type.shift;
70 if (sign)
71 val = sign_extend32(val, msb);
72 else
73 val &= GENMASK(msb, 0);
74 input_report_abs(joy->input, joy->axes[i].code, val);
77 input_sync(joy->input);
79 return 0;
82 static int adc_joystick_open(struct input_dev *dev)
84 struct adc_joystick *joy = input_get_drvdata(dev);
85 struct device *devp = &dev->dev;
86 int ret;
88 ret = iio_channel_start_all_cb(joy->buffer);
89 if (ret)
90 dev_err(devp, "Unable to start callback buffer: %d\n", ret);
92 return ret;
95 static void adc_joystick_close(struct input_dev *dev)
97 struct adc_joystick *joy = input_get_drvdata(dev);
99 iio_channel_stop_all_cb(joy->buffer);
102 static void adc_joystick_cleanup(void *data)
104 iio_channel_release_all_cb(data);
107 static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
109 struct adc_joystick_axis *axes;
110 struct fwnode_handle *child;
111 int num_axes, error, i;
113 num_axes = device_get_child_node_count(dev);
114 if (!num_axes) {
115 dev_err(dev, "Unable to find child nodes\n");
116 return -EINVAL;
119 if (num_axes != joy->num_chans) {
120 dev_err(dev, "Got %d child nodes for %d channels\n",
121 num_axes, joy->num_chans);
122 return -EINVAL;
125 axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL);
126 if (!axes)
127 return -ENOMEM;
129 device_for_each_child_node(dev, child) {
130 error = fwnode_property_read_u32(child, "reg", &i);
131 if (error) {
132 dev_err(dev, "reg invalid or missing\n");
133 goto err_fwnode_put;
136 if (i >= num_axes) {
137 error = -EINVAL;
138 dev_err(dev, "No matching axis for reg %d\n", i);
139 goto err_fwnode_put;
142 error = fwnode_property_read_u32(child, "linux,code",
143 &axes[i].code);
144 if (error) {
145 dev_err(dev, "linux,code invalid or missing\n");
146 goto err_fwnode_put;
149 error = fwnode_property_read_u32_array(child, "abs-range",
150 axes[i].range, 2);
151 if (error) {
152 dev_err(dev, "abs-range invalid or missing\n");
153 goto err_fwnode_put;
156 fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz);
157 fwnode_property_read_u32(child, "abs-flat", &axes[i].flat);
159 input_set_abs_params(joy->input, axes[i].code,
160 axes[i].range[0], axes[i].range[1],
161 axes[i].fuzz, axes[i].flat);
162 input_set_capability(joy->input, EV_ABS, axes[i].code);
165 joy->axes = axes;
167 return 0;
169 err_fwnode_put:
170 fwnode_handle_put(child);
171 return error;
174 static int adc_joystick_probe(struct platform_device *pdev)
176 struct device *dev = &pdev->dev;
177 struct adc_joystick *joy;
178 struct input_dev *input;
179 int error;
180 int bits;
181 int i;
183 joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL);
184 if (!joy)
185 return -ENOMEM;
187 joy->chans = devm_iio_channel_get_all(dev);
188 if (IS_ERR(joy->chans)) {
189 error = PTR_ERR(joy->chans);
190 if (error != -EPROBE_DEFER)
191 dev_err(dev, "Unable to get IIO channels");
192 return error;
195 /* Count how many channels we got. NULL terminated. */
196 for (i = 0; joy->chans[i].indio_dev; i++) {
197 bits = joy->chans[i].channel->scan_type.storagebits;
198 if (!bits || bits > 16) {
199 dev_err(dev, "Unsupported channel storage size\n");
200 return -EINVAL;
202 if (bits != joy->chans[0].channel->scan_type.storagebits) {
203 dev_err(dev, "Channels must have equal storage size\n");
204 return -EINVAL;
207 joy->num_chans = i;
209 input = devm_input_allocate_device(dev);
210 if (!input) {
211 dev_err(dev, "Unable to allocate input device\n");
212 return -ENOMEM;
215 joy->input = input;
216 input->name = pdev->name;
217 input->id.bustype = BUS_HOST;
218 input->open = adc_joystick_open;
219 input->close = adc_joystick_close;
221 error = adc_joystick_set_axes(dev, joy);
222 if (error)
223 return error;
225 input_set_drvdata(input, joy);
226 error = input_register_device(input);
227 if (error) {
228 dev_err(dev, "Unable to register input device\n");
229 return error;
232 joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle, joy);
233 if (IS_ERR(joy->buffer)) {
234 dev_err(dev, "Unable to allocate callback buffer\n");
235 return PTR_ERR(joy->buffer);
238 error = devm_add_action_or_reset(dev, adc_joystick_cleanup, joy->buffer);
239 if (error) {
240 dev_err(dev, "Unable to add action\n");
241 return error;
244 return 0;
247 static const struct of_device_id adc_joystick_of_match[] = {
248 { .compatible = "adc-joystick", },
251 MODULE_DEVICE_TABLE(of, adc_joystick_of_match);
253 static struct platform_driver adc_joystick_driver = {
254 .driver = {
255 .name = "adc-joystick",
256 .of_match_table = adc_joystick_of_match,
258 .probe = adc_joystick_probe,
260 module_platform_driver(adc_joystick_driver);
262 MODULE_DESCRIPTION("Input driver for joysticks connected over ADC");
263 MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
264 MODULE_LICENSE("GPL");