aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-02 23:26:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-02 23:26:32 -0400
commit497ff0344432d1c4ab493ce163a87410064b8d91 (patch)
treefbb4f5038622f475bf40d61047b3c3cf44a3d068
parent5933f2ae353a93b1d3b501bc63c925531849bbc7 (diff)
parentbf283707d5fb174ec09215ae19860ad04ba7b67a (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: wm831x-ts - move BTN_TOUCH reporting to data transfer Input: wm831x-ts - allow IRQ flags to be specified Input: wm831x-ts - fix races with IRQ management
-rw-r--r--drivers/input/touchscreen/wm831x-ts.c75
-rw-r--r--include/linux/mfd/wm831x/pdata.h2
2 files changed, 66 insertions, 11 deletions
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index 6ae054f8e0aa..9175d49d2546 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -68,8 +68,23 @@ struct wm831x_ts {
68 unsigned int pd_irq; 68 unsigned int pd_irq;
69 bool pressure; 69 bool pressure;
70 bool pen_down; 70 bool pen_down;
71 struct work_struct pd_data_work;
71}; 72};
72 73
74static void wm831x_pd_data_work(struct work_struct *work)
75{
76 struct wm831x_ts *wm831x_ts =
77 container_of(work, struct wm831x_ts, pd_data_work);
78
79 if (wm831x_ts->pen_down) {
80 enable_irq(wm831x_ts->data_irq);
81 dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n");
82 } else {
83 enable_irq(wm831x_ts->pd_irq);
84 dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n");
85 }
86}
87
73static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) 88static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
74{ 89{
75 struct wm831x_ts *wm831x_ts = irq_data; 90 struct wm831x_ts *wm831x_ts = irq_data;
@@ -110,6 +125,9 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
110 } 125 }
111 126
112 if (!wm831x_ts->pen_down) { 127 if (!wm831x_ts->pen_down) {
128 /* Switch from data to pen down */
129 dev_dbg(wm831x->dev, "IRQ DATA->PD\n");
130
113 disable_irq_nosync(wm831x_ts->data_irq); 131 disable_irq_nosync(wm831x_ts->data_irq);
114 132
115 /* Don't need data any more */ 133 /* Don't need data any more */
@@ -128,6 +146,10 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
128 ABS_PRESSURE, 0); 146 ABS_PRESSURE, 0);
129 147
130 input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); 148 input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0);
149
150 schedule_work(&wm831x_ts->pd_data_work);
151 } else {
152 input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
131 } 153 }
132 154
133 input_sync(wm831x_ts->input_dev); 155 input_sync(wm831x_ts->input_dev);
@@ -141,6 +163,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data)
141 struct wm831x *wm831x = wm831x_ts->wm831x; 163 struct wm831x *wm831x = wm831x_ts->wm831x;
142 int ena = 0; 164 int ena = 0;
143 165
166 if (wm831x_ts->pen_down)
167 return IRQ_HANDLED;
168
169 disable_irq_nosync(wm831x_ts->pd_irq);
170
144 /* Start collecting data */ 171 /* Start collecting data */
145 if (wm831x_ts->pressure) 172 if (wm831x_ts->pressure)
146 ena |= WM831X_TCH_Z_ENA; 173 ena |= WM831X_TCH_Z_ENA;
@@ -149,14 +176,14 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data)
149 WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 176 WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA,
150 WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); 177 WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena);
151 178
152 input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
153 input_sync(wm831x_ts->input_dev);
154
155 wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, 179 wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
156 WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); 180 WM831X_TCHPD_EINT, WM831X_TCHPD_EINT);
157 181
158 wm831x_ts->pen_down = true; 182 wm831x_ts->pen_down = true;
159 enable_irq(wm831x_ts->data_irq); 183
184 /* Switch from pen down to data */
185 dev_dbg(wm831x->dev, "IRQ PD->DATA\n");
186 schedule_work(&wm831x_ts->pd_data_work);
160 187
161 return IRQ_HANDLED; 188 return IRQ_HANDLED;
162} 189}
@@ -182,13 +209,28 @@ static void wm831x_ts_input_close(struct input_dev *idev)
182 struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); 209 struct wm831x_ts *wm831x_ts = input_get_drvdata(idev);
183 struct wm831x *wm831x = wm831x_ts->wm831x; 210 struct wm831x *wm831x = wm831x_ts->wm831x;
184 211
212 /* Shut the controller down, disabling all other functionality too */
185 wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 213 wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
186 WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | 214 WM831X_TCH_ENA | WM831X_TCH_X_ENA |
187 WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | 215 WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0);
188 WM831X_TCH_Z_ENA, 0);
189 216
190 if (wm831x_ts->pen_down) 217 /* Make sure any pending IRQs are done, the above will prevent
218 * new ones firing.
219 */
220 synchronize_irq(wm831x_ts->data_irq);
221 synchronize_irq(wm831x_ts->pd_irq);
222
223 /* Make sure the IRQ completion work is quiesced */
224 flush_work_sync(&wm831x_ts->pd_data_work);
225
226 /* If we ended up with the pen down then make sure we revert back
227 * to pen detection state for the next time we start up.
228 */
229 if (wm831x_ts->pen_down) {
191 disable_irq(wm831x_ts->data_irq); 230 disable_irq(wm831x_ts->data_irq);
231 enable_irq(wm831x_ts->pd_irq);
232 wm831x_ts->pen_down = false;
233 }
192} 234}
193 235
194static __devinit int wm831x_ts_probe(struct platform_device *pdev) 236static __devinit int wm831x_ts_probe(struct platform_device *pdev)
@@ -198,7 +240,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
198 struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); 240 struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent);
199 struct wm831x_touch_pdata *pdata = NULL; 241 struct wm831x_touch_pdata *pdata = NULL;
200 struct input_dev *input_dev; 242 struct input_dev *input_dev;
201 int error; 243 int error, irqf;
202 244
203 if (core_pdata) 245 if (core_pdata)
204 pdata = core_pdata->touch; 246 pdata = core_pdata->touch;
@@ -212,6 +254,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
212 254
213 wm831x_ts->wm831x = wm831x; 255 wm831x_ts->wm831x = wm831x;
214 wm831x_ts->input_dev = input_dev; 256 wm831x_ts->input_dev = input_dev;
257 INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work);
215 258
216 /* 259 /*
217 * If we have a direct IRQ use it, otherwise use the interrupt 260 * If we have a direct IRQ use it, otherwise use the interrupt
@@ -270,9 +313,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
270 wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, 313 wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
271 WM831X_TCH_RATE_MASK, 6); 314 WM831X_TCH_RATE_MASK, 6);
272 315
316 if (pdata && pdata->data_irqf)
317 irqf = pdata->data_irqf;
318 else
319 irqf = IRQF_TRIGGER_HIGH;
320
273 error = request_threaded_irq(wm831x_ts->data_irq, 321 error = request_threaded_irq(wm831x_ts->data_irq,
274 NULL, wm831x_ts_data_irq, 322 NULL, wm831x_ts_data_irq,
275 IRQF_ONESHOT, 323 irqf | IRQF_ONESHOT,
276 "Touchscreen data", wm831x_ts); 324 "Touchscreen data", wm831x_ts);
277 if (error) { 325 if (error) {
278 dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", 326 dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n",
@@ -281,9 +329,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
281 } 329 }
282 disable_irq(wm831x_ts->data_irq); 330 disable_irq(wm831x_ts->data_irq);
283 331
332 if (pdata && pdata->pd_irqf)
333 irqf = pdata->pd_irqf;
334 else
335 irqf = IRQF_TRIGGER_HIGH;
336
284 error = request_threaded_irq(wm831x_ts->pd_irq, 337 error = request_threaded_irq(wm831x_ts->pd_irq,
285 NULL, wm831x_ts_pen_down_irq, 338 NULL, wm831x_ts_pen_down_irq,
286 IRQF_ONESHOT, 339 irqf | IRQF_ONESHOT,
287 "Touchscreen pen down", wm831x_ts); 340 "Touchscreen pen down", wm831x_ts);
288 if (error) { 341 if (error) {
289 dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", 342 dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n",
diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h
index afe4db49402d..632d1567a1b6 100644
--- a/include/linux/mfd/wm831x/pdata.h
+++ b/include/linux/mfd/wm831x/pdata.h
@@ -81,7 +81,9 @@ struct wm831x_touch_pdata {
81 int rpu; /** Pen down sensitivity resistor divider */ 81 int rpu; /** Pen down sensitivity resistor divider */
82 int pressure; /** Report pressure (boolean) */ 82 int pressure; /** Report pressure (boolean) */
83 unsigned int data_irq; /** Touch data ready IRQ */ 83 unsigned int data_irq; /** Touch data ready IRQ */
84 int data_irqf; /** IRQ flags for data ready IRQ */
84 unsigned int pd_irq; /** Touch pendown detect IRQ */ 85 unsigned int pd_irq; /** Touch pendown detect IRQ */
86 int pd_irqf; /** IRQ flags for pen down IRQ */
85}; 87};
86 88
87enum wm831x_watchdog_action { 89enum wm831x_watchdog_action {