diff options
Diffstat (limited to 'drivers/input/touchscreen')
24 files changed, 3163 insertions, 243 deletions
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index c7068942ebe8..f7de14a268bf 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c | |||
@@ -237,7 +237,7 @@ static int pm860x_touch_probe(struct platform_device *pdev) | |||
237 | touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); | 237 | touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); |
238 | if (touch == NULL) | 238 | if (touch == NULL) |
239 | return -ENOMEM; | 239 | return -ENOMEM; |
240 | dev_set_drvdata(&pdev->dev, touch); | 240 | platform_set_drvdata(pdev, touch); |
241 | 241 | ||
242 | touch->idev = input_allocate_device(); | 242 | touch->idev = input_allocate_device(); |
243 | if (touch->idev == NULL) { | 243 | if (touch->idev == NULL) { |
@@ -299,7 +299,6 @@ static int pm860x_touch_remove(struct platform_device *pdev) | |||
299 | 299 | ||
300 | input_unregister_device(touch->idev); | 300 | input_unregister_device(touch->idev); |
301 | free_irq(touch->irq, touch); | 301 | free_irq(touch->irq, touch); |
302 | platform_set_drvdata(pdev, NULL); | ||
303 | kfree(touch); | 302 | kfree(touch); |
304 | return 0; | 303 | return 0; |
305 | } | 304 | } |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f9a5fd89bc02..3b9758b5f4d7 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -167,6 +167,36 @@ config TOUCHSCREEN_CYTTSP_SPI | |||
167 | To compile this driver as a module, choose M here: the | 167 | To compile this driver as a module, choose M here: the |
168 | module will be called cyttsp_spi. | 168 | module will be called cyttsp_spi. |
169 | 169 | ||
170 | config TOUCHSCREEN_CYTTSP4_CORE | ||
171 | tristate "Cypress TrueTouch Gen4 Touchscreen Driver" | ||
172 | help | ||
173 | Core driver for Cypress TrueTouch(tm) Standard Product | ||
174 | Generation4 touchscreen controllers. | ||
175 | |||
176 | Say Y here if you have a Cypress Gen4 touchscreen. | ||
177 | |||
178 | If unsure, say N. | ||
179 | |||
180 | To compile this driver as a module, choose M here. | ||
181 | |||
182 | config TOUCHSCREEN_CYTTSP4_I2C | ||
183 | tristate "support I2C bus connection" | ||
184 | depends on TOUCHSCREEN_CYTTSP4_CORE && I2C | ||
185 | help | ||
186 | Say Y here if the touchscreen is connected via I2C bus. | ||
187 | |||
188 | To compile this driver as a module, choose M here: the | ||
189 | module will be called cyttsp4_i2c. | ||
190 | |||
191 | config TOUCHSCREEN_CYTTSP4_SPI | ||
192 | tristate "support SPI bus connection" | ||
193 | depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER | ||
194 | help | ||
195 | Say Y here if the touchscreen is connected via SPI bus. | ||
196 | |||
197 | To compile this driver as a module, choose M here: the | ||
198 | module will be called cyttsp4_spi. | ||
199 | |||
170 | config TOUCHSCREEN_DA9034 | 200 | config TOUCHSCREEN_DA9034 |
171 | tristate "Touchscreen support for Dialog Semiconductor DA9034" | 201 | tristate "Touchscreen support for Dialog Semiconductor DA9034" |
172 | depends on PMIC_DA903X | 202 | depends on PMIC_DA903X |
@@ -879,6 +909,7 @@ config TOUCHSCREEN_STMPE | |||
879 | config TOUCHSCREEN_TPS6507X | 909 | config TOUCHSCREEN_TPS6507X |
880 | tristate "TPS6507x based touchscreens" | 910 | tristate "TPS6507x based touchscreens" |
881 | depends on I2C | 911 | depends on I2C |
912 | select INPUT_POLLDEV | ||
882 | help | 913 | help |
883 | Say Y here if you have a TPS6507x based touchscreen | 914 | Say Y here if you have a TPS6507x based touchscreen |
884 | controller. | 915 | controller. |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 6bfbeab67c9f..f5216c1bf53e 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -18,8 +18,11 @@ obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o | |||
18 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o | 18 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o |
19 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o | 19 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o |
20 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o | 20 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o |
21 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o | 21 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o |
22 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o | 22 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o |
23 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o | ||
24 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o | ||
25 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o | ||
23 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o | 26 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o |
24 | obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o | 27 | obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o |
25 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o | 28 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o |
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 2c1e46b7e45b..268a35e55d7f 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c | |||
@@ -372,7 +372,6 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev) | |||
372 | err_irq: | 372 | err_irq: |
373 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); | 373 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); |
374 | err: | 374 | err: |
375 | platform_set_drvdata(pdev, NULL); | ||
376 | kfree(atmel_wm97xx); | 375 | kfree(atmel_wm97xx); |
377 | return ret; | 376 | return ret; |
378 | } | 377 | } |
@@ -386,7 +385,6 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev) | |||
386 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); | 385 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); |
387 | del_timer_sync(&atmel_wm97xx->pen_timer); | 386 | del_timer_sync(&atmel_wm97xx->pen_timer); |
388 | wm97xx_unregister_mach_ops(wm); | 387 | wm97xx_unregister_mach_ops(wm); |
389 | platform_set_drvdata(pdev, NULL); | ||
390 | kfree(atmel_wm97xx); | 388 | kfree(atmel_wm97xx); |
391 | 389 | ||
392 | return 0; | 390 | return 0; |
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 95f6785a94b0..bddabc595077 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c | |||
@@ -183,10 +183,13 @@ static int atmel_tsadcc_probe(struct platform_device *pdev) | |||
183 | struct input_dev *input_dev; | 183 | struct input_dev *input_dev; |
184 | struct resource *res; | 184 | struct resource *res; |
185 | struct at91_tsadcc_data *pdata = pdev->dev.platform_data; | 185 | struct at91_tsadcc_data *pdata = pdev->dev.platform_data; |
186 | int err = 0; | 186 | int err; |
187 | unsigned int prsc; | 187 | unsigned int prsc; |
188 | unsigned int reg; | 188 | unsigned int reg; |
189 | 189 | ||
190 | if (!pdata) | ||
191 | return -EINVAL; | ||
192 | |||
190 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 193 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
191 | if (!res) { | 194 | if (!res) { |
192 | dev_err(&pdev->dev, "no mmio resource defined.\n"); | 195 | dev_err(&pdev->dev, "no mmio resource defined.\n"); |
@@ -265,9 +268,6 @@ static int atmel_tsadcc_probe(struct platform_device *pdev) | |||
265 | prsc = clk_get_rate(ts_dev->clk); | 268 | prsc = clk_get_rate(ts_dev->clk); |
266 | dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); | 269 | dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); |
267 | 270 | ||
268 | if (!pdata) | ||
269 | goto err_fail; | ||
270 | |||
271 | if (!pdata->adc_clock) | 271 | if (!pdata->adc_clock) |
272 | pdata->adc_clock = ADC_DEFAULT_CLOCK; | 272 | pdata->adc_clock = ADC_DEFAULT_CLOCK; |
273 | 273 | ||
@@ -325,7 +325,7 @@ err_free_mem: | |||
325 | 325 | ||
326 | static int atmel_tsadcc_remove(struct platform_device *pdev) | 326 | static int atmel_tsadcc_remove(struct platform_device *pdev) |
327 | { | 327 | { |
328 | struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); | 328 | struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev); |
329 | struct resource *res; | 329 | struct resource *res; |
330 | 330 | ||
331 | free_irq(ts_dev->irq, ts_dev); | 331 | free_irq(ts_dev->irq, ts_dev); |
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c new file mode 100644 index 000000000000..edcf7993034b --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_core.c | |||
@@ -0,0 +1,2166 @@ | |||
1 | /* | ||
2 | * cyttsp4_core.c | ||
3 | * Cypress TrueTouch(TM) Standard Product V4 Core driver module. | ||
4 | * For use with Cypress Txx4xx parts. | ||
5 | * Supported parts include: | ||
6 | * TMA4XX | ||
7 | * TMA1036 | ||
8 | * | ||
9 | * Copyright (C) 2012 Cypress Semiconductor | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * version 2, and only version 2, as published by the | ||
14 | * Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "cyttsp4_core.h" | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <linux/input/mt.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/pm_runtime.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/slab.h> | ||
33 | |||
34 | /* Timeout in ms. */ | ||
35 | #define CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT 500 | ||
36 | #define CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT 5000 | ||
37 | #define CY_CORE_MODE_CHANGE_TIMEOUT 1000 | ||
38 | #define CY_CORE_RESET_AND_WAIT_TIMEOUT 500 | ||
39 | #define CY_CORE_WAKEUP_TIMEOUT 500 | ||
40 | |||
41 | #define CY_CORE_STARTUP_RETRY_COUNT 3 | ||
42 | |||
43 | static const u8 ldr_exit[] = { | ||
44 | 0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17 | ||
45 | }; | ||
46 | |||
47 | static const u8 ldr_err_app[] = { | ||
48 | 0x01, 0x02, 0x00, 0x00, 0x55, 0xDD, 0x17 | ||
49 | }; | ||
50 | |||
51 | static inline size_t merge_bytes(u8 high, u8 low) | ||
52 | { | ||
53 | return (high << 8) + low; | ||
54 | } | ||
55 | |||
56 | #ifdef VERBOSE_DEBUG | ||
57 | static void cyttsp4_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size, | ||
58 | const char *data_name) | ||
59 | { | ||
60 | int i, k; | ||
61 | const char fmt[] = "%02X "; | ||
62 | int max; | ||
63 | |||
64 | if (!size) | ||
65 | return; | ||
66 | |||
67 | max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED); | ||
68 | |||
69 | pr_buf[0] = 0; | ||
70 | for (i = k = 0; i < size && k < max; i++, k += 3) | ||
71 | scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]); | ||
72 | |||
73 | dev_vdbg(dev, "%s: %s[0..%d]=%s%s\n", __func__, data_name, size - 1, | ||
74 | pr_buf, size <= max ? "" : CY_PR_TRUNCATED); | ||
75 | } | ||
76 | #else | ||
77 | #define cyttsp4_pr_buf(dev, pr_buf, dptr, size, data_name) do { } while (0) | ||
78 | #endif | ||
79 | |||
80 | static int cyttsp4_load_status_regs(struct cyttsp4 *cd) | ||
81 | { | ||
82 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
83 | struct device *dev = cd->dev; | ||
84 | int rc; | ||
85 | |||
86 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, si->si_ofs.mode_size, | ||
87 | si->xy_mode); | ||
88 | if (rc < 0) | ||
89 | dev_err(dev, "%s: fail read mode regs r=%d\n", | ||
90 | __func__, rc); | ||
91 | else | ||
92 | cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_mode, | ||
93 | si->si_ofs.mode_size, "xy_mode"); | ||
94 | |||
95 | return rc; | ||
96 | } | ||
97 | |||
98 | static int cyttsp4_handshake(struct cyttsp4 *cd, u8 mode) | ||
99 | { | ||
100 | u8 cmd = mode ^ CY_HST_TOGGLE; | ||
101 | int rc; | ||
102 | |||
103 | /* | ||
104 | * Mode change issued, handshaking now will cause endless mode change | ||
105 | * requests, for sync mode modechange will do same with handshake | ||
106 | * */ | ||
107 | if (mode & CY_HST_MODE_CHANGE) | ||
108 | return 0; | ||
109 | |||
110 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd); | ||
111 | if (rc < 0) | ||
112 | dev_err(cd->dev, "%s: bus write fail on handshake (ret=%d)\n", | ||
113 | __func__, rc); | ||
114 | |||
115 | return rc; | ||
116 | } | ||
117 | |||
118 | static int cyttsp4_hw_soft_reset(struct cyttsp4 *cd) | ||
119 | { | ||
120 | u8 cmd = CY_HST_RESET; | ||
121 | int rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd); | ||
122 | if (rc < 0) { | ||
123 | dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n", | ||
124 | __func__); | ||
125 | return rc; | ||
126 | } | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int cyttsp4_hw_hard_reset(struct cyttsp4 *cd) | ||
131 | { | ||
132 | if (cd->cpdata->xres) { | ||
133 | cd->cpdata->xres(cd->cpdata, cd->dev); | ||
134 | dev_dbg(cd->dev, "%s: execute HARD reset\n", __func__); | ||
135 | return 0; | ||
136 | } | ||
137 | dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__); | ||
138 | return -ENOSYS; | ||
139 | } | ||
140 | |||
141 | static int cyttsp4_hw_reset(struct cyttsp4 *cd) | ||
142 | { | ||
143 | int rc = cyttsp4_hw_hard_reset(cd); | ||
144 | if (rc == -ENOSYS) | ||
145 | rc = cyttsp4_hw_soft_reset(cd); | ||
146 | return rc; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Gets number of bits for a touch filed as parameter, | ||
151 | * sets maximum value for field which is used as bit mask | ||
152 | * and returns number of bytes required for that field | ||
153 | */ | ||
154 | static int cyttsp4_bits_2_bytes(unsigned int nbits, size_t *max) | ||
155 | { | ||
156 | *max = 1UL << nbits; | ||
157 | return (nbits + 7) / 8; | ||
158 | } | ||
159 | |||
160 | static int cyttsp4_si_data_offsets(struct cyttsp4 *cd) | ||
161 | { | ||
162 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
163 | int rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(si->si_data), | ||
164 | &si->si_data); | ||
165 | if (rc < 0) { | ||
166 | dev_err(cd->dev, "%s: fail read sysinfo data offsets r=%d\n", | ||
167 | __func__, rc); | ||
168 | return rc; | ||
169 | } | ||
170 | |||
171 | /* Print sysinfo data offsets */ | ||
172 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)&si->si_data, | ||
173 | sizeof(si->si_data), "sysinfo_data_offsets"); | ||
174 | |||
175 | /* convert sysinfo data offset bytes into integers */ | ||
176 | |||
177 | si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh, | ||
178 | si->si_data.map_szl); | ||
179 | si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh, | ||
180 | si->si_data.map_szl); | ||
181 | si->si_ofs.cydata_ofs = merge_bytes(si->si_data.cydata_ofsh, | ||
182 | si->si_data.cydata_ofsl); | ||
183 | si->si_ofs.test_ofs = merge_bytes(si->si_data.test_ofsh, | ||
184 | si->si_data.test_ofsl); | ||
185 | si->si_ofs.pcfg_ofs = merge_bytes(si->si_data.pcfg_ofsh, | ||
186 | si->si_data.pcfg_ofsl); | ||
187 | si->si_ofs.opcfg_ofs = merge_bytes(si->si_data.opcfg_ofsh, | ||
188 | si->si_data.opcfg_ofsl); | ||
189 | si->si_ofs.ddata_ofs = merge_bytes(si->si_data.ddata_ofsh, | ||
190 | si->si_data.ddata_ofsl); | ||
191 | si->si_ofs.mdata_ofs = merge_bytes(si->si_data.mdata_ofsh, | ||
192 | si->si_data.mdata_ofsl); | ||
193 | return rc; | ||
194 | } | ||
195 | |||
196 | static int cyttsp4_si_get_cydata(struct cyttsp4 *cd) | ||
197 | { | ||
198 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
199 | int read_offset; | ||
200 | int mfgid_sz, calc_mfgid_sz; | ||
201 | void *p; | ||
202 | int rc; | ||
203 | |||
204 | si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs; | ||
205 | dev_dbg(cd->dev, "%s: cydata size: %Zd\n", __func__, | ||
206 | si->si_ofs.cydata_size); | ||
207 | |||
208 | p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL); | ||
209 | if (p == NULL) { | ||
210 | dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__); | ||
211 | return -ENOMEM; | ||
212 | } | ||
213 | si->si_ptrs.cydata = p; | ||
214 | |||
215 | read_offset = si->si_ofs.cydata_ofs; | ||
216 | |||
217 | /* Read the CYDA registers up to MFGID field */ | ||
218 | rc = cyttsp4_adap_read(cd, read_offset, | ||
219 | offsetof(struct cyttsp4_cydata, mfgid_sz) | ||
220 | + sizeof(si->si_ptrs.cydata->mfgid_sz), | ||
221 | si->si_ptrs.cydata); | ||
222 | if (rc < 0) { | ||
223 | dev_err(cd->dev, "%s: fail read cydata r=%d\n", | ||
224 | __func__, rc); | ||
225 | return rc; | ||
226 | } | ||
227 | |||
228 | /* Check MFGID size */ | ||
229 | mfgid_sz = si->si_ptrs.cydata->mfgid_sz; | ||
230 | calc_mfgid_sz = si->si_ofs.cydata_size - sizeof(struct cyttsp4_cydata); | ||
231 | if (mfgid_sz != calc_mfgid_sz) { | ||
232 | dev_err(cd->dev, "%s: mismatch in MFGID size, reported:%d calculated:%d\n", | ||
233 | __func__, mfgid_sz, calc_mfgid_sz); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | |||
237 | read_offset += offsetof(struct cyttsp4_cydata, mfgid_sz) | ||
238 | + sizeof(si->si_ptrs.cydata->mfgid_sz); | ||
239 | |||
240 | /* Read the CYDA registers for MFGID field */ | ||
241 | rc = cyttsp4_adap_read(cd, read_offset, si->si_ptrs.cydata->mfgid_sz, | ||
242 | si->si_ptrs.cydata->mfg_id); | ||
243 | if (rc < 0) { | ||
244 | dev_err(cd->dev, "%s: fail read cydata r=%d\n", | ||
245 | __func__, rc); | ||
246 | return rc; | ||
247 | } | ||
248 | |||
249 | read_offset += si->si_ptrs.cydata->mfgid_sz; | ||
250 | |||
251 | /* Read the rest of the CYDA registers */ | ||
252 | rc = cyttsp4_adap_read(cd, read_offset, | ||
253 | sizeof(struct cyttsp4_cydata) | ||
254 | - offsetof(struct cyttsp4_cydata, cyito_idh), | ||
255 | &si->si_ptrs.cydata->cyito_idh); | ||
256 | if (rc < 0) { | ||
257 | dev_err(cd->dev, "%s: fail read cydata r=%d\n", | ||
258 | __func__, rc); | ||
259 | return rc; | ||
260 | } | ||
261 | |||
262 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.cydata, | ||
263 | si->si_ofs.cydata_size, "sysinfo_cydata"); | ||
264 | return rc; | ||
265 | } | ||
266 | |||
267 | static int cyttsp4_si_get_test_data(struct cyttsp4 *cd) | ||
268 | { | ||
269 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
270 | void *p; | ||
271 | int rc; | ||
272 | |||
273 | si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs; | ||
274 | |||
275 | p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL); | ||
276 | if (p == NULL) { | ||
277 | dev_err(cd->dev, "%s: fail alloc test memory\n", __func__); | ||
278 | return -ENOMEM; | ||
279 | } | ||
280 | si->si_ptrs.test = p; | ||
281 | |||
282 | rc = cyttsp4_adap_read(cd, si->si_ofs.test_ofs, si->si_ofs.test_size, | ||
283 | si->si_ptrs.test); | ||
284 | if (rc < 0) { | ||
285 | dev_err(cd->dev, "%s: fail read test data r=%d\n", | ||
286 | __func__, rc); | ||
287 | return rc; | ||
288 | } | ||
289 | |||
290 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
291 | (u8 *)si->si_ptrs.test, si->si_ofs.test_size, | ||
292 | "sysinfo_test_data"); | ||
293 | if (si->si_ptrs.test->post_codel & | ||
294 | CY_POST_CODEL_WDG_RST) | ||
295 | dev_info(cd->dev, "%s: %s codel=%02X\n", | ||
296 | __func__, "Reset was a WATCHDOG RESET", | ||
297 | si->si_ptrs.test->post_codel); | ||
298 | |||
299 | if (!(si->si_ptrs.test->post_codel & | ||
300 | CY_POST_CODEL_CFG_DATA_CRC_FAIL)) | ||
301 | dev_info(cd->dev, "%s: %s codel=%02X\n", __func__, | ||
302 | "Config Data CRC FAIL", | ||
303 | si->si_ptrs.test->post_codel); | ||
304 | |||
305 | if (!(si->si_ptrs.test->post_codel & | ||
306 | CY_POST_CODEL_PANEL_TEST_FAIL)) | ||
307 | dev_info(cd->dev, "%s: %s codel=%02X\n", | ||
308 | __func__, "PANEL TEST FAIL", | ||
309 | si->si_ptrs.test->post_codel); | ||
310 | |||
311 | dev_info(cd->dev, "%s: SCANNING is %s codel=%02X\n", | ||
312 | __func__, si->si_ptrs.test->post_codel & 0x08 ? | ||
313 | "ENABLED" : "DISABLED", | ||
314 | si->si_ptrs.test->post_codel); | ||
315 | return rc; | ||
316 | } | ||
317 | |||
318 | static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd) | ||
319 | { | ||
320 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
321 | void *p; | ||
322 | int rc; | ||
323 | |||
324 | si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs; | ||
325 | |||
326 | p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL); | ||
327 | if (p == NULL) { | ||
328 | rc = -ENOMEM; | ||
329 | dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n", | ||
330 | __func__, rc); | ||
331 | return rc; | ||
332 | } | ||
333 | si->si_ptrs.pcfg = p; | ||
334 | |||
335 | rc = cyttsp4_adap_read(cd, si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size, | ||
336 | si->si_ptrs.pcfg); | ||
337 | if (rc < 0) { | ||
338 | dev_err(cd->dev, "%s: fail read pcfg data r=%d\n", | ||
339 | __func__, rc); | ||
340 | return rc; | ||
341 | } | ||
342 | |||
343 | si->si_ofs.max_x = merge_bytes((si->si_ptrs.pcfg->res_xh | ||
344 | & CY_PCFG_RESOLUTION_X_MASK), si->si_ptrs.pcfg->res_xl); | ||
345 | si->si_ofs.x_origin = !!(si->si_ptrs.pcfg->res_xh | ||
346 | & CY_PCFG_ORIGIN_X_MASK); | ||
347 | si->si_ofs.max_y = merge_bytes((si->si_ptrs.pcfg->res_yh | ||
348 | & CY_PCFG_RESOLUTION_Y_MASK), si->si_ptrs.pcfg->res_yl); | ||
349 | si->si_ofs.y_origin = !!(si->si_ptrs.pcfg->res_yh | ||
350 | & CY_PCFG_ORIGIN_Y_MASK); | ||
351 | si->si_ofs.max_p = merge_bytes(si->si_ptrs.pcfg->max_zh, | ||
352 | si->si_ptrs.pcfg->max_zl); | ||
353 | |||
354 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
355 | (u8 *)si->si_ptrs.pcfg, | ||
356 | si->si_ofs.pcfg_size, "sysinfo_pcfg_data"); | ||
357 | return rc; | ||
358 | } | ||
359 | |||
360 | static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd) | ||
361 | { | ||
362 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
363 | struct cyttsp4_tch_abs_params *tch; | ||
364 | struct cyttsp4_tch_rec_params *tch_old, *tch_new; | ||
365 | enum cyttsp4_tch_abs abs; | ||
366 | int i; | ||
367 | void *p; | ||
368 | int rc; | ||
369 | |||
370 | si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs; | ||
371 | |||
372 | p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL); | ||
373 | if (p == NULL) { | ||
374 | dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__); | ||
375 | rc = -ENOMEM; | ||
376 | goto cyttsp4_si_get_opcfg_data_exit; | ||
377 | } | ||
378 | si->si_ptrs.opcfg = p; | ||
379 | |||
380 | rc = cyttsp4_adap_read(cd, si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size, | ||
381 | si->si_ptrs.opcfg); | ||
382 | if (rc < 0) { | ||
383 | dev_err(cd->dev, "%s: fail read opcfg data r=%d\n", | ||
384 | __func__, rc); | ||
385 | goto cyttsp4_si_get_opcfg_data_exit; | ||
386 | } | ||
387 | si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs; | ||
388 | si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs; | ||
389 | si->si_ofs.rep_sz = (si->si_ptrs.opcfg->rep_szh * 256) + | ||
390 | si->si_ptrs.opcfg->rep_szl; | ||
391 | si->si_ofs.num_btns = si->si_ptrs.opcfg->num_btns; | ||
392 | si->si_ofs.num_btn_regs = (si->si_ofs.num_btns + | ||
393 | CY_NUM_BTN_PER_REG - 1) / CY_NUM_BTN_PER_REG; | ||
394 | si->si_ofs.tt_stat_ofs = si->si_ptrs.opcfg->tt_stat_ofs; | ||
395 | si->si_ofs.obj_cfg0 = si->si_ptrs.opcfg->obj_cfg0; | ||
396 | si->si_ofs.max_tchs = si->si_ptrs.opcfg->max_tchs & | ||
397 | CY_BYTE_OFS_MASK; | ||
398 | si->si_ofs.tch_rec_size = si->si_ptrs.opcfg->tch_rec_size & | ||
399 | CY_BYTE_OFS_MASK; | ||
400 | |||
401 | /* Get the old touch fields */ | ||
402 | for (abs = CY_TCH_X; abs < CY_NUM_TCH_FIELDS; abs++) { | ||
403 | tch = &si->si_ofs.tch_abs[abs]; | ||
404 | tch_old = &si->si_ptrs.opcfg->tch_rec_old[abs]; | ||
405 | |||
406 | tch->ofs = tch_old->loc & CY_BYTE_OFS_MASK; | ||
407 | tch->size = cyttsp4_bits_2_bytes(tch_old->size, | ||
408 | &tch->max); | ||
409 | tch->bofs = (tch_old->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT; | ||
410 | } | ||
411 | |||
412 | /* button fields */ | ||
413 | si->si_ofs.btn_rec_size = si->si_ptrs.opcfg->btn_rec_size; | ||
414 | si->si_ofs.btn_diff_ofs = si->si_ptrs.opcfg->btn_diff_ofs; | ||
415 | si->si_ofs.btn_diff_size = si->si_ptrs.opcfg->btn_diff_size; | ||
416 | |||
417 | if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) { | ||
418 | /* Get the extended touch fields */ | ||
419 | for (i = 0; i < CY_NUM_EXT_TCH_FIELDS; abs++, i++) { | ||
420 | tch = &si->si_ofs.tch_abs[abs]; | ||
421 | tch_new = &si->si_ptrs.opcfg->tch_rec_new[i]; | ||
422 | |||
423 | tch->ofs = tch_new->loc & CY_BYTE_OFS_MASK; | ||
424 | tch->size = cyttsp4_bits_2_bytes(tch_new->size, | ||
425 | &tch->max); | ||
426 | tch->bofs = (tch_new->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | for (abs = 0; abs < CY_TCH_NUM_ABS; abs++) { | ||
431 | dev_dbg(cd->dev, "%s: tch_rec_%s\n", __func__, | ||
432 | cyttsp4_tch_abs_string[abs]); | ||
433 | dev_dbg(cd->dev, "%s: ofs =%2Zd\n", __func__, | ||
434 | si->si_ofs.tch_abs[abs].ofs); | ||
435 | dev_dbg(cd->dev, "%s: siz =%2Zd\n", __func__, | ||
436 | si->si_ofs.tch_abs[abs].size); | ||
437 | dev_dbg(cd->dev, "%s: max =%2Zd\n", __func__, | ||
438 | si->si_ofs.tch_abs[abs].max); | ||
439 | dev_dbg(cd->dev, "%s: bofs=%2Zd\n", __func__, | ||
440 | si->si_ofs.tch_abs[abs].bofs); | ||
441 | } | ||
442 | |||
443 | si->si_ofs.mode_size = si->si_ofs.tt_stat_ofs + 1; | ||
444 | si->si_ofs.data_size = si->si_ofs.max_tchs * | ||
445 | si->si_ptrs.opcfg->tch_rec_size; | ||
446 | |||
447 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg, | ||
448 | si->si_ofs.opcfg_size, "sysinfo_opcfg_data"); | ||
449 | |||
450 | cyttsp4_si_get_opcfg_data_exit: | ||
451 | return rc; | ||
452 | } | ||
453 | |||
454 | static int cyttsp4_si_get_ddata(struct cyttsp4 *cd) | ||
455 | { | ||
456 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
457 | void *p; | ||
458 | int rc; | ||
459 | |||
460 | si->si_ofs.ddata_size = si->si_ofs.mdata_ofs - si->si_ofs.ddata_ofs; | ||
461 | |||
462 | p = krealloc(si->si_ptrs.ddata, si->si_ofs.ddata_size, GFP_KERNEL); | ||
463 | if (p == NULL) { | ||
464 | dev_err(cd->dev, "%s: fail alloc ddata memory\n", __func__); | ||
465 | return -ENOMEM; | ||
466 | } | ||
467 | si->si_ptrs.ddata = p; | ||
468 | |||
469 | rc = cyttsp4_adap_read(cd, si->si_ofs.ddata_ofs, si->si_ofs.ddata_size, | ||
470 | si->si_ptrs.ddata); | ||
471 | if (rc < 0) | ||
472 | dev_err(cd->dev, "%s: fail read ddata data r=%d\n", | ||
473 | __func__, rc); | ||
474 | else | ||
475 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
476 | (u8 *)si->si_ptrs.ddata, | ||
477 | si->si_ofs.ddata_size, "sysinfo_ddata"); | ||
478 | return rc; | ||
479 | } | ||
480 | |||
481 | static int cyttsp4_si_get_mdata(struct cyttsp4 *cd) | ||
482 | { | ||
483 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
484 | void *p; | ||
485 | int rc; | ||
486 | |||
487 | si->si_ofs.mdata_size = si->si_ofs.map_sz - si->si_ofs.mdata_ofs; | ||
488 | |||
489 | p = krealloc(si->si_ptrs.mdata, si->si_ofs.mdata_size, GFP_KERNEL); | ||
490 | if (p == NULL) { | ||
491 | dev_err(cd->dev, "%s: fail alloc mdata memory\n", __func__); | ||
492 | return -ENOMEM; | ||
493 | } | ||
494 | si->si_ptrs.mdata = p; | ||
495 | |||
496 | rc = cyttsp4_adap_read(cd, si->si_ofs.mdata_ofs, si->si_ofs.mdata_size, | ||
497 | si->si_ptrs.mdata); | ||
498 | if (rc < 0) | ||
499 | dev_err(cd->dev, "%s: fail read mdata data r=%d\n", | ||
500 | __func__, rc); | ||
501 | else | ||
502 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
503 | (u8 *)si->si_ptrs.mdata, | ||
504 | si->si_ofs.mdata_size, "sysinfo_mdata"); | ||
505 | return rc; | ||
506 | } | ||
507 | |||
508 | static int cyttsp4_si_get_btn_data(struct cyttsp4 *cd) | ||
509 | { | ||
510 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
511 | int btn; | ||
512 | int num_defined_keys; | ||
513 | u16 *key_table; | ||
514 | void *p; | ||
515 | int rc = 0; | ||
516 | |||
517 | if (si->si_ofs.num_btns) { | ||
518 | si->si_ofs.btn_keys_size = si->si_ofs.num_btns * | ||
519 | sizeof(struct cyttsp4_btn); | ||
520 | |||
521 | p = krealloc(si->btn, si->si_ofs.btn_keys_size, | ||
522 | GFP_KERNEL|__GFP_ZERO); | ||
523 | if (p == NULL) { | ||
524 | dev_err(cd->dev, "%s: %s\n", __func__, | ||
525 | "fail alloc btn_keys memory"); | ||
526 | return -ENOMEM; | ||
527 | } | ||
528 | si->btn = p; | ||
529 | |||
530 | if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS] == NULL) | ||
531 | num_defined_keys = 0; | ||
532 | else if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS]->data == NULL) | ||
533 | num_defined_keys = 0; | ||
534 | else | ||
535 | num_defined_keys = cd->cpdata->sett | ||
536 | [CY_IC_GRPNUM_BTN_KEYS]->size; | ||
537 | |||
538 | for (btn = 0; btn < si->si_ofs.num_btns && | ||
539 | btn < num_defined_keys; btn++) { | ||
540 | key_table = (u16 *)cd->cpdata->sett | ||
541 | [CY_IC_GRPNUM_BTN_KEYS]->data; | ||
542 | si->btn[btn].key_code = key_table[btn]; | ||
543 | si->btn[btn].state = CY_BTN_RELEASED; | ||
544 | si->btn[btn].enabled = true; | ||
545 | } | ||
546 | for (; btn < si->si_ofs.num_btns; btn++) { | ||
547 | si->btn[btn].key_code = KEY_RESERVED; | ||
548 | si->btn[btn].state = CY_BTN_RELEASED; | ||
549 | si->btn[btn].enabled = true; | ||
550 | } | ||
551 | |||
552 | return rc; | ||
553 | } | ||
554 | |||
555 | si->si_ofs.btn_keys_size = 0; | ||
556 | kfree(si->btn); | ||
557 | si->btn = NULL; | ||
558 | return rc; | ||
559 | } | ||
560 | |||
561 | static int cyttsp4_si_get_op_data_ptrs(struct cyttsp4 *cd) | ||
562 | { | ||
563 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
564 | void *p; | ||
565 | |||
566 | p = krealloc(si->xy_mode, si->si_ofs.mode_size, GFP_KERNEL|__GFP_ZERO); | ||
567 | if (p == NULL) | ||
568 | return -ENOMEM; | ||
569 | si->xy_mode = p; | ||
570 | |||
571 | p = krealloc(si->xy_data, si->si_ofs.data_size, GFP_KERNEL|__GFP_ZERO); | ||
572 | if (p == NULL) | ||
573 | return -ENOMEM; | ||
574 | si->xy_data = p; | ||
575 | |||
576 | p = krealloc(si->btn_rec_data, | ||
577 | si->si_ofs.btn_rec_size * si->si_ofs.num_btns, | ||
578 | GFP_KERNEL|__GFP_ZERO); | ||
579 | if (p == NULL) | ||
580 | return -ENOMEM; | ||
581 | si->btn_rec_data = p; | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static void cyttsp4_si_put_log_data(struct cyttsp4 *cd) | ||
587 | { | ||
588 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
589 | dev_dbg(cd->dev, "%s: cydata_ofs =%4Zd siz=%4Zd\n", __func__, | ||
590 | si->si_ofs.cydata_ofs, si->si_ofs.cydata_size); | ||
591 | dev_dbg(cd->dev, "%s: test_ofs =%4Zd siz=%4Zd\n", __func__, | ||
592 | si->si_ofs.test_ofs, si->si_ofs.test_size); | ||
593 | dev_dbg(cd->dev, "%s: pcfg_ofs =%4Zd siz=%4Zd\n", __func__, | ||
594 | si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size); | ||
595 | dev_dbg(cd->dev, "%s: opcfg_ofs =%4Zd siz=%4Zd\n", __func__, | ||
596 | si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size); | ||
597 | dev_dbg(cd->dev, "%s: ddata_ofs =%4Zd siz=%4Zd\n", __func__, | ||
598 | si->si_ofs.ddata_ofs, si->si_ofs.ddata_size); | ||
599 | dev_dbg(cd->dev, "%s: mdata_ofs =%4Zd siz=%4Zd\n", __func__, | ||
600 | si->si_ofs.mdata_ofs, si->si_ofs.mdata_size); | ||
601 | |||
602 | dev_dbg(cd->dev, "%s: cmd_ofs =%4Zd\n", __func__, | ||
603 | si->si_ofs.cmd_ofs); | ||
604 | dev_dbg(cd->dev, "%s: rep_ofs =%4Zd\n", __func__, | ||
605 | si->si_ofs.rep_ofs); | ||
606 | dev_dbg(cd->dev, "%s: rep_sz =%4Zd\n", __func__, | ||
607 | si->si_ofs.rep_sz); | ||
608 | dev_dbg(cd->dev, "%s: num_btns =%4Zd\n", __func__, | ||
609 | si->si_ofs.num_btns); | ||
610 | dev_dbg(cd->dev, "%s: num_btn_regs =%4Zd\n", __func__, | ||
611 | si->si_ofs.num_btn_regs); | ||
612 | dev_dbg(cd->dev, "%s: tt_stat_ofs =%4Zd\n", __func__, | ||
613 | si->si_ofs.tt_stat_ofs); | ||
614 | dev_dbg(cd->dev, "%s: tch_rec_size =%4Zd\n", __func__, | ||
615 | si->si_ofs.tch_rec_size); | ||
616 | dev_dbg(cd->dev, "%s: max_tchs =%4Zd\n", __func__, | ||
617 | si->si_ofs.max_tchs); | ||
618 | dev_dbg(cd->dev, "%s: mode_size =%4Zd\n", __func__, | ||
619 | si->si_ofs.mode_size); | ||
620 | dev_dbg(cd->dev, "%s: data_size =%4Zd\n", __func__, | ||
621 | si->si_ofs.data_size); | ||
622 | dev_dbg(cd->dev, "%s: map_sz =%4Zd\n", __func__, | ||
623 | si->si_ofs.map_sz); | ||
624 | |||
625 | dev_dbg(cd->dev, "%s: btn_rec_size =%2Zd\n", __func__, | ||
626 | si->si_ofs.btn_rec_size); | ||
627 | dev_dbg(cd->dev, "%s: btn_diff_ofs =%2Zd\n", __func__, | ||
628 | si->si_ofs.btn_diff_ofs); | ||
629 | dev_dbg(cd->dev, "%s: btn_diff_size =%2Zd\n", __func__, | ||
630 | si->si_ofs.btn_diff_size); | ||
631 | |||
632 | dev_dbg(cd->dev, "%s: max_x = 0x%04ZX (%Zd)\n", __func__, | ||
633 | si->si_ofs.max_x, si->si_ofs.max_x); | ||
634 | dev_dbg(cd->dev, "%s: x_origin = %Zd (%s)\n", __func__, | ||
635 | si->si_ofs.x_origin, | ||
636 | si->si_ofs.x_origin == CY_NORMAL_ORIGIN ? | ||
637 | "left corner" : "right corner"); | ||
638 | dev_dbg(cd->dev, "%s: max_y = 0x%04ZX (%Zd)\n", __func__, | ||
639 | si->si_ofs.max_y, si->si_ofs.max_y); | ||
640 | dev_dbg(cd->dev, "%s: y_origin = %Zd (%s)\n", __func__, | ||
641 | si->si_ofs.y_origin, | ||
642 | si->si_ofs.y_origin == CY_NORMAL_ORIGIN ? | ||
643 | "upper corner" : "lower corner"); | ||
644 | dev_dbg(cd->dev, "%s: max_p = 0x%04ZX (%Zd)\n", __func__, | ||
645 | si->si_ofs.max_p, si->si_ofs.max_p); | ||
646 | |||
647 | dev_dbg(cd->dev, "%s: xy_mode=%p xy_data=%p\n", __func__, | ||
648 | si->xy_mode, si->xy_data); | ||
649 | } | ||
650 | |||
651 | static int cyttsp4_get_sysinfo_regs(struct cyttsp4 *cd) | ||
652 | { | ||
653 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
654 | int rc; | ||
655 | |||
656 | rc = cyttsp4_si_data_offsets(cd); | ||
657 | if (rc < 0) | ||
658 | return rc; | ||
659 | |||
660 | rc = cyttsp4_si_get_cydata(cd); | ||
661 | if (rc < 0) | ||
662 | return rc; | ||
663 | |||
664 | rc = cyttsp4_si_get_test_data(cd); | ||
665 | if (rc < 0) | ||
666 | return rc; | ||
667 | |||
668 | rc = cyttsp4_si_get_pcfg_data(cd); | ||
669 | if (rc < 0) | ||
670 | return rc; | ||
671 | |||
672 | rc = cyttsp4_si_get_opcfg_data(cd); | ||
673 | if (rc < 0) | ||
674 | return rc; | ||
675 | |||
676 | rc = cyttsp4_si_get_ddata(cd); | ||
677 | if (rc < 0) | ||
678 | return rc; | ||
679 | |||
680 | rc = cyttsp4_si_get_mdata(cd); | ||
681 | if (rc < 0) | ||
682 | return rc; | ||
683 | |||
684 | rc = cyttsp4_si_get_btn_data(cd); | ||
685 | if (rc < 0) | ||
686 | return rc; | ||
687 | |||
688 | rc = cyttsp4_si_get_op_data_ptrs(cd); | ||
689 | if (rc < 0) { | ||
690 | dev_err(cd->dev, "%s: failed to get_op_data\n", | ||
691 | __func__); | ||
692 | return rc; | ||
693 | } | ||
694 | |||
695 | cyttsp4_si_put_log_data(cd); | ||
696 | |||
697 | /* provide flow control handshake */ | ||
698 | rc = cyttsp4_handshake(cd, si->si_data.hst_mode); | ||
699 | if (rc < 0) | ||
700 | dev_err(cd->dev, "%s: handshake fail on sysinfo reg\n", | ||
701 | __func__); | ||
702 | |||
703 | si->ready = true; | ||
704 | return rc; | ||
705 | } | ||
706 | |||
707 | static void cyttsp4_queue_startup_(struct cyttsp4 *cd) | ||
708 | { | ||
709 | if (cd->startup_state == STARTUP_NONE) { | ||
710 | cd->startup_state = STARTUP_QUEUED; | ||
711 | schedule_work(&cd->startup_work); | ||
712 | dev_dbg(cd->dev, "%s: cyttsp4_startup queued\n", __func__); | ||
713 | } else { | ||
714 | dev_dbg(cd->dev, "%s: startup_state = %d\n", __func__, | ||
715 | cd->startup_state); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md, | ||
720 | int max_slots) | ||
721 | { | ||
722 | int t; | ||
723 | |||
724 | if (md->num_prv_tch == 0) | ||
725 | return; | ||
726 | |||
727 | for (t = 0; t < max_slots; t++) { | ||
728 | input_mt_slot(md->input, t); | ||
729 | input_mt_report_slot_state(md->input, | ||
730 | MT_TOOL_FINGER, false); | ||
731 | } | ||
732 | } | ||
733 | |||
734 | static void cyttsp4_lift_all(struct cyttsp4_mt_data *md) | ||
735 | { | ||
736 | if (!md->si) | ||
737 | return; | ||
738 | |||
739 | if (md->num_prv_tch != 0) { | ||
740 | cyttsp4_report_slot_liftoff(md, | ||
741 | md->si->si_ofs.tch_abs[CY_TCH_T].max); | ||
742 | input_sync(md->input); | ||
743 | md->num_prv_tch = 0; | ||
744 | } | ||
745 | } | ||
746 | |||
747 | static void cyttsp4_get_touch_axis(struct cyttsp4_mt_data *md, | ||
748 | int *axis, int size, int max, u8 *xy_data, int bofs) | ||
749 | { | ||
750 | int nbyte; | ||
751 | int next; | ||
752 | |||
753 | for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) { | ||
754 | dev_vdbg(&md->input->dev, | ||
755 | "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p" | ||
756 | " xy_data[%d]=%02X(%d) bofs=%d\n", | ||
757 | __func__, *axis, *axis, size, max, xy_data, next, | ||
758 | xy_data[next], xy_data[next], bofs); | ||
759 | *axis = (*axis * 256) + (xy_data[next] >> bofs); | ||
760 | next++; | ||
761 | } | ||
762 | |||
763 | *axis &= max - 1; | ||
764 | |||
765 | dev_vdbg(&md->input->dev, | ||
766 | "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p" | ||
767 | " xy_data[%d]=%02X(%d)\n", | ||
768 | __func__, *axis, *axis, size, max, xy_data, next, | ||
769 | xy_data[next], xy_data[next]); | ||
770 | } | ||
771 | |||
772 | static void cyttsp4_get_touch(struct cyttsp4_mt_data *md, | ||
773 | struct cyttsp4_touch *touch, u8 *xy_data) | ||
774 | { | ||
775 | struct device *dev = &md->input->dev; | ||
776 | struct cyttsp4_sysinfo *si = md->si; | ||
777 | enum cyttsp4_tch_abs abs; | ||
778 | int tmp; | ||
779 | bool flipped; | ||
780 | |||
781 | for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) { | ||
782 | cyttsp4_get_touch_axis(md, &touch->abs[abs], | ||
783 | si->si_ofs.tch_abs[abs].size, | ||
784 | si->si_ofs.tch_abs[abs].max, | ||
785 | xy_data + si->si_ofs.tch_abs[abs].ofs, | ||
786 | si->si_ofs.tch_abs[abs].bofs); | ||
787 | dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__, | ||
788 | cyttsp4_tch_abs_string[abs], | ||
789 | touch->abs[abs], touch->abs[abs]); | ||
790 | } | ||
791 | |||
792 | if (md->pdata->flags & CY_FLAG_FLIP) { | ||
793 | tmp = touch->abs[CY_TCH_X]; | ||
794 | touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y]; | ||
795 | touch->abs[CY_TCH_Y] = tmp; | ||
796 | flipped = true; | ||
797 | } else | ||
798 | flipped = false; | ||
799 | |||
800 | if (md->pdata->flags & CY_FLAG_INV_X) { | ||
801 | if (flipped) | ||
802 | touch->abs[CY_TCH_X] = md->si->si_ofs.max_y - | ||
803 | touch->abs[CY_TCH_X]; | ||
804 | else | ||
805 | touch->abs[CY_TCH_X] = md->si->si_ofs.max_x - | ||
806 | touch->abs[CY_TCH_X]; | ||
807 | } | ||
808 | if (md->pdata->flags & CY_FLAG_INV_Y) { | ||
809 | if (flipped) | ||
810 | touch->abs[CY_TCH_Y] = md->si->si_ofs.max_x - | ||
811 | touch->abs[CY_TCH_Y]; | ||
812 | else | ||
813 | touch->abs[CY_TCH_Y] = md->si->si_ofs.max_y - | ||
814 | touch->abs[CY_TCH_Y]; | ||
815 | } | ||
816 | |||
817 | dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n", | ||
818 | __func__, flipped ? "true" : "false", | ||
819 | md->pdata->flags & CY_FLAG_INV_X ? "true" : "false", | ||
820 | md->pdata->flags & CY_FLAG_INV_Y ? "true" : "false", | ||
821 | touch->abs[CY_TCH_X], touch->abs[CY_TCH_X], | ||
822 | touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]); | ||
823 | } | ||
824 | |||
825 | static void cyttsp4_final_sync(struct input_dev *input, int max_slots, int *ids) | ||
826 | { | ||
827 | int t; | ||
828 | |||
829 | for (t = 0; t < max_slots; t++) { | ||
830 | if (ids[t]) | ||
831 | continue; | ||
832 | input_mt_slot(input, t); | ||
833 | input_mt_report_slot_state(input, MT_TOOL_FINGER, false); | ||
834 | } | ||
835 | |||
836 | input_sync(input); | ||
837 | } | ||
838 | |||
839 | static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch) | ||
840 | { | ||
841 | struct device *dev = &md->input->dev; | ||
842 | struct cyttsp4_sysinfo *si = md->si; | ||
843 | struct cyttsp4_touch tch; | ||
844 | int sig; | ||
845 | int i, j, t = 0; | ||
846 | int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)]; | ||
847 | |||
848 | memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int)); | ||
849 | for (i = 0; i < num_cur_tch; i++) { | ||
850 | cyttsp4_get_touch(md, &tch, si->xy_data + | ||
851 | (i * si->si_ofs.tch_rec_size)); | ||
852 | if ((tch.abs[CY_TCH_T] < md->pdata->frmwrk->abs | ||
853 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]) || | ||
854 | (tch.abs[CY_TCH_T] > md->pdata->frmwrk->abs | ||
855 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MAX_OST])) { | ||
856 | dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n", | ||
857 | __func__, i, tch.abs[CY_TCH_T], | ||
858 | md->pdata->frmwrk->abs[(CY_ABS_ID_OST * | ||
859 | CY_NUM_ABS_SET) + CY_MAX_OST]); | ||
860 | continue; | ||
861 | } | ||
862 | |||
863 | /* use 0 based track id's */ | ||
864 | sig = md->pdata->frmwrk->abs | ||
865 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + 0]; | ||
866 | if (sig != CY_IGNORE_VALUE) { | ||
867 | t = tch.abs[CY_TCH_T] - md->pdata->frmwrk->abs | ||
868 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]; | ||
869 | if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF) { | ||
870 | dev_dbg(dev, "%s: t=%d e=%d lift-off\n", | ||
871 | __func__, t, tch.abs[CY_TCH_E]); | ||
872 | goto cyttsp4_get_mt_touches_pr_tch; | ||
873 | } | ||
874 | input_mt_slot(md->input, t); | ||
875 | input_mt_report_slot_state(md->input, MT_TOOL_FINGER, | ||
876 | true); | ||
877 | ids[t] = true; | ||
878 | } | ||
879 | |||
880 | /* all devices: position and pressure fields */ | ||
881 | for (j = 0; j <= CY_ABS_W_OST; j++) { | ||
882 | sig = md->pdata->frmwrk->abs[((CY_ABS_X_OST + j) * | ||
883 | CY_NUM_ABS_SET) + 0]; | ||
884 | if (sig != CY_IGNORE_VALUE) | ||
885 | input_report_abs(md->input, sig, | ||
886 | tch.abs[CY_TCH_X + j]); | ||
887 | } | ||
888 | if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) { | ||
889 | /* | ||
890 | * TMA400 size and orientation fields: | ||
891 | * if pressure is non-zero and major touch | ||
892 | * signal is zero, then set major and minor touch | ||
893 | * signals to minimum non-zero value | ||
894 | */ | ||
895 | if (tch.abs[CY_TCH_P] > 0 && tch.abs[CY_TCH_MAJ] == 0) | ||
896 | tch.abs[CY_TCH_MAJ] = tch.abs[CY_TCH_MIN] = 1; | ||
897 | |||
898 | /* Get the extended touch fields */ | ||
899 | for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) { | ||
900 | sig = md->pdata->frmwrk->abs | ||
901 | [((CY_ABS_MAJ_OST + j) * | ||
902 | CY_NUM_ABS_SET) + 0]; | ||
903 | if (sig != CY_IGNORE_VALUE) | ||
904 | input_report_abs(md->input, sig, | ||
905 | tch.abs[CY_TCH_MAJ + j]); | ||
906 | } | ||
907 | } | ||
908 | |||
909 | cyttsp4_get_mt_touches_pr_tch: | ||
910 | if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) | ||
911 | dev_dbg(dev, | ||
912 | "%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d\n", | ||
913 | __func__, t, | ||
914 | tch.abs[CY_TCH_X], | ||
915 | tch.abs[CY_TCH_Y], | ||
916 | tch.abs[CY_TCH_P], | ||
917 | tch.abs[CY_TCH_MAJ], | ||
918 | tch.abs[CY_TCH_MIN], | ||
919 | tch.abs[CY_TCH_OR], | ||
920 | tch.abs[CY_TCH_E]); | ||
921 | else | ||
922 | dev_dbg(dev, | ||
923 | "%s: t=%d x=%d y=%d z=%d e=%d\n", __func__, | ||
924 | t, | ||
925 | tch.abs[CY_TCH_X], | ||
926 | tch.abs[CY_TCH_Y], | ||
927 | tch.abs[CY_TCH_P], | ||
928 | tch.abs[CY_TCH_E]); | ||
929 | } | ||
930 | |||
931 | cyttsp4_final_sync(md->input, si->si_ofs.tch_abs[CY_TCH_T].max, ids); | ||
932 | |||
933 | md->num_prv_tch = num_cur_tch; | ||
934 | |||
935 | return; | ||
936 | } | ||
937 | |||
938 | /* read xy_data for all current touches */ | ||
939 | static int cyttsp4_xy_worker(struct cyttsp4 *cd) | ||
940 | { | ||
941 | struct cyttsp4_mt_data *md = &cd->md; | ||
942 | struct device *dev = &md->input->dev; | ||
943 | struct cyttsp4_sysinfo *si = md->si; | ||
944 | u8 num_cur_tch; | ||
945 | u8 hst_mode; | ||
946 | u8 rep_len; | ||
947 | u8 rep_stat; | ||
948 | u8 tt_stat; | ||
949 | int rc = 0; | ||
950 | |||
951 | /* | ||
952 | * Get event data from cyttsp4 device. | ||
953 | * The event data includes all data | ||
954 | * for all active touches. | ||
955 | * Event data also includes button data | ||
956 | */ | ||
957 | /* | ||
958 | * Use 2 reads: | ||
959 | * 1st read to get mode + button bytes + touch count (core) | ||
960 | * 2nd read (optional) to get touch 1 - touch n data | ||
961 | */ | ||
962 | hst_mode = si->xy_mode[CY_REG_BASE]; | ||
963 | rep_len = si->xy_mode[si->si_ofs.rep_ofs]; | ||
964 | rep_stat = si->xy_mode[si->si_ofs.rep_ofs + 1]; | ||
965 | tt_stat = si->xy_mode[si->si_ofs.tt_stat_ofs]; | ||
966 | dev_vdbg(dev, "%s: %s%02X %s%d %s%02X %s%02X\n", __func__, | ||
967 | "hst_mode=", hst_mode, "rep_len=", rep_len, | ||
968 | "rep_stat=", rep_stat, "tt_stat=", tt_stat); | ||
969 | |||
970 | num_cur_tch = GET_NUM_TOUCHES(tt_stat); | ||
971 | dev_vdbg(dev, "%s: num_cur_tch=%d\n", __func__, num_cur_tch); | ||
972 | |||
973 | if (rep_len == 0 && num_cur_tch > 0) { | ||
974 | dev_err(dev, "%s: report length error rep_len=%d num_tch=%d\n", | ||
975 | __func__, rep_len, num_cur_tch); | ||
976 | goto cyttsp4_xy_worker_exit; | ||
977 | } | ||
978 | |||
979 | /* read touches */ | ||
980 | if (num_cur_tch > 0) { | ||
981 | rc = cyttsp4_adap_read(cd, si->si_ofs.tt_stat_ofs + 1, | ||
982 | num_cur_tch * si->si_ofs.tch_rec_size, | ||
983 | si->xy_data); | ||
984 | if (rc < 0) { | ||
985 | dev_err(dev, "%s: read fail on touch regs r=%d\n", | ||
986 | __func__, rc); | ||
987 | goto cyttsp4_xy_worker_exit; | ||
988 | } | ||
989 | } | ||
990 | |||
991 | /* print xy data */ | ||
992 | cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_data, num_cur_tch * | ||
993 | si->si_ofs.tch_rec_size, "xy_data"); | ||
994 | |||
995 | /* check any error conditions */ | ||
996 | if (IS_BAD_PKT(rep_stat)) { | ||
997 | dev_dbg(dev, "%s: Invalid buffer detected\n", __func__); | ||
998 | rc = 0; | ||
999 | goto cyttsp4_xy_worker_exit; | ||
1000 | } | ||
1001 | |||
1002 | if (IS_LARGE_AREA(tt_stat)) | ||
1003 | dev_dbg(dev, "%s: Large area detected\n", __func__); | ||
1004 | |||
1005 | if (num_cur_tch > si->si_ofs.max_tchs) { | ||
1006 | dev_err(dev, "%s: too many tch; set to max tch (n=%d c=%Zd)\n", | ||
1007 | __func__, num_cur_tch, si->si_ofs.max_tchs); | ||
1008 | num_cur_tch = si->si_ofs.max_tchs; | ||
1009 | } | ||
1010 | |||
1011 | /* extract xy_data for all currently reported touches */ | ||
1012 | dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__, | ||
1013 | num_cur_tch); | ||
1014 | if (num_cur_tch) | ||
1015 | cyttsp4_get_mt_touches(md, num_cur_tch); | ||
1016 | else | ||
1017 | cyttsp4_lift_all(md); | ||
1018 | |||
1019 | rc = 0; | ||
1020 | |||
1021 | cyttsp4_xy_worker_exit: | ||
1022 | return rc; | ||
1023 | } | ||
1024 | |||
1025 | static int cyttsp4_mt_attention(struct cyttsp4 *cd) | ||
1026 | { | ||
1027 | struct device *dev = cd->dev; | ||
1028 | struct cyttsp4_mt_data *md = &cd->md; | ||
1029 | int rc = 0; | ||
1030 | |||
1031 | if (!md->si) | ||
1032 | return 0; | ||
1033 | |||
1034 | mutex_lock(&md->report_lock); | ||
1035 | if (!md->is_suspended) { | ||
1036 | /* core handles handshake */ | ||
1037 | rc = cyttsp4_xy_worker(cd); | ||
1038 | } else { | ||
1039 | dev_vdbg(dev, "%s: Ignoring report while suspended\n", | ||
1040 | __func__); | ||
1041 | } | ||
1042 | mutex_unlock(&md->report_lock); | ||
1043 | if (rc < 0) | ||
1044 | dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc); | ||
1045 | |||
1046 | return rc; | ||
1047 | } | ||
1048 | |||
1049 | static irqreturn_t cyttsp4_irq(int irq, void *handle) | ||
1050 | { | ||
1051 | struct cyttsp4 *cd = handle; | ||
1052 | struct device *dev = cd->dev; | ||
1053 | enum cyttsp4_mode cur_mode; | ||
1054 | u8 cmd_ofs = cd->sysinfo.si_ofs.cmd_ofs; | ||
1055 | u8 mode[3]; | ||
1056 | int rc; | ||
1057 | |||
1058 | /* | ||
1059 | * Check whether this IRQ should be ignored (external) | ||
1060 | * This should be the very first thing to check since | ||
1061 | * ignore_irq may be set for a very short period of time | ||
1062 | */ | ||
1063 | if (atomic_read(&cd->ignore_irq)) { | ||
1064 | dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__); | ||
1065 | return IRQ_HANDLED; | ||
1066 | } | ||
1067 | |||
1068 | dev_dbg(dev, "%s int:0x%x\n", __func__, cd->int_status); | ||
1069 | |||
1070 | mutex_lock(&cd->system_lock); | ||
1071 | |||
1072 | /* Just to debug */ | ||
1073 | if (cd->sleep_state == SS_SLEEP_ON || cd->sleep_state == SS_SLEEPING) | ||
1074 | dev_vdbg(dev, "%s: Received IRQ while in sleep\n", __func__); | ||
1075 | |||
1076 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), mode); | ||
1077 | if (rc) { | ||
1078 | dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc); | ||
1079 | goto cyttsp4_irq_exit; | ||
1080 | } | ||
1081 | dev_vdbg(dev, "%s mode[0-2]:0x%X 0x%X 0x%X\n", __func__, | ||
1082 | mode[0], mode[1], mode[2]); | ||
1083 | |||
1084 | if (IS_BOOTLOADER(mode[0], mode[1])) { | ||
1085 | cur_mode = CY_MODE_BOOTLOADER; | ||
1086 | dev_vdbg(dev, "%s: bl running\n", __func__); | ||
1087 | if (cd->mode == CY_MODE_BOOTLOADER) { | ||
1088 | /* Signal bootloader heartbeat heard */ | ||
1089 | wake_up(&cd->wait_q); | ||
1090 | goto cyttsp4_irq_exit; | ||
1091 | } | ||
1092 | |||
1093 | /* switch to bootloader */ | ||
1094 | dev_dbg(dev, "%s: restart switch to bl m=%d -> m=%d\n", | ||
1095 | __func__, cd->mode, cur_mode); | ||
1096 | |||
1097 | /* catch operation->bl glitch */ | ||
1098 | if (cd->mode != CY_MODE_UNKNOWN) { | ||
1099 | /* Incase startup_state do not let startup_() */ | ||
1100 | cd->mode = CY_MODE_UNKNOWN; | ||
1101 | cyttsp4_queue_startup_(cd); | ||
1102 | goto cyttsp4_irq_exit; | ||
1103 | } | ||
1104 | |||
1105 | /* | ||
1106 | * do not wake thread on this switch since | ||
1107 | * it is possible to get an early heartbeat | ||
1108 | * prior to performing the reset | ||
1109 | */ | ||
1110 | cd->mode = cur_mode; | ||
1111 | |||
1112 | goto cyttsp4_irq_exit; | ||
1113 | } | ||
1114 | |||
1115 | switch (mode[0] & CY_HST_MODE) { | ||
1116 | case CY_HST_OPERATE: | ||
1117 | cur_mode = CY_MODE_OPERATIONAL; | ||
1118 | dev_vdbg(dev, "%s: operational\n", __func__); | ||
1119 | break; | ||
1120 | case CY_HST_CAT: | ||
1121 | cur_mode = CY_MODE_CAT; | ||
1122 | dev_vdbg(dev, "%s: CaT\n", __func__); | ||
1123 | break; | ||
1124 | case CY_HST_SYSINFO: | ||
1125 | cur_mode = CY_MODE_SYSINFO; | ||
1126 | dev_vdbg(dev, "%s: sysinfo\n", __func__); | ||
1127 | break; | ||
1128 | default: | ||
1129 | cur_mode = CY_MODE_UNKNOWN; | ||
1130 | dev_err(dev, "%s: unknown HST mode 0x%02X\n", __func__, | ||
1131 | mode[0]); | ||
1132 | break; | ||
1133 | } | ||
1134 | |||
1135 | /* Check whether this IRQ should be ignored (internal) */ | ||
1136 | if (cd->int_status & CY_INT_IGNORE) { | ||
1137 | dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__); | ||
1138 | goto cyttsp4_irq_exit; | ||
1139 | } | ||
1140 | |||
1141 | /* Check for wake up interrupt */ | ||
1142 | if (cd->int_status & CY_INT_AWAKE) { | ||
1143 | cd->int_status &= ~CY_INT_AWAKE; | ||
1144 | wake_up(&cd->wait_q); | ||
1145 | dev_vdbg(dev, "%s: Received wake up interrupt\n", __func__); | ||
1146 | goto cyttsp4_irq_handshake; | ||
1147 | } | ||
1148 | |||
1149 | /* Expecting mode change interrupt */ | ||
1150 | if ((cd->int_status & CY_INT_MODE_CHANGE) | ||
1151 | && (mode[0] & CY_HST_MODE_CHANGE) == 0) { | ||
1152 | cd->int_status &= ~CY_INT_MODE_CHANGE; | ||
1153 | dev_dbg(dev, "%s: finish mode switch m=%d -> m=%d\n", | ||
1154 | __func__, cd->mode, cur_mode); | ||
1155 | cd->mode = cur_mode; | ||
1156 | wake_up(&cd->wait_q); | ||
1157 | goto cyttsp4_irq_handshake; | ||
1158 | } | ||
1159 | |||
1160 | /* compare current core mode to current device mode */ | ||
1161 | dev_vdbg(dev, "%s: cd->mode=%d cur_mode=%d\n", | ||
1162 | __func__, cd->mode, cur_mode); | ||
1163 | if ((mode[0] & CY_HST_MODE_CHANGE) == 0 && cd->mode != cur_mode) { | ||
1164 | /* Unexpected mode change occurred */ | ||
1165 | dev_err(dev, "%s %d->%d 0x%x\n", __func__, cd->mode, | ||
1166 | cur_mode, cd->int_status); | ||
1167 | dev_dbg(dev, "%s: Unexpected mode change, startup\n", | ||
1168 | __func__); | ||
1169 | cyttsp4_queue_startup_(cd); | ||
1170 | goto cyttsp4_irq_exit; | ||
1171 | } | ||
1172 | |||
1173 | /* Expecting command complete interrupt */ | ||
1174 | dev_vdbg(dev, "%s: command byte:0x%x\n", __func__, mode[cmd_ofs]); | ||
1175 | if ((cd->int_status & CY_INT_EXEC_CMD) | ||
1176 | && mode[cmd_ofs] & CY_CMD_COMPLETE) { | ||
1177 | cd->int_status &= ~CY_INT_EXEC_CMD; | ||
1178 | dev_vdbg(dev, "%s: Received command complete interrupt\n", | ||
1179 | __func__); | ||
1180 | wake_up(&cd->wait_q); | ||
1181 | /* | ||
1182 | * It is possible to receive a single interrupt for | ||
1183 | * command complete and touch/button status report. | ||
1184 | * Continue processing for a possible status report. | ||
1185 | */ | ||
1186 | } | ||
1187 | |||
1188 | /* This should be status report, read status regs */ | ||
1189 | if (cd->mode == CY_MODE_OPERATIONAL) { | ||
1190 | dev_vdbg(dev, "%s: Read status registers\n", __func__); | ||
1191 | rc = cyttsp4_load_status_regs(cd); | ||
1192 | if (rc < 0) | ||
1193 | dev_err(dev, "%s: fail read mode regs r=%d\n", | ||
1194 | __func__, rc); | ||
1195 | } | ||
1196 | |||
1197 | cyttsp4_mt_attention(cd); | ||
1198 | |||
1199 | cyttsp4_irq_handshake: | ||
1200 | /* handshake the event */ | ||
1201 | dev_vdbg(dev, "%s: Handshake mode=0x%02X r=%d\n", | ||
1202 | __func__, mode[0], rc); | ||
1203 | rc = cyttsp4_handshake(cd, mode[0]); | ||
1204 | if (rc < 0) | ||
1205 | dev_err(dev, "%s: Fail handshake mode=0x%02X r=%d\n", | ||
1206 | __func__, mode[0], rc); | ||
1207 | |||
1208 | /* | ||
1209 | * a non-zero udelay period is required for using | ||
1210 | * IRQF_TRIGGER_LOW in order to delay until the | ||
1211 | * device completes isr deassert | ||
1212 | */ | ||
1213 | udelay(cd->cpdata->level_irq_udelay); | ||
1214 | |||
1215 | cyttsp4_irq_exit: | ||
1216 | mutex_unlock(&cd->system_lock); | ||
1217 | return IRQ_HANDLED; | ||
1218 | } | ||
1219 | |||
1220 | static void cyttsp4_start_wd_timer(struct cyttsp4 *cd) | ||
1221 | { | ||
1222 | if (!CY_WATCHDOG_TIMEOUT) | ||
1223 | return; | ||
1224 | |||
1225 | mod_timer(&cd->watchdog_timer, jiffies + | ||
1226 | msecs_to_jiffies(CY_WATCHDOG_TIMEOUT)); | ||
1227 | } | ||
1228 | |||
1229 | static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd) | ||
1230 | { | ||
1231 | if (!CY_WATCHDOG_TIMEOUT) | ||
1232 | return; | ||
1233 | |||
1234 | /* | ||
1235 | * Ensure we wait until the watchdog timer | ||
1236 | * running on a different CPU finishes | ||
1237 | */ | ||
1238 | del_timer_sync(&cd->watchdog_timer); | ||
1239 | cancel_work_sync(&cd->watchdog_work); | ||
1240 | del_timer_sync(&cd->watchdog_timer); | ||
1241 | } | ||
1242 | |||
1243 | static void cyttsp4_watchdog_timer(unsigned long handle) | ||
1244 | { | ||
1245 | struct cyttsp4 *cd = (struct cyttsp4 *)handle; | ||
1246 | |||
1247 | dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__); | ||
1248 | |||
1249 | if (!cd) | ||
1250 | return; | ||
1251 | |||
1252 | if (!work_pending(&cd->watchdog_work)) | ||
1253 | schedule_work(&cd->watchdog_work); | ||
1254 | |||
1255 | return; | ||
1256 | } | ||
1257 | |||
1258 | static int cyttsp4_request_exclusive(struct cyttsp4 *cd, void *ownptr, | ||
1259 | int timeout_ms) | ||
1260 | { | ||
1261 | int t = msecs_to_jiffies(timeout_ms); | ||
1262 | bool with_timeout = (timeout_ms != 0); | ||
1263 | |||
1264 | mutex_lock(&cd->system_lock); | ||
1265 | if (!cd->exclusive_dev && cd->exclusive_waits == 0) { | ||
1266 | cd->exclusive_dev = ownptr; | ||
1267 | goto exit; | ||
1268 | } | ||
1269 | |||
1270 | cd->exclusive_waits++; | ||
1271 | wait: | ||
1272 | mutex_unlock(&cd->system_lock); | ||
1273 | if (with_timeout) { | ||
1274 | t = wait_event_timeout(cd->wait_q, !cd->exclusive_dev, t); | ||
1275 | if (IS_TMO(t)) { | ||
1276 | dev_err(cd->dev, "%s: tmo waiting exclusive access\n", | ||
1277 | __func__); | ||
1278 | mutex_lock(&cd->system_lock); | ||
1279 | cd->exclusive_waits--; | ||
1280 | mutex_unlock(&cd->system_lock); | ||
1281 | return -ETIME; | ||
1282 | } | ||
1283 | } else { | ||
1284 | wait_event(cd->wait_q, !cd->exclusive_dev); | ||
1285 | } | ||
1286 | mutex_lock(&cd->system_lock); | ||
1287 | if (cd->exclusive_dev) | ||
1288 | goto wait; | ||
1289 | cd->exclusive_dev = ownptr; | ||
1290 | cd->exclusive_waits--; | ||
1291 | exit: | ||
1292 | mutex_unlock(&cd->system_lock); | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | /* | ||
1298 | * returns error if was not owned | ||
1299 | */ | ||
1300 | static int cyttsp4_release_exclusive(struct cyttsp4 *cd, void *ownptr) | ||
1301 | { | ||
1302 | mutex_lock(&cd->system_lock); | ||
1303 | if (cd->exclusive_dev != ownptr) { | ||
1304 | mutex_unlock(&cd->system_lock); | ||
1305 | return -EINVAL; | ||
1306 | } | ||
1307 | |||
1308 | dev_vdbg(cd->dev, "%s: exclusive_dev %p freed\n", | ||
1309 | __func__, cd->exclusive_dev); | ||
1310 | cd->exclusive_dev = NULL; | ||
1311 | wake_up(&cd->wait_q); | ||
1312 | mutex_unlock(&cd->system_lock); | ||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | static int cyttsp4_wait_bl_heartbeat(struct cyttsp4 *cd) | ||
1317 | { | ||
1318 | long t; | ||
1319 | int rc = 0; | ||
1320 | |||
1321 | /* wait heartbeat */ | ||
1322 | dev_vdbg(cd->dev, "%s: wait heartbeat...\n", __func__); | ||
1323 | t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_BOOTLOADER, | ||
1324 | msecs_to_jiffies(CY_CORE_RESET_AND_WAIT_TIMEOUT)); | ||
1325 | if (IS_TMO(t)) { | ||
1326 | dev_err(cd->dev, "%s: tmo waiting bl heartbeat cd->mode=%d\n", | ||
1327 | __func__, cd->mode); | ||
1328 | rc = -ETIME; | ||
1329 | } | ||
1330 | |||
1331 | return rc; | ||
1332 | } | ||
1333 | |||
1334 | static int cyttsp4_wait_sysinfo_mode(struct cyttsp4 *cd) | ||
1335 | { | ||
1336 | long t; | ||
1337 | |||
1338 | dev_vdbg(cd->dev, "%s: wait sysinfo...\n", __func__); | ||
1339 | |||
1340 | t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_SYSINFO, | ||
1341 | msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT)); | ||
1342 | if (IS_TMO(t)) { | ||
1343 | dev_err(cd->dev, "%s: tmo waiting exit bl cd->mode=%d\n", | ||
1344 | __func__, cd->mode); | ||
1345 | mutex_lock(&cd->system_lock); | ||
1346 | cd->int_status &= ~CY_INT_MODE_CHANGE; | ||
1347 | mutex_unlock(&cd->system_lock); | ||
1348 | return -ETIME; | ||
1349 | } | ||
1350 | |||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | static int cyttsp4_reset_and_wait(struct cyttsp4 *cd) | ||
1355 | { | ||
1356 | int rc; | ||
1357 | |||
1358 | /* reset hardware */ | ||
1359 | mutex_lock(&cd->system_lock); | ||
1360 | dev_dbg(cd->dev, "%s: reset hw...\n", __func__); | ||
1361 | rc = cyttsp4_hw_reset(cd); | ||
1362 | cd->mode = CY_MODE_UNKNOWN; | ||
1363 | mutex_unlock(&cd->system_lock); | ||
1364 | if (rc < 0) { | ||
1365 | dev_err(cd->dev, "%s:Fail hw reset r=%d\n", __func__, rc); | ||
1366 | return rc; | ||
1367 | } | ||
1368 | |||
1369 | return cyttsp4_wait_bl_heartbeat(cd); | ||
1370 | } | ||
1371 | |||
1372 | /* | ||
1373 | * returns err if refused or timeout; block until mode change complete | ||
1374 | * bit is set (mode change interrupt) | ||
1375 | */ | ||
1376 | static int cyttsp4_set_mode(struct cyttsp4 *cd, int new_mode) | ||
1377 | { | ||
1378 | u8 new_dev_mode; | ||
1379 | u8 mode; | ||
1380 | long t; | ||
1381 | int rc; | ||
1382 | |||
1383 | switch (new_mode) { | ||
1384 | case CY_MODE_OPERATIONAL: | ||
1385 | new_dev_mode = CY_HST_OPERATE; | ||
1386 | break; | ||
1387 | case CY_MODE_SYSINFO: | ||
1388 | new_dev_mode = CY_HST_SYSINFO; | ||
1389 | break; | ||
1390 | case CY_MODE_CAT: | ||
1391 | new_dev_mode = CY_HST_CAT; | ||
1392 | break; | ||
1393 | default: | ||
1394 | dev_err(cd->dev, "%s: invalid mode: %02X(%d)\n", | ||
1395 | __func__, new_mode, new_mode); | ||
1396 | return -EINVAL; | ||
1397 | } | ||
1398 | |||
1399 | /* change mode */ | ||
1400 | dev_dbg(cd->dev, "%s: %s=%p new_dev_mode=%02X new_mode=%d\n", | ||
1401 | __func__, "have exclusive", cd->exclusive_dev, | ||
1402 | new_dev_mode, new_mode); | ||
1403 | |||
1404 | mutex_lock(&cd->system_lock); | ||
1405 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
1406 | if (rc < 0) { | ||
1407 | mutex_unlock(&cd->system_lock); | ||
1408 | dev_err(cd->dev, "%s: Fail read mode r=%d\n", | ||
1409 | __func__, rc); | ||
1410 | goto exit; | ||
1411 | } | ||
1412 | |||
1413 | /* Clear device mode bits and set to new mode */ | ||
1414 | mode &= ~CY_HST_MODE; | ||
1415 | mode |= new_dev_mode | CY_HST_MODE_CHANGE; | ||
1416 | |||
1417 | cd->int_status |= CY_INT_MODE_CHANGE; | ||
1418 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
1419 | mutex_unlock(&cd->system_lock); | ||
1420 | if (rc < 0) { | ||
1421 | dev_err(cd->dev, "%s: Fail write mode change r=%d\n", | ||
1422 | __func__, rc); | ||
1423 | goto exit; | ||
1424 | } | ||
1425 | |||
1426 | /* wait for mode change done interrupt */ | ||
1427 | t = wait_event_timeout(cd->wait_q, | ||
1428 | (cd->int_status & CY_INT_MODE_CHANGE) == 0, | ||
1429 | msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT)); | ||
1430 | dev_dbg(cd->dev, "%s: back from wait t=%ld cd->mode=%d\n", | ||
1431 | __func__, t, cd->mode); | ||
1432 | |||
1433 | if (IS_TMO(t)) { | ||
1434 | dev_err(cd->dev, "%s: %s\n", __func__, | ||
1435 | "tmo waiting mode change"); | ||
1436 | mutex_lock(&cd->system_lock); | ||
1437 | cd->int_status &= ~CY_INT_MODE_CHANGE; | ||
1438 | mutex_unlock(&cd->system_lock); | ||
1439 | rc = -EINVAL; | ||
1440 | } | ||
1441 | |||
1442 | exit: | ||
1443 | return rc; | ||
1444 | } | ||
1445 | |||
1446 | static void cyttsp4_watchdog_work(struct work_struct *work) | ||
1447 | { | ||
1448 | struct cyttsp4 *cd = | ||
1449 | container_of(work, struct cyttsp4, watchdog_work); | ||
1450 | u8 *mode; | ||
1451 | int retval; | ||
1452 | |||
1453 | mutex_lock(&cd->system_lock); | ||
1454 | retval = cyttsp4_load_status_regs(cd); | ||
1455 | if (retval < 0) { | ||
1456 | dev_err(cd->dev, | ||
1457 | "%s: failed to access device in watchdog timer r=%d\n", | ||
1458 | __func__, retval); | ||
1459 | cyttsp4_queue_startup_(cd); | ||
1460 | goto cyttsp4_timer_watchdog_exit_error; | ||
1461 | } | ||
1462 | mode = &cd->sysinfo.xy_mode[CY_REG_BASE]; | ||
1463 | if (IS_BOOTLOADER(mode[0], mode[1])) { | ||
1464 | dev_err(cd->dev, | ||
1465 | "%s: device found in bootloader mode when operational mode\n", | ||
1466 | __func__); | ||
1467 | cyttsp4_queue_startup_(cd); | ||
1468 | goto cyttsp4_timer_watchdog_exit_error; | ||
1469 | } | ||
1470 | |||
1471 | cyttsp4_start_wd_timer(cd); | ||
1472 | cyttsp4_timer_watchdog_exit_error: | ||
1473 | mutex_unlock(&cd->system_lock); | ||
1474 | return; | ||
1475 | } | ||
1476 | |||
1477 | static int cyttsp4_core_sleep_(struct cyttsp4 *cd) | ||
1478 | { | ||
1479 | enum cyttsp4_sleep_state ss = SS_SLEEP_ON; | ||
1480 | enum cyttsp4_int_state int_status = CY_INT_IGNORE; | ||
1481 | int rc = 0; | ||
1482 | u8 mode[2]; | ||
1483 | |||
1484 | /* Already in sleep mode? */ | ||
1485 | mutex_lock(&cd->system_lock); | ||
1486 | if (cd->sleep_state == SS_SLEEP_ON) { | ||
1487 | mutex_unlock(&cd->system_lock); | ||
1488 | return 0; | ||
1489 | } | ||
1490 | cd->sleep_state = SS_SLEEPING; | ||
1491 | mutex_unlock(&cd->system_lock); | ||
1492 | |||
1493 | cyttsp4_stop_wd_timer(cd); | ||
1494 | |||
1495 | /* Wait until currently running IRQ handler exits and disable IRQ */ | ||
1496 | disable_irq(cd->irq); | ||
1497 | |||
1498 | dev_vdbg(cd->dev, "%s: write DEEP SLEEP...\n", __func__); | ||
1499 | mutex_lock(&cd->system_lock); | ||
1500 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
1501 | if (rc) { | ||
1502 | mutex_unlock(&cd->system_lock); | ||
1503 | dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc); | ||
1504 | goto error; | ||
1505 | } | ||
1506 | |||
1507 | if (IS_BOOTLOADER(mode[0], mode[1])) { | ||
1508 | mutex_unlock(&cd->system_lock); | ||
1509 | dev_err(cd->dev, "%s: Device in BOOTLADER mode.\n", __func__); | ||
1510 | rc = -EINVAL; | ||
1511 | goto error; | ||
1512 | } | ||
1513 | |||
1514 | mode[0] |= CY_HST_SLEEP; | ||
1515 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode[0]), &mode[0]); | ||
1516 | mutex_unlock(&cd->system_lock); | ||
1517 | if (rc) { | ||
1518 | dev_err(cd->dev, "%s: Fail write adapter r=%d\n", __func__, rc); | ||
1519 | goto error; | ||
1520 | } | ||
1521 | dev_vdbg(cd->dev, "%s: write DEEP SLEEP succeeded\n", __func__); | ||
1522 | |||
1523 | if (cd->cpdata->power) { | ||
1524 | dev_dbg(cd->dev, "%s: Power down HW\n", __func__); | ||
1525 | rc = cd->cpdata->power(cd->cpdata, 0, cd->dev, &cd->ignore_irq); | ||
1526 | } else { | ||
1527 | dev_dbg(cd->dev, "%s: No power function\n", __func__); | ||
1528 | rc = 0; | ||
1529 | } | ||
1530 | if (rc < 0) { | ||
1531 | dev_err(cd->dev, "%s: HW Power down fails r=%d\n", | ||
1532 | __func__, rc); | ||
1533 | goto error; | ||
1534 | } | ||
1535 | |||
1536 | /* Give time to FW to sleep */ | ||
1537 | msleep(50); | ||
1538 | |||
1539 | goto exit; | ||
1540 | |||
1541 | error: | ||
1542 | ss = SS_SLEEP_OFF; | ||
1543 | int_status = CY_INT_NONE; | ||
1544 | cyttsp4_start_wd_timer(cd); | ||
1545 | |||
1546 | exit: | ||
1547 | mutex_lock(&cd->system_lock); | ||
1548 | cd->sleep_state = ss; | ||
1549 | cd->int_status |= int_status; | ||
1550 | mutex_unlock(&cd->system_lock); | ||
1551 | enable_irq(cd->irq); | ||
1552 | return rc; | ||
1553 | } | ||
1554 | |||
1555 | static int cyttsp4_core_sleep(struct cyttsp4 *cd) | ||
1556 | { | ||
1557 | int rc; | ||
1558 | |||
1559 | rc = cyttsp4_request_exclusive(cd, cd->dev, | ||
1560 | CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT); | ||
1561 | if (rc < 0) { | ||
1562 | dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n", | ||
1563 | __func__, cd->exclusive_dev, cd->dev); | ||
1564 | return 0; | ||
1565 | } | ||
1566 | |||
1567 | rc = cyttsp4_core_sleep_(cd); | ||
1568 | |||
1569 | if (cyttsp4_release_exclusive(cd, cd->dev) < 0) | ||
1570 | dev_err(cd->dev, "%s: fail to release exclusive\n", __func__); | ||
1571 | else | ||
1572 | dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__); | ||
1573 | |||
1574 | return rc; | ||
1575 | } | ||
1576 | |||
1577 | static int cyttsp4_core_wake_(struct cyttsp4 *cd) | ||
1578 | { | ||
1579 | struct device *dev = cd->dev; | ||
1580 | int rc; | ||
1581 | u8 mode; | ||
1582 | int t; | ||
1583 | |||
1584 | /* Already woken? */ | ||
1585 | mutex_lock(&cd->system_lock); | ||
1586 | if (cd->sleep_state == SS_SLEEP_OFF) { | ||
1587 | mutex_unlock(&cd->system_lock); | ||
1588 | return 0; | ||
1589 | } | ||
1590 | cd->int_status &= ~CY_INT_IGNORE; | ||
1591 | cd->int_status |= CY_INT_AWAKE; | ||
1592 | cd->sleep_state = SS_WAKING; | ||
1593 | |||
1594 | if (cd->cpdata->power) { | ||
1595 | dev_dbg(dev, "%s: Power up HW\n", __func__); | ||
1596 | rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq); | ||
1597 | } else { | ||
1598 | dev_dbg(dev, "%s: No power function\n", __func__); | ||
1599 | rc = -ENOSYS; | ||
1600 | } | ||
1601 | if (rc < 0) { | ||
1602 | dev_err(dev, "%s: HW Power up fails r=%d\n", | ||
1603 | __func__, rc); | ||
1604 | |||
1605 | /* Initiate a read transaction to wake up */ | ||
1606 | cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
1607 | } else | ||
1608 | dev_vdbg(cd->dev, "%s: HW power up succeeds\n", | ||
1609 | __func__); | ||
1610 | mutex_unlock(&cd->system_lock); | ||
1611 | |||
1612 | t = wait_event_timeout(cd->wait_q, | ||
1613 | (cd->int_status & CY_INT_AWAKE) == 0, | ||
1614 | msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT)); | ||
1615 | if (IS_TMO(t)) { | ||
1616 | dev_err(dev, "%s: TMO waiting for wakeup\n", __func__); | ||
1617 | mutex_lock(&cd->system_lock); | ||
1618 | cd->int_status &= ~CY_INT_AWAKE; | ||
1619 | /* Try starting up */ | ||
1620 | cyttsp4_queue_startup_(cd); | ||
1621 | mutex_unlock(&cd->system_lock); | ||
1622 | } | ||
1623 | |||
1624 | mutex_lock(&cd->system_lock); | ||
1625 | cd->sleep_state = SS_SLEEP_OFF; | ||
1626 | mutex_unlock(&cd->system_lock); | ||
1627 | |||
1628 | cyttsp4_start_wd_timer(cd); | ||
1629 | |||
1630 | return 0; | ||
1631 | } | ||
1632 | |||
1633 | static int cyttsp4_core_wake(struct cyttsp4 *cd) | ||
1634 | { | ||
1635 | int rc; | ||
1636 | |||
1637 | rc = cyttsp4_request_exclusive(cd, cd->dev, | ||
1638 | CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT); | ||
1639 | if (rc < 0) { | ||
1640 | dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n", | ||
1641 | __func__, cd->exclusive_dev, cd->dev); | ||
1642 | return 0; | ||
1643 | } | ||
1644 | |||
1645 | rc = cyttsp4_core_wake_(cd); | ||
1646 | |||
1647 | if (cyttsp4_release_exclusive(cd, cd->dev) < 0) | ||
1648 | dev_err(cd->dev, "%s: fail to release exclusive\n", __func__); | ||
1649 | else | ||
1650 | dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__); | ||
1651 | |||
1652 | return rc; | ||
1653 | } | ||
1654 | |||
1655 | static int cyttsp4_startup_(struct cyttsp4 *cd) | ||
1656 | { | ||
1657 | int retry = CY_CORE_STARTUP_RETRY_COUNT; | ||
1658 | int rc; | ||
1659 | |||
1660 | cyttsp4_stop_wd_timer(cd); | ||
1661 | |||
1662 | reset: | ||
1663 | if (retry != CY_CORE_STARTUP_RETRY_COUNT) | ||
1664 | dev_dbg(cd->dev, "%s: Retry %d\n", __func__, | ||
1665 | CY_CORE_STARTUP_RETRY_COUNT - retry); | ||
1666 | |||
1667 | /* reset hardware and wait for heartbeat */ | ||
1668 | rc = cyttsp4_reset_and_wait(cd); | ||
1669 | if (rc < 0) { | ||
1670 | dev_err(cd->dev, "%s: Error on h/w reset r=%d\n", __func__, rc); | ||
1671 | if (retry--) | ||
1672 | goto reset; | ||
1673 | goto exit; | ||
1674 | } | ||
1675 | |||
1676 | /* exit bl into sysinfo mode */ | ||
1677 | dev_vdbg(cd->dev, "%s: write exit ldr...\n", __func__); | ||
1678 | mutex_lock(&cd->system_lock); | ||
1679 | cd->int_status &= ~CY_INT_IGNORE; | ||
1680 | cd->int_status |= CY_INT_MODE_CHANGE; | ||
1681 | |||
1682 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(ldr_exit), | ||
1683 | (u8 *)ldr_exit); | ||
1684 | mutex_unlock(&cd->system_lock); | ||
1685 | if (rc < 0) { | ||
1686 | dev_err(cd->dev, "%s: Fail write r=%d\n", __func__, rc); | ||
1687 | if (retry--) | ||
1688 | goto reset; | ||
1689 | goto exit; | ||
1690 | } | ||
1691 | |||
1692 | rc = cyttsp4_wait_sysinfo_mode(cd); | ||
1693 | if (rc < 0) { | ||
1694 | u8 buf[sizeof(ldr_err_app)]; | ||
1695 | int rc1; | ||
1696 | |||
1697 | /* Check for invalid/corrupted touch application */ | ||
1698 | rc1 = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(ldr_err_app), | ||
1699 | buf); | ||
1700 | if (rc1) { | ||
1701 | dev_err(cd->dev, "%s: Fail read r=%d\n", __func__, rc1); | ||
1702 | } else if (!memcmp(buf, ldr_err_app, sizeof(ldr_err_app))) { | ||
1703 | dev_err(cd->dev, "%s: Error launching touch application\n", | ||
1704 | __func__); | ||
1705 | mutex_lock(&cd->system_lock); | ||
1706 | cd->invalid_touch_app = true; | ||
1707 | mutex_unlock(&cd->system_lock); | ||
1708 | goto exit_no_wd; | ||
1709 | } | ||
1710 | |||
1711 | if (retry--) | ||
1712 | goto reset; | ||
1713 | goto exit; | ||
1714 | } | ||
1715 | |||
1716 | mutex_lock(&cd->system_lock); | ||
1717 | cd->invalid_touch_app = false; | ||
1718 | mutex_unlock(&cd->system_lock); | ||
1719 | |||
1720 | /* read sysinfo data */ | ||
1721 | dev_vdbg(cd->dev, "%s: get sysinfo regs..\n", __func__); | ||
1722 | rc = cyttsp4_get_sysinfo_regs(cd); | ||
1723 | if (rc < 0) { | ||
1724 | dev_err(cd->dev, "%s: failed to get sysinfo regs rc=%d\n", | ||
1725 | __func__, rc); | ||
1726 | if (retry--) | ||
1727 | goto reset; | ||
1728 | goto exit; | ||
1729 | } | ||
1730 | |||
1731 | rc = cyttsp4_set_mode(cd, CY_MODE_OPERATIONAL); | ||
1732 | if (rc < 0) { | ||
1733 | dev_err(cd->dev, "%s: failed to set mode to operational rc=%d\n", | ||
1734 | __func__, rc); | ||
1735 | if (retry--) | ||
1736 | goto reset; | ||
1737 | goto exit; | ||
1738 | } | ||
1739 | |||
1740 | cyttsp4_lift_all(&cd->md); | ||
1741 | |||
1742 | /* restore to sleep if was suspended */ | ||
1743 | mutex_lock(&cd->system_lock); | ||
1744 | if (cd->sleep_state == SS_SLEEP_ON) { | ||
1745 | cd->sleep_state = SS_SLEEP_OFF; | ||
1746 | mutex_unlock(&cd->system_lock); | ||
1747 | cyttsp4_core_sleep_(cd); | ||
1748 | goto exit_no_wd; | ||
1749 | } | ||
1750 | mutex_unlock(&cd->system_lock); | ||
1751 | |||
1752 | exit: | ||
1753 | cyttsp4_start_wd_timer(cd); | ||
1754 | exit_no_wd: | ||
1755 | return rc; | ||
1756 | } | ||
1757 | |||
1758 | static int cyttsp4_startup(struct cyttsp4 *cd) | ||
1759 | { | ||
1760 | int rc; | ||
1761 | |||
1762 | mutex_lock(&cd->system_lock); | ||
1763 | cd->startup_state = STARTUP_RUNNING; | ||
1764 | mutex_unlock(&cd->system_lock); | ||
1765 | |||
1766 | rc = cyttsp4_request_exclusive(cd, cd->dev, | ||
1767 | CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT); | ||
1768 | if (rc < 0) { | ||
1769 | dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n", | ||
1770 | __func__, cd->exclusive_dev, cd->dev); | ||
1771 | goto exit; | ||
1772 | } | ||
1773 | |||
1774 | rc = cyttsp4_startup_(cd); | ||
1775 | |||
1776 | if (cyttsp4_release_exclusive(cd, cd->dev) < 0) | ||
1777 | /* Don't return fail code, mode is already changed. */ | ||
1778 | dev_err(cd->dev, "%s: fail to release exclusive\n", __func__); | ||
1779 | else | ||
1780 | dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__); | ||
1781 | |||
1782 | exit: | ||
1783 | mutex_lock(&cd->system_lock); | ||
1784 | cd->startup_state = STARTUP_NONE; | ||
1785 | mutex_unlock(&cd->system_lock); | ||
1786 | |||
1787 | /* Wake the waiters for end of startup */ | ||
1788 | wake_up(&cd->wait_q); | ||
1789 | |||
1790 | return rc; | ||
1791 | } | ||
1792 | |||
1793 | static void cyttsp4_startup_work_function(struct work_struct *work) | ||
1794 | { | ||
1795 | struct cyttsp4 *cd = container_of(work, struct cyttsp4, startup_work); | ||
1796 | int rc; | ||
1797 | |||
1798 | rc = cyttsp4_startup(cd); | ||
1799 | if (rc < 0) | ||
1800 | dev_err(cd->dev, "%s: Fail queued startup r=%d\n", | ||
1801 | __func__, rc); | ||
1802 | } | ||
1803 | |||
1804 | static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd) | ||
1805 | { | ||
1806 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
1807 | |||
1808 | if (!si) | ||
1809 | return; | ||
1810 | |||
1811 | kfree(si->si_ptrs.cydata); | ||
1812 | kfree(si->si_ptrs.test); | ||
1813 | kfree(si->si_ptrs.pcfg); | ||
1814 | kfree(si->si_ptrs.opcfg); | ||
1815 | kfree(si->si_ptrs.ddata); | ||
1816 | kfree(si->si_ptrs.mdata); | ||
1817 | kfree(si->btn); | ||
1818 | kfree(si->xy_mode); | ||
1819 | kfree(si->xy_data); | ||
1820 | kfree(si->btn_rec_data); | ||
1821 | } | ||
1822 | |||
1823 | #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) | ||
1824 | static int cyttsp4_core_suspend(struct device *dev) | ||
1825 | { | ||
1826 | struct cyttsp4 *cd = dev_get_drvdata(dev); | ||
1827 | struct cyttsp4_mt_data *md = &cd->md; | ||
1828 | int rc; | ||
1829 | |||
1830 | md->is_suspended = true; | ||
1831 | |||
1832 | rc = cyttsp4_core_sleep(cd); | ||
1833 | if (rc < 0) { | ||
1834 | dev_err(dev, "%s: Error on sleep\n", __func__); | ||
1835 | return -EAGAIN; | ||
1836 | } | ||
1837 | return 0; | ||
1838 | } | ||
1839 | |||
1840 | static int cyttsp4_core_resume(struct device *dev) | ||
1841 | { | ||
1842 | struct cyttsp4 *cd = dev_get_drvdata(dev); | ||
1843 | struct cyttsp4_mt_data *md = &cd->md; | ||
1844 | int rc; | ||
1845 | |||
1846 | md->is_suspended = false; | ||
1847 | |||
1848 | rc = cyttsp4_core_wake(cd); | ||
1849 | if (rc < 0) { | ||
1850 | dev_err(dev, "%s: Error on wake\n", __func__); | ||
1851 | return -EAGAIN; | ||
1852 | } | ||
1853 | |||
1854 | return 0; | ||
1855 | } | ||
1856 | #endif | ||
1857 | |||
1858 | const struct dev_pm_ops cyttsp4_pm_ops = { | ||
1859 | SET_SYSTEM_SLEEP_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume) | ||
1860 | SET_RUNTIME_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume, NULL) | ||
1861 | }; | ||
1862 | EXPORT_SYMBOL_GPL(cyttsp4_pm_ops); | ||
1863 | |||
1864 | static int cyttsp4_mt_open(struct input_dev *input) | ||
1865 | { | ||
1866 | pm_runtime_get(input->dev.parent); | ||
1867 | return 0; | ||
1868 | } | ||
1869 | |||
1870 | static void cyttsp4_mt_close(struct input_dev *input) | ||
1871 | { | ||
1872 | struct cyttsp4_mt_data *md = input_get_drvdata(input); | ||
1873 | mutex_lock(&md->report_lock); | ||
1874 | if (!md->is_suspended) | ||
1875 | pm_runtime_put(input->dev.parent); | ||
1876 | mutex_unlock(&md->report_lock); | ||
1877 | } | ||
1878 | |||
1879 | |||
1880 | static int cyttsp4_setup_input_device(struct cyttsp4 *cd) | ||
1881 | { | ||
1882 | struct device *dev = cd->dev; | ||
1883 | struct cyttsp4_mt_data *md = &cd->md; | ||
1884 | int signal = CY_IGNORE_VALUE; | ||
1885 | int max_x, max_y, max_p, min, max; | ||
1886 | int max_x_tmp, max_y_tmp; | ||
1887 | int i; | ||
1888 | int rc; | ||
1889 | |||
1890 | dev_vdbg(dev, "%s: Initialize event signals\n", __func__); | ||
1891 | __set_bit(EV_ABS, md->input->evbit); | ||
1892 | __set_bit(EV_REL, md->input->evbit); | ||
1893 | __set_bit(EV_KEY, md->input->evbit); | ||
1894 | |||
1895 | max_x_tmp = md->si->si_ofs.max_x; | ||
1896 | max_y_tmp = md->si->si_ofs.max_y; | ||
1897 | |||
1898 | /* get maximum values from the sysinfo data */ | ||
1899 | if (md->pdata->flags & CY_FLAG_FLIP) { | ||
1900 | max_x = max_y_tmp - 1; | ||
1901 | max_y = max_x_tmp - 1; | ||
1902 | } else { | ||
1903 | max_x = max_x_tmp - 1; | ||
1904 | max_y = max_y_tmp - 1; | ||
1905 | } | ||
1906 | max_p = md->si->si_ofs.max_p; | ||
1907 | |||
1908 | /* set event signal capabilities */ | ||
1909 | for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) { | ||
1910 | signal = md->pdata->frmwrk->abs | ||
1911 | [(i * CY_NUM_ABS_SET) + CY_SIGNAL_OST]; | ||
1912 | if (signal != CY_IGNORE_VALUE) { | ||
1913 | __set_bit(signal, md->input->absbit); | ||
1914 | min = md->pdata->frmwrk->abs | ||
1915 | [(i * CY_NUM_ABS_SET) + CY_MIN_OST]; | ||
1916 | max = md->pdata->frmwrk->abs | ||
1917 | [(i * CY_NUM_ABS_SET) + CY_MAX_OST]; | ||
1918 | if (i == CY_ABS_ID_OST) { | ||
1919 | /* shift track ids down to start at 0 */ | ||
1920 | max = max - min; | ||
1921 | min = min - min; | ||
1922 | } else if (i == CY_ABS_X_OST) | ||
1923 | max = max_x; | ||
1924 | else if (i == CY_ABS_Y_OST) | ||
1925 | max = max_y; | ||
1926 | else if (i == CY_ABS_P_OST) | ||
1927 | max = max_p; | ||
1928 | input_set_abs_params(md->input, signal, min, max, | ||
1929 | md->pdata->frmwrk->abs | ||
1930 | [(i * CY_NUM_ABS_SET) + CY_FUZZ_OST], | ||
1931 | md->pdata->frmwrk->abs | ||
1932 | [(i * CY_NUM_ABS_SET) + CY_FLAT_OST]); | ||
1933 | dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n", | ||
1934 | __func__, signal, min, max); | ||
1935 | if ((i == CY_ABS_ID_OST) && | ||
1936 | (md->si->si_ofs.tch_rec_size < | ||
1937 | CY_TMA4XX_TCH_REC_SIZE)) | ||
1938 | break; | ||
1939 | } | ||
1940 | } | ||
1941 | |||
1942 | input_mt_init_slots(md->input, md->si->si_ofs.tch_abs[CY_TCH_T].max, | ||
1943 | INPUT_MT_DIRECT); | ||
1944 | rc = input_register_device(md->input); | ||
1945 | if (rc < 0) | ||
1946 | dev_err(dev, "%s: Error, failed register input device r=%d\n", | ||
1947 | __func__, rc); | ||
1948 | return rc; | ||
1949 | } | ||
1950 | |||
1951 | static int cyttsp4_mt_probe(struct cyttsp4 *cd) | ||
1952 | { | ||
1953 | struct device *dev = cd->dev; | ||
1954 | struct cyttsp4_mt_data *md = &cd->md; | ||
1955 | struct cyttsp4_mt_platform_data *pdata = cd->pdata->mt_pdata; | ||
1956 | int rc = 0; | ||
1957 | |||
1958 | mutex_init(&md->report_lock); | ||
1959 | md->pdata = pdata; | ||
1960 | /* Create the input device and register it. */ | ||
1961 | dev_vdbg(dev, "%s: Create the input device and register it\n", | ||
1962 | __func__); | ||
1963 | md->input = input_allocate_device(); | ||
1964 | if (md->input == NULL) { | ||
1965 | dev_err(dev, "%s: Error, failed to allocate input device\n", | ||
1966 | __func__); | ||
1967 | rc = -ENOSYS; | ||
1968 | goto error_alloc_failed; | ||
1969 | } | ||
1970 | |||
1971 | md->input->name = pdata->inp_dev_name; | ||
1972 | scnprintf(md->phys, sizeof(md->phys)-1, "%s", dev_name(dev)); | ||
1973 | md->input->phys = md->phys; | ||
1974 | md->input->id.bustype = cd->bus_ops->bustype; | ||
1975 | md->input->dev.parent = dev; | ||
1976 | md->input->open = cyttsp4_mt_open; | ||
1977 | md->input->close = cyttsp4_mt_close; | ||
1978 | input_set_drvdata(md->input, md); | ||
1979 | |||
1980 | /* get sysinfo */ | ||
1981 | md->si = &cd->sysinfo; | ||
1982 | if (!md->si) { | ||
1983 | dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n", | ||
1984 | __func__, md->si); | ||
1985 | goto error_get_sysinfo; | ||
1986 | } | ||
1987 | |||
1988 | rc = cyttsp4_setup_input_device(cd); | ||
1989 | if (rc) | ||
1990 | goto error_init_input; | ||
1991 | |||
1992 | return 0; | ||
1993 | |||
1994 | error_init_input: | ||
1995 | input_free_device(md->input); | ||
1996 | error_get_sysinfo: | ||
1997 | input_set_drvdata(md->input, NULL); | ||
1998 | error_alloc_failed: | ||
1999 | dev_err(dev, "%s failed.\n", __func__); | ||
2000 | return rc; | ||
2001 | } | ||
2002 | |||
2003 | struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops, | ||
2004 | struct device *dev, u16 irq, size_t xfer_buf_size) | ||
2005 | { | ||
2006 | struct cyttsp4 *cd; | ||
2007 | struct cyttsp4_platform_data *pdata = dev_get_platdata(dev); | ||
2008 | unsigned long irq_flags; | ||
2009 | int rc = 0; | ||
2010 | |||
2011 | if (!pdata || !pdata->core_pdata || !pdata->mt_pdata) { | ||
2012 | dev_err(dev, "%s: Missing platform data\n", __func__); | ||
2013 | rc = -ENODEV; | ||
2014 | goto error_no_pdata; | ||
2015 | } | ||
2016 | |||
2017 | cd = kzalloc(sizeof(*cd), GFP_KERNEL); | ||
2018 | if (!cd) { | ||
2019 | dev_err(dev, "%s: Error, kzalloc\n", __func__); | ||
2020 | rc = -ENOMEM; | ||
2021 | goto error_alloc_data; | ||
2022 | } | ||
2023 | |||
2024 | cd->xfer_buf = kzalloc(xfer_buf_size, GFP_KERNEL); | ||
2025 | if (!cd->xfer_buf) { | ||
2026 | dev_err(dev, "%s: Error, kzalloc\n", __func__); | ||
2027 | rc = -ENOMEM; | ||
2028 | goto error_free_cd; | ||
2029 | } | ||
2030 | |||
2031 | /* Initialize device info */ | ||
2032 | cd->dev = dev; | ||
2033 | cd->pdata = pdata; | ||
2034 | cd->cpdata = pdata->core_pdata; | ||
2035 | cd->bus_ops = ops; | ||
2036 | |||
2037 | /* Initialize mutexes and spinlocks */ | ||
2038 | mutex_init(&cd->system_lock); | ||
2039 | mutex_init(&cd->adap_lock); | ||
2040 | |||
2041 | /* Initialize wait queue */ | ||
2042 | init_waitqueue_head(&cd->wait_q); | ||
2043 | |||
2044 | /* Initialize works */ | ||
2045 | INIT_WORK(&cd->startup_work, cyttsp4_startup_work_function); | ||
2046 | INIT_WORK(&cd->watchdog_work, cyttsp4_watchdog_work); | ||
2047 | |||
2048 | /* Initialize IRQ */ | ||
2049 | cd->irq = gpio_to_irq(cd->cpdata->irq_gpio); | ||
2050 | if (cd->irq < 0) { | ||
2051 | rc = -EINVAL; | ||
2052 | goto error_free_xfer; | ||
2053 | } | ||
2054 | |||
2055 | dev_set_drvdata(dev, cd); | ||
2056 | |||
2057 | /* Call platform init function */ | ||
2058 | if (cd->cpdata->init) { | ||
2059 | dev_dbg(cd->dev, "%s: Init HW\n", __func__); | ||
2060 | rc = cd->cpdata->init(cd->cpdata, 1, cd->dev); | ||
2061 | } else { | ||
2062 | dev_dbg(cd->dev, "%s: No HW INIT function\n", __func__); | ||
2063 | rc = 0; | ||
2064 | } | ||
2065 | if (rc < 0) | ||
2066 | dev_err(cd->dev, "%s: HW Init fail r=%d\n", __func__, rc); | ||
2067 | |||
2068 | dev_dbg(dev, "%s: initialize threaded irq=%d\n", __func__, cd->irq); | ||
2069 | if (cd->cpdata->level_irq_udelay > 0) | ||
2070 | /* use level triggered interrupts */ | ||
2071 | irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT; | ||
2072 | else | ||
2073 | /* use edge triggered interrupts */ | ||
2074 | irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | ||
2075 | |||
2076 | rc = request_threaded_irq(cd->irq, NULL, cyttsp4_irq, irq_flags, | ||
2077 | dev_name(dev), cd); | ||
2078 | if (rc < 0) { | ||
2079 | dev_err(dev, "%s: Error, could not request irq\n", __func__); | ||
2080 | goto error_request_irq; | ||
2081 | } | ||
2082 | |||
2083 | /* Setup watchdog timer */ | ||
2084 | setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer, | ||
2085 | (unsigned long)cd); | ||
2086 | |||
2087 | /* | ||
2088 | * call startup directly to ensure that the device | ||
2089 | * is tested before leaving the probe | ||
2090 | */ | ||
2091 | rc = cyttsp4_startup(cd); | ||
2092 | |||
2093 | /* Do not fail probe if startup fails but the device is detected */ | ||
2094 | if (rc < 0 && cd->mode == CY_MODE_UNKNOWN) { | ||
2095 | dev_err(cd->dev, "%s: Fail initial startup r=%d\n", | ||
2096 | __func__, rc); | ||
2097 | goto error_startup; | ||
2098 | } | ||
2099 | |||
2100 | rc = cyttsp4_mt_probe(cd); | ||
2101 | if (rc < 0) { | ||
2102 | dev_err(dev, "%s: Error, fail mt probe\n", __func__); | ||
2103 | goto error_startup; | ||
2104 | } | ||
2105 | |||
2106 | pm_runtime_enable(dev); | ||
2107 | |||
2108 | return cd; | ||
2109 | |||
2110 | error_startup: | ||
2111 | cancel_work_sync(&cd->startup_work); | ||
2112 | cyttsp4_stop_wd_timer(cd); | ||
2113 | pm_runtime_disable(dev); | ||
2114 | cyttsp4_free_si_ptrs(cd); | ||
2115 | free_irq(cd->irq, cd); | ||
2116 | error_request_irq: | ||
2117 | if (cd->cpdata->init) | ||
2118 | cd->cpdata->init(cd->cpdata, 0, dev); | ||
2119 | dev_set_drvdata(dev, NULL); | ||
2120 | error_free_xfer: | ||
2121 | kfree(cd->xfer_buf); | ||
2122 | error_free_cd: | ||
2123 | kfree(cd); | ||
2124 | error_alloc_data: | ||
2125 | error_no_pdata: | ||
2126 | dev_err(dev, "%s failed.\n", __func__); | ||
2127 | return ERR_PTR(rc); | ||
2128 | } | ||
2129 | EXPORT_SYMBOL_GPL(cyttsp4_probe); | ||
2130 | |||
2131 | static void cyttsp4_mt_release(struct cyttsp4_mt_data *md) | ||
2132 | { | ||
2133 | input_unregister_device(md->input); | ||
2134 | input_set_drvdata(md->input, NULL); | ||
2135 | } | ||
2136 | |||
2137 | int cyttsp4_remove(struct cyttsp4 *cd) | ||
2138 | { | ||
2139 | struct device *dev = cd->dev; | ||
2140 | |||
2141 | cyttsp4_mt_release(&cd->md); | ||
2142 | |||
2143 | /* | ||
2144 | * Suspend the device before freeing the startup_work and stopping | ||
2145 | * the watchdog since sleep function restarts watchdog on failure | ||
2146 | */ | ||
2147 | pm_runtime_suspend(dev); | ||
2148 | pm_runtime_disable(dev); | ||
2149 | |||
2150 | cancel_work_sync(&cd->startup_work); | ||
2151 | |||
2152 | cyttsp4_stop_wd_timer(cd); | ||
2153 | |||
2154 | free_irq(cd->irq, cd); | ||
2155 | if (cd->cpdata->init) | ||
2156 | cd->cpdata->init(cd->cpdata, 0, dev); | ||
2157 | dev_set_drvdata(dev, NULL); | ||
2158 | cyttsp4_free_si_ptrs(cd); | ||
2159 | kfree(cd); | ||
2160 | return 0; | ||
2161 | } | ||
2162 | EXPORT_SYMBOL_GPL(cyttsp4_remove); | ||
2163 | |||
2164 | MODULE_LICENSE("GPL"); | ||
2165 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen core driver"); | ||
2166 | MODULE_AUTHOR("Cypress"); | ||
diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h new file mode 100644 index 000000000000..86a254354136 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_core.h | |||
@@ -0,0 +1,472 @@ | |||
1 | /* | ||
2 | * cyttsp4_core.h | ||
3 | * Cypress TrueTouch(TM) Standard Product V4 Core driver module. | ||
4 | * For use with Cypress Txx4xx parts. | ||
5 | * Supported parts include: | ||
6 | * TMA4XX | ||
7 | * TMA1036 | ||
8 | * | ||
9 | * Copyright (C) 2012 Cypress Semiconductor | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * version 2, and only version 2, as published by the | ||
14 | * Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef _LINUX_CYTTSP4_CORE_H | ||
26 | #define _LINUX_CYTTSP4_CORE_H | ||
27 | |||
28 | #include <linux/device.h> | ||
29 | #include <linux/err.h> | ||
30 | #include <linux/input.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/limits.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/stringify.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/platform_data/cyttsp4.h> | ||
37 | |||
38 | #define CY_REG_BASE 0x00 | ||
39 | |||
40 | #define CY_POST_CODEL_WDG_RST 0x01 | ||
41 | #define CY_POST_CODEL_CFG_DATA_CRC_FAIL 0x02 | ||
42 | #define CY_POST_CODEL_PANEL_TEST_FAIL 0x04 | ||
43 | |||
44 | #define CY_NUM_BTN_PER_REG 4 | ||
45 | |||
46 | /* touch record system information offset masks and shifts */ | ||
47 | #define CY_BYTE_OFS_MASK 0x1F | ||
48 | #define CY_BOFS_MASK 0xE0 | ||
49 | #define CY_BOFS_SHIFT 5 | ||
50 | |||
51 | #define CY_TMA1036_TCH_REC_SIZE 6 | ||
52 | #define CY_TMA4XX_TCH_REC_SIZE 9 | ||
53 | #define CY_TMA1036_MAX_TCH 0x0E | ||
54 | #define CY_TMA4XX_MAX_TCH 0x1E | ||
55 | |||
56 | #define CY_NORMAL_ORIGIN 0 /* upper, left corner */ | ||
57 | #define CY_INVERT_ORIGIN 1 /* lower, right corner */ | ||
58 | |||
59 | /* helpers */ | ||
60 | #define GET_NUM_TOUCHES(x) ((x) & 0x1F) | ||
61 | #define IS_LARGE_AREA(x) ((x) & 0x20) | ||
62 | #define IS_BAD_PKT(x) ((x) & 0x20) | ||
63 | #define IS_BOOTLOADER(hst_mode, reset_detect) \ | ||
64 | ((hst_mode) & 0x01 || (reset_detect) != 0) | ||
65 | #define IS_TMO(t) ((t) == 0) | ||
66 | |||
67 | |||
68 | enum cyttsp_cmd_bits { | ||
69 | CY_CMD_COMPLETE = (1 << 6), | ||
70 | }; | ||
71 | |||
72 | /* Timeout in ms. */ | ||
73 | #define CY_WATCHDOG_TIMEOUT 1000 | ||
74 | |||
75 | #define CY_MAX_PRINT_SIZE 512 | ||
76 | #ifdef VERBOSE_DEBUG | ||
77 | #define CY_MAX_PRBUF_SIZE PIPE_BUF | ||
78 | #define CY_PR_TRUNCATED " truncated..." | ||
79 | #endif | ||
80 | |||
81 | enum cyttsp4_ic_grpnum { | ||
82 | CY_IC_GRPNUM_RESERVED, | ||
83 | CY_IC_GRPNUM_CMD_REGS, | ||
84 | CY_IC_GRPNUM_TCH_REP, | ||
85 | CY_IC_GRPNUM_DATA_REC, | ||
86 | CY_IC_GRPNUM_TEST_REC, | ||
87 | CY_IC_GRPNUM_PCFG_REC, | ||
88 | CY_IC_GRPNUM_TCH_PARM_VAL, | ||
89 | CY_IC_GRPNUM_TCH_PARM_SIZE, | ||
90 | CY_IC_GRPNUM_RESERVED1, | ||
91 | CY_IC_GRPNUM_RESERVED2, | ||
92 | CY_IC_GRPNUM_OPCFG_REC, | ||
93 | CY_IC_GRPNUM_DDATA_REC, | ||
94 | CY_IC_GRPNUM_MDATA_REC, | ||
95 | CY_IC_GRPNUM_TEST_REGS, | ||
96 | CY_IC_GRPNUM_BTN_KEYS, | ||
97 | CY_IC_GRPNUM_TTHE_REGS, | ||
98 | CY_IC_GRPNUM_NUM | ||
99 | }; | ||
100 | |||
101 | enum cyttsp4_int_state { | ||
102 | CY_INT_NONE, | ||
103 | CY_INT_IGNORE = (1 << 0), | ||
104 | CY_INT_MODE_CHANGE = (1 << 1), | ||
105 | CY_INT_EXEC_CMD = (1 << 2), | ||
106 | CY_INT_AWAKE = (1 << 3), | ||
107 | }; | ||
108 | |||
109 | enum cyttsp4_mode { | ||
110 | CY_MODE_UNKNOWN, | ||
111 | CY_MODE_BOOTLOADER = (1 << 1), | ||
112 | CY_MODE_OPERATIONAL = (1 << 2), | ||
113 | CY_MODE_SYSINFO = (1 << 3), | ||
114 | CY_MODE_CAT = (1 << 4), | ||
115 | CY_MODE_STARTUP = (1 << 5), | ||
116 | CY_MODE_LOADER = (1 << 6), | ||
117 | CY_MODE_CHANGE_MODE = (1 << 7), | ||
118 | CY_MODE_CHANGED = (1 << 8), | ||
119 | CY_MODE_CMD_COMPLETE = (1 << 9), | ||
120 | }; | ||
121 | |||
122 | enum cyttsp4_sleep_state { | ||
123 | SS_SLEEP_OFF, | ||
124 | SS_SLEEP_ON, | ||
125 | SS_SLEEPING, | ||
126 | SS_WAKING, | ||
127 | }; | ||
128 | |||
129 | enum cyttsp4_startup_state { | ||
130 | STARTUP_NONE, | ||
131 | STARTUP_QUEUED, | ||
132 | STARTUP_RUNNING, | ||
133 | }; | ||
134 | |||
135 | #define CY_NUM_REVCTRL 8 | ||
136 | struct cyttsp4_cydata { | ||
137 | u8 ttpidh; | ||
138 | u8 ttpidl; | ||
139 | u8 fw_ver_major; | ||
140 | u8 fw_ver_minor; | ||
141 | u8 revctrl[CY_NUM_REVCTRL]; | ||
142 | u8 blver_major; | ||
143 | u8 blver_minor; | ||
144 | u8 jtag_si_id3; | ||
145 | u8 jtag_si_id2; | ||
146 | u8 jtag_si_id1; | ||
147 | u8 jtag_si_id0; | ||
148 | u8 mfgid_sz; | ||
149 | u8 cyito_idh; | ||
150 | u8 cyito_idl; | ||
151 | u8 cyito_verh; | ||
152 | u8 cyito_verl; | ||
153 | u8 ttsp_ver_major; | ||
154 | u8 ttsp_ver_minor; | ||
155 | u8 device_info; | ||
156 | u8 mfg_id[]; | ||
157 | } __packed; | ||
158 | |||
159 | struct cyttsp4_test { | ||
160 | u8 post_codeh; | ||
161 | u8 post_codel; | ||
162 | } __packed; | ||
163 | |||
164 | struct cyttsp4_pcfg { | ||
165 | u8 electrodes_x; | ||
166 | u8 electrodes_y; | ||
167 | u8 len_xh; | ||
168 | u8 len_xl; | ||
169 | u8 len_yh; | ||
170 | u8 len_yl; | ||
171 | u8 res_xh; | ||
172 | u8 res_xl; | ||
173 | u8 res_yh; | ||
174 | u8 res_yl; | ||
175 | u8 max_zh; | ||
176 | u8 max_zl; | ||
177 | u8 panel_info0; | ||
178 | } __packed; | ||
179 | |||
180 | struct cyttsp4_tch_rec_params { | ||
181 | u8 loc; | ||
182 | u8 size; | ||
183 | } __packed; | ||
184 | |||
185 | #define CY_NUM_TCH_FIELDS 7 | ||
186 | #define CY_NUM_EXT_TCH_FIELDS 3 | ||
187 | struct cyttsp4_opcfg { | ||
188 | u8 cmd_ofs; | ||
189 | u8 rep_ofs; | ||
190 | u8 rep_szh; | ||
191 | u8 rep_szl; | ||
192 | u8 num_btns; | ||
193 | u8 tt_stat_ofs; | ||
194 | u8 obj_cfg0; | ||
195 | u8 max_tchs; | ||
196 | u8 tch_rec_size; | ||
197 | struct cyttsp4_tch_rec_params tch_rec_old[CY_NUM_TCH_FIELDS]; | ||
198 | u8 btn_rec_size; /* btn record size (in bytes) */ | ||
199 | u8 btn_diff_ofs; /* btn data loc, diff counts */ | ||
200 | u8 btn_diff_size; /* btn size of diff counts (in bits) */ | ||
201 | struct cyttsp4_tch_rec_params tch_rec_new[CY_NUM_EXT_TCH_FIELDS]; | ||
202 | } __packed; | ||
203 | |||
204 | struct cyttsp4_sysinfo_ptr { | ||
205 | struct cyttsp4_cydata *cydata; | ||
206 | struct cyttsp4_test *test; | ||
207 | struct cyttsp4_pcfg *pcfg; | ||
208 | struct cyttsp4_opcfg *opcfg; | ||
209 | struct cyttsp4_ddata *ddata; | ||
210 | struct cyttsp4_mdata *mdata; | ||
211 | } __packed; | ||
212 | |||
213 | struct cyttsp4_sysinfo_data { | ||
214 | u8 hst_mode; | ||
215 | u8 reserved; | ||
216 | u8 map_szh; | ||
217 | u8 map_szl; | ||
218 | u8 cydata_ofsh; | ||
219 | u8 cydata_ofsl; | ||
220 | u8 test_ofsh; | ||
221 | u8 test_ofsl; | ||
222 | u8 pcfg_ofsh; | ||
223 | u8 pcfg_ofsl; | ||
224 | u8 opcfg_ofsh; | ||
225 | u8 opcfg_ofsl; | ||
226 | u8 ddata_ofsh; | ||
227 | u8 ddata_ofsl; | ||
228 | u8 mdata_ofsh; | ||
229 | u8 mdata_ofsl; | ||
230 | } __packed; | ||
231 | |||
232 | enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */ | ||
233 | CY_TCH_X, /* X */ | ||
234 | CY_TCH_Y, /* Y */ | ||
235 | CY_TCH_P, /* P (Z) */ | ||
236 | CY_TCH_T, /* TOUCH ID */ | ||
237 | CY_TCH_E, /* EVENT ID */ | ||
238 | CY_TCH_O, /* OBJECT ID */ | ||
239 | CY_TCH_W, /* SIZE */ | ||
240 | CY_TCH_MAJ, /* TOUCH_MAJOR */ | ||
241 | CY_TCH_MIN, /* TOUCH_MINOR */ | ||
242 | CY_TCH_OR, /* ORIENTATION */ | ||
243 | CY_TCH_NUM_ABS | ||
244 | }; | ||
245 | |||
246 | static const char * const cyttsp4_tch_abs_string[] = { | ||
247 | [CY_TCH_X] = "X", | ||
248 | [CY_TCH_Y] = "Y", | ||
249 | [CY_TCH_P] = "P", | ||
250 | [CY_TCH_T] = "T", | ||
251 | [CY_TCH_E] = "E", | ||
252 | [CY_TCH_O] = "O", | ||
253 | [CY_TCH_W] = "W", | ||
254 | [CY_TCH_MAJ] = "MAJ", | ||
255 | [CY_TCH_MIN] = "MIN", | ||
256 | [CY_TCH_OR] = "OR", | ||
257 | [CY_TCH_NUM_ABS] = "INVALID" | ||
258 | }; | ||
259 | |||
260 | struct cyttsp4_touch { | ||
261 | int abs[CY_TCH_NUM_ABS]; | ||
262 | }; | ||
263 | |||
264 | struct cyttsp4_tch_abs_params { | ||
265 | size_t ofs; /* abs byte offset */ | ||
266 | size_t size; /* size in bits */ | ||
267 | size_t max; /* max value */ | ||
268 | size_t bofs; /* bit offset */ | ||
269 | }; | ||
270 | |||
271 | struct cyttsp4_sysinfo_ofs { | ||
272 | size_t chip_type; | ||
273 | size_t cmd_ofs; | ||
274 | size_t rep_ofs; | ||
275 | size_t rep_sz; | ||
276 | size_t num_btns; | ||
277 | size_t num_btn_regs; /* ceil(num_btns/4) */ | ||
278 | size_t tt_stat_ofs; | ||
279 | size_t tch_rec_size; | ||
280 | size_t obj_cfg0; | ||
281 | size_t max_tchs; | ||
282 | size_t mode_size; | ||
283 | size_t data_size; | ||
284 | size_t map_sz; | ||
285 | size_t max_x; | ||
286 | size_t x_origin; /* left or right corner */ | ||
287 | size_t max_y; | ||
288 | size_t y_origin; /* upper or lower corner */ | ||
289 | size_t max_p; | ||
290 | size_t cydata_ofs; | ||
291 | size_t test_ofs; | ||
292 | size_t pcfg_ofs; | ||
293 | size_t opcfg_ofs; | ||
294 | size_t ddata_ofs; | ||
295 | size_t mdata_ofs; | ||
296 | size_t cydata_size; | ||
297 | size_t test_size; | ||
298 | size_t pcfg_size; | ||
299 | size_t opcfg_size; | ||
300 | size_t ddata_size; | ||
301 | size_t mdata_size; | ||
302 | size_t btn_keys_size; | ||
303 | struct cyttsp4_tch_abs_params tch_abs[CY_TCH_NUM_ABS]; | ||
304 | size_t btn_rec_size; /* btn record size (in bytes) */ | ||
305 | size_t btn_diff_ofs;/* btn data loc ,diff counts, (Op-Mode byte ofs) */ | ||
306 | size_t btn_diff_size;/* btn size of diff counts (in bits) */ | ||
307 | }; | ||
308 | |||
309 | enum cyttsp4_btn_state { | ||
310 | CY_BTN_RELEASED, | ||
311 | CY_BTN_PRESSED, | ||
312 | CY_BTN_NUM_STATE | ||
313 | }; | ||
314 | |||
315 | struct cyttsp4_btn { | ||
316 | bool enabled; | ||
317 | int state; /* CY_BTN_PRESSED, CY_BTN_RELEASED */ | ||
318 | int key_code; | ||
319 | }; | ||
320 | |||
321 | struct cyttsp4_sysinfo { | ||
322 | bool ready; | ||
323 | struct cyttsp4_sysinfo_data si_data; | ||
324 | struct cyttsp4_sysinfo_ptr si_ptrs; | ||
325 | struct cyttsp4_sysinfo_ofs si_ofs; | ||
326 | struct cyttsp4_btn *btn; /* button states */ | ||
327 | u8 *btn_rec_data; /* button diff count data */ | ||
328 | u8 *xy_mode; /* operational mode and status regs */ | ||
329 | u8 *xy_data; /* operational touch regs */ | ||
330 | }; | ||
331 | |||
332 | struct cyttsp4_mt_data { | ||
333 | struct cyttsp4_mt_platform_data *pdata; | ||
334 | struct cyttsp4_sysinfo *si; | ||
335 | struct input_dev *input; | ||
336 | struct mutex report_lock; | ||
337 | bool is_suspended; | ||
338 | char phys[NAME_MAX]; | ||
339 | int num_prv_tch; | ||
340 | }; | ||
341 | |||
342 | struct cyttsp4 { | ||
343 | struct device *dev; | ||
344 | struct mutex system_lock; | ||
345 | struct mutex adap_lock; | ||
346 | enum cyttsp4_mode mode; | ||
347 | enum cyttsp4_sleep_state sleep_state; | ||
348 | enum cyttsp4_startup_state startup_state; | ||
349 | int int_status; | ||
350 | wait_queue_head_t wait_q; | ||
351 | int irq; | ||
352 | struct work_struct startup_work; | ||
353 | struct work_struct watchdog_work; | ||
354 | struct timer_list watchdog_timer; | ||
355 | struct cyttsp4_sysinfo sysinfo; | ||
356 | void *exclusive_dev; | ||
357 | int exclusive_waits; | ||
358 | atomic_t ignore_irq; | ||
359 | bool invalid_touch_app; | ||
360 | struct cyttsp4_mt_data md; | ||
361 | struct cyttsp4_platform_data *pdata; | ||
362 | struct cyttsp4_core_platform_data *cpdata; | ||
363 | const struct cyttsp4_bus_ops *bus_ops; | ||
364 | u8 *xfer_buf; | ||
365 | #ifdef VERBOSE_DEBUG | ||
366 | u8 pr_buf[CY_MAX_PRBUF_SIZE]; | ||
367 | #endif | ||
368 | }; | ||
369 | |||
370 | struct cyttsp4_bus_ops { | ||
371 | u16 bustype; | ||
372 | int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, | ||
373 | const void *values); | ||
374 | int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, | ||
375 | void *values); | ||
376 | }; | ||
377 | |||
378 | enum cyttsp4_hst_mode_bits { | ||
379 | CY_HST_TOGGLE = (1 << 7), | ||
380 | CY_HST_MODE_CHANGE = (1 << 3), | ||
381 | CY_HST_MODE = (7 << 4), | ||
382 | CY_HST_OPERATE = (0 << 4), | ||
383 | CY_HST_SYSINFO = (1 << 4), | ||
384 | CY_HST_CAT = (2 << 4), | ||
385 | CY_HST_LOWPOW = (1 << 2), | ||
386 | CY_HST_SLEEP = (1 << 1), | ||
387 | CY_HST_RESET = (1 << 0), | ||
388 | }; | ||
389 | |||
390 | /* abs settings */ | ||
391 | #define CY_IGNORE_VALUE 0xFFFF | ||
392 | |||
393 | /* abs signal capabilities offsets in the frameworks array */ | ||
394 | enum cyttsp4_sig_caps { | ||
395 | CY_SIGNAL_OST, | ||
396 | CY_MIN_OST, | ||
397 | CY_MAX_OST, | ||
398 | CY_FUZZ_OST, | ||
399 | CY_FLAT_OST, | ||
400 | CY_NUM_ABS_SET /* number of signal capability fields */ | ||
401 | }; | ||
402 | |||
403 | /* abs axis signal offsets in the framworks array */ | ||
404 | enum cyttsp4_sig_ost { | ||
405 | CY_ABS_X_OST, | ||
406 | CY_ABS_Y_OST, | ||
407 | CY_ABS_P_OST, | ||
408 | CY_ABS_W_OST, | ||
409 | CY_ABS_ID_OST, | ||
410 | CY_ABS_MAJ_OST, | ||
411 | CY_ABS_MIN_OST, | ||
412 | CY_ABS_OR_OST, | ||
413 | CY_NUM_ABS_OST /* number of abs signals */ | ||
414 | }; | ||
415 | |||
416 | enum cyttsp4_flags { | ||
417 | CY_FLAG_NONE = 0x00, | ||
418 | CY_FLAG_HOVER = 0x04, | ||
419 | CY_FLAG_FLIP = 0x08, | ||
420 | CY_FLAG_INV_X = 0x10, | ||
421 | CY_FLAG_INV_Y = 0x20, | ||
422 | CY_FLAG_VKEYS = 0x40, | ||
423 | }; | ||
424 | |||
425 | enum cyttsp4_object_id { | ||
426 | CY_OBJ_STANDARD_FINGER, | ||
427 | CY_OBJ_LARGE_OBJECT, | ||
428 | CY_OBJ_STYLUS, | ||
429 | CY_OBJ_HOVER, | ||
430 | }; | ||
431 | |||
432 | enum cyttsp4_event_id { | ||
433 | CY_EV_NO_EVENT, | ||
434 | CY_EV_TOUCHDOWN, | ||
435 | CY_EV_MOVE, /* significant displacement (> act dist) */ | ||
436 | CY_EV_LIFTOFF, /* record reports last position */ | ||
437 | }; | ||
438 | |||
439 | /* x-axis resolution of panel in pixels */ | ||
440 | #define CY_PCFG_RESOLUTION_X_MASK 0x7F | ||
441 | |||
442 | /* y-axis resolution of panel in pixels */ | ||
443 | #define CY_PCFG_RESOLUTION_Y_MASK 0x7F | ||
444 | |||
445 | /* x-axis, 0:origin is on left side of panel, 1: right */ | ||
446 | #define CY_PCFG_ORIGIN_X_MASK 0x80 | ||
447 | |||
448 | /* y-axis, 0:origin is on top side of panel, 1: bottom */ | ||
449 | #define CY_PCFG_ORIGIN_Y_MASK 0x80 | ||
450 | |||
451 | static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u8 addr, int size, | ||
452 | void *buf) | ||
453 | { | ||
454 | return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf); | ||
455 | } | ||
456 | |||
457 | static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size, | ||
458 | const void *buf) | ||
459 | { | ||
460 | return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf); | ||
461 | } | ||
462 | |||
463 | extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops, | ||
464 | struct device *dev, u16 irq, size_t xfer_buf_size); | ||
465 | extern int cyttsp4_remove(struct cyttsp4 *ts); | ||
466 | int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
467 | u8 length, const void *values); | ||
468 | int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
469 | u8 length, void *values); | ||
470 | extern const struct dev_pm_ops cyttsp4_pm_ops; | ||
471 | |||
472 | #endif /* _LINUX_CYTTSP4_CORE_H */ | ||
diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c new file mode 100644 index 000000000000..8e2012c79058 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_i2c.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * cyttsp_i2c.c | ||
3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. | ||
4 | * For use with Cypress Txx4xx parts. | ||
5 | * Supported parts include: | ||
6 | * TMA4XX | ||
7 | * TMA1036 | ||
8 | * | ||
9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
11 | * Copyright (C) 2013 Cypress Semiconductor | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * version 2, and only version 2, as published by the | ||
16 | * Free Software Foundation. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include "cyttsp4_core.h" | ||
28 | |||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/input.h> | ||
31 | |||
32 | #define CYTTSP4_I2C_DATA_SIZE (3 * 256) | ||
33 | |||
34 | static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = { | ||
35 | .bustype = BUS_I2C, | ||
36 | .write = cyttsp_i2c_write_block_data, | ||
37 | .read = cyttsp_i2c_read_block_data, | ||
38 | }; | ||
39 | |||
40 | static int cyttsp4_i2c_probe(struct i2c_client *client, | ||
41 | const struct i2c_device_id *id) | ||
42 | { | ||
43 | struct cyttsp4 *ts; | ||
44 | |||
45 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
46 | dev_err(&client->dev, "I2C functionality not Supported\n"); | ||
47 | return -EIO; | ||
48 | } | ||
49 | |||
50 | ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq, | ||
51 | CYTTSP4_I2C_DATA_SIZE); | ||
52 | |||
53 | if (IS_ERR(ts)) | ||
54 | return PTR_ERR(ts); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int cyttsp4_i2c_remove(struct i2c_client *client) | ||
60 | { | ||
61 | struct cyttsp4 *ts = i2c_get_clientdata(client); | ||
62 | |||
63 | cyttsp4_remove(ts); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static const struct i2c_device_id cyttsp4_i2c_id[] = { | ||
69 | { CYTTSP4_I2C_NAME, 0 }, | ||
70 | { } | ||
71 | }; | ||
72 | MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id); | ||
73 | |||
74 | static struct i2c_driver cyttsp4_i2c_driver = { | ||
75 | .driver = { | ||
76 | .name = CYTTSP4_I2C_NAME, | ||
77 | .owner = THIS_MODULE, | ||
78 | .pm = &cyttsp4_pm_ops, | ||
79 | }, | ||
80 | .probe = cyttsp4_i2c_probe, | ||
81 | .remove = cyttsp4_i2c_remove, | ||
82 | .id_table = cyttsp4_i2c_id, | ||
83 | }; | ||
84 | |||
85 | module_i2c_driver(cyttsp4_i2c_driver); | ||
86 | |||
87 | MODULE_LICENSE("GPL"); | ||
88 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"); | ||
89 | MODULE_AUTHOR("Cypress"); | ||
90 | MODULE_ALIAS("i2c:cyttsp4"); | ||
diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c new file mode 100644 index 000000000000..f8f891bead34 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_spi.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * Source for: | ||
3 | * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver. | ||
4 | * For use with Cypress Txx4xx parts. | ||
5 | * Supported parts include: | ||
6 | * TMA4XX | ||
7 | * TMA1036 | ||
8 | * | ||
9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
11 | * Copyright (C) 2013 Cypress Semiconductor | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * version 2, and only version 2, as published by the | ||
16 | * Free Software Foundation. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include "cyttsp4_core.h" | ||
28 | |||
29 | #include <linux/delay.h> | ||
30 | #include <linux/input.h> | ||
31 | #include <linux/spi/spi.h> | ||
32 | |||
33 | #define CY_SPI_WR_OP 0x00 /* r/~w */ | ||
34 | #define CY_SPI_RD_OP 0x01 | ||
35 | #define CY_SPI_BITS_PER_WORD 8 | ||
36 | #define CY_SPI_A8_BIT 0x02 | ||
37 | #define CY_SPI_WR_HEADER_BYTES 2 | ||
38 | #define CY_SPI_RD_HEADER_BYTES 1 | ||
39 | #define CY_SPI_CMD_BYTES 2 | ||
40 | #define CY_SPI_SYNC_BYTE 0 | ||
41 | #define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */ | ||
42 | #define CY_SPI_DATA_SIZE (2 * 256) | ||
43 | |||
44 | #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) | ||
45 | |||
46 | static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, | ||
47 | u8 op, u8 reg, u8 *buf, int length) | ||
48 | { | ||
49 | struct spi_device *spi = to_spi_device(dev); | ||
50 | struct spi_message msg; | ||
51 | struct spi_transfer xfer[2]; | ||
52 | u8 *wr_buf = &xfer_buf[0]; | ||
53 | u8 rd_buf[CY_SPI_CMD_BYTES]; | ||
54 | int retval; | ||
55 | int i; | ||
56 | |||
57 | if (length > CY_SPI_DATA_SIZE) { | ||
58 | dev_err(dev, "%s: length %d is too big.\n", | ||
59 | __func__, length); | ||
60 | return -EINVAL; | ||
61 | } | ||
62 | |||
63 | memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE); | ||
64 | memset(rd_buf, 0, CY_SPI_CMD_BYTES); | ||
65 | |||
66 | if (reg > 255) | ||
67 | wr_buf[0] = op + CY_SPI_A8_BIT; | ||
68 | else | ||
69 | wr_buf[0] = op; | ||
70 | if (op == CY_SPI_WR_OP) | ||
71 | wr_buf[1] = reg % 256; | ||
72 | if (op == CY_SPI_WR_OP && length > 0) | ||
73 | memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); | ||
74 | |||
75 | memset(xfer, 0, sizeof(xfer)); | ||
76 | spi_message_init(&msg); | ||
77 | |||
78 | /* | ||
79 | We set both TX and RX buffers because Cypress TTSP | ||
80 | requires full duplex operation. | ||
81 | */ | ||
82 | xfer[0].tx_buf = wr_buf; | ||
83 | xfer[0].rx_buf = rd_buf; | ||
84 | switch (op) { | ||
85 | case CY_SPI_WR_OP: | ||
86 | xfer[0].len = length + CY_SPI_CMD_BYTES; | ||
87 | spi_message_add_tail(&xfer[0], &msg); | ||
88 | break; | ||
89 | |||
90 | case CY_SPI_RD_OP: | ||
91 | xfer[0].len = CY_SPI_RD_HEADER_BYTES; | ||
92 | spi_message_add_tail(&xfer[0], &msg); | ||
93 | |||
94 | xfer[1].rx_buf = buf; | ||
95 | xfer[1].len = length; | ||
96 | spi_message_add_tail(&xfer[1], &msg); | ||
97 | break; | ||
98 | |||
99 | default: | ||
100 | dev_err(dev, "%s: bad operation code=%d\n", __func__, op); | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | retval = spi_sync(spi, &msg); | ||
105 | if (retval < 0) { | ||
106 | dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n", | ||
107 | __func__, retval, xfer[1].len, op); | ||
108 | |||
109 | /* | ||
110 | * do not return here since was a bad ACK sequence | ||
111 | * let the following ACK check handle any errors and | ||
112 | * allow silent retries | ||
113 | */ | ||
114 | } | ||
115 | |||
116 | if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) { | ||
117 | dev_dbg(dev, "%s: operation %d failed\n", __func__, op); | ||
118 | |||
119 | for (i = 0; i < CY_SPI_CMD_BYTES; i++) | ||
120 | dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n", | ||
121 | __func__, i, rd_buf[i]); | ||
122 | for (i = 0; i < length; i++) | ||
123 | dev_dbg(dev, "%s: test buf[%d]:0x%02x\n", | ||
124 | __func__, i, buf[i]); | ||
125 | |||
126 | return -EIO; | ||
127 | } | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf, | ||
133 | u8 addr, u8 length, void *data) | ||
134 | { | ||
135 | int rc; | ||
136 | |||
137 | rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0); | ||
138 | if (rc) | ||
139 | return rc; | ||
140 | else | ||
141 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data, | ||
142 | length); | ||
143 | } | ||
144 | |||
145 | static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf, | ||
146 | u8 addr, u8 length, const void *data) | ||
147 | { | ||
148 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data, | ||
149 | length); | ||
150 | } | ||
151 | |||
152 | static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = { | ||
153 | .bustype = BUS_SPI, | ||
154 | .write = cyttsp_spi_write_block_data, | ||
155 | .read = cyttsp_spi_read_block_data, | ||
156 | }; | ||
157 | |||
158 | static int cyttsp4_spi_probe(struct spi_device *spi) | ||
159 | { | ||
160 | struct cyttsp4 *ts; | ||
161 | int error; | ||
162 | |||
163 | /* Set up SPI*/ | ||
164 | spi->bits_per_word = CY_SPI_BITS_PER_WORD; | ||
165 | spi->mode = SPI_MODE_0; | ||
166 | error = spi_setup(spi); | ||
167 | if (error < 0) { | ||
168 | dev_err(&spi->dev, "%s: SPI setup error %d\n", | ||
169 | __func__, error); | ||
170 | return error; | ||
171 | } | ||
172 | |||
173 | ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq, | ||
174 | CY_SPI_DATA_BUF_SIZE); | ||
175 | |||
176 | if (IS_ERR(ts)) | ||
177 | return PTR_ERR(ts); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int cyttsp4_spi_remove(struct spi_device *spi) | ||
183 | { | ||
184 | struct cyttsp4 *ts = spi_get_drvdata(spi); | ||
185 | cyttsp4_remove(ts); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static struct spi_driver cyttsp4_spi_driver = { | ||
191 | .driver = { | ||
192 | .name = CYTTSP4_SPI_NAME, | ||
193 | .owner = THIS_MODULE, | ||
194 | .pm = &cyttsp4_pm_ops, | ||
195 | }, | ||
196 | .probe = cyttsp4_spi_probe, | ||
197 | .remove = cyttsp4_spi_remove, | ||
198 | }; | ||
199 | |||
200 | module_spi_driver(cyttsp4_spi_driver); | ||
201 | |||
202 | MODULE_LICENSE("GPL"); | ||
203 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver"); | ||
204 | MODULE_AUTHOR("Cypress"); | ||
205 | MODULE_ALIAS("spi:cyttsp4"); | ||
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index ae89d2609ab0..d53e0b72a407 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c | |||
@@ -84,7 +84,8 @@ static int ttsp_read_block_data(struct cyttsp *ts, u8 command, | |||
84 | int tries; | 84 | int tries; |
85 | 85 | ||
86 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { | 86 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { |
87 | error = ts->bus_ops->read(ts, command, length, buf); | 87 | error = ts->bus_ops->read(ts->dev, ts->xfer_buf, command, |
88 | length, buf); | ||
88 | if (!error) | 89 | if (!error) |
89 | return 0; | 90 | return 0; |
90 | 91 | ||
@@ -101,7 +102,8 @@ static int ttsp_write_block_data(struct cyttsp *ts, u8 command, | |||
101 | int tries; | 102 | int tries; |
102 | 103 | ||
103 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { | 104 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { |
104 | error = ts->bus_ops->write(ts, command, length, buf); | 105 | error = ts->bus_ops->write(ts->dev, ts->xfer_buf, command, |
106 | length, buf); | ||
105 | if (!error) | 107 | if (!error) |
106 | return 0; | 108 | return 0; |
107 | 109 | ||
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h index f1ebde369f86..0cf564a79fb5 100644 --- a/drivers/input/touchscreen/cyttsp_core.h +++ b/drivers/input/touchscreen/cyttsp_core.h | |||
@@ -112,9 +112,10 @@ struct cyttsp; | |||
112 | 112 | ||
113 | struct cyttsp_bus_ops { | 113 | struct cyttsp_bus_ops { |
114 | u16 bustype; | 114 | u16 bustype; |
115 | int (*write)(struct cyttsp *ts, | 115 | int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, |
116 | u8 addr, u8 length, const void *values); | 116 | const void *values); |
117 | int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values); | 117 | int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, |
118 | void *values); | ||
118 | }; | 119 | }; |
119 | 120 | ||
120 | enum cyttsp_state { | 121 | enum cyttsp_state { |
@@ -144,6 +145,10 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, | |||
144 | struct device *dev, int irq, size_t xfer_buf_size); | 145 | struct device *dev, int irq, size_t xfer_buf_size); |
145 | void cyttsp_remove(struct cyttsp *ts); | 146 | void cyttsp_remove(struct cyttsp *ts); |
146 | 147 | ||
148 | int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
149 | u8 length, const void *values); | ||
150 | int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
151 | u8 length, void *values); | ||
147 | extern const struct dev_pm_ops cyttsp_pm_ops; | 152 | extern const struct dev_pm_ops cyttsp_pm_ops; |
148 | 153 | ||
149 | #endif /* __CYTTSP_CORE_H__ */ | 154 | #endif /* __CYTTSP_CORE_H__ */ |
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 4dbdf44b8fc5..63104a86a9bd 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Source for: | 2 | * cyttsp_i2c.c |
3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. | 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. |
4 | * For use with Cypress Txx3xx parts. | 4 | * For use with Cypress Txx3xx parts. |
5 | * Supported parts include: | 5 | * Supported parts include: |
@@ -19,11 +19,7 @@ | |||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License along | 22 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> |
23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
24 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
25 | * | ||
26 | * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> | ||
27 | * | 23 | * |
28 | */ | 24 | */ |
29 | 25 | ||
@@ -34,47 +30,6 @@ | |||
34 | 30 | ||
35 | #define CY_I2C_DATA_SIZE 128 | 31 | #define CY_I2C_DATA_SIZE 128 |
36 | 32 | ||
37 | static int cyttsp_i2c_read_block_data(struct cyttsp *ts, | ||
38 | u8 addr, u8 length, void *values) | ||
39 | { | ||
40 | struct i2c_client *client = to_i2c_client(ts->dev); | ||
41 | struct i2c_msg msgs[] = { | ||
42 | { | ||
43 | .addr = client->addr, | ||
44 | .flags = 0, | ||
45 | .len = 1, | ||
46 | .buf = &addr, | ||
47 | }, | ||
48 | { | ||
49 | .addr = client->addr, | ||
50 | .flags = I2C_M_RD, | ||
51 | .len = length, | ||
52 | .buf = values, | ||
53 | }, | ||
54 | }; | ||
55 | int retval; | ||
56 | |||
57 | retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
58 | if (retval < 0) | ||
59 | return retval; | ||
60 | |||
61 | return retval != ARRAY_SIZE(msgs) ? -EIO : 0; | ||
62 | } | ||
63 | |||
64 | static int cyttsp_i2c_write_block_data(struct cyttsp *ts, | ||
65 | u8 addr, u8 length, const void *values) | ||
66 | { | ||
67 | struct i2c_client *client = to_i2c_client(ts->dev); | ||
68 | int retval; | ||
69 | |||
70 | ts->xfer_buf[0] = addr; | ||
71 | memcpy(&ts->xfer_buf[1], values, length); | ||
72 | |||
73 | retval = i2c_master_send(client, ts->xfer_buf, length + 1); | ||
74 | |||
75 | return retval < 0 ? retval : 0; | ||
76 | } | ||
77 | |||
78 | static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { | 33 | static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { |
79 | .bustype = BUS_I2C, | 34 | .bustype = BUS_I2C, |
80 | .write = cyttsp_i2c_write_block_data, | 35 | .write = cyttsp_i2c_write_block_data, |
@@ -98,7 +53,6 @@ static int cyttsp_i2c_probe(struct i2c_client *client, | |||
98 | return PTR_ERR(ts); | 53 | return PTR_ERR(ts); |
99 | 54 | ||
100 | i2c_set_clientdata(client, ts); | 55 | i2c_set_clientdata(client, ts); |
101 | |||
102 | return 0; | 56 | return 0; |
103 | } | 57 | } |
104 | 58 | ||
diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c new file mode 100644 index 000000000000..07c553fbcef2 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp_i2c_common.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * cyttsp_i2c_common.c | ||
3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. | ||
4 | * For use with Cypress Txx3xx and Txx4xx parts. | ||
5 | * Supported parts include: | ||
6 | * CY8CTST341 | ||
7 | * CY8CTMA340 | ||
8 | * TMA4XX | ||
9 | * TMA1036 | ||
10 | * | ||
11 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
12 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * version 2, and only version 2, as published by the | ||
17 | * Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/device.h> | ||
29 | #include <linux/export.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/types.h> | ||
33 | |||
34 | int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, | ||
35 | u8 addr, u8 length, void *values) | ||
36 | { | ||
37 | struct i2c_client *client = to_i2c_client(dev); | ||
38 | struct i2c_msg msgs[] = { | ||
39 | { | ||
40 | .addr = client->addr, | ||
41 | .flags = 0, | ||
42 | .len = 1, | ||
43 | .buf = &addr, | ||
44 | }, | ||
45 | { | ||
46 | .addr = client->addr, | ||
47 | .flags = I2C_M_RD, | ||
48 | .len = length, | ||
49 | .buf = values, | ||
50 | }, | ||
51 | }; | ||
52 | int retval; | ||
53 | |||
54 | retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
55 | if (retval < 0) | ||
56 | return retval; | ||
57 | |||
58 | return retval != ARRAY_SIZE(msgs) ? -EIO : 0; | ||
59 | } | ||
60 | EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data); | ||
61 | |||
62 | int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, | ||
63 | u8 addr, u8 length, const void *values) | ||
64 | { | ||
65 | struct i2c_client *client = to_i2c_client(dev); | ||
66 | int retval; | ||
67 | |||
68 | xfer_buf[0] = addr; | ||
69 | memcpy(&xfer_buf[1], values, length); | ||
70 | |||
71 | retval = i2c_master_send(client, xfer_buf, length + 1); | ||
72 | |||
73 | return retval < 0 ? retval : 0; | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data); | ||
76 | |||
77 | |||
78 | MODULE_LICENSE("GPL"); | ||
79 | MODULE_AUTHOR("Cypress"); | ||
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c index 861b7f77605b..1df625337b84 100644 --- a/drivers/input/touchscreen/cyttsp_spi.c +++ b/drivers/input/touchscreen/cyttsp_spi.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * | 8 | * |
9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. |
10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> |
11 | * Copyright (C) 2013 Cypress Semiconductor | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
@@ -19,11 +20,7 @@ | |||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
21 | * | 22 | * |
22 | * You should have received a copy of the GNU General Public License along | 23 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> |
23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
24 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
25 | * | ||
26 | * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> | ||
27 | * | 24 | * |
28 | */ | 25 | */ |
29 | 26 | ||
@@ -43,19 +40,19 @@ | |||
43 | #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) | 40 | #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) |
44 | #define CY_SPI_BITS_PER_WORD 8 | 41 | #define CY_SPI_BITS_PER_WORD 8 |
45 | 42 | ||
46 | static int cyttsp_spi_xfer(struct cyttsp *ts, | 43 | static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, |
47 | u8 op, u8 reg, u8 *buf, int length) | 44 | u8 op, u8 reg, u8 *buf, int length) |
48 | { | 45 | { |
49 | struct spi_device *spi = to_spi_device(ts->dev); | 46 | struct spi_device *spi = to_spi_device(dev); |
50 | struct spi_message msg; | 47 | struct spi_message msg; |
51 | struct spi_transfer xfer[2]; | 48 | struct spi_transfer xfer[2]; |
52 | u8 *wr_buf = &ts->xfer_buf[0]; | 49 | u8 *wr_buf = &xfer_buf[0]; |
53 | u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE]; | 50 | u8 *rd_buf = &xfer_buf[CY_SPI_DATA_BUF_SIZE]; |
54 | int retval; | 51 | int retval; |
55 | int i; | 52 | int i; |
56 | 53 | ||
57 | if (length > CY_SPI_DATA_SIZE) { | 54 | if (length > CY_SPI_DATA_SIZE) { |
58 | dev_err(ts->dev, "%s: length %d is too big.\n", | 55 | dev_err(dev, "%s: length %d is too big.\n", |
59 | __func__, length); | 56 | __func__, length); |
60 | return -EINVAL; | 57 | return -EINVAL; |
61 | } | 58 | } |
@@ -95,13 +92,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts, | |||
95 | break; | 92 | break; |
96 | 93 | ||
97 | default: | 94 | default: |
98 | dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op); | 95 | dev_err(dev, "%s: bad operation code=%d\n", __func__, op); |
99 | return -EINVAL; | 96 | return -EINVAL; |
100 | } | 97 | } |
101 | 98 | ||
102 | retval = spi_sync(spi, &msg); | 99 | retval = spi_sync(spi, &msg); |
103 | if (retval < 0) { | 100 | if (retval < 0) { |
104 | dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n", | 101 | dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n", |
105 | __func__, retval, xfer[1].len, op); | 102 | __func__, retval, xfer[1].len, op); |
106 | 103 | ||
107 | /* | 104 | /* |
@@ -113,14 +110,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts, | |||
113 | 110 | ||
114 | if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 || | 111 | if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 || |
115 | rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) { | 112 | rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) { |
116 | 113 | dev_dbg(dev, "%s: operation %d failed\n", __func__, op); | |
117 | dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op); | ||
118 | 114 | ||
119 | for (i = 0; i < CY_SPI_CMD_BYTES; i++) | 115 | for (i = 0; i < CY_SPI_CMD_BYTES; i++) |
120 | dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n", | 116 | dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n", |
121 | __func__, i, rd_buf[i]); | 117 | __func__, i, rd_buf[i]); |
122 | for (i = 0; i < length; i++) | 118 | for (i = 0; i < length; i++) |
123 | dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n", | 119 | dev_dbg(dev, "%s: test buf[%d]:0x%02x\n", |
124 | __func__, i, buf[i]); | 120 | __func__, i, buf[i]); |
125 | 121 | ||
126 | return -EIO; | 122 | return -EIO; |
@@ -129,16 +125,18 @@ static int cyttsp_spi_xfer(struct cyttsp *ts, | |||
129 | return 0; | 125 | return 0; |
130 | } | 126 | } |
131 | 127 | ||
132 | static int cyttsp_spi_read_block_data(struct cyttsp *ts, | 128 | static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf, |
133 | u8 addr, u8 length, void *data) | 129 | u8 addr, u8 length, void *data) |
134 | { | 130 | { |
135 | return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length); | 131 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data, |
132 | length); | ||
136 | } | 133 | } |
137 | 134 | ||
138 | static int cyttsp_spi_write_block_data(struct cyttsp *ts, | 135 | static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf, |
139 | u8 addr, u8 length, const void *data) | 136 | u8 addr, u8 length, const void *data) |
140 | { | 137 | { |
141 | return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length); | 138 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data, |
139 | length); | ||
142 | } | 140 | } |
143 | 141 | ||
144 | static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = { | 142 | static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = { |
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index 8f561e22bdd4..ab64d58c3ac0 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c | |||
@@ -329,8 +329,6 @@ static int da9052_ts_remove(struct platform_device *pdev) | |||
329 | input_unregister_device(tsi->dev); | 329 | input_unregister_device(tsi->dev); |
330 | kfree(tsi); | 330 | kfree(tsi); |
331 | 331 | ||
332 | platform_set_drvdata(pdev, NULL); | ||
333 | |||
334 | return 0; | 332 | return 0; |
335 | } | 333 | } |
336 | 334 | ||
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 39f3df8670c3..ef5fcb0945e9 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c | |||
@@ -166,24 +166,22 @@ static int egalax_firmware_version(struct i2c_client *client) | |||
166 | } | 166 | } |
167 | 167 | ||
168 | static int egalax_ts_probe(struct i2c_client *client, | 168 | static int egalax_ts_probe(struct i2c_client *client, |
169 | const struct i2c_device_id *id) | 169 | const struct i2c_device_id *id) |
170 | { | 170 | { |
171 | struct egalax_ts *ts; | 171 | struct egalax_ts *ts; |
172 | struct input_dev *input_dev; | 172 | struct input_dev *input_dev; |
173 | int ret; | ||
174 | int error; | 173 | int error; |
175 | 174 | ||
176 | ts = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL); | 175 | ts = devm_kzalloc(&client->dev, sizeof(struct egalax_ts), GFP_KERNEL); |
177 | if (!ts) { | 176 | if (!ts) { |
178 | dev_err(&client->dev, "Failed to allocate memory\n"); | 177 | dev_err(&client->dev, "Failed to allocate memory\n"); |
179 | return -ENOMEM; | 178 | return -ENOMEM; |
180 | } | 179 | } |
181 | 180 | ||
182 | input_dev = input_allocate_device(); | 181 | input_dev = devm_input_allocate_device(&client->dev); |
183 | if (!input_dev) { | 182 | if (!input_dev) { |
184 | dev_err(&client->dev, "Failed to allocate memory\n"); | 183 | dev_err(&client->dev, "Failed to allocate memory\n"); |
185 | error = -ENOMEM; | 184 | return -ENOMEM; |
186 | goto err_free_ts; | ||
187 | } | 185 | } |
188 | 186 | ||
189 | ts->client = client; | 187 | ts->client = client; |
@@ -193,19 +191,17 @@ static int egalax_ts_probe(struct i2c_client *client, | |||
193 | error = egalax_wake_up_device(client); | 191 | error = egalax_wake_up_device(client); |
194 | if (error) { | 192 | if (error) { |
195 | dev_err(&client->dev, "Failed to wake up the controller\n"); | 193 | dev_err(&client->dev, "Failed to wake up the controller\n"); |
196 | goto err_free_dev; | 194 | return error; |
197 | } | 195 | } |
198 | 196 | ||
199 | ret = egalax_firmware_version(client); | 197 | error = egalax_firmware_version(client); |
200 | if (ret < 0) { | 198 | if (error < 0) { |
201 | dev_err(&client->dev, "Failed to read firmware version\n"); | 199 | dev_err(&client->dev, "Failed to read firmware version\n"); |
202 | error = -EIO; | 200 | return error; |
203 | goto err_free_dev; | ||
204 | } | 201 | } |
205 | 202 | ||
206 | input_dev->name = "EETI eGalax Touch Screen"; | 203 | input_dev->name = "EETI eGalax Touch Screen"; |
207 | input_dev->id.bustype = BUS_I2C; | 204 | input_dev->id.bustype = BUS_I2C; |
208 | input_dev->dev.parent = &client->dev; | ||
209 | 205 | ||
210 | __set_bit(EV_ABS, input_dev->evbit); | 206 | __set_bit(EV_ABS, input_dev->evbit); |
211 | __set_bit(EV_KEY, input_dev->evbit); | 207 | __set_bit(EV_KEY, input_dev->evbit); |
@@ -221,41 +217,21 @@ static int egalax_ts_probe(struct i2c_client *client, | |||
221 | 217 | ||
222 | input_set_drvdata(input_dev, ts); | 218 | input_set_drvdata(input_dev, ts); |
223 | 219 | ||
224 | error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt, | 220 | error = devm_request_threaded_irq(&client->dev, client->irq, NULL, |
225 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 221 | egalax_ts_interrupt, |
226 | "egalax_ts", ts); | 222 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
223 | "egalax_ts", ts); | ||
227 | if (error < 0) { | 224 | if (error < 0) { |
228 | dev_err(&client->dev, "Failed to register interrupt\n"); | 225 | dev_err(&client->dev, "Failed to register interrupt\n"); |
229 | goto err_free_dev; | 226 | return error; |
230 | } | 227 | } |
231 | 228 | ||
232 | error = input_register_device(ts->input_dev); | 229 | error = input_register_device(ts->input_dev); |
233 | if (error) | 230 | if (error) |
234 | goto err_free_irq; | 231 | return error; |
235 | 232 | ||
236 | i2c_set_clientdata(client, ts); | 233 | i2c_set_clientdata(client, ts); |
237 | return 0; | 234 | return 0; |
238 | |||
239 | err_free_irq: | ||
240 | free_irq(client->irq, ts); | ||
241 | err_free_dev: | ||
242 | input_free_device(input_dev); | ||
243 | err_free_ts: | ||
244 | kfree(ts); | ||
245 | |||
246 | return error; | ||
247 | } | ||
248 | |||
249 | static int egalax_ts_remove(struct i2c_client *client) | ||
250 | { | ||
251 | struct egalax_ts *ts = i2c_get_clientdata(client); | ||
252 | |||
253 | free_irq(client->irq, ts); | ||
254 | |||
255 | input_unregister_device(ts->input_dev); | ||
256 | kfree(ts); | ||
257 | |||
258 | return 0; | ||
259 | } | 235 | } |
260 | 236 | ||
261 | static const struct i2c_device_id egalax_ts_id[] = { | 237 | static const struct i2c_device_id egalax_ts_id[] = { |
@@ -301,7 +277,6 @@ static struct i2c_driver egalax_ts_driver = { | |||
301 | }, | 277 | }, |
302 | .id_table = egalax_ts_id, | 278 | .id_table = egalax_ts_id, |
303 | .probe = egalax_ts_probe, | 279 | .probe = egalax_ts_probe, |
304 | .remove = egalax_ts_remove, | ||
305 | }; | 280 | }; |
306 | 281 | ||
307 | module_i2c_driver(egalax_ts_driver); | 282 | module_i2c_driver(egalax_ts_driver); |
diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index 465db5dba8b4..e30d837dae2f 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c | |||
@@ -651,8 +651,6 @@ static int mrstouch_remove(struct platform_device *pdev) | |||
651 | input_unregister_device(tsdev->input); | 651 | input_unregister_device(tsdev->input); |
652 | kfree(tsdev); | 652 | kfree(tsdev); |
653 | 653 | ||
654 | platform_set_drvdata(pdev, NULL); | ||
655 | |||
656 | return 0; | 654 | return 0; |
657 | } | 655 | } |
658 | 656 | ||
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 282d7c7ad2fc..e463a79ffecc 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c | |||
@@ -145,7 +145,6 @@ static int jornada720_ts_probe(struct platform_device *pdev) | |||
145 | fail2: | 145 | fail2: |
146 | free_irq(IRQ_GPIO9, pdev); | 146 | free_irq(IRQ_GPIO9, pdev); |
147 | fail1: | 147 | fail1: |
148 | platform_set_drvdata(pdev, NULL); | ||
149 | input_free_device(input_dev); | 148 | input_free_device(input_dev); |
150 | kfree(jornada_ts); | 149 | kfree(jornada_ts); |
151 | return error; | 150 | return error; |
@@ -156,7 +155,6 @@ static int jornada720_ts_remove(struct platform_device *pdev) | |||
156 | struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); | 155 | struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); |
157 | 156 | ||
158 | free_irq(IRQ_GPIO9, pdev); | 157 | free_irq(IRQ_GPIO9, pdev); |
159 | platform_set_drvdata(pdev, NULL); | ||
160 | input_unregister_device(jornada_ts->dev); | 158 | input_unregister_device(jornada_ts->dev); |
161 | kfree(jornada_ts); | 159 | kfree(jornada_ts); |
162 | 160 | ||
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index 89308fe38752..d6f099c47f84 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c | |||
@@ -233,8 +233,6 @@ static int mc13783_ts_remove(struct platform_device *pdev) | |||
233 | { | 233 | { |
234 | struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); | 234 | struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); |
235 | 235 | ||
236 | platform_set_drvdata(pdev, NULL); | ||
237 | |||
238 | destroy_workqueue(priv->workq); | 236 | destroy_workqueue(priv->workq); |
239 | input_unregister_device(priv->idev); | 237 | input_unregister_device(priv->idev); |
240 | kfree(priv); | 238 | kfree(priv); |
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 51e7b87827a4..50fb1293874e 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
@@ -336,7 +336,6 @@ static int titsc_remove(struct platform_device *pdev) | |||
336 | 336 | ||
337 | input_unregister_device(ts_dev->input); | 337 | input_unregister_device(ts_dev->input); |
338 | 338 | ||
339 | platform_set_drvdata(pdev, NULL); | ||
340 | kfree(ts_dev); | 339 | kfree(ts_dev); |
341 | return 0; | 340 | return 0; |
342 | } | 341 | } |
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c index acfb87607b87..c47827a26e3c 100644 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ b/drivers/input/touchscreen/tnetv107x-ts.c | |||
@@ -351,7 +351,6 @@ error_clk: | |||
351 | error_map: | 351 | error_map: |
352 | release_mem_region(ts->res->start, resource_size(ts->res)); | 352 | release_mem_region(ts->res->start, resource_size(ts->res)); |
353 | error_res: | 353 | error_res: |
354 | platform_set_drvdata(pdev, NULL); | ||
355 | kfree(ts); | 354 | kfree(ts); |
356 | 355 | ||
357 | return error; | 356 | return error; |
@@ -366,7 +365,6 @@ static int tsc_remove(struct platform_device *pdev) | |||
366 | clk_put(ts->clk); | 365 | clk_put(ts->clk); |
367 | iounmap(ts->regs); | 366 | iounmap(ts->regs); |
368 | release_mem_region(ts->res->start, resource_size(ts->res)); | 367 | release_mem_region(ts->res->start, resource_size(ts->res)); |
369 | platform_set_drvdata(pdev, NULL); | ||
370 | kfree(ts); | 368 | kfree(ts); |
371 | 369 | ||
372 | return 0; | 370 | return 0; |
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index 820a066c3b8a..94cde2cb1491 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/workqueue.h> | 17 | #include <linux/workqueue.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/input.h> | 19 | #include <linux/input.h> |
20 | #include <linux/input-polldev.h> | ||
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | #include <linux/mfd/tps6507x.h> | 22 | #include <linux/mfd/tps6507x.h> |
22 | #include <linux/input/tps6507x-ts.h> | 23 | #include <linux/input/tps6507x-ts.h> |
@@ -38,20 +39,13 @@ struct ts_event { | |||
38 | }; | 39 | }; |
39 | 40 | ||
40 | struct tps6507x_ts { | 41 | struct tps6507x_ts { |
41 | struct input_dev *input_dev; | ||
42 | struct device *dev; | 42 | struct device *dev; |
43 | struct input_polled_dev *poll_dev; | ||
44 | struct tps6507x_dev *mfd; | ||
43 | char phys[32]; | 45 | char phys[32]; |
44 | struct delayed_work work; | ||
45 | unsigned polling; /* polling is active */ | ||
46 | struct ts_event tc; | 46 | struct ts_event tc; |
47 | struct tps6507x_dev *mfd; | ||
48 | u16 model; | ||
49 | unsigned pendown; | ||
50 | int irq; | ||
51 | void (*clear_penirq)(void); | ||
52 | unsigned long poll_period; /* ms */ | ||
53 | u16 min_pressure; | 47 | u16 min_pressure; |
54 | int vref; /* non-zero to leave vref on */ | 48 | bool pendown; |
55 | }; | 49 | }; |
56 | 50 | ||
57 | static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data) | 51 | static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data) |
@@ -161,18 +155,15 @@ static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc) | |||
161 | return ret; | 155 | return ret; |
162 | } | 156 | } |
163 | 157 | ||
164 | static void tps6507x_ts_handler(struct work_struct *work) | 158 | static void tps6507x_ts_poll(struct input_polled_dev *poll_dev) |
165 | { | 159 | { |
166 | struct tps6507x_ts *tsc = container_of(work, | 160 | struct tps6507x_ts *tsc = poll_dev->private; |
167 | struct tps6507x_ts, work.work); | 161 | struct input_dev *input_dev = poll_dev->input; |
168 | struct input_dev *input_dev = tsc->input_dev; | 162 | bool pendown; |
169 | int pendown; | ||
170 | int schd; | ||
171 | int poll = 0; | ||
172 | s32 ret; | 163 | s32 ret; |
173 | 164 | ||
174 | ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE, | 165 | ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE, |
175 | &tsc->tc.pressure); | 166 | &tsc->tc.pressure); |
176 | if (ret) | 167 | if (ret) |
177 | goto done; | 168 | goto done; |
178 | 169 | ||
@@ -183,7 +174,7 @@ static void tps6507x_ts_handler(struct work_struct *work) | |||
183 | input_report_key(input_dev, BTN_TOUCH, 0); | 174 | input_report_key(input_dev, BTN_TOUCH, 0); |
184 | input_report_abs(input_dev, ABS_PRESSURE, 0); | 175 | input_report_abs(input_dev, ABS_PRESSURE, 0); |
185 | input_sync(input_dev); | 176 | input_sync(input_dev); |
186 | tsc->pendown = 0; | 177 | tsc->pendown = false; |
187 | } | 178 | } |
188 | 179 | ||
189 | if (pendown) { | 180 | if (pendown) { |
@@ -208,76 +199,69 @@ static void tps6507x_ts_handler(struct work_struct *work) | |||
208 | input_report_abs(input_dev, ABS_Y, tsc->tc.y); | 199 | input_report_abs(input_dev, ABS_Y, tsc->tc.y); |
209 | input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure); | 200 | input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure); |
210 | input_sync(input_dev); | 201 | input_sync(input_dev); |
211 | tsc->pendown = 1; | 202 | tsc->pendown = true; |
212 | poll = 1; | ||
213 | } | 203 | } |
214 | 204 | ||
215 | done: | 205 | done: |
216 | /* always poll if not using interrupts */ | 206 | tps6507x_adc_standby(tsc); |
217 | poll = 1; | ||
218 | |||
219 | if (poll) { | ||
220 | schd = schedule_delayed_work(&tsc->work, | ||
221 | msecs_to_jiffies(tsc->poll_period)); | ||
222 | if (schd) | ||
223 | tsc->polling = 1; | ||
224 | else { | ||
225 | tsc->polling = 0; | ||
226 | dev_err(tsc->dev, "re-schedule failed"); | ||
227 | } | ||
228 | } else | ||
229 | tsc->polling = 0; | ||
230 | |||
231 | ret = tps6507x_adc_standby(tsc); | ||
232 | } | 207 | } |
233 | 208 | ||
234 | static int tps6507x_ts_probe(struct platform_device *pdev) | 209 | static int tps6507x_ts_probe(struct platform_device *pdev) |
235 | { | 210 | { |
236 | int error; | ||
237 | struct tps6507x_ts *tsc; | ||
238 | struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); | 211 | struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); |
239 | struct touchscreen_init_data *init_data; | 212 | const struct tps6507x_board *tps_board; |
213 | const struct touchscreen_init_data *init_data; | ||
214 | struct tps6507x_ts *tsc; | ||
215 | struct input_polled_dev *poll_dev; | ||
240 | struct input_dev *input_dev; | 216 | struct input_dev *input_dev; |
241 | struct tps6507x_board *tps_board; | 217 | int error; |
242 | int schd; | ||
243 | 218 | ||
244 | /** | 219 | /* |
245 | * tps_board points to pmic related constants | 220 | * tps_board points to pmic related constants |
246 | * coming from the board-evm file. | 221 | * coming from the board-evm file. |
247 | */ | 222 | */ |
248 | 223 | tps_board = dev_get_platdata(tps6507x_dev->dev); | |
249 | tps_board = (struct tps6507x_board *)tps6507x_dev->dev->platform_data; | ||
250 | |||
251 | if (!tps_board) { | 224 | if (!tps_board) { |
252 | dev_err(tps6507x_dev->dev, | 225 | dev_err(tps6507x_dev->dev, |
253 | "Could not find tps6507x platform data\n"); | 226 | "Could not find tps6507x platform data\n"); |
254 | return -EIO; | 227 | return -ENODEV; |
255 | } | 228 | } |
256 | 229 | ||
257 | /** | 230 | /* |
258 | * init_data points to array of regulator_init structures | 231 | * init_data points to array of regulator_init structures |
259 | * coming from the board-evm file. | 232 | * coming from the board-evm file. |
260 | */ | 233 | */ |
261 | |||
262 | init_data = tps_board->tps6507x_ts_init_data; | 234 | init_data = tps_board->tps6507x_ts_init_data; |
263 | 235 | ||
264 | tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL); | 236 | tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL); |
265 | if (!tsc) { | 237 | if (!tsc) { |
266 | dev_err(tps6507x_dev->dev, "failed to allocate driver data\n"); | 238 | dev_err(tps6507x_dev->dev, "failed to allocate driver data\n"); |
267 | error = -ENOMEM; | 239 | return -ENOMEM; |
268 | goto err0; | ||
269 | } | 240 | } |
270 | 241 | ||
271 | tps6507x_dev->ts = tsc; | ||
272 | tsc->mfd = tps6507x_dev; | 242 | tsc->mfd = tps6507x_dev; |
273 | tsc->dev = tps6507x_dev->dev; | 243 | tsc->dev = tps6507x_dev->dev; |
274 | input_dev = input_allocate_device(); | 244 | tsc->min_pressure = init_data ? |
275 | if (!input_dev) { | 245 | init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE; |
276 | dev_err(tsc->dev, "Failed to allocate input device.\n"); | 246 | |
247 | snprintf(tsc->phys, sizeof(tsc->phys), | ||
248 | "%s/input0", dev_name(tsc->dev)); | ||
249 | |||
250 | poll_dev = input_allocate_polled_device(); | ||
251 | if (!poll_dev) { | ||
252 | dev_err(tsc->dev, "Failed to allocate polled input device.\n"); | ||
277 | error = -ENOMEM; | 253 | error = -ENOMEM; |
278 | goto err1; | 254 | goto err_free_mem; |
279 | } | 255 | } |
280 | 256 | ||
257 | tsc->poll_dev = poll_dev; | ||
258 | |||
259 | poll_dev->private = tsc; | ||
260 | poll_dev->poll = tps6507x_ts_poll; | ||
261 | poll_dev->poll_interval = init_data ? | ||
262 | init_data->poll_period : TSC_DEFAULT_POLL_PERIOD; | ||
263 | |||
264 | input_dev = poll_dev->input; | ||
281 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 265 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
282 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | 266 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
283 | 267 | ||
@@ -286,76 +270,42 @@ static int tps6507x_ts_probe(struct platform_device *pdev) | |||
286 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0); | 270 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0); |
287 | 271 | ||
288 | input_dev->name = "TPS6507x Touchscreen"; | 272 | input_dev->name = "TPS6507x Touchscreen"; |
289 | input_dev->id.bustype = BUS_I2C; | ||
290 | input_dev->dev.parent = tsc->dev; | ||
291 | |||
292 | snprintf(tsc->phys, sizeof(tsc->phys), | ||
293 | "%s/input0", dev_name(tsc->dev)); | ||
294 | input_dev->phys = tsc->phys; | 273 | input_dev->phys = tsc->phys; |
295 | 274 | input_dev->dev.parent = tsc->dev; | |
296 | dev_dbg(tsc->dev, "device: %s\n", input_dev->phys); | 275 | input_dev->id.bustype = BUS_I2C; |
297 | |||
298 | input_set_drvdata(input_dev, tsc); | ||
299 | |||
300 | tsc->input_dev = input_dev; | ||
301 | |||
302 | INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler); | ||
303 | |||
304 | if (init_data) { | 276 | if (init_data) { |
305 | tsc->poll_period = init_data->poll_period; | ||
306 | tsc->vref = init_data->vref; | ||
307 | tsc->min_pressure = init_data->min_pressure; | ||
308 | input_dev->id.vendor = init_data->vendor; | 277 | input_dev->id.vendor = init_data->vendor; |
309 | input_dev->id.product = init_data->product; | 278 | input_dev->id.product = init_data->product; |
310 | input_dev->id.version = init_data->version; | 279 | input_dev->id.version = init_data->version; |
311 | } else { | ||
312 | tsc->poll_period = TSC_DEFAULT_POLL_PERIOD; | ||
313 | tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE; | ||
314 | } | 280 | } |
315 | 281 | ||
316 | error = tps6507x_adc_standby(tsc); | 282 | error = tps6507x_adc_standby(tsc); |
317 | if (error) | 283 | if (error) |
318 | goto err2; | 284 | goto err_free_polled_dev; |
319 | 285 | ||
320 | error = input_register_device(input_dev); | 286 | error = input_register_polled_device(poll_dev); |
321 | if (error) | 287 | if (error) |
322 | goto err2; | 288 | goto err_free_polled_dev; |
323 | 289 | ||
324 | schd = schedule_delayed_work(&tsc->work, | 290 | platform_set_drvdata(pdev, tsc); |
325 | msecs_to_jiffies(tsc->poll_period)); | ||
326 | |||
327 | if (schd) | ||
328 | tsc->polling = 1; | ||
329 | else { | ||
330 | tsc->polling = 0; | ||
331 | dev_err(tsc->dev, "schedule failed"); | ||
332 | goto err2; | ||
333 | } | ||
334 | platform_set_drvdata(pdev, tps6507x_dev); | ||
335 | 291 | ||
336 | return 0; | 292 | return 0; |
337 | 293 | ||
338 | err2: | 294 | err_free_polled_dev: |
339 | cancel_delayed_work_sync(&tsc->work); | 295 | input_free_polled_device(poll_dev); |
340 | input_free_device(input_dev); | 296 | err_free_mem: |
341 | err1: | ||
342 | kfree(tsc); | 297 | kfree(tsc); |
343 | tps6507x_dev->ts = NULL; | ||
344 | err0: | ||
345 | return error; | 298 | return error; |
346 | } | 299 | } |
347 | 300 | ||
348 | static int tps6507x_ts_remove(struct platform_device *pdev) | 301 | static int tps6507x_ts_remove(struct platform_device *pdev) |
349 | { | 302 | { |
350 | struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); | 303 | struct tps6507x_ts *tsc = platform_get_drvdata(pdev); |
351 | struct tps6507x_ts *tsc = tps6507x_dev->ts; | 304 | struct input_polled_dev *poll_dev = tsc->poll_dev; |
352 | struct input_dev *input_dev = tsc->input_dev; | ||
353 | |||
354 | cancel_delayed_work_sync(&tsc->work); | ||
355 | 305 | ||
356 | input_unregister_device(input_dev); | 306 | input_unregister_polled_device(poll_dev); |
307 | input_free_polled_device(poll_dev); | ||
357 | 308 | ||
358 | tps6507x_dev->ts = NULL; | ||
359 | kfree(tsc); | 309 | kfree(tsc); |
360 | 310 | ||
361 | return 0; | 311 | return 0; |
diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index d2ef8f05c66e..003d0c3b5d08 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c | |||
@@ -318,8 +318,6 @@ static int w90x900ts_remove(struct platform_device *pdev) | |||
318 | input_unregister_device(w90p910_ts->input); | 318 | input_unregister_device(w90p910_ts->input); |
319 | kfree(w90p910_ts); | 319 | kfree(w90p910_ts); |
320 | 320 | ||
321 | platform_set_drvdata(pdev, NULL); | ||
322 | |||
323 | return 0; | 321 | return 0; |
324 | } | 322 | } |
325 | 323 | ||
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index bf0d07620bac..7ccaa1b12b05 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Wacom Penabled Driver for I2C | 2 | * Wacom Penabled Driver for I2C |
3 | * | 3 | * |
4 | * Copyright (c) 2011 Tatsunosuke Tobita, Wacom. | 4 | * Copyright (c) 2011 - 2013 Tatsunosuke Tobita, Wacom. |
5 | * <tobita.tatsunosuke@wacom.co.jp> | 5 | * <tobita.tatsunosuke@wacom.co.jp> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it | 7 | * This program is free software; you can redistribute it |
@@ -27,7 +27,6 @@ | |||
27 | #define WACOM_CMD_THROW0 0x05 | 27 | #define WACOM_CMD_THROW0 0x05 |
28 | #define WACOM_CMD_THROW1 0x00 | 28 | #define WACOM_CMD_THROW1 0x00 |
29 | #define WACOM_QUERY_SIZE 19 | 29 | #define WACOM_QUERY_SIZE 19 |
30 | #define WACOM_RETRY_CNT 100 | ||
31 | 30 | ||
32 | struct wacom_features { | 31 | struct wacom_features { |
33 | int x_max; | 32 | int x_max; |
@@ -40,6 +39,8 @@ struct wacom_i2c { | |||
40 | struct i2c_client *client; | 39 | struct i2c_client *client; |
41 | struct input_dev *input; | 40 | struct input_dev *input; |
42 | u8 data[WACOM_QUERY_SIZE]; | 41 | u8 data[WACOM_QUERY_SIZE]; |
42 | bool prox; | ||
43 | int tool; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | static int wacom_query_device(struct i2c_client *client, | 46 | static int wacom_query_device(struct i2c_client *client, |
@@ -112,9 +113,14 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id) | |||
112 | y = le16_to_cpup((__le16 *)&data[6]); | 113 | y = le16_to_cpup((__le16 *)&data[6]); |
113 | pressure = le16_to_cpup((__le16 *)&data[8]); | 114 | pressure = le16_to_cpup((__le16 *)&data[8]); |
114 | 115 | ||
116 | if (!wac_i2c->prox) | ||
117 | wac_i2c->tool = (data[3] & 0x0c) ? | ||
118 | BTN_TOOL_RUBBER : BTN_TOOL_PEN; | ||
119 | |||
120 | wac_i2c->prox = data[3] & 0x20; | ||
121 | |||
115 | input_report_key(input, BTN_TOUCH, tsw || ers); | 122 | input_report_key(input, BTN_TOUCH, tsw || ers); |
116 | input_report_key(input, BTN_TOOL_PEN, tsw); | 123 | input_report_key(input, wac_i2c->tool, wac_i2c->prox); |
117 | input_report_key(input, BTN_TOOL_RUBBER, ers); | ||
118 | input_report_key(input, BTN_STYLUS, f1); | 124 | input_report_key(input, BTN_STYLUS, f1); |
119 | input_report_key(input, BTN_STYLUS2, f2); | 125 | input_report_key(input, BTN_STYLUS2, f2); |
120 | input_report_abs(input, ABS_X, x); | 126 | input_report_abs(input, ABS_X, x); |