linux/drivers/input/touchscreen/pcap_ts.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform.
   4 *
   5 *  Copyright (C) 2006 Harald Welte <laforge@openezx.org>
   6 *  Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/fs.h>
  11#include <linux/string.h>
  12#include <linux/slab.h>
  13#include <linux/pm.h>
  14#include <linux/timer.h>
  15#include <linux/interrupt.h>
  16#include <linux/platform_device.h>
  17#include <linux/input.h>
  18#include <linux/mfd/ezx-pcap.h>
  19
  20struct pcap_ts {
  21        struct pcap_chip *pcap;
  22        struct input_dev *input;
  23        struct delayed_work work;
  24        u16 x, y;
  25        u16 pressure;
  26        u8 read_state;
  27};
  28
  29#define SAMPLE_DELAY    20 /* msecs */
  30
  31#define X_AXIS_MIN      0
  32#define X_AXIS_MAX      1023
  33#define Y_AXIS_MAX      X_AXIS_MAX
  34#define Y_AXIS_MIN      X_AXIS_MIN
  35#define PRESSURE_MAX    X_AXIS_MAX
  36#define PRESSURE_MIN    X_AXIS_MIN
  37
  38static void pcap_ts_read_xy(void *data, u16 res[2])
  39{
  40        struct pcap_ts *pcap_ts = data;
  41
  42        switch (pcap_ts->read_state) {
  43        case PCAP_ADC_TS_M_PRESSURE:
  44                /* pressure reading is unreliable */
  45                if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX)
  46                        pcap_ts->pressure = res[0];
  47                pcap_ts->read_state = PCAP_ADC_TS_M_XY;
  48                schedule_delayed_work(&pcap_ts->work, 0);
  49                break;
  50        case PCAP_ADC_TS_M_XY:
  51                pcap_ts->y = res[0];
  52                pcap_ts->x = res[1];
  53                if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX ||
  54                    pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) {
  55                        /* pen has been released */
  56                        input_report_abs(pcap_ts->input, ABS_PRESSURE, 0);
  57                        input_report_key(pcap_ts->input, BTN_TOUCH, 0);
  58
  59                        pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
  60                        schedule_delayed_work(&pcap_ts->work, 0);
  61                } else {
  62                        /* pen is touching the screen */
  63                        input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x);
  64                        input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y);
  65                        input_report_key(pcap_ts->input, BTN_TOUCH, 1);
  66                        input_report_abs(pcap_ts->input, ABS_PRESSURE,
  67                                                pcap_ts->pressure);
  68
  69                        /* switch back to pressure read mode */
  70                        pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
  71                        schedule_delayed_work(&pcap_ts->work,
  72                                        msecs_to_jiffies(SAMPLE_DELAY));
  73                }
  74                input_sync(pcap_ts->input);
  75                break;
  76        default:
  77                dev_warn(&pcap_ts->input->dev,
  78                                "pcap_ts: Warning, unhandled read_state %d\n",
  79                                pcap_ts->read_state);
  80                break;
  81        }
  82}
  83
  84static void pcap_ts_work(struct work_struct *work)
  85{
  86        struct delayed_work *dw = to_delayed_work(work);
  87        struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work);
  88        u8 ch[2];
  89
  90        pcap_set_ts_bits(pcap_ts->pcap,
  91                        pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
  92
  93        if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY)
  94                return;
  95
  96        /* start adc conversion */
  97        ch[0] = PCAP_ADC_CH_TS_X1;
  98        ch[1] = PCAP_ADC_CH_TS_Y1;
  99        pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch,
 100                                                pcap_ts_read_xy, pcap_ts);
 101}
 102
 103static irqreturn_t pcap_ts_event_touch(int pirq, void *data)
 104{
 105        struct pcap_ts *pcap_ts = data;
 106
 107        if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) {
 108                pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
 109                schedule_delayed_work(&pcap_ts->work, 0);
 110        }
 111        return IRQ_HANDLED;
 112}
 113
 114static int pcap_ts_open(struct input_dev *dev)
 115{
 116        struct pcap_ts *pcap_ts = input_get_drvdata(dev);
 117
 118        pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
 119        schedule_delayed_work(&pcap_ts->work, 0);
 120
 121        return 0;
 122}
 123
 124static void pcap_ts_close(struct input_dev *dev)
 125{
 126        struct pcap_ts *pcap_ts = input_get_drvdata(dev);
 127
 128        cancel_delayed_work_sync(&pcap_ts->work);
 129
 130        pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
 131        pcap_set_ts_bits(pcap_ts->pcap,
 132                                pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
 133}
 134
 135static int pcap_ts_probe(struct platform_device *pdev)
 136{
 137        struct input_dev *input_dev;
 138        struct pcap_ts *pcap_ts;
 139        int err = -ENOMEM;
 140
 141        pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL);
 142        if (!pcap_ts)
 143                return err;
 144
 145        pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent);
 146        platform_set_drvdata(pdev, pcap_ts);
 147
 148        input_dev = input_allocate_device();
 149        if (!input_dev)
 150                goto fail;
 151
 152        INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work);
 153
 154        pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
 155        pcap_set_ts_bits(pcap_ts->pcap,
 156                                pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
 157
 158        pcap_ts->input = input_dev;
 159        input_set_drvdata(input_dev, pcap_ts);
 160
 161        input_dev->name = "pcap-touchscreen";
 162        input_dev->phys = "pcap_ts/input0";
 163        input_dev->id.bustype = BUS_HOST;
 164        input_dev->id.vendor = 0x0001;
 165        input_dev->id.product = 0x0002;
 166        input_dev->id.version = 0x0100;
 167        input_dev->dev.parent = &pdev->dev;
 168        input_dev->open = pcap_ts_open;
 169        input_dev->close = pcap_ts_close;
 170
 171        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 172        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 173        input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
 174        input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
 175        input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN,
 176                             PRESSURE_MAX, 0, 0);
 177
 178        err = input_register_device(pcap_ts->input);
 179        if (err)
 180                goto fail_allocate;
 181
 182        err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS),
 183                        pcap_ts_event_touch, 0, "Touch Screen", pcap_ts);
 184        if (err)
 185                goto fail_register;
 186
 187        return 0;
 188
 189fail_register:
 190        input_unregister_device(input_dev);
 191        goto fail;
 192fail_allocate:
 193        input_free_device(input_dev);
 194fail:
 195        kfree(pcap_ts);
 196
 197        return err;
 198}
 199
 200static int pcap_ts_remove(struct platform_device *pdev)
 201{
 202        struct pcap_ts *pcap_ts = platform_get_drvdata(pdev);
 203
 204        free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts);
 205        cancel_delayed_work_sync(&pcap_ts->work);
 206
 207        input_unregister_device(pcap_ts->input);
 208
 209        kfree(pcap_ts);
 210
 211        return 0;
 212}
 213
 214#ifdef CONFIG_PM
 215static int pcap_ts_suspend(struct device *dev)
 216{
 217        struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
 218
 219        pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR);
 220        return 0;
 221}
 222
 223static int pcap_ts_resume(struct device *dev)
 224{
 225        struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
 226
 227        pcap_set_ts_bits(pcap_ts->pcap,
 228                                pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
 229        return 0;
 230}
 231
 232static const struct dev_pm_ops pcap_ts_pm_ops = {
 233        .suspend        = pcap_ts_suspend,
 234        .resume         = pcap_ts_resume,
 235};
 236#define PCAP_TS_PM_OPS (&pcap_ts_pm_ops)
 237#else
 238#define PCAP_TS_PM_OPS NULL
 239#endif
 240
 241static struct platform_driver pcap_ts_driver = {
 242        .probe          = pcap_ts_probe,
 243        .remove         = pcap_ts_remove,
 244        .driver         = {
 245                .name   = "pcap-ts",
 246                .pm     = PCAP_TS_PM_OPS,
 247        },
 248};
 249module_platform_driver(pcap_ts_driver);
 250
 251MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver");
 252MODULE_AUTHOR("Daniel Ribeiro / Harald Welte");
 253MODULE_LICENSE("GPL");
 254MODULE_ALIAS("platform:pcap_ts");
 255