diff options
author | Patil, Rachna <rachna@ti.com> | 2012-10-16 03:25:44 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-11-05 17:50:27 -0500 |
commit | 2b99bafab19145a72e2c557326fc4662a864a162 (patch) | |
tree | d70c833c0b64297439f5b44568754e4fcc592d49 /drivers/input/touchscreen/ti_am335x_tsc.c | |
parent | 01636eb970a029897b06fb96026941429212ddd9 (diff) |
input: TSC: ti_tsc: Convert TSC into a MFDevice
This patch converts touchscreen into a MFD client.
All the register definitions, clock initialization,
etc has been moved to MFD core driver.
Signed-off-by: Patil, Rachna <rachna@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/input/touchscreen/ti_am335x_tsc.c')
-rw-r--r-- | drivers/input/touchscreen/ti_am335x_tsc.c | 318 |
1 files changed, 97 insertions, 221 deletions
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 462950acb97b..7a18a8a15228 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
@@ -27,106 +27,15 @@ | |||
27 | #include <linux/input/ti_am335x_tsc.h> | 27 | #include <linux/input/ti_am335x_tsc.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | 29 | ||
30 | #define REG_RAWIRQSTATUS 0x024 | 30 | #include <linux/mfd/ti_am335x_tscadc.h> |
31 | #define REG_IRQSTATUS 0x028 | ||
32 | #define REG_IRQENABLE 0x02C | ||
33 | #define REG_IRQWAKEUP 0x034 | ||
34 | #define REG_CTRL 0x040 | ||
35 | #define REG_ADCFSM 0x044 | ||
36 | #define REG_CLKDIV 0x04C | ||
37 | #define REG_SE 0x054 | ||
38 | #define REG_IDLECONFIG 0x058 | ||
39 | #define REG_CHARGECONFIG 0x05C | ||
40 | #define REG_CHARGEDELAY 0x060 | ||
41 | #define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) | ||
42 | #define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) | ||
43 | #define REG_FIFO0CNT 0xE4 | ||
44 | #define REG_FIFO0THR 0xE8 | ||
45 | #define REG_FIFO1THR 0xF4 | ||
46 | #define REG_FIFO0 0x100 | ||
47 | #define REG_FIFO1 0x200 | ||
48 | |||
49 | /* Register Bitfields */ | ||
50 | #define IRQWKUP_ENB BIT(0) | ||
51 | |||
52 | /* Step Enable */ | ||
53 | #define STEPENB_MASK (0x1FFFF << 0) | ||
54 | #define STEPENB(val) (val << 0) | ||
55 | #define STPENB_STEPENB STEPENB(0x7FFF) | ||
56 | |||
57 | /* IRQ enable */ | ||
58 | #define IRQENB_FIFO0THRES BIT(2) | ||
59 | #define IRQENB_FIFO1THRES BIT(5) | ||
60 | #define IRQENB_PENUP BIT(9) | ||
61 | |||
62 | /* Step Configuration */ | ||
63 | #define STEPCONFIG_MODE_MASK (3 << 0) | ||
64 | #define STEPCONFIG_MODE(val) (val << 0) | ||
65 | #define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) | ||
66 | #define STEPCONFIG_AVG_MASK (7 << 2) | ||
67 | #define STEPCONFIG_AVG(val) (val << 2) | ||
68 | #define STEPCONFIG_AVG_16 STEPCONFIG_AVG(4) | ||
69 | #define STEPCONFIG_XPP BIT(5) | ||
70 | #define STEPCONFIG_XNN BIT(6) | ||
71 | #define STEPCONFIG_YPP BIT(7) | ||
72 | #define STEPCONFIG_YNN BIT(8) | ||
73 | #define STEPCONFIG_XNP BIT(9) | ||
74 | #define STEPCONFIG_YPN BIT(10) | ||
75 | #define STEPCONFIG_INM_MASK (0xF << 15) | ||
76 | #define STEPCONFIG_INM(val) (val << 15) | ||
77 | #define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) | ||
78 | #define STEPCONFIG_INP_MASK (0xF << 19) | ||
79 | #define STEPCONFIG_INP(val) (val << 19) | ||
80 | #define STEPCONFIG_INP_AN2 STEPCONFIG_INP(2) | ||
81 | #define STEPCONFIG_INP_AN3 STEPCONFIG_INP(3) | ||
82 | #define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) | ||
83 | #define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) | ||
84 | #define STEPCONFIG_FIFO1 BIT(26) | ||
85 | |||
86 | /* Delay register */ | ||
87 | #define STEPDELAY_OPEN_MASK (0x3FFFF << 0) | ||
88 | #define STEPDELAY_OPEN(val) (val << 0) | ||
89 | #define STEPCONFIG_OPENDLY STEPDELAY_OPEN(0x098) | ||
90 | |||
91 | /* Charge Config */ | ||
92 | #define STEPCHARGE_RFP_MASK (7 << 12) | ||
93 | #define STEPCHARGE_RFP(val) (val << 12) | ||
94 | #define STEPCHARGE_RFP_XPUL STEPCHARGE_RFP(1) | ||
95 | #define STEPCHARGE_INM_MASK (0xF << 15) | ||
96 | #define STEPCHARGE_INM(val) (val << 15) | ||
97 | #define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) | ||
98 | #define STEPCHARGE_INP_MASK (0xF << 19) | ||
99 | #define STEPCHARGE_INP(val) (val << 19) | ||
100 | #define STEPCHARGE_INP_AN1 STEPCHARGE_INP(1) | ||
101 | #define STEPCHARGE_RFM_MASK (3 << 23) | ||
102 | #define STEPCHARGE_RFM(val) (val << 23) | ||
103 | #define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) | ||
104 | |||
105 | /* Charge delay */ | ||
106 | #define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) | ||
107 | #define CHARGEDLY_OPEN(val) (val << 0) | ||
108 | #define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(1) | ||
109 | |||
110 | /* Control register */ | ||
111 | #define CNTRLREG_TSCSSENB BIT(0) | ||
112 | #define CNTRLREG_STEPID BIT(1) | ||
113 | #define CNTRLREG_STEPCONFIGWRT BIT(2) | ||
114 | #define CNTRLREG_AFE_CTRL_MASK (3 << 5) | ||
115 | #define CNTRLREG_AFE_CTRL(val) (val << 5) | ||
116 | #define CNTRLREG_4WIRE CNTRLREG_AFE_CTRL(1) | ||
117 | #define CNTRLREG_5WIRE CNTRLREG_AFE_CTRL(2) | ||
118 | #define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) | ||
119 | #define CNTRLREG_TSCENB BIT(7) | ||
120 | 31 | ||
121 | #define ADCFSM_STEPID 0x10 | 32 | #define ADCFSM_STEPID 0x10 |
122 | #define SEQ_SETTLE 275 | 33 | #define SEQ_SETTLE 275 |
123 | #define ADC_CLK 3000000 | ||
124 | #define MAX_12BIT ((1 << 12) - 1) | 34 | #define MAX_12BIT ((1 << 12) - 1) |
125 | 35 | ||
126 | struct titsc { | 36 | struct titsc { |
127 | struct input_dev *input; | 37 | struct input_dev *input; |
128 | struct clk *tsc_ick; | 38 | struct ti_tscadc_dev *mfd_tscadc; |
129 | void __iomem *tsc_base; | ||
130 | unsigned int irq; | 39 | unsigned int irq; |
131 | unsigned int wires; | 40 | unsigned int wires; |
132 | unsigned int x_plate_resistance; | 41 | unsigned int x_plate_resistance; |
@@ -136,13 +45,13 @@ struct titsc { | |||
136 | 45 | ||
137 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) | 46 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) |
138 | { | 47 | { |
139 | return readl(ts->tsc_base + reg); | 48 | return readl(ts->mfd_tscadc->tscadc_base + reg); |
140 | } | 49 | } |
141 | 50 | ||
142 | static void titsc_writel(struct titsc *tsc, unsigned int reg, | 51 | static void titsc_writel(struct titsc *tsc, unsigned int reg, |
143 | unsigned int val) | 52 | unsigned int val) |
144 | { | 53 | { |
145 | writel(val, tsc->tsc_base + reg); | 54 | writel(val, tsc->mfd_tscadc->tscadc_base + reg); |
146 | } | 55 | } |
147 | 56 | ||
148 | static void titsc_step_config(struct titsc *ts_dev) | 57 | static void titsc_step_config(struct titsc *ts_dev) |
@@ -219,17 +128,7 @@ static void titsc_step_config(struct titsc *ts_dev) | |||
219 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), | 128 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), |
220 | STEPCONFIG_OPENDLY); | 129 | STEPCONFIG_OPENDLY); |
221 | 130 | ||
222 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB); | 131 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); |
223 | } | ||
224 | |||
225 | static void titsc_idle_config(struct titsc *ts_config) | ||
226 | { | ||
227 | unsigned int idleconfig; | ||
228 | |||
229 | idleconfig = STEPCONFIG_YNN | | ||
230 | STEPCONFIG_INM_ADCREFM | | ||
231 | STEPCONFIG_YPN | STEPCONFIG_INP_ADCREFM; | ||
232 | titsc_writel(ts_config, REG_IDLECONFIG, idleconfig); | ||
233 | } | 132 | } |
234 | 133 | ||
235 | static void titsc_read_coordinates(struct titsc *ts_dev, | 134 | static void titsc_read_coordinates(struct titsc *ts_dev, |
@@ -239,7 +138,7 @@ static void titsc_read_coordinates(struct titsc *ts_dev, | |||
239 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | 138 | unsigned int prev_val_x = ~0, prev_val_y = ~0; |
240 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | 139 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; |
241 | unsigned int read, diff; | 140 | unsigned int read, diff; |
242 | unsigned int i; | 141 | unsigned int i, channel; |
243 | 142 | ||
244 | /* | 143 | /* |
245 | * Delta filter is used to remove large variations in sampled | 144 | * Delta filter is used to remove large variations in sampled |
@@ -250,21 +149,32 @@ static void titsc_read_coordinates(struct titsc *ts_dev, | |||
250 | * if true the value is reported to the sub system. | 149 | * if true the value is reported to the sub system. |
251 | */ | 150 | */ |
252 | for (i = 0; i < fifocount - 1; i++) { | 151 | for (i = 0; i < fifocount - 1; i++) { |
253 | read = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; | 152 | read = titsc_readl(ts_dev, REG_FIFO0); |
254 | diff = abs(read - prev_val_x); | 153 | channel = read & 0xf0000; |
255 | if (diff < prev_diff_x) { | 154 | channel = channel >> 0x10; |
256 | prev_diff_x = diff; | 155 | if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) { |
257 | *x = read; | 156 | read &= 0xfff; |
157 | diff = abs(read - prev_val_x); | ||
158 | if (diff < prev_diff_x) { | ||
159 | prev_diff_x = diff; | ||
160 | *x = read; | ||
161 | } | ||
162 | prev_val_x = read; | ||
258 | } | 163 | } |
259 | prev_val_x = read; | ||
260 | 164 | ||
261 | read = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; | 165 | read = titsc_readl(ts_dev, REG_FIFO1); |
262 | diff = abs(read - prev_val_y); | 166 | channel = read & 0xf0000; |
263 | if (diff < prev_diff_y) { | 167 | channel = channel >> 0x10; |
264 | prev_diff_y = diff; | 168 | if ((channel >= ts_dev->steps_to_configure) && |
265 | *y = read; | 169 | (channel < (2 * ts_dev->steps_to_configure - 1))) { |
170 | read &= 0xfff; | ||
171 | diff = abs(read - prev_val_y); | ||
172 | if (diff < prev_diff_y) { | ||
173 | prev_diff_y = diff; | ||
174 | *y = read; | ||
175 | } | ||
176 | prev_val_y = read; | ||
266 | } | 177 | } |
267 | prev_val_y = read; | ||
268 | } | 178 | } |
269 | } | 179 | } |
270 | 180 | ||
@@ -276,6 +186,8 @@ static irqreturn_t titsc_irq(int irq, void *dev) | |||
276 | unsigned int x = 0, y = 0; | 186 | unsigned int x = 0, y = 0; |
277 | unsigned int z1, z2, z; | 187 | unsigned int z1, z2, z; |
278 | unsigned int fsm; | 188 | unsigned int fsm; |
189 | unsigned int fifo1count, fifo0count; | ||
190 | int i; | ||
279 | 191 | ||
280 | status = titsc_readl(ts_dev, REG_IRQSTATUS); | 192 | status = titsc_readl(ts_dev, REG_IRQSTATUS); |
281 | if (status & IRQENB_FIFO0THRES) { | 193 | if (status & IRQENB_FIFO0THRES) { |
@@ -284,6 +196,14 @@ static irqreturn_t titsc_irq(int irq, void *dev) | |||
284 | z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; | 196 | z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; |
285 | z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; | 197 | z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; |
286 | 198 | ||
199 | fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT); | ||
200 | for (i = 0; i < fifo1count; i++) | ||
201 | titsc_readl(ts_dev, REG_FIFO1); | ||
202 | |||
203 | fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT); | ||
204 | for (i = 0; i < fifo0count; i++) | ||
205 | titsc_readl(ts_dev, REG_FIFO0); | ||
206 | |||
287 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | 207 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { |
288 | /* | 208 | /* |
289 | * Calculate pressure using formula | 209 | * Calculate pressure using formula |
@@ -330,7 +250,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) | |||
330 | 250 | ||
331 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); | 251 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); |
332 | 252 | ||
333 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB); | 253 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); |
334 | return IRQ_HANDLED; | 254 | return IRQ_HANDLED; |
335 | } | 255 | } |
336 | 256 | ||
@@ -340,28 +260,16 @@ static irqreturn_t titsc_irq(int irq, void *dev) | |||
340 | 260 | ||
341 | static int __devinit titsc_probe(struct platform_device *pdev) | 261 | static int __devinit titsc_probe(struct platform_device *pdev) |
342 | { | 262 | { |
343 | const struct tsc_data *pdata = pdev->dev.platform_data; | ||
344 | struct resource *res; | ||
345 | struct titsc *ts_dev; | 263 | struct titsc *ts_dev; |
346 | struct input_dev *input_dev; | 264 | struct input_dev *input_dev; |
347 | struct clk *clk; | 265 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; |
266 | struct mfd_tscadc_board *pdata; | ||
348 | int err; | 267 | int err; |
349 | int clk_value, ctrl, irq; | ||
350 | 268 | ||
351 | if (!pdata) { | 269 | pdata = tscadc_dev->dev->platform_data; |
352 | dev_err(&pdev->dev, "missing platform data.\n"); | ||
353 | return -EINVAL; | ||
354 | } | ||
355 | |||
356 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
357 | if (!res) { | ||
358 | dev_err(&pdev->dev, "no memory resource defined.\n"); | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | 270 | ||
362 | irq = platform_get_irq(pdev, 0); | 271 | if (!pdata) { |
363 | if (irq < 0) { | 272 | dev_err(&pdev->dev, "Could not find platform data\n"); |
364 | dev_err(&pdev->dev, "no irq ID is specified.\n"); | ||
365 | return -EINVAL; | 273 | return -EINVAL; |
366 | } | 274 | } |
367 | 275 | ||
@@ -374,85 +282,26 @@ static int __devinit titsc_probe(struct platform_device *pdev) | |||
374 | goto err_free_mem; | 282 | goto err_free_mem; |
375 | } | 283 | } |
376 | 284 | ||
285 | tscadc_dev->tsc = ts_dev; | ||
286 | ts_dev->mfd_tscadc = tscadc_dev; | ||
377 | ts_dev->input = input_dev; | 287 | ts_dev->input = input_dev; |
378 | ts_dev->irq = irq; | 288 | ts_dev->irq = tscadc_dev->irq; |
379 | ts_dev->wires = pdata->wires; | 289 | ts_dev->wires = pdata->tsc_init->wires; |
380 | ts_dev->x_plate_resistance = pdata->x_plate_resistance; | 290 | ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance; |
381 | ts_dev->steps_to_configure = pdata->steps_to_configure; | 291 | ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure; |
382 | |||
383 | res = request_mem_region(res->start, resource_size(res), pdev->name); | ||
384 | if (!res) { | ||
385 | dev_err(&pdev->dev, "failed to reserve registers.\n"); | ||
386 | err = -EBUSY; | ||
387 | goto err_free_mem; | ||
388 | } | ||
389 | |||
390 | ts_dev->tsc_base = ioremap(res->start, resource_size(res)); | ||
391 | if (!ts_dev->tsc_base) { | ||
392 | dev_err(&pdev->dev, "failed to map registers.\n"); | ||
393 | err = -ENOMEM; | ||
394 | goto err_release_mem_region; | ||
395 | } | ||
396 | 292 | ||
397 | err = request_irq(ts_dev->irq, titsc_irq, | 293 | err = request_irq(ts_dev->irq, titsc_irq, |
398 | 0, pdev->dev.driver->name, ts_dev); | 294 | 0, pdev->dev.driver->name, ts_dev); |
399 | if (err) { | 295 | if (err) { |
400 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | 296 | dev_err(&pdev->dev, "failed to allocate irq.\n"); |
401 | goto err_unmap_regs; | 297 | goto err_free_mem; |
402 | } | ||
403 | |||
404 | ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); | ||
405 | if (IS_ERR(ts_dev->tsc_ick)) { | ||
406 | dev_err(&pdev->dev, "failed to get TSC ick\n"); | ||
407 | goto err_free_irq; | ||
408 | } | ||
409 | clk_enable(ts_dev->tsc_ick); | ||
410 | |||
411 | clk = clk_get(&pdev->dev, "adc_tsc_fck"); | ||
412 | if (IS_ERR(clk)) { | ||
413 | dev_err(&pdev->dev, "failed to get TSC fck\n"); | ||
414 | err = PTR_ERR(clk); | ||
415 | goto err_disable_clk; | ||
416 | } | ||
417 | |||
418 | clk_value = clk_get_rate(clk) / ADC_CLK; | ||
419 | clk_put(clk); | ||
420 | |||
421 | if (clk_value < 7) { | ||
422 | dev_err(&pdev->dev, "clock input less than min clock requirement\n"); | ||
423 | goto err_disable_clk; | ||
424 | } | ||
425 | /* CLKDIV needs to be configured to the value minus 1 */ | ||
426 | titsc_writel(ts_dev, REG_CLKDIV, clk_value - 1); | ||
427 | |||
428 | /* Enable wake-up of the SoC using touchscreen */ | ||
429 | titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
430 | |||
431 | ctrl = CNTRLREG_STEPCONFIGWRT | | ||
432 | CNTRLREG_TSCENB | | ||
433 | CNTRLREG_STEPID; | ||
434 | switch (ts_dev->wires) { | ||
435 | case 4: | ||
436 | ctrl |= CNTRLREG_4WIRE; | ||
437 | break; | ||
438 | case 5: | ||
439 | ctrl |= CNTRLREG_5WIRE; | ||
440 | break; | ||
441 | case 8: | ||
442 | ctrl |= CNTRLREG_8WIRE; | ||
443 | break; | ||
444 | } | 298 | } |
445 | titsc_writel(ts_dev, REG_CTRL, ctrl); | ||
446 | 299 | ||
447 | titsc_idle_config(ts_dev); | ||
448 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); | 300 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); |
449 | titsc_step_config(ts_dev); | 301 | titsc_step_config(ts_dev); |
450 | titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); | 302 | titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); |
451 | 303 | ||
452 | ctrl |= CNTRLREG_TSCSSENB; | 304 | input_dev->name = "ti-tsc"; |
453 | titsc_writel(ts_dev, REG_CTRL, ctrl); | ||
454 | |||
455 | input_dev->name = "ti-tsc-adc"; | ||
456 | input_dev->dev.parent = &pdev->dev; | 305 | input_dev->dev.parent = &pdev->dev; |
457 | 306 | ||
458 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 307 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
@@ -465,20 +314,13 @@ static int __devinit titsc_probe(struct platform_device *pdev) | |||
465 | /* register to the input system */ | 314 | /* register to the input system */ |
466 | err = input_register_device(input_dev); | 315 | err = input_register_device(input_dev); |
467 | if (err) | 316 | if (err) |
468 | goto err_disable_clk; | 317 | goto err_free_irq; |
469 | 318 | ||
470 | platform_set_drvdata(pdev, ts_dev); | 319 | platform_set_drvdata(pdev, ts_dev); |
471 | return 0; | 320 | return 0; |
472 | 321 | ||
473 | err_disable_clk: | ||
474 | clk_disable(ts_dev->tsc_ick); | ||
475 | clk_put(ts_dev->tsc_ick); | ||
476 | err_free_irq: | 322 | err_free_irq: |
477 | free_irq(ts_dev->irq, ts_dev); | 323 | free_irq(ts_dev->irq, ts_dev); |
478 | err_unmap_regs: | ||
479 | iounmap(ts_dev->tsc_base); | ||
480 | err_release_mem_region: | ||
481 | release_mem_region(res->start, resource_size(res)); | ||
482 | err_free_mem: | 324 | err_free_mem: |
483 | input_free_device(input_dev); | 325 | input_free_device(input_dev); |
484 | kfree(ts_dev); | 326 | kfree(ts_dev); |
@@ -487,32 +329,66 @@ err_free_mem: | |||
487 | 329 | ||
488 | static int __devexit titsc_remove(struct platform_device *pdev) | 330 | static int __devexit titsc_remove(struct platform_device *pdev) |
489 | { | 331 | { |
490 | struct titsc *ts_dev = platform_get_drvdata(pdev); | 332 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; |
491 | struct resource *res; | 333 | struct titsc *ts_dev = tscadc_dev->tsc; |
492 | 334 | ||
493 | free_irq(ts_dev->irq, ts_dev); | 335 | free_irq(ts_dev->irq, ts_dev); |
494 | 336 | ||
495 | input_unregister_device(ts_dev->input); | 337 | input_unregister_device(ts_dev->input); |
496 | 338 | ||
497 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 339 | platform_set_drvdata(pdev, NULL); |
498 | iounmap(ts_dev->tsc_base); | 340 | kfree(ts_dev); |
499 | release_mem_region(res->start, resource_size(res)); | 341 | return 0; |
342 | } | ||
500 | 343 | ||
501 | clk_disable(ts_dev->tsc_ick); | 344 | #ifdef CONFIG_PM |
502 | clk_put(ts_dev->tsc_ick); | 345 | static int titsc_suspend(struct device *dev) |
346 | { | ||
347 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
348 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
349 | unsigned int idle; | ||
350 | |||
351 | if (device_may_wakeup(tscadc_dev->dev)) { | ||
352 | idle = titsc_readl(ts_dev, REG_IRQENABLE); | ||
353 | titsc_writel(ts_dev, REG_IRQENABLE, | ||
354 | (idle | IRQENB_HW_PEN)); | ||
355 | titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
356 | } | ||
357 | return 0; | ||
358 | } | ||
503 | 359 | ||
504 | kfree(ts_dev); | 360 | static int titsc_resume(struct device *dev) |
361 | { | ||
362 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
363 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
505 | 364 | ||
506 | platform_set_drvdata(pdev, NULL); | 365 | if (device_may_wakeup(tscadc_dev->dev)) { |
366 | titsc_writel(ts_dev, REG_IRQWAKEUP, | ||
367 | 0x00); | ||
368 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); | ||
369 | } | ||
370 | titsc_step_config(ts_dev); | ||
371 | titsc_writel(ts_dev, REG_FIFO0THR, | ||
372 | ts_dev->steps_to_configure); | ||
507 | return 0; | 373 | return 0; |
508 | } | 374 | } |
509 | 375 | ||
376 | static const struct dev_pm_ops titsc_pm_ops = { | ||
377 | .suspend = titsc_suspend, | ||
378 | .resume = titsc_resume, | ||
379 | }; | ||
380 | #define TITSC_PM_OPS (&titsc_pm_ops) | ||
381 | #else | ||
382 | #define TITSC_PM_OPS NULL | ||
383 | #endif | ||
384 | |||
510 | static struct platform_driver ti_tsc_driver = { | 385 | static struct platform_driver ti_tsc_driver = { |
511 | .probe = titsc_probe, | 386 | .probe = titsc_probe, |
512 | .remove = __devexit_p(titsc_remove), | 387 | .remove = __devexit_p(titsc_remove), |
513 | .driver = { | 388 | .driver = { |
514 | .name = "tsc", | 389 | .name = "tsc", |
515 | .owner = THIS_MODULE, | 390 | .owner = THIS_MODULE, |
391 | .pm = TITSC_PM_OPS, | ||
516 | }, | 392 | }, |
517 | }; | 393 | }; |
518 | module_platform_driver(ti_tsc_driver); | 394 | module_platform_driver(ti_tsc_driver); |