10387e107SDaniel Ribeiro /* 20387e107SDaniel Ribeiro * Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform. 30387e107SDaniel Ribeiro * 40387e107SDaniel Ribeiro * Copyright (C) 2006 Harald Welte <laforge@openezx.org> 50387e107SDaniel Ribeiro * Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com> 60387e107SDaniel Ribeiro * 70387e107SDaniel Ribeiro * This program is free software; you can redistribute it and/or modify 80387e107SDaniel Ribeiro * it under the terms of the GNU General Public License version 2 as 90387e107SDaniel Ribeiro * published by the Free Software Foundation. 100387e107SDaniel Ribeiro * 110387e107SDaniel Ribeiro */ 120387e107SDaniel Ribeiro 130387e107SDaniel Ribeiro #include <linux/module.h> 140387e107SDaniel Ribeiro #include <linux/init.h> 150387e107SDaniel Ribeiro #include <linux/fs.h> 160387e107SDaniel Ribeiro #include <linux/string.h> 170387e107SDaniel Ribeiro #include <linux/pm.h> 180387e107SDaniel Ribeiro #include <linux/timer.h> 190387e107SDaniel Ribeiro #include <linux/interrupt.h> 200387e107SDaniel Ribeiro #include <linux/platform_device.h> 210387e107SDaniel Ribeiro #include <linux/input.h> 220387e107SDaniel Ribeiro #include <linux/mfd/ezx-pcap.h> 230387e107SDaniel Ribeiro 240387e107SDaniel Ribeiro struct pcap_ts { 250387e107SDaniel Ribeiro struct pcap_chip *pcap; 260387e107SDaniel Ribeiro struct input_dev *input; 270387e107SDaniel Ribeiro struct delayed_work work; 280387e107SDaniel Ribeiro u16 x, y; 290387e107SDaniel Ribeiro u16 pressure; 300387e107SDaniel Ribeiro u8 read_state; 310387e107SDaniel Ribeiro }; 320387e107SDaniel Ribeiro 330387e107SDaniel Ribeiro #define SAMPLE_DELAY 20 /* msecs */ 340387e107SDaniel Ribeiro 350387e107SDaniel Ribeiro #define X_AXIS_MIN 0 360387e107SDaniel Ribeiro #define X_AXIS_MAX 1023 370387e107SDaniel Ribeiro #define Y_AXIS_MAX X_AXIS_MAX 380387e107SDaniel Ribeiro #define Y_AXIS_MIN X_AXIS_MIN 390387e107SDaniel Ribeiro #define PRESSURE_MAX X_AXIS_MAX 400387e107SDaniel Ribeiro #define PRESSURE_MIN X_AXIS_MIN 410387e107SDaniel Ribeiro 420387e107SDaniel Ribeiro static void pcap_ts_read_xy(void *data, u16 res[2]) 430387e107SDaniel Ribeiro { 440387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = data; 450387e107SDaniel Ribeiro 460387e107SDaniel Ribeiro switch (pcap_ts->read_state) { 470387e107SDaniel Ribeiro case PCAP_ADC_TS_M_PRESSURE: 480387e107SDaniel Ribeiro /* pressure reading is unreliable */ 490387e107SDaniel Ribeiro if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX) 500387e107SDaniel Ribeiro pcap_ts->pressure = res[0]; 510387e107SDaniel Ribeiro pcap_ts->read_state = PCAP_ADC_TS_M_XY; 520387e107SDaniel Ribeiro schedule_delayed_work(&pcap_ts->work, 0); 530387e107SDaniel Ribeiro break; 540387e107SDaniel Ribeiro case PCAP_ADC_TS_M_XY: 550387e107SDaniel Ribeiro pcap_ts->y = res[0]; 560387e107SDaniel Ribeiro pcap_ts->x = res[1]; 570387e107SDaniel Ribeiro if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX || 580387e107SDaniel Ribeiro pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) { 590387e107SDaniel Ribeiro /* pen has been released */ 600387e107SDaniel Ribeiro input_report_abs(pcap_ts->input, ABS_PRESSURE, 0); 610387e107SDaniel Ribeiro input_report_key(pcap_ts->input, BTN_TOUCH, 0); 620387e107SDaniel Ribeiro 630387e107SDaniel Ribeiro pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; 640387e107SDaniel Ribeiro schedule_delayed_work(&pcap_ts->work, 0); 650387e107SDaniel Ribeiro } else { 660387e107SDaniel Ribeiro /* pen is touching the screen */ 670387e107SDaniel Ribeiro input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x); 680387e107SDaniel Ribeiro input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y); 690387e107SDaniel Ribeiro input_report_key(pcap_ts->input, BTN_TOUCH, 1); 700387e107SDaniel Ribeiro input_report_abs(pcap_ts->input, ABS_PRESSURE, 710387e107SDaniel Ribeiro pcap_ts->pressure); 720387e107SDaniel Ribeiro 730387e107SDaniel Ribeiro /* switch back to pressure read mode */ 740387e107SDaniel Ribeiro pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; 750387e107SDaniel Ribeiro schedule_delayed_work(&pcap_ts->work, 760387e107SDaniel Ribeiro msecs_to_jiffies(SAMPLE_DELAY)); 770387e107SDaniel Ribeiro } 780387e107SDaniel Ribeiro input_sync(pcap_ts->input); 790387e107SDaniel Ribeiro break; 800387e107SDaniel Ribeiro default: 810387e107SDaniel Ribeiro dev_warn(&pcap_ts->input->dev, 820387e107SDaniel Ribeiro "pcap_ts: Warning, unhandled read_state %d\n", 830387e107SDaniel Ribeiro pcap_ts->read_state); 840387e107SDaniel Ribeiro break; 850387e107SDaniel Ribeiro } 860387e107SDaniel Ribeiro } 870387e107SDaniel Ribeiro 880387e107SDaniel Ribeiro static void pcap_ts_work(struct work_struct *work) 890387e107SDaniel Ribeiro { 900387e107SDaniel Ribeiro struct delayed_work *dw = container_of(work, struct delayed_work, work); 910387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work); 920387e107SDaniel Ribeiro u8 ch[2]; 930387e107SDaniel Ribeiro 940387e107SDaniel Ribeiro pcap_set_ts_bits(pcap_ts->pcap, 950387e107SDaniel Ribeiro pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); 960387e107SDaniel Ribeiro 970387e107SDaniel Ribeiro if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) 980387e107SDaniel Ribeiro return; 990387e107SDaniel Ribeiro 1000387e107SDaniel Ribeiro /* start adc conversion */ 1010387e107SDaniel Ribeiro ch[0] = PCAP_ADC_CH_TS_X1; 1020387e107SDaniel Ribeiro ch[1] = PCAP_ADC_CH_TS_Y1; 1030387e107SDaniel Ribeiro pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch, 1040387e107SDaniel Ribeiro pcap_ts_read_xy, pcap_ts); 1050387e107SDaniel Ribeiro } 1060387e107SDaniel Ribeiro 1070387e107SDaniel Ribeiro static irqreturn_t pcap_ts_event_touch(int pirq, void *data) 1080387e107SDaniel Ribeiro { 1090387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = data; 1100387e107SDaniel Ribeiro 1110387e107SDaniel Ribeiro if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) { 1120387e107SDaniel Ribeiro pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; 1130387e107SDaniel Ribeiro schedule_delayed_work(&pcap_ts->work, 0); 1140387e107SDaniel Ribeiro } 1150387e107SDaniel Ribeiro return IRQ_HANDLED; 1160387e107SDaniel Ribeiro } 1170387e107SDaniel Ribeiro 1180387e107SDaniel Ribeiro static int pcap_ts_open(struct input_dev *dev) 1190387e107SDaniel Ribeiro { 1200387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = input_get_drvdata(dev); 1210387e107SDaniel Ribeiro 1220387e107SDaniel Ribeiro pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; 1230387e107SDaniel Ribeiro schedule_delayed_work(&pcap_ts->work, 0); 1240387e107SDaniel Ribeiro 1250387e107SDaniel Ribeiro return 0; 1260387e107SDaniel Ribeiro } 1270387e107SDaniel Ribeiro 1280387e107SDaniel Ribeiro static void pcap_ts_close(struct input_dev *dev) 1290387e107SDaniel Ribeiro { 1300387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = input_get_drvdata(dev); 1310387e107SDaniel Ribeiro 1320387e107SDaniel Ribeiro cancel_delayed_work_sync(&pcap_ts->work); 1330387e107SDaniel Ribeiro 1340387e107SDaniel Ribeiro pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; 1350387e107SDaniel Ribeiro pcap_set_ts_bits(pcap_ts->pcap, 1360387e107SDaniel Ribeiro pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); 1370387e107SDaniel Ribeiro } 1380387e107SDaniel Ribeiro 1390387e107SDaniel Ribeiro static int __devinit pcap_ts_probe(struct platform_device *pdev) 1400387e107SDaniel Ribeiro { 1410387e107SDaniel Ribeiro struct input_dev *input_dev; 1420387e107SDaniel Ribeiro struct pcap_ts *pcap_ts; 1430387e107SDaniel Ribeiro int err = -ENOMEM; 1440387e107SDaniel Ribeiro 1450387e107SDaniel Ribeiro pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL); 1460387e107SDaniel Ribeiro if (!pcap_ts) 1470387e107SDaniel Ribeiro return err; 1480387e107SDaniel Ribeiro 1490387e107SDaniel Ribeiro pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent); 1500387e107SDaniel Ribeiro platform_set_drvdata(pdev, pcap_ts); 1510387e107SDaniel Ribeiro 1520387e107SDaniel Ribeiro input_dev = input_allocate_device(); 1530387e107SDaniel Ribeiro if (!input_dev) 1540387e107SDaniel Ribeiro goto fail; 1550387e107SDaniel Ribeiro 1560387e107SDaniel Ribeiro INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work); 1570387e107SDaniel Ribeiro 1580387e107SDaniel Ribeiro pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; 1590387e107SDaniel Ribeiro pcap_set_ts_bits(pcap_ts->pcap, 1600387e107SDaniel Ribeiro pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); 1610387e107SDaniel Ribeiro 1620387e107SDaniel Ribeiro pcap_ts->input = input_dev; 1630387e107SDaniel Ribeiro input_set_drvdata(input_dev, pcap_ts); 1640387e107SDaniel Ribeiro 1650387e107SDaniel Ribeiro input_dev->name = "pcap-touchscreen"; 1660387e107SDaniel Ribeiro input_dev->phys = "pcap_ts/input0"; 1670387e107SDaniel Ribeiro input_dev->id.bustype = BUS_HOST; 1680387e107SDaniel Ribeiro input_dev->id.vendor = 0x0001; 1690387e107SDaniel Ribeiro input_dev->id.product = 0x0002; 1700387e107SDaniel Ribeiro input_dev->id.version = 0x0100; 1710387e107SDaniel Ribeiro input_dev->dev.parent = &pdev->dev; 1720387e107SDaniel Ribeiro input_dev->open = pcap_ts_open; 1730387e107SDaniel Ribeiro input_dev->close = pcap_ts_close; 1740387e107SDaniel Ribeiro 1750387e107SDaniel Ribeiro input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 1760387e107SDaniel Ribeiro input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 1770387e107SDaniel Ribeiro input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); 1780387e107SDaniel Ribeiro input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); 1790387e107SDaniel Ribeiro input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, 1800387e107SDaniel Ribeiro PRESSURE_MAX, 0, 0); 1810387e107SDaniel Ribeiro 1820387e107SDaniel Ribeiro err = input_register_device(pcap_ts->input); 1830387e107SDaniel Ribeiro if (err) 1840387e107SDaniel Ribeiro goto fail_allocate; 1850387e107SDaniel Ribeiro 1860387e107SDaniel Ribeiro err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), 1870387e107SDaniel Ribeiro pcap_ts_event_touch, 0, "Touch Screen", pcap_ts); 1880387e107SDaniel Ribeiro if (err) 1890387e107SDaniel Ribeiro goto fail_register; 1900387e107SDaniel Ribeiro 1910387e107SDaniel Ribeiro return 0; 1920387e107SDaniel Ribeiro 1930387e107SDaniel Ribeiro fail_register: 1940387e107SDaniel Ribeiro input_unregister_device(input_dev); 1950387e107SDaniel Ribeiro goto fail; 1960387e107SDaniel Ribeiro fail_allocate: 1970387e107SDaniel Ribeiro input_free_device(input_dev); 1980387e107SDaniel Ribeiro fail: 1990387e107SDaniel Ribeiro kfree(pcap_ts); 2000387e107SDaniel Ribeiro 2010387e107SDaniel Ribeiro return err; 2020387e107SDaniel Ribeiro } 2030387e107SDaniel Ribeiro 2040387e107SDaniel Ribeiro static int __devexit pcap_ts_remove(struct platform_device *pdev) 2050387e107SDaniel Ribeiro { 2060387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); 2070387e107SDaniel Ribeiro 2080387e107SDaniel Ribeiro free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts); 2090387e107SDaniel Ribeiro cancel_delayed_work_sync(&pcap_ts->work); 2100387e107SDaniel Ribeiro 2110387e107SDaniel Ribeiro input_unregister_device(pcap_ts->input); 2120387e107SDaniel Ribeiro 2130387e107SDaniel Ribeiro kfree(pcap_ts); 2140387e107SDaniel Ribeiro 2150387e107SDaniel Ribeiro return 0; 2160387e107SDaniel Ribeiro } 2170387e107SDaniel Ribeiro 2180387e107SDaniel Ribeiro #ifdef CONFIG_PM 2190387e107SDaniel Ribeiro static int pcap_ts_suspend(struct device *dev) 2200387e107SDaniel Ribeiro { 2210387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = dev_get_drvdata(dev); 2220387e107SDaniel Ribeiro 2230387e107SDaniel Ribeiro pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR); 2240387e107SDaniel Ribeiro return 0; 2250387e107SDaniel Ribeiro } 2260387e107SDaniel Ribeiro 2270387e107SDaniel Ribeiro static int pcap_ts_resume(struct device *dev) 2280387e107SDaniel Ribeiro { 2290387e107SDaniel Ribeiro struct pcap_ts *pcap_ts = dev_get_drvdata(dev); 2300387e107SDaniel Ribeiro 2310387e107SDaniel Ribeiro pcap_set_ts_bits(pcap_ts->pcap, 2320387e107SDaniel Ribeiro pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); 2330387e107SDaniel Ribeiro return 0; 2340387e107SDaniel Ribeiro } 2350387e107SDaniel Ribeiro 236*47145210SAlexey Dobriyan static const struct dev_pm_ops pcap_ts_pm_ops = { 2370387e107SDaniel Ribeiro .suspend = pcap_ts_suspend, 2380387e107SDaniel Ribeiro .resume = pcap_ts_resume, 2390387e107SDaniel Ribeiro }; 2400387e107SDaniel Ribeiro #define PCAP_TS_PM_OPS (&pcap_ts_pm_ops) 2410387e107SDaniel Ribeiro #else 2420387e107SDaniel Ribeiro #define PCAP_TS_PM_OPS NULL 2430387e107SDaniel Ribeiro #endif 2440387e107SDaniel Ribeiro 2450387e107SDaniel Ribeiro static struct platform_driver pcap_ts_driver = { 2460387e107SDaniel Ribeiro .probe = pcap_ts_probe, 2470387e107SDaniel Ribeiro .remove = __devexit_p(pcap_ts_remove), 2480387e107SDaniel Ribeiro .driver = { 2490387e107SDaniel Ribeiro .name = "pcap-ts", 2500387e107SDaniel Ribeiro .owner = THIS_MODULE, 2510387e107SDaniel Ribeiro .pm = PCAP_TS_PM_OPS, 2520387e107SDaniel Ribeiro }, 2530387e107SDaniel Ribeiro }; 2540387e107SDaniel Ribeiro 2550387e107SDaniel Ribeiro static int __init pcap_ts_init(void) 2560387e107SDaniel Ribeiro { 2570387e107SDaniel Ribeiro return platform_driver_register(&pcap_ts_driver); 2580387e107SDaniel Ribeiro } 2590387e107SDaniel Ribeiro 2600387e107SDaniel Ribeiro static void __exit pcap_ts_exit(void) 2610387e107SDaniel Ribeiro { 2620387e107SDaniel Ribeiro platform_driver_unregister(&pcap_ts_driver); 2630387e107SDaniel Ribeiro } 2640387e107SDaniel Ribeiro 2650387e107SDaniel Ribeiro module_init(pcap_ts_init); 2660387e107SDaniel Ribeiro module_exit(pcap_ts_exit); 2670387e107SDaniel Ribeiro 2680387e107SDaniel Ribeiro MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver"); 2690387e107SDaniel Ribeiro MODULE_AUTHOR("Daniel Ribeiro / Harald Welte"); 2700387e107SDaniel Ribeiro MODULE_LICENSE("GPL"); 2710387e107SDaniel Ribeiro MODULE_ALIAS("platform:pcap_ts"); 272