linux/drivers/input/touchscreen/resistive-adc-touch.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ADC generic resistive touchscreen (GRTS)
   4 * This is a generic input driver that connects to an ADC
   5 * given the channels in device tree, and reports events to the input
   6 * subsystem.
   7 *
   8 * Copyright (C) 2017,2018 Microchip Technology,
   9 * Author: Eugen Hristev <eugen.hristev@microchip.com>
  10 *
  11 */
  12#include <linux/input.h>
  13#include <linux/input/touchscreen.h>
  14#include <linux/iio/consumer.h>
  15#include <linux/iio/iio.h>
  16#include <linux/module.h>
  17#include <linux/of.h>
  18#include <linux/of_device.h>
  19#include <linux/platform_device.h>
  20
  21#define DRIVER_NAME                                     "resistive-adc-touch"
  22#define GRTS_DEFAULT_PRESSURE_MIN                       50000
  23#define GRTS_MAX_POS_MASK                               GENMASK(11, 0)
  24
  25/**
  26 * struct grts_state - generic resistive touch screen information struct
  27 * @pressure_min:       number representing the minimum for the pressure
  28 * @pressure:           are we getting pressure info or not
  29 * @iio_chans:          list of channels acquired
  30 * @iio_cb:             iio_callback buffer for the data
  31 * @input:              the input device structure that we register
  32 * @prop:               touchscreen properties struct
  33 */
  34struct grts_state {
  35        u32                             pressure_min;
  36        bool                            pressure;
  37        struct iio_channel              *iio_chans;
  38        struct iio_cb_buffer            *iio_cb;
  39        struct input_dev                *input;
  40        struct touchscreen_properties   prop;
  41};
  42
  43static int grts_cb(const void *data, void *private)
  44{
  45        const u16 *touch_info = data;
  46        struct grts_state *st = private;
  47        unsigned int x, y, press = 0x0;
  48
  49        /* channel data coming in buffer in the order below */
  50        x = touch_info[0];
  51        y = touch_info[1];
  52        if (st->pressure)
  53                press = touch_info[2];
  54
  55        if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
  56                /* report end of touch */
  57                input_report_key(st->input, BTN_TOUCH, 0);
  58                input_sync(st->input);
  59                return 0;
  60        }
  61
  62        /* report proper touch to subsystem*/
  63        touchscreen_report_pos(st->input, &st->prop, x, y, false);
  64        if (st->pressure)
  65                input_report_abs(st->input, ABS_PRESSURE, press);
  66        input_report_key(st->input, BTN_TOUCH, 1);
  67        input_sync(st->input);
  68
  69        return 0;
  70}
  71
  72static int grts_open(struct input_dev *dev)
  73{
  74        int error;
  75        struct grts_state *st = input_get_drvdata(dev);
  76
  77        error = iio_channel_start_all_cb(st->iio_cb);
  78        if (error) {
  79                dev_err(dev->dev.parent, "failed to start callback buffer.\n");
  80                return error;
  81        }
  82        return 0;
  83}
  84
  85static void grts_close(struct input_dev *dev)
  86{
  87        struct grts_state *st = input_get_drvdata(dev);
  88
  89        iio_channel_stop_all_cb(st->iio_cb);
  90}
  91
  92static void grts_disable(void *data)
  93{
  94        iio_channel_release_all_cb(data);
  95}
  96
  97static int grts_probe(struct platform_device *pdev)
  98{
  99        struct grts_state *st;
 100        struct input_dev *input;
 101        struct device *dev = &pdev->dev;
 102        struct iio_channel *chan;
 103        int error;
 104
 105        st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
 106        if (!st)
 107                return -ENOMEM;
 108
 109        /* get the channels from IIO device */
 110        st->iio_chans = devm_iio_channel_get_all(dev);
 111        if (IS_ERR(st->iio_chans)) {
 112                error = PTR_ERR(st->iio_chans);
 113                if (error != -EPROBE_DEFER)
 114                        dev_err(dev, "can't get iio channels.\n");
 115                return error;
 116        }
 117
 118        chan = &st->iio_chans[0];
 119        st->pressure = false;
 120        while (chan && chan->indio_dev) {
 121                if (!strcmp(chan->channel->datasheet_name, "pressure"))
 122                        st->pressure = true;
 123                chan++;
 124        }
 125
 126        if (st->pressure) {
 127                error = device_property_read_u32(dev,
 128                                                 "touchscreen-min-pressure",
 129                                                 &st->pressure_min);
 130                if (error) {
 131                        dev_dbg(dev, "can't get touchscreen-min-pressure property.\n");
 132                        st->pressure_min = GRTS_DEFAULT_PRESSURE_MIN;
 133                }
 134        }
 135
 136        input = devm_input_allocate_device(dev);
 137        if (!input) {
 138                dev_err(dev, "failed to allocate input device.\n");
 139                return -ENOMEM;
 140        }
 141
 142        input->name = DRIVER_NAME;
 143        input->id.bustype = BUS_HOST;
 144        input->open = grts_open;
 145        input->close = grts_close;
 146
 147        input_set_abs_params(input, ABS_X, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
 148        input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
 149        if (st->pressure)
 150                input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
 151                                     0xffff, 0, 0);
 152
 153        input_set_capability(input, EV_KEY, BTN_TOUCH);
 154
 155        /* parse optional device tree properties */
 156        touchscreen_parse_properties(input, false, &st->prop);
 157
 158        st->input = input;
 159        input_set_drvdata(input, st);
 160
 161        error = input_register_device(input);
 162        if (error) {
 163                dev_err(dev, "failed to register input device.");
 164                return error;
 165        }
 166
 167        st->iio_cb = iio_channel_get_all_cb(dev, grts_cb, st);
 168        if (IS_ERR(st->iio_cb)) {
 169                dev_err(dev, "failed to allocate callback buffer.\n");
 170                return PTR_ERR(st->iio_cb);
 171        }
 172
 173        error = devm_add_action_or_reset(dev, grts_disable, st->iio_cb);
 174        if (error) {
 175                dev_err(dev, "failed to add disable action.\n");
 176                return error;
 177        }
 178
 179        return 0;
 180}
 181
 182static const struct of_device_id grts_of_match[] = {
 183        {
 184                .compatible = "resistive-adc-touch",
 185        }, {
 186                /* sentinel */
 187        },
 188};
 189
 190MODULE_DEVICE_TABLE(of, grts_of_match);
 191
 192static struct platform_driver grts_driver = {
 193        .probe = grts_probe,
 194        .driver = {
 195                .name = DRIVER_NAME,
 196                .of_match_table = of_match_ptr(grts_of_match),
 197        },
 198};
 199
 200module_platform_driver(grts_driver);
 201
 202MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
 203MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver");
 204MODULE_LICENSE("GPL v2");
 205