diff options
-rw-r--r-- | drivers/input/touchscreen/wm831x-ts.c | 54 |
1 files changed, 49 insertions, 5 deletions
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6ae054f8e0aa..b9373012b3e6 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 | ||
74 | static 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 | |||
73 | static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) | 88 | static 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,8 @@ 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); | ||
131 | } | 151 | } |
132 | 152 | ||
133 | input_sync(wm831x_ts->input_dev); | 153 | input_sync(wm831x_ts->input_dev); |
@@ -141,6 +161,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) | |||
141 | struct wm831x *wm831x = wm831x_ts->wm831x; | 161 | struct wm831x *wm831x = wm831x_ts->wm831x; |
142 | int ena = 0; | 162 | int ena = 0; |
143 | 163 | ||
164 | if (wm831x_ts->pen_down) | ||
165 | return IRQ_HANDLED; | ||
166 | |||
167 | disable_irq_nosync(wm831x_ts->pd_irq); | ||
168 | |||
144 | /* Start collecting data */ | 169 | /* Start collecting data */ |
145 | if (wm831x_ts->pressure) | 170 | if (wm831x_ts->pressure) |
146 | ena |= WM831X_TCH_Z_ENA; | 171 | ena |= WM831X_TCH_Z_ENA; |
@@ -156,7 +181,10 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) | |||
156 | WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); | 181 | WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); |
157 | 182 | ||
158 | wm831x_ts->pen_down = true; | 183 | wm831x_ts->pen_down = true; |
159 | enable_irq(wm831x_ts->data_irq); | 184 | |
185 | /* Switch from pen down to data */ | ||
186 | dev_dbg(wm831x->dev, "IRQ PD->DATA\n"); | ||
187 | schedule_work(&wm831x_ts->pd_data_work); | ||
160 | 188 | ||
161 | return IRQ_HANDLED; | 189 | return IRQ_HANDLED; |
162 | } | 190 | } |
@@ -182,13 +210,28 @@ static void wm831x_ts_input_close(struct input_dev *idev) | |||
182 | struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); | 210 | struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); |
183 | struct wm831x *wm831x = wm831x_ts->wm831x; | 211 | struct wm831x *wm831x = wm831x_ts->wm831x; |
184 | 212 | ||
213 | /* Shut the controller down, disabling all other functionality too */ | ||
185 | wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, | 214 | wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, |
186 | WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | | 215 | WM831X_TCH_ENA | WM831X_TCH_X_ENA | |
187 | WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | | 216 | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); |
188 | WM831X_TCH_Z_ENA, 0); | ||
189 | 217 | ||
190 | if (wm831x_ts->pen_down) | 218 | /* Make sure any pending IRQs are done, the above will prevent |
219 | * new ones firing. | ||
220 | */ | ||
221 | synchronize_irq(wm831x_ts->data_irq); | ||
222 | synchronize_irq(wm831x_ts->pd_irq); | ||
223 | |||
224 | /* Make sure the IRQ completion work is quiesced */ | ||
225 | flush_work_sync(&wm831x_ts->pd_data_work); | ||
226 | |||
227 | /* If we ended up with the pen down then make sure we revert back | ||
228 | * to pen detection state for the next time we start up. | ||
229 | */ | ||
230 | if (wm831x_ts->pen_down) { | ||
191 | disable_irq(wm831x_ts->data_irq); | 231 | disable_irq(wm831x_ts->data_irq); |
232 | enable_irq(wm831x_ts->pd_irq); | ||
233 | wm831x_ts->pen_down = false; | ||
234 | } | ||
192 | } | 235 | } |
193 | 236 | ||
194 | static __devinit int wm831x_ts_probe(struct platform_device *pdev) | 237 | static __devinit int wm831x_ts_probe(struct platform_device *pdev) |
@@ -212,6 +255,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) | |||
212 | 255 | ||
213 | wm831x_ts->wm831x = wm831x; | 256 | wm831x_ts->wm831x = wm831x; |
214 | wm831x_ts->input_dev = input_dev; | 257 | wm831x_ts->input_dev = input_dev; |
258 | INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work); | ||
215 | 259 | ||
216 | /* | 260 | /* |
217 | * If we have a direct IRQ use it, otherwise use the interrupt | 261 | * If we have a direct IRQ use it, otherwise use the interrupt |