diff options
| -rw-r--r-- | drivers/input/touchscreen/wm831x-ts.c | 75 | ||||
| -rw-r--r-- | include/linux/mfd/wm831x/pdata.h | 2 |
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 | ||
| 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,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 | ||
| 194 | static __devinit int wm831x_ts_probe(struct platform_device *pdev) | 236 | static __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 | ||
| 87 | enum wm831x_watchdog_action { | 89 | enum wm831x_watchdog_action { |
