adc-joystick.c (6285B)
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 16struct adc_joystick_axis { 17 u32 code; 18 s32 range[2]; 19 s32 fuzz; 20 s32 flat; 21}; 22 23struct 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 31static 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 82static 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 95static 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 102static void adc_joystick_cleanup(void *data) 103{ 104 iio_channel_release_all_cb(data); 105} 106 107static 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 169err_fwnode_put: 170 fwnode_handle_put(child); 171 return error; 172} 173 174static 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 247static const struct of_device_id adc_joystick_of_match[] = { 248 { .compatible = "adc-joystick", }, 249 { } 250}; 251MODULE_DEVICE_TABLE(of, adc_joystick_of_match); 252 253static 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}; 260module_platform_driver(adc_joystick_driver); 261 262MODULE_DESCRIPTION("Input driver for joysticks connected over ADC"); 263MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>"); 264MODULE_LICENSE("GPL");