Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: joystick - add ADC attached joystick driver.

Add a driver for joystick devices connected to ADC controllers
supporting the Industrial I/O subsystem.

Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
Tested-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Link: https://lore.kernel.org/r/20200927123302.31062-2-contact@artur-rojek.eu
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Artur Rojek and committed by
Dmitry Torokhov
2c2b364f 7956b0d4

+275
+10
drivers/input/joystick/Kconfig
··· 42 42 To compile this driver as a module, choose M here: the 43 43 module will be called a3d. 44 44 45 + config JOYSTICK_ADC 46 + tristate "Simple joystick connected over ADC" 47 + depends on IIO 48 + select IIO_BUFFER_CB 49 + help 50 + Say Y here if you have a simple joystick connected over ADC. 51 + 52 + To compile this driver as a module, choose M here: the 53 + module will be called adc-joystick. 54 + 45 55 config JOYSTICK_ADI 46 56 tristate "Logitech ADI digital joysticks and gamepads" 47 57 select GAMEPORT
+1
drivers/input/joystick/Makefile
··· 6 6 # Each configuration option enables a list of files. 7 7 8 8 obj-$(CONFIG_JOYSTICK_A3D) += a3d.o 9 + obj-$(CONFIG_JOYSTICK_ADC) += adc-joystick.o 9 10 obj-$(CONFIG_JOYSTICK_ADI) += adi.o 10 11 obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o 11 12 obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o
+264
drivers/input/joystick/adc-joystick.c
··· 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> 13 + 14 + #include <asm/unaligned.h> 15 + 16 + struct adc_joystick_axis { 17 + u32 code; 18 + s32 range[2]; 19 + s32 fuzz; 20 + s32 flat; 21 + }; 22 + 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; 29 + }; 30 + 31 + static int adc_joystick_handle(const void *data, void *private) 32 + { 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; 38 + 39 + bytes = joy->chans[0].channel->scan_type.storagebits >> 3; 40 + 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'; 46 + 47 + switch (bytes) { 48 + case 1: 49 + val = ((const u8 *)data)[idx]; 50 + break; 51 + case 2: 52 + data_u16 = (const u16 *)data + idx; 53 + 54 + /* 55 + * Data is aligned to the sample size by IIO core. 56 + * Call `get_unaligned_xe16` to hide type casting. 57 + */ 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; 67 + } 68 + 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); 75 + } 76 + 77 + input_sync(joy->input); 78 + 79 + return 0; 80 + } 81 + 82 + static int adc_joystick_open(struct input_dev *dev) 83 + { 84 + struct adc_joystick *joy = input_get_drvdata(dev); 85 + struct device *devp = &dev->dev; 86 + int ret; 87 + 88 + ret = iio_channel_start_all_cb(joy->buffer); 89 + if (ret) 90 + dev_err(devp, "Unable to start callback buffer: %d\n", ret); 91 + 92 + return ret; 93 + } 94 + 95 + static void adc_joystick_close(struct input_dev *dev) 96 + { 97 + struct adc_joystick *joy = input_get_drvdata(dev); 98 + 99 + iio_channel_stop_all_cb(joy->buffer); 100 + } 101 + 102 + static void adc_joystick_cleanup(void *data) 103 + { 104 + iio_channel_release_all_cb(data); 105 + } 106 + 107 + static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy) 108 + { 109 + struct adc_joystick_axis *axes; 110 + struct fwnode_handle *child; 111 + int num_axes, error, i; 112 + 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; 117 + } 118 + 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; 123 + } 124 + 125 + axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL); 126 + if (!axes) 127 + return -ENOMEM; 128 + 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; 134 + } 135 + 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; 140 + } 141 + 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; 147 + } 148 + 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; 154 + } 155 + 156 + fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz); 157 + fwnode_property_read_u32(child, "abs-flat", &axes[i].flat); 158 + 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); 163 + } 164 + 165 + joy->axes = axes; 166 + 167 + return 0; 168 + 169 + err_fwnode_put: 170 + fwnode_handle_put(child); 171 + return error; 172 + } 173 + 174 + static int adc_joystick_probe(struct platform_device *pdev) 175 + { 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; 182 + 183 + joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL); 184 + if (!joy) 185 + return -ENOMEM; 186 + 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; 193 + } 194 + 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; 201 + } 202 + if (bits != joy->chans[0].channel->scan_type.storagebits) { 203 + dev_err(dev, "Channels must have equal storage size\n"); 204 + return -EINVAL; 205 + } 206 + } 207 + joy->num_chans = i; 208 + 209 + input = devm_input_allocate_device(dev); 210 + if (!input) { 211 + dev_err(dev, "Unable to allocate input device\n"); 212 + return -ENOMEM; 213 + } 214 + 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; 220 + 221 + error = adc_joystick_set_axes(dev, joy); 222 + if (error) 223 + return error; 224 + 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; 230 + } 231 + 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); 236 + } 237 + 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; 242 + } 243 + 244 + return 0; 245 + } 246 + 247 + static const struct of_device_id adc_joystick_of_match[] = { 248 + { .compatible = "adc-joystick", }, 249 + { } 250 + }; 251 + MODULE_DEVICE_TABLE(of, adc_joystick_of_match); 252 + 253 + static struct platform_driver adc_joystick_driver = { 254 + .driver = { 255 + .name = "adc-joystick", 256 + .of_match_table = adc_joystick_of_match, 257 + }, 258 + .probe = adc_joystick_probe, 259 + }; 260 + module_platform_driver(adc_joystick_driver); 261 + 262 + MODULE_DESCRIPTION("Input driver for joysticks connected over ADC"); 263 + MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>"); 264 + MODULE_LICENSE("GPL");