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