Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Input driver for joysticks connected over ADC.
0004  * Copyright (c) 2019-2020 Artur Rojek <contact@artur-rojek.eu>
0005  */
0006 #include <linux/ctype.h>
0007 #include <linux/input.h>
0008 #include <linux/iio/iio.h>
0009 #include <linux/iio/consumer.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/property.h>
0013 
0014 #include <asm/unaligned.h>
0015 
0016 struct adc_joystick_axis {
0017     u32 code;
0018     s32 range[2];
0019     s32 fuzz;
0020     s32 flat;
0021 };
0022 
0023 struct adc_joystick {
0024     struct input_dev *input;
0025     struct iio_cb_buffer *buffer;
0026     struct adc_joystick_axis *axes;
0027     struct iio_channel *chans;
0028     int num_chans;
0029 };
0030 
0031 static int adc_joystick_handle(const void *data, void *private)
0032 {
0033     struct adc_joystick *joy = private;
0034     enum iio_endian endianness;
0035     int bytes, msb, val, idx, i;
0036     const u16 *data_u16;
0037     bool sign;
0038 
0039     bytes = joy->chans[0].channel->scan_type.storagebits >> 3;
0040 
0041     for (i = 0; i < joy->num_chans; ++i) {
0042         idx = joy->chans[i].channel->scan_index;
0043         endianness = joy->chans[i].channel->scan_type.endianness;
0044         msb = joy->chans[i].channel->scan_type.realbits - 1;
0045         sign = tolower(joy->chans[i].channel->scan_type.sign) == 's';
0046 
0047         switch (bytes) {
0048         case 1:
0049             val = ((const u8 *)data)[idx];
0050             break;
0051         case 2:
0052             data_u16 = (const u16 *)data + idx;
0053 
0054             /*
0055              * Data is aligned to the sample size by IIO core.
0056              * Call `get_unaligned_xe16` to hide type casting.
0057              */
0058             if (endianness == IIO_BE)
0059                 val = get_unaligned_be16(data_u16);
0060             else if (endianness == IIO_LE)
0061                 val = get_unaligned_le16(data_u16);
0062             else /* IIO_CPU */
0063                 val = *data_u16;
0064             break;
0065         default:
0066             return -EINVAL;
0067         }
0068 
0069         val >>= joy->chans[i].channel->scan_type.shift;
0070         if (sign)
0071             val = sign_extend32(val, msb);
0072         else
0073             val &= GENMASK(msb, 0);
0074         input_report_abs(joy->input, joy->axes[i].code, val);
0075     }
0076 
0077     input_sync(joy->input);
0078 
0079     return 0;
0080 }
0081 
0082 static int adc_joystick_open(struct input_dev *dev)
0083 {
0084     struct adc_joystick *joy = input_get_drvdata(dev);
0085     struct device *devp = &dev->dev;
0086     int ret;
0087 
0088     ret = iio_channel_start_all_cb(joy->buffer);
0089     if (ret)
0090         dev_err(devp, "Unable to start callback buffer: %d\n", ret);
0091 
0092     return ret;
0093 }
0094 
0095 static void adc_joystick_close(struct input_dev *dev)
0096 {
0097     struct adc_joystick *joy = input_get_drvdata(dev);
0098 
0099     iio_channel_stop_all_cb(joy->buffer);
0100 }
0101 
0102 static void adc_joystick_cleanup(void *data)
0103 {
0104     iio_channel_release_all_cb(data);
0105 }
0106 
0107 static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
0108 {
0109     struct adc_joystick_axis *axes;
0110     struct fwnode_handle *child;
0111     int num_axes, error, i;
0112 
0113     num_axes = device_get_child_node_count(dev);
0114     if (!num_axes) {
0115         dev_err(dev, "Unable to find child nodes\n");
0116         return -EINVAL;
0117     }
0118 
0119     if (num_axes != joy->num_chans) {
0120         dev_err(dev, "Got %d child nodes for %d channels\n",
0121             num_axes, joy->num_chans);
0122         return -EINVAL;
0123     }
0124 
0125     axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL);
0126     if (!axes)
0127         return -ENOMEM;
0128 
0129     device_for_each_child_node(dev, child) {
0130         error = fwnode_property_read_u32(child, "reg", &i);
0131         if (error) {
0132             dev_err(dev, "reg invalid or missing\n");
0133             goto err_fwnode_put;
0134         }
0135 
0136         if (i >= num_axes) {
0137             error = -EINVAL;
0138             dev_err(dev, "No matching axis for reg %d\n", i);
0139             goto err_fwnode_put;
0140         }
0141 
0142         error = fwnode_property_read_u32(child, "linux,code",
0143                          &axes[i].code);
0144         if (error) {
0145             dev_err(dev, "linux,code invalid or missing\n");
0146             goto err_fwnode_put;
0147         }
0148 
0149         error = fwnode_property_read_u32_array(child, "abs-range",
0150                                axes[i].range, 2);
0151         if (error) {
0152             dev_err(dev, "abs-range invalid or missing\n");
0153             goto err_fwnode_put;
0154         }
0155 
0156         fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz);
0157         fwnode_property_read_u32(child, "abs-flat", &axes[i].flat);
0158 
0159         input_set_abs_params(joy->input, axes[i].code,
0160                      axes[i].range[0], axes[i].range[1],
0161                      axes[i].fuzz, axes[i].flat);
0162         input_set_capability(joy->input, EV_ABS, axes[i].code);
0163     }
0164 
0165     joy->axes = axes;
0166 
0167     return 0;
0168 
0169 err_fwnode_put:
0170     fwnode_handle_put(child);
0171     return error;
0172 }
0173 
0174 static int adc_joystick_probe(struct platform_device *pdev)
0175 {
0176     struct device *dev = &pdev->dev;
0177     struct adc_joystick *joy;
0178     struct input_dev *input;
0179     int error;
0180     int bits;
0181     int i;
0182 
0183     joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL);
0184     if (!joy)
0185         return -ENOMEM;
0186 
0187     joy->chans = devm_iio_channel_get_all(dev);
0188     if (IS_ERR(joy->chans)) {
0189         error = PTR_ERR(joy->chans);
0190         if (error != -EPROBE_DEFER)
0191             dev_err(dev, "Unable to get IIO channels");
0192         return error;
0193     }
0194 
0195     /* Count how many channels we got. NULL terminated. */
0196     for (i = 0; joy->chans[i].indio_dev; i++) {
0197         bits = joy->chans[i].channel->scan_type.storagebits;
0198         if (!bits || bits > 16) {
0199             dev_err(dev, "Unsupported channel storage size\n");
0200             return -EINVAL;
0201         }
0202         if (bits != joy->chans[0].channel->scan_type.storagebits) {
0203             dev_err(dev, "Channels must have equal storage size\n");
0204             return -EINVAL;
0205         }
0206     }
0207     joy->num_chans = i;
0208 
0209     input = devm_input_allocate_device(dev);
0210     if (!input) {
0211         dev_err(dev, "Unable to allocate input device\n");
0212         return -ENOMEM;
0213     }
0214 
0215     joy->input = input;
0216     input->name = pdev->name;
0217     input->id.bustype = BUS_HOST;
0218     input->open = adc_joystick_open;
0219     input->close = adc_joystick_close;
0220 
0221     error = adc_joystick_set_axes(dev, joy);
0222     if (error)
0223         return error;
0224 
0225     joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle, joy);
0226     if (IS_ERR(joy->buffer)) {
0227         dev_err(dev, "Unable to allocate callback buffer\n");
0228         return PTR_ERR(joy->buffer);
0229     }
0230 
0231     error = devm_add_action_or_reset(dev, adc_joystick_cleanup, joy->buffer);
0232     if (error)  {
0233         dev_err(dev, "Unable to add action\n");
0234         return error;
0235     }
0236 
0237     input_set_drvdata(input, joy);
0238 
0239     error = input_register_device(input);
0240     if (error) {
0241         dev_err(dev, "Unable to register input device\n");
0242         return error;
0243     }
0244 
0245     return 0;
0246 }
0247 
0248 static const struct of_device_id adc_joystick_of_match[] = {
0249     { .compatible = "adc-joystick", },
0250     { }
0251 };
0252 MODULE_DEVICE_TABLE(of, adc_joystick_of_match);
0253 
0254 static struct platform_driver adc_joystick_driver = {
0255     .driver = {
0256         .name = "adc-joystick",
0257         .of_match_table = adc_joystick_of_match,
0258     },
0259     .probe = adc_joystick_probe,
0260 };
0261 module_platform_driver(adc_joystick_driver);
0262 
0263 MODULE_DESCRIPTION("Input driver for joysticks connected over ADC");
0264 MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
0265 MODULE_LICENSE("GPL");