cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pcap_ts.c (6460B)


      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");