12c2b364fSArtur Rojek // SPDX-License-Identifier: GPL-2.0
22c2b364fSArtur Rojek /*
32c2b364fSArtur Rojek  * Input driver for joysticks connected over ADC.
42c2b364fSArtur Rojek  * Copyright (c) 2019-2020 Artur Rojek <contact@artur-rojek.eu>
52c2b364fSArtur Rojek  */
62c2b364fSArtur Rojek #include <linux/ctype.h>
72c2b364fSArtur Rojek #include <linux/input.h>
82c2b364fSArtur Rojek #include <linux/iio/iio.h>
92c2b364fSArtur Rojek #include <linux/iio/consumer.h>
102c2b364fSArtur Rojek #include <linux/module.h>
112c2b364fSArtur Rojek #include <linux/platform_device.h>
122c2b364fSArtur Rojek #include <linux/property.h>
132c2b364fSArtur Rojek 
142c2b364fSArtur Rojek #include <asm/unaligned.h>
152c2b364fSArtur Rojek 
162c2b364fSArtur Rojek struct adc_joystick_axis {
172c2b364fSArtur Rojek 	u32 code;
182c2b364fSArtur Rojek 	s32 range[2];
192c2b364fSArtur Rojek 	s32 fuzz;
202c2b364fSArtur Rojek 	s32 flat;
212c2b364fSArtur Rojek };
222c2b364fSArtur Rojek 
232c2b364fSArtur Rojek struct adc_joystick {
242c2b364fSArtur Rojek 	struct input_dev *input;
252c2b364fSArtur Rojek 	struct iio_cb_buffer *buffer;
262c2b364fSArtur Rojek 	struct adc_joystick_axis *axes;
272c2b364fSArtur Rojek 	struct iio_channel *chans;
282c2b364fSArtur Rojek 	int num_chans;
29*24c06e00SChris Morgan 	bool polled;
302c2b364fSArtur Rojek };
312c2b364fSArtur Rojek 
adc_joystick_poll(struct input_dev * input)32*24c06e00SChris Morgan static void adc_joystick_poll(struct input_dev *input)
33*24c06e00SChris Morgan {
34*24c06e00SChris Morgan 	struct adc_joystick *joy = input_get_drvdata(input);
35*24c06e00SChris Morgan 	int i, val, ret;
36*24c06e00SChris Morgan 
37*24c06e00SChris Morgan 	for (i = 0; i < joy->num_chans; i++) {
38*24c06e00SChris Morgan 		ret = iio_read_channel_raw(&joy->chans[i], &val);
39*24c06e00SChris Morgan 		if (ret < 0)
40*24c06e00SChris Morgan 			return;
41*24c06e00SChris Morgan 		input_report_abs(input, joy->axes[i].code, val);
42*24c06e00SChris Morgan 	}
43*24c06e00SChris Morgan 	input_sync(input);
44*24c06e00SChris Morgan }
45*24c06e00SChris Morgan 
adc_joystick_handle(const void * data,void * private)462c2b364fSArtur Rojek static int adc_joystick_handle(const void *data, void *private)
472c2b364fSArtur Rojek {
482c2b364fSArtur Rojek 	struct adc_joystick *joy = private;
492c2b364fSArtur Rojek 	enum iio_endian endianness;
502c2b364fSArtur Rojek 	int bytes, msb, val, idx, i;
512c2b364fSArtur Rojek 	const u16 *data_u16;
522c2b364fSArtur Rojek 	bool sign;
532c2b364fSArtur Rojek 
542c2b364fSArtur Rojek 	bytes = joy->chans[0].channel->scan_type.storagebits >> 3;
552c2b364fSArtur Rojek 
562c2b364fSArtur Rojek 	for (i = 0; i < joy->num_chans; ++i) {
572c2b364fSArtur Rojek 		idx = joy->chans[i].channel->scan_index;
582c2b364fSArtur Rojek 		endianness = joy->chans[i].channel->scan_type.endianness;
592c2b364fSArtur Rojek 		msb = joy->chans[i].channel->scan_type.realbits - 1;
602c2b364fSArtur Rojek 		sign = tolower(joy->chans[i].channel->scan_type.sign) == 's';
612c2b364fSArtur Rojek 
622c2b364fSArtur Rojek 		switch (bytes) {
632c2b364fSArtur Rojek 		case 1:
642c2b364fSArtur Rojek 			val = ((const u8 *)data)[idx];
652c2b364fSArtur Rojek 			break;
662c2b364fSArtur Rojek 		case 2:
672c2b364fSArtur Rojek 			data_u16 = (const u16 *)data + idx;
682c2b364fSArtur Rojek 
692c2b364fSArtur Rojek 			/*
702c2b364fSArtur Rojek 			 * Data is aligned to the sample size by IIO core.
712c2b364fSArtur Rojek 			 * Call `get_unaligned_xe16` to hide type casting.
722c2b364fSArtur Rojek 			 */
732c2b364fSArtur Rojek 			if (endianness == IIO_BE)
742c2b364fSArtur Rojek 				val = get_unaligned_be16(data_u16);
752c2b364fSArtur Rojek 			else if (endianness == IIO_LE)
762c2b364fSArtur Rojek 				val = get_unaligned_le16(data_u16);
772c2b364fSArtur Rojek 			else /* IIO_CPU */
782c2b364fSArtur Rojek 				val = *data_u16;
792c2b364fSArtur Rojek 			break;
802c2b364fSArtur Rojek 		default:
812c2b364fSArtur Rojek 			return -EINVAL;
822c2b364fSArtur Rojek 		}
832c2b364fSArtur Rojek 
842c2b364fSArtur Rojek 		val >>= joy->chans[i].channel->scan_type.shift;
852c2b364fSArtur Rojek 		if (sign)
862c2b364fSArtur Rojek 			val = sign_extend32(val, msb);
872c2b364fSArtur Rojek 		else
882c2b364fSArtur Rojek 			val &= GENMASK(msb, 0);
892c2b364fSArtur Rojek 		input_report_abs(joy->input, joy->axes[i].code, val);
902c2b364fSArtur Rojek 	}
912c2b364fSArtur Rojek 
922c2b364fSArtur Rojek 	input_sync(joy->input);
932c2b364fSArtur Rojek 
942c2b364fSArtur Rojek 	return 0;
952c2b364fSArtur Rojek }
962c2b364fSArtur Rojek 
adc_joystick_open(struct input_dev * dev)972c2b364fSArtur Rojek static int adc_joystick_open(struct input_dev *dev)
982c2b364fSArtur Rojek {
992c2b364fSArtur Rojek 	struct adc_joystick *joy = input_get_drvdata(dev);
1002c2b364fSArtur Rojek 	struct device *devp = &dev->dev;
1012c2b364fSArtur Rojek 	int ret;
1022c2b364fSArtur Rojek 
1032c2b364fSArtur Rojek 	ret = iio_channel_start_all_cb(joy->buffer);
1042c2b364fSArtur Rojek 	if (ret)
1052c2b364fSArtur Rojek 		dev_err(devp, "Unable to start callback buffer: %d\n", ret);
1062c2b364fSArtur Rojek 
1072c2b364fSArtur Rojek 	return ret;
1082c2b364fSArtur Rojek }
1092c2b364fSArtur Rojek 
adc_joystick_close(struct input_dev * dev)1102c2b364fSArtur Rojek static void adc_joystick_close(struct input_dev *dev)
1112c2b364fSArtur Rojek {
1122c2b364fSArtur Rojek 	struct adc_joystick *joy = input_get_drvdata(dev);
1132c2b364fSArtur Rojek 
1142c2b364fSArtur Rojek 	iio_channel_stop_all_cb(joy->buffer);
1152c2b364fSArtur Rojek }
1162c2b364fSArtur Rojek 
adc_joystick_cleanup(void * data)1172c2b364fSArtur Rojek static void adc_joystick_cleanup(void *data)
1182c2b364fSArtur Rojek {
1192c2b364fSArtur Rojek 	iio_channel_release_all_cb(data);
1202c2b364fSArtur Rojek }
1212c2b364fSArtur Rojek 
adc_joystick_set_axes(struct device * dev,struct adc_joystick * joy)1222c2b364fSArtur Rojek static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
1232c2b364fSArtur Rojek {
1242c2b364fSArtur Rojek 	struct adc_joystick_axis *axes;
1252c2b364fSArtur Rojek 	struct fwnode_handle *child;
1262c2b364fSArtur Rojek 	int num_axes, error, i;
1272c2b364fSArtur Rojek 
1282c2b364fSArtur Rojek 	num_axes = device_get_child_node_count(dev);
1292c2b364fSArtur Rojek 	if (!num_axes) {
1302c2b364fSArtur Rojek 		dev_err(dev, "Unable to find child nodes\n");
1312c2b364fSArtur Rojek 		return -EINVAL;
1322c2b364fSArtur Rojek 	}
1332c2b364fSArtur Rojek 
1342c2b364fSArtur Rojek 	if (num_axes != joy->num_chans) {
1352c2b364fSArtur Rojek 		dev_err(dev, "Got %d child nodes for %d channels\n",
1362c2b364fSArtur Rojek 			num_axes, joy->num_chans);
1372c2b364fSArtur Rojek 		return -EINVAL;
1382c2b364fSArtur Rojek 	}
1392c2b364fSArtur Rojek 
1402c2b364fSArtur Rojek 	axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL);
1412c2b364fSArtur Rojek 	if (!axes)
1422c2b364fSArtur Rojek 		return -ENOMEM;
1432c2b364fSArtur Rojek 
1442c2b364fSArtur Rojek 	device_for_each_child_node(dev, child) {
1452c2b364fSArtur Rojek 		error = fwnode_property_read_u32(child, "reg", &i);
1462c2b364fSArtur Rojek 		if (error) {
1472c2b364fSArtur Rojek 			dev_err(dev, "reg invalid or missing\n");
1482c2b364fSArtur Rojek 			goto err_fwnode_put;
1492c2b364fSArtur Rojek 		}
1502c2b364fSArtur Rojek 
1512c2b364fSArtur Rojek 		if (i >= num_axes) {
1522c2b364fSArtur Rojek 			error = -EINVAL;
1532c2b364fSArtur Rojek 			dev_err(dev, "No matching axis for reg %d\n", i);
1542c2b364fSArtur Rojek 			goto err_fwnode_put;
1552c2b364fSArtur Rojek 		}
1562c2b364fSArtur Rojek 
1572c2b364fSArtur Rojek 		error = fwnode_property_read_u32(child, "linux,code",
1582c2b364fSArtur Rojek 						 &axes[i].code);
1592c2b364fSArtur Rojek 		if (error) {
1602c2b364fSArtur Rojek 			dev_err(dev, "linux,code invalid or missing\n");
1612c2b364fSArtur Rojek 			goto err_fwnode_put;
1622c2b364fSArtur Rojek 		}
1632c2b364fSArtur Rojek 
1642c2b364fSArtur Rojek 		error = fwnode_property_read_u32_array(child, "abs-range",
1652c2b364fSArtur Rojek 						       axes[i].range, 2);
1662c2b364fSArtur Rojek 		if (error) {
1672c2b364fSArtur Rojek 			dev_err(dev, "abs-range invalid or missing\n");
1682c2b364fSArtur Rojek 			goto err_fwnode_put;
1692c2b364fSArtur Rojek 		}
1702c2b364fSArtur Rojek 
1712c2b364fSArtur Rojek 		fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz);
1722c2b364fSArtur Rojek 		fwnode_property_read_u32(child, "abs-flat", &axes[i].flat);
1732c2b364fSArtur Rojek 
1742c2b364fSArtur Rojek 		input_set_abs_params(joy->input, axes[i].code,
1752c2b364fSArtur Rojek 				     axes[i].range[0], axes[i].range[1],
1762c2b364fSArtur Rojek 				     axes[i].fuzz, axes[i].flat);
1772c2b364fSArtur Rojek 		input_set_capability(joy->input, EV_ABS, axes[i].code);
1782c2b364fSArtur Rojek 	}
1792c2b364fSArtur Rojek 
1802c2b364fSArtur Rojek 	joy->axes = axes;
1812c2b364fSArtur Rojek 
1822c2b364fSArtur Rojek 	return 0;
1832c2b364fSArtur Rojek 
1842c2b364fSArtur Rojek err_fwnode_put:
1852c2b364fSArtur Rojek 	fwnode_handle_put(child);
1862c2b364fSArtur Rojek 	return error;
1872c2b364fSArtur Rojek }
1882c2b364fSArtur Rojek 
adc_joystick_probe(struct platform_device * pdev)1892c2b364fSArtur Rojek static int adc_joystick_probe(struct platform_device *pdev)
1902c2b364fSArtur Rojek {
1912c2b364fSArtur Rojek 	struct device *dev = &pdev->dev;
1922c2b364fSArtur Rojek 	struct adc_joystick *joy;
1932c2b364fSArtur Rojek 	struct input_dev *input;
1942c2b364fSArtur Rojek 	int error;
1952c2b364fSArtur Rojek 	int bits;
1962c2b364fSArtur Rojek 	int i;
197*24c06e00SChris Morgan 	unsigned int poll_interval;
1982c2b364fSArtur Rojek 
1992c2b364fSArtur Rojek 	joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL);
2002c2b364fSArtur Rojek 	if (!joy)
2012c2b364fSArtur Rojek 		return -ENOMEM;
2022c2b364fSArtur Rojek 
2032c2b364fSArtur Rojek 	joy->chans = devm_iio_channel_get_all(dev);
2042c2b364fSArtur Rojek 	if (IS_ERR(joy->chans)) {
2052c2b364fSArtur Rojek 		error = PTR_ERR(joy->chans);
2062c2b364fSArtur Rojek 		if (error != -EPROBE_DEFER)
2072c2b364fSArtur Rojek 			dev_err(dev, "Unable to get IIO channels");
2082c2b364fSArtur Rojek 		return error;
2092c2b364fSArtur Rojek 	}
2102c2b364fSArtur Rojek 
211*24c06e00SChris Morgan 	error = device_property_read_u32(dev, "poll-interval", &poll_interval);
212*24c06e00SChris Morgan 	if (error) {
213*24c06e00SChris Morgan 		/* -EINVAL means the property is absent. */
214*24c06e00SChris Morgan 		if (error != -EINVAL)
215*24c06e00SChris Morgan 			return error;
216*24c06e00SChris Morgan 	} else if (poll_interval == 0) {
217*24c06e00SChris Morgan 		dev_err(dev, "Unable to get poll-interval\n");
218*24c06e00SChris Morgan 		return -EINVAL;
219*24c06e00SChris Morgan 	} else {
220*24c06e00SChris Morgan 		joy->polled = true;
221*24c06e00SChris Morgan 	}
222*24c06e00SChris Morgan 
223*24c06e00SChris Morgan 	/*
224*24c06e00SChris Morgan 	 * Count how many channels we got. NULL terminated.
225*24c06e00SChris Morgan 	 * Do not check the storage size if using polling.
226*24c06e00SChris Morgan 	 */
2272c2b364fSArtur Rojek 	for (i = 0; joy->chans[i].indio_dev; i++) {
228*24c06e00SChris Morgan 		if (joy->polled)
229*24c06e00SChris Morgan 			continue;
2302c2b364fSArtur Rojek 		bits = joy->chans[i].channel->scan_type.storagebits;
2312c2b364fSArtur Rojek 		if (!bits || bits > 16) {
2322c2b364fSArtur Rojek 			dev_err(dev, "Unsupported channel storage size\n");
2332c2b364fSArtur Rojek 			return -EINVAL;
2342c2b364fSArtur Rojek 		}
2352c2b364fSArtur Rojek 		if (bits != joy->chans[0].channel->scan_type.storagebits) {
2362c2b364fSArtur Rojek 			dev_err(dev, "Channels must have equal storage size\n");
2372c2b364fSArtur Rojek 			return -EINVAL;
2382c2b364fSArtur Rojek 		}
2392c2b364fSArtur Rojek 	}
2402c2b364fSArtur Rojek 	joy->num_chans = i;
2412c2b364fSArtur Rojek 
2422c2b364fSArtur Rojek 	input = devm_input_allocate_device(dev);
2432c2b364fSArtur Rojek 	if (!input) {
2442c2b364fSArtur Rojek 		dev_err(dev, "Unable to allocate input device\n");
2452c2b364fSArtur Rojek 		return -ENOMEM;
2462c2b364fSArtur Rojek 	}
2472c2b364fSArtur Rojek 
2482c2b364fSArtur Rojek 	joy->input = input;
2492c2b364fSArtur Rojek 	input->name = pdev->name;
2502c2b364fSArtur Rojek 	input->id.bustype = BUS_HOST;
2512c2b364fSArtur Rojek 
2522c2b364fSArtur Rojek 	error = adc_joystick_set_axes(dev, joy);
2532c2b364fSArtur Rojek 	if (error)
2542c2b364fSArtur Rojek 		return error;
2552c2b364fSArtur Rojek 
256*24c06e00SChris Morgan 	if (joy->polled) {
257*24c06e00SChris Morgan 		input_setup_polling(input, adc_joystick_poll);
258*24c06e00SChris Morgan 		input_set_poll_interval(input, poll_interval);
259*24c06e00SChris Morgan 	} else {
260*24c06e00SChris Morgan 		input->open = adc_joystick_open;
261*24c06e00SChris Morgan 		input->close = adc_joystick_close;
262*24c06e00SChris Morgan 
263*24c06e00SChris Morgan 		joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle,
264*24c06e00SChris Morgan 						     joy);
2652c2b364fSArtur Rojek 		if (IS_ERR(joy->buffer)) {
2662c2b364fSArtur Rojek 			dev_err(dev, "Unable to allocate callback buffer\n");
2672c2b364fSArtur Rojek 			return PTR_ERR(joy->buffer);
2682c2b364fSArtur Rojek 		}
2692c2b364fSArtur Rojek 
270*24c06e00SChris Morgan 		error = devm_add_action_or_reset(dev, adc_joystick_cleanup,
271*24c06e00SChris Morgan 						 joy->buffer);
2722c2b364fSArtur Rojek 		if (error)  {
2732c2b364fSArtur Rojek 			dev_err(dev, "Unable to add action\n");
2742c2b364fSArtur Rojek 			return error;
2752c2b364fSArtur Rojek 		}
276*24c06e00SChris Morgan 	}
2772c2b364fSArtur Rojek 
2787c744d00SDmitry Torokhov 	input_set_drvdata(input, joy);
2797c744d00SDmitry Torokhov 
2807c744d00SDmitry Torokhov 	error = input_register_device(input);
2817c744d00SDmitry Torokhov 	if (error) {
2827c744d00SDmitry Torokhov 		dev_err(dev, "Unable to register input device\n");
2837c744d00SDmitry Torokhov 		return error;
2847c744d00SDmitry Torokhov 	}
2857c744d00SDmitry Torokhov 
2862c2b364fSArtur Rojek 	return 0;
2872c2b364fSArtur Rojek }
2882c2b364fSArtur Rojek 
2892c2b364fSArtur Rojek static const struct of_device_id adc_joystick_of_match[] = {
2902c2b364fSArtur Rojek 	{ .compatible = "adc-joystick", },
2912c2b364fSArtur Rojek 	{ }
2922c2b364fSArtur Rojek };
2932c2b364fSArtur Rojek MODULE_DEVICE_TABLE(of, adc_joystick_of_match);
2942c2b364fSArtur Rojek 
2952c2b364fSArtur Rojek static struct platform_driver adc_joystick_driver = {
2962c2b364fSArtur Rojek 	.driver = {
2972c2b364fSArtur Rojek 		.name = "adc-joystick",
2982c2b364fSArtur Rojek 		.of_match_table = adc_joystick_of_match,
2992c2b364fSArtur Rojek 	},
3002c2b364fSArtur Rojek 	.probe = adc_joystick_probe,
3012c2b364fSArtur Rojek };
3022c2b364fSArtur Rojek module_platform_driver(adc_joystick_driver);
3032c2b364fSArtur Rojek 
3042c2b364fSArtur Rojek MODULE_DESCRIPTION("Input driver for joysticks connected over ADC");
3052c2b364fSArtur Rojek MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
3062c2b364fSArtur Rojek MODULE_LICENSE("GPL");
307