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