162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Input driver for joysticks connected over ADC.
462306a36Sopenharmony_ci * Copyright (c) 2019-2020 Artur Rojek <contact@artur-rojek.eu>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/ctype.h>
762306a36Sopenharmony_ci#include <linux/input.h>
862306a36Sopenharmony_ci#include <linux/iio/iio.h>
962306a36Sopenharmony_ci#include <linux/iio/consumer.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/property.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <asm/unaligned.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct adc_joystick_axis {
1762306a36Sopenharmony_ci	u32 code;
1862306a36Sopenharmony_ci	s32 range[2];
1962306a36Sopenharmony_ci	s32 fuzz;
2062306a36Sopenharmony_ci	s32 flat;
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct adc_joystick {
2462306a36Sopenharmony_ci	struct input_dev *input;
2562306a36Sopenharmony_ci	struct iio_cb_buffer *buffer;
2662306a36Sopenharmony_ci	struct adc_joystick_axis *axes;
2762306a36Sopenharmony_ci	struct iio_channel *chans;
2862306a36Sopenharmony_ci	int num_chans;
2962306a36Sopenharmony_ci	bool polled;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void adc_joystick_poll(struct input_dev *input)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	struct adc_joystick *joy = input_get_drvdata(input);
3562306a36Sopenharmony_ci	int i, val, ret;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	for (i = 0; i < joy->num_chans; i++) {
3862306a36Sopenharmony_ci		ret = iio_read_channel_raw(&joy->chans[i], &val);
3962306a36Sopenharmony_ci		if (ret < 0)
4062306a36Sopenharmony_ci			return;
4162306a36Sopenharmony_ci		input_report_abs(input, joy->axes[i].code, val);
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci	input_sync(input);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int adc_joystick_handle(const void *data, void *private)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct adc_joystick *joy = private;
4962306a36Sopenharmony_ci	enum iio_endian endianness;
5062306a36Sopenharmony_ci	int bytes, msb, val, idx, i;
5162306a36Sopenharmony_ci	const u16 *data_u16;
5262306a36Sopenharmony_ci	bool sign;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	bytes = joy->chans[0].channel->scan_type.storagebits >> 3;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	for (i = 0; i < joy->num_chans; ++i) {
5762306a36Sopenharmony_ci		idx = joy->chans[i].channel->scan_index;
5862306a36Sopenharmony_ci		endianness = joy->chans[i].channel->scan_type.endianness;
5962306a36Sopenharmony_ci		msb = joy->chans[i].channel->scan_type.realbits - 1;
6062306a36Sopenharmony_ci		sign = tolower(joy->chans[i].channel->scan_type.sign) == 's';
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci		switch (bytes) {
6362306a36Sopenharmony_ci		case 1:
6462306a36Sopenharmony_ci			val = ((const u8 *)data)[idx];
6562306a36Sopenharmony_ci			break;
6662306a36Sopenharmony_ci		case 2:
6762306a36Sopenharmony_ci			data_u16 = (const u16 *)data + idx;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci			/*
7062306a36Sopenharmony_ci			 * Data is aligned to the sample size by IIO core.
7162306a36Sopenharmony_ci			 * Call `get_unaligned_xe16` to hide type casting.
7262306a36Sopenharmony_ci			 */
7362306a36Sopenharmony_ci			if (endianness == IIO_BE)
7462306a36Sopenharmony_ci				val = get_unaligned_be16(data_u16);
7562306a36Sopenharmony_ci			else if (endianness == IIO_LE)
7662306a36Sopenharmony_ci				val = get_unaligned_le16(data_u16);
7762306a36Sopenharmony_ci			else /* IIO_CPU */
7862306a36Sopenharmony_ci				val = *data_u16;
7962306a36Sopenharmony_ci			break;
8062306a36Sopenharmony_ci		default:
8162306a36Sopenharmony_ci			return -EINVAL;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		val >>= joy->chans[i].channel->scan_type.shift;
8562306a36Sopenharmony_ci		if (sign)
8662306a36Sopenharmony_ci			val = sign_extend32(val, msb);
8762306a36Sopenharmony_ci		else
8862306a36Sopenharmony_ci			val &= GENMASK(msb, 0);
8962306a36Sopenharmony_ci		input_report_abs(joy->input, joy->axes[i].code, val);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	input_sync(joy->input);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int adc_joystick_open(struct input_dev *dev)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct adc_joystick *joy = input_get_drvdata(dev);
10062306a36Sopenharmony_ci	struct device *devp = &dev->dev;
10162306a36Sopenharmony_ci	int ret;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	ret = iio_channel_start_all_cb(joy->buffer);
10462306a36Sopenharmony_ci	if (ret)
10562306a36Sopenharmony_ci		dev_err(devp, "Unable to start callback buffer: %d\n", ret);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return ret;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void adc_joystick_close(struct input_dev *dev)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct adc_joystick *joy = input_get_drvdata(dev);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	iio_channel_stop_all_cb(joy->buffer);
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic void adc_joystick_cleanup(void *data)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	iio_channel_release_all_cb(data);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct adc_joystick_axis *axes;
12562306a36Sopenharmony_ci	struct fwnode_handle *child;
12662306a36Sopenharmony_ci	int num_axes, error, i;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	num_axes = device_get_child_node_count(dev);
12962306a36Sopenharmony_ci	if (!num_axes) {
13062306a36Sopenharmony_ci		dev_err(dev, "Unable to find child nodes\n");
13162306a36Sopenharmony_ci		return -EINVAL;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (num_axes != joy->num_chans) {
13562306a36Sopenharmony_ci		dev_err(dev, "Got %d child nodes for %d channels\n",
13662306a36Sopenharmony_ci			num_axes, joy->num_chans);
13762306a36Sopenharmony_ci		return -EINVAL;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL);
14162306a36Sopenharmony_ci	if (!axes)
14262306a36Sopenharmony_ci		return -ENOMEM;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	device_for_each_child_node(dev, child) {
14562306a36Sopenharmony_ci		error = fwnode_property_read_u32(child, "reg", &i);
14662306a36Sopenharmony_ci		if (error) {
14762306a36Sopenharmony_ci			dev_err(dev, "reg invalid or missing\n");
14862306a36Sopenharmony_ci			goto err_fwnode_put;
14962306a36Sopenharmony_ci		}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		if (i >= num_axes) {
15262306a36Sopenharmony_ci			error = -EINVAL;
15362306a36Sopenharmony_ci			dev_err(dev, "No matching axis for reg %d\n", i);
15462306a36Sopenharmony_ci			goto err_fwnode_put;
15562306a36Sopenharmony_ci		}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		error = fwnode_property_read_u32(child, "linux,code",
15862306a36Sopenharmony_ci						 &axes[i].code);
15962306a36Sopenharmony_ci		if (error) {
16062306a36Sopenharmony_ci			dev_err(dev, "linux,code invalid or missing\n");
16162306a36Sopenharmony_ci			goto err_fwnode_put;
16262306a36Sopenharmony_ci		}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		error = fwnode_property_read_u32_array(child, "abs-range",
16562306a36Sopenharmony_ci						       axes[i].range, 2);
16662306a36Sopenharmony_ci		if (error) {
16762306a36Sopenharmony_ci			dev_err(dev, "abs-range invalid or missing\n");
16862306a36Sopenharmony_ci			goto err_fwnode_put;
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz);
17262306a36Sopenharmony_ci		fwnode_property_read_u32(child, "abs-flat", &axes[i].flat);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		input_set_abs_params(joy->input, axes[i].code,
17562306a36Sopenharmony_ci				     axes[i].range[0], axes[i].range[1],
17662306a36Sopenharmony_ci				     axes[i].fuzz, axes[i].flat);
17762306a36Sopenharmony_ci		input_set_capability(joy->input, EV_ABS, axes[i].code);
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	joy->axes = axes;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cierr_fwnode_put:
18562306a36Sopenharmony_ci	fwnode_handle_put(child);
18662306a36Sopenharmony_ci	return error;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int adc_joystick_probe(struct platform_device *pdev)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
19262306a36Sopenharmony_ci	struct adc_joystick *joy;
19362306a36Sopenharmony_ci	struct input_dev *input;
19462306a36Sopenharmony_ci	int error;
19562306a36Sopenharmony_ci	int bits;
19662306a36Sopenharmony_ci	int i;
19762306a36Sopenharmony_ci	unsigned int poll_interval;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL);
20062306a36Sopenharmony_ci	if (!joy)
20162306a36Sopenharmony_ci		return -ENOMEM;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	joy->chans = devm_iio_channel_get_all(dev);
20462306a36Sopenharmony_ci	if (IS_ERR(joy->chans)) {
20562306a36Sopenharmony_ci		error = PTR_ERR(joy->chans);
20662306a36Sopenharmony_ci		if (error != -EPROBE_DEFER)
20762306a36Sopenharmony_ci			dev_err(dev, "Unable to get IIO channels");
20862306a36Sopenharmony_ci		return error;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	error = device_property_read_u32(dev, "poll-interval", &poll_interval);
21262306a36Sopenharmony_ci	if (error) {
21362306a36Sopenharmony_ci		/* -EINVAL means the property is absent. */
21462306a36Sopenharmony_ci		if (error != -EINVAL)
21562306a36Sopenharmony_ci			return error;
21662306a36Sopenharmony_ci	} else if (poll_interval == 0) {
21762306a36Sopenharmony_ci		dev_err(dev, "Unable to get poll-interval\n");
21862306a36Sopenharmony_ci		return -EINVAL;
21962306a36Sopenharmony_ci	} else {
22062306a36Sopenharmony_ci		joy->polled = true;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/*
22462306a36Sopenharmony_ci	 * Count how many channels we got. NULL terminated.
22562306a36Sopenharmony_ci	 * Do not check the storage size if using polling.
22662306a36Sopenharmony_ci	 */
22762306a36Sopenharmony_ci	for (i = 0; joy->chans[i].indio_dev; i++) {
22862306a36Sopenharmony_ci		if (joy->polled)
22962306a36Sopenharmony_ci			continue;
23062306a36Sopenharmony_ci		bits = joy->chans[i].channel->scan_type.storagebits;
23162306a36Sopenharmony_ci		if (!bits || bits > 16) {
23262306a36Sopenharmony_ci			dev_err(dev, "Unsupported channel storage size\n");
23362306a36Sopenharmony_ci			return -EINVAL;
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci		if (bits != joy->chans[0].channel->scan_type.storagebits) {
23662306a36Sopenharmony_ci			dev_err(dev, "Channels must have equal storage size\n");
23762306a36Sopenharmony_ci			return -EINVAL;
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci	joy->num_chans = i;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	input = devm_input_allocate_device(dev);
24362306a36Sopenharmony_ci	if (!input) {
24462306a36Sopenharmony_ci		dev_err(dev, "Unable to allocate input device\n");
24562306a36Sopenharmony_ci		return -ENOMEM;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	joy->input = input;
24962306a36Sopenharmony_ci	input->name = pdev->name;
25062306a36Sopenharmony_ci	input->id.bustype = BUS_HOST;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	error = adc_joystick_set_axes(dev, joy);
25362306a36Sopenharmony_ci	if (error)
25462306a36Sopenharmony_ci		return error;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (joy->polled) {
25762306a36Sopenharmony_ci		input_setup_polling(input, adc_joystick_poll);
25862306a36Sopenharmony_ci		input_set_poll_interval(input, poll_interval);
25962306a36Sopenharmony_ci	} else {
26062306a36Sopenharmony_ci		input->open = adc_joystick_open;
26162306a36Sopenharmony_ci		input->close = adc_joystick_close;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle,
26462306a36Sopenharmony_ci						     joy);
26562306a36Sopenharmony_ci		if (IS_ERR(joy->buffer)) {
26662306a36Sopenharmony_ci			dev_err(dev, "Unable to allocate callback buffer\n");
26762306a36Sopenharmony_ci			return PTR_ERR(joy->buffer);
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		error = devm_add_action_or_reset(dev, adc_joystick_cleanup,
27162306a36Sopenharmony_ci						 joy->buffer);
27262306a36Sopenharmony_ci		if (error)  {
27362306a36Sopenharmony_ci			dev_err(dev, "Unable to add action\n");
27462306a36Sopenharmony_ci			return error;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	input_set_drvdata(input, joy);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	error = input_register_device(input);
28162306a36Sopenharmony_ci	if (error) {
28262306a36Sopenharmony_ci		dev_err(dev, "Unable to register input device\n");
28362306a36Sopenharmony_ci		return error;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return 0;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic const struct of_device_id adc_joystick_of_match[] = {
29062306a36Sopenharmony_ci	{ .compatible = "adc-joystick", },
29162306a36Sopenharmony_ci	{ }
29262306a36Sopenharmony_ci};
29362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, adc_joystick_of_match);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic struct platform_driver adc_joystick_driver = {
29662306a36Sopenharmony_ci	.driver = {
29762306a36Sopenharmony_ci		.name = "adc-joystick",
29862306a36Sopenharmony_ci		.of_match_table = adc_joystick_of_match,
29962306a36Sopenharmony_ci	},
30062306a36Sopenharmony_ci	.probe = adc_joystick_probe,
30162306a36Sopenharmony_ci};
30262306a36Sopenharmony_cimodule_platform_driver(adc_joystick_driver);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ciMODULE_DESCRIPTION("Input driver for joysticks connected over ADC");
30562306a36Sopenharmony_ciMODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
30662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
307