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