diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 01:02:30 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 01:02:30 +0000 |
commit | 76cb841cb886eef6b3bee341a2266c76578724ad (patch) | |
tree | f5892e5ba6cc11949952a6ce4ecbe6d516d6ce58 /drivers/input/misc/gpio_decoder.c | |
parent | Initial commit. (diff) | |
download | linux-76cb841cb886eef6b3bee341a2266c76578724ad.tar.xz linux-76cb841cb886eef6b3bee341a2266c76578724ad.zip |
Adding upstream version 4.19.249.upstream/4.19.249
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/input/misc/gpio_decoder.c')
-rw-r--r-- | drivers/input/misc/gpio_decoder.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c new file mode 100644 index 000000000..1dca526e6 --- /dev/null +++ b/drivers/input/misc/gpio_decoder.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * A generic driver to read multiple gpio lines and translate the + * encoded numeric value into an input event. + */ + +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +struct gpio_decoder { + struct input_polled_dev *poll_dev; + struct gpio_descs *input_gpios; + struct device *dev; + u32 axis; + u32 last_stable; +}; + +static int gpio_decoder_get_gpios_state(struct gpio_decoder *decoder) +{ + struct gpio_descs *gpios = decoder->input_gpios; + unsigned int ret = 0; + int i, val; + + for (i = 0; i < gpios->ndescs; i++) { + val = gpiod_get_value_cansleep(gpios->desc[i]); + if (val < 0) { + dev_err(decoder->dev, + "Error reading gpio %d: %d\n", + desc_to_gpio(gpios->desc[i]), val); + return val; + } + + val = !!val; + ret = (ret << 1) | val; + } + + return ret; +} + +static void gpio_decoder_poll_gpios(struct input_polled_dev *poll_dev) +{ + struct gpio_decoder *decoder = poll_dev->private; + int state; + + state = gpio_decoder_get_gpios_state(decoder); + if (state >= 0 && state != decoder->last_stable) { + input_report_abs(poll_dev->input, decoder->axis, state); + input_sync(poll_dev->input); + decoder->last_stable = state; + } +} + +static int gpio_decoder_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_decoder *decoder; + struct input_polled_dev *poll_dev; + u32 max; + int err; + + decoder = devm_kzalloc(dev, sizeof(struct gpio_decoder), GFP_KERNEL); + if (!decoder) + return -ENOMEM; + + device_property_read_u32(dev, "linux,axis", &decoder->axis); + decoder->input_gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); + if (IS_ERR(decoder->input_gpios)) { + dev_err(dev, "unable to acquire input gpios\n"); + return PTR_ERR(decoder->input_gpios); + } + if (decoder->input_gpios->ndescs < 2) { + dev_err(dev, "not enough gpios found\n"); + return -EINVAL; + } + + if (device_property_read_u32(dev, "decoder-max-value", &max)) + max = (1U << decoder->input_gpios->ndescs) - 1; + + decoder->dev = dev; + poll_dev = devm_input_allocate_polled_device(decoder->dev); + if (!poll_dev) + return -ENOMEM; + + poll_dev->private = decoder; + poll_dev->poll = gpio_decoder_poll_gpios; + decoder->poll_dev = poll_dev; + + poll_dev->input->name = pdev->name; + poll_dev->input->id.bustype = BUS_HOST; + input_set_abs_params(poll_dev->input, decoder->axis, 0, max, 0, 0); + + err = input_register_polled_device(poll_dev); + if (err) { + dev_err(dev, "failed to register polled device\n"); + return err; + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id gpio_decoder_of_match[] = { + { .compatible = "gpio-decoder", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_decoder_of_match); +#endif + +static struct platform_driver gpio_decoder_driver = { + .probe = gpio_decoder_probe, + .driver = { + .name = "gpio-decoder", + .of_match_table = of_match_ptr(gpio_decoder_of_match), + } +}; +module_platform_driver(gpio_decoder_driver); + +MODULE_DESCRIPTION("GPIO decoder input driver"); +MODULE_AUTHOR("Vignesh R <vigneshr@ti.com>"); +MODULE_LICENSE("GPL v2"); |