diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-17 13:06:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-17 13:06:02 -0500 |
commit | d797da41b2aceed5daa8cd2eee92cd74b2a0c652 (patch) | |
tree | f4de7daf5a81f425c057dd5a65a0e1b8056de5a9 /drivers/input/touchscreen | |
parent | d6666be6f0c43efb9475d1d35fbef9f8be61b7b1 (diff) | |
parent | f20c86cd75f1c8c728dafd0218645ff3c5e8545d (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input subsystem updates from Dmitry Torokhov:
"Two new drivers for Elan hardware (for I2C touchpad and touchscreen
found in several Chromebooks and other devices), a driver for Goodix
touch panel, and small fixes to Cypress I2C trackpad and other input
drivers.
Also we switched to use __maybe_unused instead of gating suspend/
resume code with #ifdef guards to get better compile coverage"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (27 commits)
Input: gpio_keys - fix warning regarding uninitialized 'button' variable
Input: add support for Elan eKTH I2C touchscreens
Input: gpio_keys - fix warning regarding uninitialized 'irq' variable
Input: cyapa - use 'error' for error codes
Input: cyapa - fix resuming the device
Input: gpio_keys - add device tree support for interrupt only keys
Input: amikbd - allocate temporary keymap buffer on the stack
Input: amikbd - fix build if !CONFIG_HW_CONSOLE
Input: lm8323 - missing error check in lm8323_set_disable()
Input: initialize device counter variables with -1
Input: initialize input_no to -1 to avoid subtraction
Input: i8042 - do not try to load on Intel NUC D54250WYK
Input: atkbd - correct MSC_SCAN events for force_release keys
Input: cyapa - switch to using managed resources
Input: lifebook - use "static inline" instead of "inline" in lifebook.h
Input: touchscreen - use __maybe_unused instead of ifdef around suspend/resume
Input: mouse - use __maybe_unused instead of ifdef around suspend/resume
Input: misc - use __maybe_unused instead of ifdef around suspend/resume
Input: cap11xx - support for irq-active-high option
Input: cap11xx - add support for various cap11xx devices
...
Diffstat (limited to 'drivers/input/touchscreen')
23 files changed, 1731 insertions, 78 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e1d8003d01f8..58917525126e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -295,6 +295,19 @@ config TOUCHSCREEN_FUJITSU | |||
295 | To compile this driver as a module, choose M here: the | 295 | To compile this driver as a module, choose M here: the |
296 | module will be called fujitsu-ts. | 296 | module will be called fujitsu-ts. |
297 | 297 | ||
298 | config TOUCHSCREEN_GOODIX | ||
299 | tristate "Goodix I2C touchscreen" | ||
300 | depends on I2C && ACPI | ||
301 | help | ||
302 | Say Y here if you have the Goodix touchscreen (such as one | ||
303 | installed in Onda v975w tablets) connected to your | ||
304 | system. | ||
305 | |||
306 | If unsure, say N. | ||
307 | |||
308 | To compile this driver as a module, choose M here: the | ||
309 | module will be called goodix. | ||
310 | |||
298 | config TOUCHSCREEN_ILI210X | 311 | config TOUCHSCREEN_ILI210X |
299 | tristate "Ilitek ILI210X based touchscreen" | 312 | tristate "Ilitek ILI210X based touchscreen" |
300 | depends on I2C | 313 | depends on I2C |
@@ -334,6 +347,18 @@ config TOUCHSCREEN_GUNZE | |||
334 | To compile this driver as a module, choose M here: the | 347 | To compile this driver as a module, choose M here: the |
335 | module will be called gunze. | 348 | module will be called gunze. |
336 | 349 | ||
350 | config TOUCHSCREEN_ELAN | ||
351 | tristate "Elan eKTH I2C touchscreen" | ||
352 | depends on I2C | ||
353 | help | ||
354 | Say Y here if you have an Elan eKTH I2C touchscreen | ||
355 | connected to your system. | ||
356 | |||
357 | If unsure, say N. | ||
358 | |||
359 | To compile this driver as a module, choose M here: the | ||
360 | module will be called elants_i2c. | ||
361 | |||
337 | config TOUCHSCREEN_ELO | 362 | config TOUCHSCREEN_ELO |
338 | tristate "Elo serial touchscreens" | 363 | tristate "Elo serial touchscreens" |
339 | select SERIO | 364 | select SERIO |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 090e61cc9171..0242fea2102a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -31,9 +31,11 @@ obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o | |||
31 | obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o | 31 | obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o |
32 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o | 32 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o |
33 | obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o | 33 | obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o |
34 | obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o | ||
34 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o | 35 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o |
35 | obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o | 36 | obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o |
36 | obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o | 37 | obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o |
38 | obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o | ||
37 | obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o | 39 | obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o |
38 | obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o | 40 | obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o |
39 | obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o | 41 | obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o |
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 523865daa1d3..da4e5bb5e045 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c | |||
@@ -820,8 +820,7 @@ static int ad7877_remove(struct spi_device *spi) | |||
820 | return 0; | 820 | return 0; |
821 | } | 821 | } |
822 | 822 | ||
823 | #ifdef CONFIG_PM_SLEEP | 823 | static int __maybe_unused ad7877_suspend(struct device *dev) |
824 | static int ad7877_suspend(struct device *dev) | ||
825 | { | 824 | { |
826 | struct ad7877 *ts = dev_get_drvdata(dev); | 825 | struct ad7877 *ts = dev_get_drvdata(dev); |
827 | 826 | ||
@@ -830,7 +829,7 @@ static int ad7877_suspend(struct device *dev) | |||
830 | return 0; | 829 | return 0; |
831 | } | 830 | } |
832 | 831 | ||
833 | static int ad7877_resume(struct device *dev) | 832 | static int __maybe_unused ad7877_resume(struct device *dev) |
834 | { | 833 | { |
835 | struct ad7877 *ts = dev_get_drvdata(dev); | 834 | struct ad7877 *ts = dev_get_drvdata(dev); |
836 | 835 | ||
@@ -838,7 +837,6 @@ static int ad7877_resume(struct device *dev) | |||
838 | 837 | ||
839 | return 0; | 838 | return 0; |
840 | } | 839 | } |
841 | #endif | ||
842 | 840 | ||
843 | static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume); | 841 | static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume); |
844 | 842 | ||
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 1eb9d3c20886..fec66ad80513 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c | |||
@@ -284,8 +284,7 @@ static void ad7879_close(struct input_dev* input) | |||
284 | __ad7879_disable(ts); | 284 | __ad7879_disable(ts); |
285 | } | 285 | } |
286 | 286 | ||
287 | #ifdef CONFIG_PM_SLEEP | 287 | static int __maybe_unused ad7879_suspend(struct device *dev) |
288 | static int ad7879_suspend(struct device *dev) | ||
289 | { | 288 | { |
290 | struct ad7879 *ts = dev_get_drvdata(dev); | 289 | struct ad7879 *ts = dev_get_drvdata(dev); |
291 | 290 | ||
@@ -301,7 +300,7 @@ static int ad7879_suspend(struct device *dev) | |||
301 | return 0; | 300 | return 0; |
302 | } | 301 | } |
303 | 302 | ||
304 | static int ad7879_resume(struct device *dev) | 303 | static int __maybe_unused ad7879_resume(struct device *dev) |
305 | { | 304 | { |
306 | struct ad7879 *ts = dev_get_drvdata(dev); | 305 | struct ad7879 *ts = dev_get_drvdata(dev); |
307 | 306 | ||
@@ -316,7 +315,6 @@ static int ad7879_resume(struct device *dev) | |||
316 | 315 | ||
317 | return 0; | 316 | return 0; |
318 | } | 317 | } |
319 | #endif | ||
320 | 318 | ||
321 | SIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume); | 319 | SIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume); |
322 | EXPORT_SYMBOL(ad7879_pm_ops); | 320 | EXPORT_SYMBOL(ad7879_pm_ops); |
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index e57ba52bf484..e4eb8a6c658f 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
@@ -883,8 +883,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) | |||
883 | return IRQ_HANDLED; | 883 | return IRQ_HANDLED; |
884 | } | 884 | } |
885 | 885 | ||
886 | #ifdef CONFIG_PM_SLEEP | 886 | static int __maybe_unused ads7846_suspend(struct device *dev) |
887 | static int ads7846_suspend(struct device *dev) | ||
888 | { | 887 | { |
889 | struct ads7846 *ts = dev_get_drvdata(dev); | 888 | struct ads7846 *ts = dev_get_drvdata(dev); |
890 | 889 | ||
@@ -906,7 +905,7 @@ static int ads7846_suspend(struct device *dev) | |||
906 | return 0; | 905 | return 0; |
907 | } | 906 | } |
908 | 907 | ||
909 | static int ads7846_resume(struct device *dev) | 908 | static int __maybe_unused ads7846_resume(struct device *dev) |
910 | { | 909 | { |
911 | struct ads7846 *ts = dev_get_drvdata(dev); | 910 | struct ads7846 *ts = dev_get_drvdata(dev); |
912 | 911 | ||
@@ -927,7 +926,6 @@ static int ads7846_resume(struct device *dev) | |||
927 | 926 | ||
928 | return 0; | 927 | return 0; |
929 | } | 928 | } |
930 | #endif | ||
931 | 929 | ||
932 | static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); | 930 | static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); |
933 | 931 | ||
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index aaacf8bfa61f..bb070206223c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
@@ -2244,8 +2244,7 @@ static int mxt_remove(struct i2c_client *client) | |||
2244 | return 0; | 2244 | return 0; |
2245 | } | 2245 | } |
2246 | 2246 | ||
2247 | #ifdef CONFIG_PM_SLEEP | 2247 | static int __maybe_unused mxt_suspend(struct device *dev) |
2248 | static int mxt_suspend(struct device *dev) | ||
2249 | { | 2248 | { |
2250 | struct i2c_client *client = to_i2c_client(dev); | 2249 | struct i2c_client *client = to_i2c_client(dev); |
2251 | struct mxt_data *data = i2c_get_clientdata(client); | 2250 | struct mxt_data *data = i2c_get_clientdata(client); |
@@ -2261,7 +2260,7 @@ static int mxt_suspend(struct device *dev) | |||
2261 | return 0; | 2260 | return 0; |
2262 | } | 2261 | } |
2263 | 2262 | ||
2264 | static int mxt_resume(struct device *dev) | 2263 | static int __maybe_unused mxt_resume(struct device *dev) |
2265 | { | 2264 | { |
2266 | struct i2c_client *client = to_i2c_client(dev); | 2265 | struct i2c_client *client = to_i2c_client(dev); |
2267 | struct mxt_data *data = i2c_get_clientdata(client); | 2266 | struct mxt_data *data = i2c_get_clientdata(client); |
@@ -2276,7 +2275,6 @@ static int mxt_resume(struct device *dev) | |||
2276 | 2275 | ||
2277 | return 0; | 2276 | return 0; |
2278 | } | 2277 | } |
2279 | #endif | ||
2280 | 2278 | ||
2281 | static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume); | 2279 | static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume); |
2282 | 2280 | ||
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 7f3c94787787..40e02dd5b2f9 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c | |||
@@ -417,8 +417,7 @@ static void auo_pixcir_input_close(struct input_dev *dev) | |||
417 | return; | 417 | return; |
418 | } | 418 | } |
419 | 419 | ||
420 | #ifdef CONFIG_PM_SLEEP | 420 | static int __maybe_unused auo_pixcir_suspend(struct device *dev) |
421 | static int auo_pixcir_suspend(struct device *dev) | ||
422 | { | 421 | { |
423 | struct i2c_client *client = to_i2c_client(dev); | 422 | struct i2c_client *client = to_i2c_client(dev); |
424 | struct auo_pixcir_ts *ts = i2c_get_clientdata(client); | 423 | struct auo_pixcir_ts *ts = i2c_get_clientdata(client); |
@@ -450,7 +449,7 @@ unlock: | |||
450 | return ret; | 449 | return ret; |
451 | } | 450 | } |
452 | 451 | ||
453 | static int auo_pixcir_resume(struct device *dev) | 452 | static int __maybe_unused auo_pixcir_resume(struct device *dev) |
454 | { | 453 | { |
455 | struct i2c_client *client = to_i2c_client(dev); | 454 | struct i2c_client *client = to_i2c_client(dev); |
456 | struct auo_pixcir_ts *ts = i2c_get_clientdata(client); | 455 | struct auo_pixcir_ts *ts = i2c_get_clientdata(client); |
@@ -479,7 +478,6 @@ unlock: | |||
479 | 478 | ||
480 | return ret; | 479 | return ret; |
481 | } | 480 | } |
482 | #endif | ||
483 | 481 | ||
484 | static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, | 482 | static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, |
485 | auo_pixcir_suspend, auo_pixcir_resume); | 483 | auo_pixcir_suspend, auo_pixcir_resume); |
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 5bf1aeeea825..f2119ee0e21b 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c | |||
@@ -291,8 +291,7 @@ err_free_mem: | |||
291 | return err; | 291 | return err; |
292 | } | 292 | } |
293 | 293 | ||
294 | #ifdef CONFIG_PM_SLEEP | 294 | static int __maybe_unused cy8ctmg110_suspend(struct device *dev) |
295 | static int cy8ctmg110_suspend(struct device *dev) | ||
296 | { | 295 | { |
297 | struct i2c_client *client = to_i2c_client(dev); | 296 | struct i2c_client *client = to_i2c_client(dev); |
298 | struct cy8ctmg110 *ts = i2c_get_clientdata(client); | 297 | struct cy8ctmg110 *ts = i2c_get_clientdata(client); |
@@ -306,7 +305,7 @@ static int cy8ctmg110_suspend(struct device *dev) | |||
306 | return 0; | 305 | return 0; |
307 | } | 306 | } |
308 | 307 | ||
309 | static int cy8ctmg110_resume(struct device *dev) | 308 | static int __maybe_unused cy8ctmg110_resume(struct device *dev) |
310 | { | 309 | { |
311 | struct i2c_client *client = to_i2c_client(dev); | 310 | struct i2c_client *client = to_i2c_client(dev); |
312 | struct cy8ctmg110 *ts = i2c_get_clientdata(client); | 311 | struct cy8ctmg110 *ts = i2c_get_clientdata(client); |
@@ -319,7 +318,6 @@ static int cy8ctmg110_resume(struct device *dev) | |||
319 | } | 318 | } |
320 | return 0; | 319 | return 0; |
321 | } | 320 | } |
322 | #endif | ||
323 | 321 | ||
324 | static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); | 322 | static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); |
325 | 323 | ||
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index eee656f77a2e..5b74e8b84e79 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c | |||
@@ -472,8 +472,7 @@ static int cyttsp_disable(struct cyttsp *ts) | |||
472 | return 0; | 472 | return 0; |
473 | } | 473 | } |
474 | 474 | ||
475 | #ifdef CONFIG_PM_SLEEP | 475 | static int __maybe_unused cyttsp_suspend(struct device *dev) |
476 | static int cyttsp_suspend(struct device *dev) | ||
477 | { | 476 | { |
478 | struct cyttsp *ts = dev_get_drvdata(dev); | 477 | struct cyttsp *ts = dev_get_drvdata(dev); |
479 | int retval = 0; | 478 | int retval = 0; |
@@ -491,7 +490,7 @@ static int cyttsp_suspend(struct device *dev) | |||
491 | return retval; | 490 | return retval; |
492 | } | 491 | } |
493 | 492 | ||
494 | static int cyttsp_resume(struct device *dev) | 493 | static int __maybe_unused cyttsp_resume(struct device *dev) |
495 | { | 494 | { |
496 | struct cyttsp *ts = dev_get_drvdata(dev); | 495 | struct cyttsp *ts = dev_get_drvdata(dev); |
497 | 496 | ||
@@ -507,8 +506,6 @@ static int cyttsp_resume(struct device *dev) | |||
507 | return 0; | 506 | return 0; |
508 | } | 507 | } |
509 | 508 | ||
510 | #endif | ||
511 | |||
512 | SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume); | 509 | SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume); |
513 | EXPORT_SYMBOL_GPL(cyttsp_pm_ops); | 510 | EXPORT_SYMBOL_GPL(cyttsp_pm_ops); |
514 | 511 | ||
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index ee3434f1e949..3793fcc7e5db 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c | |||
@@ -1092,8 +1092,7 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client) | |||
1092 | return 0; | 1092 | return 0; |
1093 | } | 1093 | } |
1094 | 1094 | ||
1095 | #ifdef CONFIG_PM_SLEEP | 1095 | static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev) |
1096 | static int edt_ft5x06_ts_suspend(struct device *dev) | ||
1097 | { | 1096 | { |
1098 | struct i2c_client *client = to_i2c_client(dev); | 1097 | struct i2c_client *client = to_i2c_client(dev); |
1099 | 1098 | ||
@@ -1103,7 +1102,7 @@ static int edt_ft5x06_ts_suspend(struct device *dev) | |||
1103 | return 0; | 1102 | return 0; |
1104 | } | 1103 | } |
1105 | 1104 | ||
1106 | static int edt_ft5x06_ts_resume(struct device *dev) | 1105 | static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev) |
1107 | { | 1106 | { |
1108 | struct i2c_client *client = to_i2c_client(dev); | 1107 | struct i2c_client *client = to_i2c_client(dev); |
1109 | 1108 | ||
@@ -1112,7 +1111,6 @@ static int edt_ft5x06_ts_resume(struct device *dev) | |||
1112 | 1111 | ||
1113 | return 0; | 1112 | return 0; |
1114 | } | 1113 | } |
1115 | #endif | ||
1116 | 1114 | ||
1117 | static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, | 1115 | static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, |
1118 | edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); | 1116 | edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); |
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index b1884ddd7a84..09be6ced7151 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c | |||
@@ -264,8 +264,7 @@ static int eeti_ts_remove(struct i2c_client *client) | |||
264 | return 0; | 264 | return 0; |
265 | } | 265 | } |
266 | 266 | ||
267 | #ifdef CONFIG_PM_SLEEP | 267 | static int __maybe_unused eeti_ts_suspend(struct device *dev) |
268 | static int eeti_ts_suspend(struct device *dev) | ||
269 | { | 268 | { |
270 | struct i2c_client *client = to_i2c_client(dev); | 269 | struct i2c_client *client = to_i2c_client(dev); |
271 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); | 270 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); |
@@ -284,7 +283,7 @@ static int eeti_ts_suspend(struct device *dev) | |||
284 | return 0; | 283 | return 0; |
285 | } | 284 | } |
286 | 285 | ||
287 | static int eeti_ts_resume(struct device *dev) | 286 | static int __maybe_unused eeti_ts_resume(struct device *dev) |
288 | { | 287 | { |
289 | struct i2c_client *client = to_i2c_client(dev); | 288 | struct i2c_client *client = to_i2c_client(dev); |
290 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); | 289 | struct eeti_ts_priv *priv = i2c_get_clientdata(client); |
@@ -302,7 +301,6 @@ static int eeti_ts_resume(struct device *dev) | |||
302 | 301 | ||
303 | return 0; | 302 | return 0; |
304 | } | 303 | } |
305 | #endif | ||
306 | 304 | ||
307 | static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume); | 305 | static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume); |
308 | 306 | ||
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index c8057847d71d..4c56299284ef 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c | |||
@@ -239,8 +239,7 @@ static const struct i2c_device_id egalax_ts_id[] = { | |||
239 | }; | 239 | }; |
240 | MODULE_DEVICE_TABLE(i2c, egalax_ts_id); | 240 | MODULE_DEVICE_TABLE(i2c, egalax_ts_id); |
241 | 241 | ||
242 | #ifdef CONFIG_PM_SLEEP | 242 | static int __maybe_unused egalax_ts_suspend(struct device *dev) |
243 | static int egalax_ts_suspend(struct device *dev) | ||
244 | { | 243 | { |
245 | static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = { | 244 | static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = { |
246 | 0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0 | 245 | 0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0 |
@@ -252,13 +251,12 @@ static int egalax_ts_suspend(struct device *dev) | |||
252 | return ret > 0 ? 0 : ret; | 251 | return ret > 0 ? 0 : ret; |
253 | } | 252 | } |
254 | 253 | ||
255 | static int egalax_ts_resume(struct device *dev) | 254 | static int __maybe_unused egalax_ts_resume(struct device *dev) |
256 | { | 255 | { |
257 | struct i2c_client *client = to_i2c_client(dev); | 256 | struct i2c_client *client = to_i2c_client(dev); |
258 | 257 | ||
259 | return egalax_wake_up_device(client); | 258 | return egalax_wake_up_device(client); |
260 | } | 259 | } |
261 | #endif | ||
262 | 260 | ||
263 | static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume); | 261 | static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume); |
264 | 262 | ||
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c new file mode 100644 index 000000000000..a510f7ef9b66 --- /dev/null +++ b/drivers/input/touchscreen/elants_i2c.c | |||
@@ -0,0 +1,1271 @@ | |||
1 | /* | ||
2 | * Elan Microelectronics touch panels with I2C interface | ||
3 | * | ||
4 | * Copyright (C) 2014 Elan Microelectronics Corporation. | ||
5 | * Scott Liu <scott.liu@emc.com.tw> | ||
6 | * | ||
7 | * This code is partly based on hid-multitouch.c: | ||
8 | * | ||
9 | * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> | ||
10 | * Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> | ||
11 | * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France | ||
12 | * | ||
13 | * | ||
14 | * This code is partly based on i2c-hid.c: | ||
15 | * | ||
16 | * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> | ||
17 | * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France | ||
18 | * Copyright (c) 2012 Red Hat, Inc | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * This software is licensed under the terms of the GNU General Public | ||
23 | * License version 2, as published by the Free Software Foundation, and | ||
24 | * may be copied, distributed, and modified under those terms. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/input.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/async.h> | ||
32 | #include <linux/i2c.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/uaccess.h> | ||
35 | #include <linux/buffer_head.h> | ||
36 | #include <linux/version.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/firmware.h> | ||
39 | #include <linux/version.h> | ||
40 | #include <linux/input/mt.h> | ||
41 | #include <linux/acpi.h> | ||
42 | #include <linux/of.h> | ||
43 | #include <asm/unaligned.h> | ||
44 | |||
45 | /* Device, Driver information */ | ||
46 | #define DEVICE_NAME "elants_i2c" | ||
47 | #define DRV_VERSION "1.0.9" | ||
48 | |||
49 | /* Convert from rows or columns into resolution */ | ||
50 | #define ELAN_TS_RESOLUTION(n, m) (((n) - 1) * (m)) | ||
51 | |||
52 | /* FW header data */ | ||
53 | #define HEADER_SIZE 4 | ||
54 | #define FW_HDR_TYPE 0 | ||
55 | #define FW_HDR_COUNT 1 | ||
56 | #define FW_HDR_LENGTH 2 | ||
57 | |||
58 | /* Buffer mode Queue Header information */ | ||
59 | #define QUEUE_HEADER_SINGLE 0x62 | ||
60 | #define QUEUE_HEADER_NORMAL 0X63 | ||
61 | #define QUEUE_HEADER_WAIT 0x64 | ||
62 | |||
63 | /* Command header definition */ | ||
64 | #define CMD_HEADER_WRITE 0x54 | ||
65 | #define CMD_HEADER_READ 0x53 | ||
66 | #define CMD_HEADER_6B_READ 0x5B | ||
67 | #define CMD_HEADER_RESP 0x52 | ||
68 | #define CMD_HEADER_6B_RESP 0x9B | ||
69 | #define CMD_HEADER_HELLO 0x55 | ||
70 | #define CMD_HEADER_REK 0x66 | ||
71 | |||
72 | /* FW position data */ | ||
73 | #define PACKET_SIZE 55 | ||
74 | #define MAX_CONTACT_NUM 10 | ||
75 | #define FW_POS_HEADER 0 | ||
76 | #define FW_POS_STATE 1 | ||
77 | #define FW_POS_TOTAL 2 | ||
78 | #define FW_POS_XY 3 | ||
79 | #define FW_POS_CHECKSUM 34 | ||
80 | #define FW_POS_WIDTH 35 | ||
81 | #define FW_POS_PRESSURE 45 | ||
82 | |||
83 | #define HEADER_REPORT_10_FINGER 0x62 | ||
84 | |||
85 | /* Header (4 bytes) plus 3 fill 10-finger packets */ | ||
86 | #define MAX_PACKET_SIZE 169 | ||
87 | |||
88 | #define BOOT_TIME_DELAY_MS 50 | ||
89 | |||
90 | /* FW read command, 0x53 0x?? 0x0, 0x01 */ | ||
91 | #define E_ELAN_INFO_FW_VER 0x00 | ||
92 | #define E_ELAN_INFO_BC_VER 0x10 | ||
93 | #define E_ELAN_INFO_TEST_VER 0xE0 | ||
94 | #define E_ELAN_INFO_FW_ID 0xF0 | ||
95 | #define E_INFO_OSR 0xD6 | ||
96 | #define E_INFO_PHY_SCAN 0xD7 | ||
97 | #define E_INFO_PHY_DRIVER 0xD8 | ||
98 | |||
99 | #define MAX_RETRIES 3 | ||
100 | #define MAX_FW_UPDATE_RETRIES 30 | ||
101 | |||
102 | #define ELAN_FW_PAGESIZE 132 | ||
103 | #define ELAN_FW_FILENAME "elants_i2c.bin" | ||
104 | |||
105 | /* calibration timeout definition */ | ||
106 | #define ELAN_CALI_TIMEOUT_MSEC 10000 | ||
107 | |||
108 | enum elants_state { | ||
109 | ELAN_STATE_NORMAL, | ||
110 | ELAN_WAIT_QUEUE_HEADER, | ||
111 | ELAN_WAIT_RECALIBRATION, | ||
112 | }; | ||
113 | |||
114 | enum elants_iap_mode { | ||
115 | ELAN_IAP_OPERATIONAL, | ||
116 | ELAN_IAP_RECOVERY, | ||
117 | }; | ||
118 | |||
119 | /* struct elants_data - represents state of Elan touchscreen device */ | ||
120 | struct elants_data { | ||
121 | struct i2c_client *client; | ||
122 | struct input_dev *input; | ||
123 | |||
124 | u16 fw_version; | ||
125 | u8 test_version; | ||
126 | u8 solution_version; | ||
127 | u8 bc_version; | ||
128 | u8 iap_version; | ||
129 | u16 hw_version; | ||
130 | unsigned int x_res; /* resolution in units/mm */ | ||
131 | unsigned int y_res; | ||
132 | unsigned int x_max; | ||
133 | unsigned int y_max; | ||
134 | |||
135 | enum elants_state state; | ||
136 | enum elants_iap_mode iap_mode; | ||
137 | |||
138 | /* Guards against concurrent access to the device via sysfs */ | ||
139 | struct mutex sysfs_mutex; | ||
140 | |||
141 | u8 cmd_resp[HEADER_SIZE]; | ||
142 | struct completion cmd_done; | ||
143 | |||
144 | u8 buf[MAX_PACKET_SIZE]; | ||
145 | |||
146 | bool wake_irq_enabled; | ||
147 | }; | ||
148 | |||
149 | static int elants_i2c_send(struct i2c_client *client, | ||
150 | const void *data, size_t size) | ||
151 | { | ||
152 | int ret; | ||
153 | |||
154 | ret = i2c_master_send(client, data, size); | ||
155 | if (ret == size) | ||
156 | return 0; | ||
157 | |||
158 | if (ret >= 0) | ||
159 | ret = -EIO; | ||
160 | |||
161 | dev_err(&client->dev, "%s failed (%*ph): %d\n", | ||
162 | __func__, (int)size, data, ret); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | static int elants_i2c_read(struct i2c_client *client, void *data, size_t size) | ||
168 | { | ||
169 | int ret; | ||
170 | |||
171 | ret = i2c_master_recv(client, data, size); | ||
172 | if (ret == size) | ||
173 | return 0; | ||
174 | |||
175 | if (ret >= 0) | ||
176 | ret = -EIO; | ||
177 | |||
178 | dev_err(&client->dev, "%s failed: %d\n", __func__, ret); | ||
179 | |||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static int elants_i2c_execute_command(struct i2c_client *client, | ||
184 | const u8 *cmd, size_t cmd_size, | ||
185 | u8 *resp, size_t resp_size) | ||
186 | { | ||
187 | struct i2c_msg msgs[2]; | ||
188 | int ret; | ||
189 | u8 expected_response; | ||
190 | |||
191 | switch (cmd[0]) { | ||
192 | case CMD_HEADER_READ: | ||
193 | expected_response = CMD_HEADER_RESP; | ||
194 | break; | ||
195 | |||
196 | case CMD_HEADER_6B_READ: | ||
197 | expected_response = CMD_HEADER_6B_RESP; | ||
198 | break; | ||
199 | |||
200 | default: | ||
201 | dev_err(&client->dev, "%s: invalid command %*ph\n", | ||
202 | __func__, (int)cmd_size, cmd); | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | |||
206 | msgs[0].addr = client->addr; | ||
207 | msgs[0].flags = client->flags & I2C_M_TEN; | ||
208 | msgs[0].len = cmd_size; | ||
209 | msgs[0].buf = (u8 *)cmd; | ||
210 | |||
211 | msgs[1].addr = client->addr; | ||
212 | msgs[1].flags = client->flags & I2C_M_TEN; | ||
213 | msgs[1].flags |= I2C_M_RD; | ||
214 | msgs[1].len = resp_size; | ||
215 | msgs[1].buf = resp; | ||
216 | |||
217 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
218 | if (ret < 0) | ||
219 | return ret; | ||
220 | |||
221 | if (ret != ARRAY_SIZE(msgs) || resp[FW_HDR_TYPE] != expected_response) | ||
222 | return -EIO; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int elants_i2c_calibrate(struct elants_data *ts) | ||
228 | { | ||
229 | struct i2c_client *client = ts->client; | ||
230 | int ret, error; | ||
231 | static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A }; | ||
232 | static const u8 rek[] = { 0x54, 0x29, 0x00, 0x01 }; | ||
233 | static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; | ||
234 | |||
235 | disable_irq(client->irq); | ||
236 | |||
237 | ts->state = ELAN_WAIT_RECALIBRATION; | ||
238 | reinit_completion(&ts->cmd_done); | ||
239 | |||
240 | elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); | ||
241 | elants_i2c_send(client, rek, sizeof(rek)); | ||
242 | |||
243 | enable_irq(client->irq); | ||
244 | |||
245 | ret = wait_for_completion_interruptible_timeout(&ts->cmd_done, | ||
246 | msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC)); | ||
247 | |||
248 | ts->state = ELAN_STATE_NORMAL; | ||
249 | |||
250 | if (ret <= 0) { | ||
251 | error = ret < 0 ? ret : -ETIMEDOUT; | ||
252 | dev_err(&client->dev, | ||
253 | "error while waiting for calibration to complete: %d\n", | ||
254 | error); | ||
255 | return error; | ||
256 | } | ||
257 | |||
258 | if (memcmp(rek_resp, ts->cmd_resp, sizeof(rek_resp))) { | ||
259 | dev_err(&client->dev, | ||
260 | "unexpected calibration response: %*ph\n", | ||
261 | (int)sizeof(ts->cmd_resp), ts->cmd_resp); | ||
262 | return -EINVAL; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int elants_i2c_sw_reset(struct i2c_client *client) | ||
269 | { | ||
270 | const u8 soft_rst_cmd[] = { 0x77, 0x77, 0x77, 0x77 }; | ||
271 | int error; | ||
272 | |||
273 | error = elants_i2c_send(client, soft_rst_cmd, | ||
274 | sizeof(soft_rst_cmd)); | ||
275 | if (error) { | ||
276 | dev_err(&client->dev, "software reset failed: %d\n", error); | ||
277 | return error; | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * We should wait at least 10 msec (but no more than 40) before | ||
282 | * sending fastboot or IAP command to the device. | ||
283 | */ | ||
284 | msleep(30); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static u16 elants_i2c_parse_version(u8 *buf) | ||
290 | { | ||
291 | return get_unaligned_be32(buf) >> 4; | ||
292 | } | ||
293 | |||
294 | static int elants_i2c_query_fw_id(struct elants_data *ts) | ||
295 | { | ||
296 | struct i2c_client *client = ts->client; | ||
297 | int error, retry_cnt; | ||
298 | const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 }; | ||
299 | u8 resp[HEADER_SIZE]; | ||
300 | |||
301 | for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { | ||
302 | error = elants_i2c_execute_command(client, cmd, sizeof(cmd), | ||
303 | resp, sizeof(resp)); | ||
304 | if (!error) { | ||
305 | ts->hw_version = elants_i2c_parse_version(resp); | ||
306 | if (ts->hw_version != 0xffff) | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | dev_dbg(&client->dev, "read fw id error=%d, buf=%*phC\n", | ||
311 | error, (int)sizeof(resp), resp); | ||
312 | } | ||
313 | |||
314 | dev_err(&client->dev, | ||
315 | "Failed to read fw id or fw id is invalid\n"); | ||
316 | |||
317 | return -EINVAL; | ||
318 | } | ||
319 | |||
320 | static int elants_i2c_query_fw_version(struct elants_data *ts) | ||
321 | { | ||
322 | struct i2c_client *client = ts->client; | ||
323 | int error, retry_cnt; | ||
324 | const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 }; | ||
325 | u8 resp[HEADER_SIZE]; | ||
326 | |||
327 | for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { | ||
328 | error = elants_i2c_execute_command(client, cmd, sizeof(cmd), | ||
329 | resp, sizeof(resp)); | ||
330 | if (!error) { | ||
331 | ts->fw_version = elants_i2c_parse_version(resp); | ||
332 | if (ts->fw_version != 0x0000 && | ||
333 | ts->fw_version != 0xffff) | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | dev_dbg(&client->dev, "read fw version error=%d, buf=%*phC\n", | ||
338 | error, (int)sizeof(resp), resp); | ||
339 | } | ||
340 | |||
341 | dev_err(&client->dev, | ||
342 | "Failed to read fw version or fw version is invalid\n"); | ||
343 | |||
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | static int elants_i2c_query_test_version(struct elants_data *ts) | ||
348 | { | ||
349 | struct i2c_client *client = ts->client; | ||
350 | int error, retry_cnt; | ||
351 | u16 version; | ||
352 | const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 }; | ||
353 | u8 resp[HEADER_SIZE]; | ||
354 | |||
355 | for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { | ||
356 | error = elants_i2c_execute_command(client, cmd, sizeof(cmd), | ||
357 | resp, sizeof(resp)); | ||
358 | if (!error) { | ||
359 | version = elants_i2c_parse_version(resp); | ||
360 | ts->test_version = version >> 8; | ||
361 | ts->solution_version = version & 0xff; | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | dev_dbg(&client->dev, | ||
367 | "read test version error rc=%d, buf=%*phC\n", | ||
368 | error, (int)sizeof(resp), resp); | ||
369 | } | ||
370 | |||
371 | dev_err(&client->dev, "Failed to read test version\n"); | ||
372 | |||
373 | return -EINVAL; | ||
374 | } | ||
375 | |||
376 | static int elants_i2c_query_bc_version(struct elants_data *ts) | ||
377 | { | ||
378 | struct i2c_client *client = ts->client; | ||
379 | const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_BC_VER, 0x00, 0x01 }; | ||
380 | u8 resp[HEADER_SIZE]; | ||
381 | u16 version; | ||
382 | int error; | ||
383 | |||
384 | error = elants_i2c_execute_command(client, cmd, sizeof(cmd), | ||
385 | resp, sizeof(resp)); | ||
386 | if (error) { | ||
387 | dev_err(&client->dev, | ||
388 | "read BC version error=%d, buf=%*phC\n", | ||
389 | error, (int)sizeof(resp), resp); | ||
390 | return error; | ||
391 | } | ||
392 | |||
393 | version = elants_i2c_parse_version(resp); | ||
394 | ts->bc_version = version >> 8; | ||
395 | ts->iap_version = version & 0xff; | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int elants_i2c_query_ts_info(struct elants_data *ts) | ||
401 | { | ||
402 | struct i2c_client *client = ts->client; | ||
403 | int error; | ||
404 | u8 resp[17]; | ||
405 | u16 phy_x, phy_y, rows, cols, osr; | ||
406 | const u8 get_resolution_cmd[] = { | ||
407 | CMD_HEADER_6B_READ, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
408 | }; | ||
409 | const u8 get_osr_cmd[] = { | ||
410 | CMD_HEADER_READ, E_INFO_OSR, 0x00, 0x01 | ||
411 | }; | ||
412 | const u8 get_physical_scan_cmd[] = { | ||
413 | CMD_HEADER_READ, E_INFO_PHY_SCAN, 0x00, 0x01 | ||
414 | }; | ||
415 | const u8 get_physical_drive_cmd[] = { | ||
416 | CMD_HEADER_READ, E_INFO_PHY_DRIVER, 0x00, 0x01 | ||
417 | }; | ||
418 | |||
419 | /* Get trace number */ | ||
420 | error = elants_i2c_execute_command(client, | ||
421 | get_resolution_cmd, | ||
422 | sizeof(get_resolution_cmd), | ||
423 | resp, sizeof(resp)); | ||
424 | if (error) { | ||
425 | dev_err(&client->dev, "get resolution command failed: %d\n", | ||
426 | error); | ||
427 | return error; | ||
428 | } | ||
429 | |||
430 | rows = resp[2] + resp[6] + resp[10]; | ||
431 | cols = resp[3] + resp[7] + resp[11]; | ||
432 | |||
433 | /* Process mm_to_pixel information */ | ||
434 | error = elants_i2c_execute_command(client, | ||
435 | get_osr_cmd, sizeof(get_osr_cmd), | ||
436 | resp, sizeof(resp)); | ||
437 | if (error) { | ||
438 | dev_err(&client->dev, "get osr command failed: %d\n", | ||
439 | error); | ||
440 | return error; | ||
441 | } | ||
442 | |||
443 | osr = resp[3]; | ||
444 | |||
445 | error = elants_i2c_execute_command(client, | ||
446 | get_physical_scan_cmd, | ||
447 | sizeof(get_physical_scan_cmd), | ||
448 | resp, sizeof(resp)); | ||
449 | if (error) { | ||
450 | dev_err(&client->dev, "get physical scan command failed: %d\n", | ||
451 | error); | ||
452 | return error; | ||
453 | } | ||
454 | |||
455 | phy_x = get_unaligned_be16(&resp[2]); | ||
456 | |||
457 | error = elants_i2c_execute_command(client, | ||
458 | get_physical_drive_cmd, | ||
459 | sizeof(get_physical_drive_cmd), | ||
460 | resp, sizeof(resp)); | ||
461 | if (error) { | ||
462 | dev_err(&client->dev, "get physical drive command failed: %d\n", | ||
463 | error); | ||
464 | return error; | ||
465 | } | ||
466 | |||
467 | phy_y = get_unaligned_be16(&resp[2]); | ||
468 | |||
469 | dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); | ||
470 | |||
471 | if (rows == 0 || cols == 0 || osr == 0) { | ||
472 | dev_warn(&client->dev, | ||
473 | "invalid trace number data: %d, %d, %d\n", | ||
474 | rows, cols, osr); | ||
475 | } else { | ||
476 | /* translate trace number to TS resolution */ | ||
477 | ts->x_max = ELAN_TS_RESOLUTION(rows, osr); | ||
478 | ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); | ||
479 | ts->y_max = ELAN_TS_RESOLUTION(cols, osr); | ||
480 | ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); | ||
481 | } | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static int elants_i2c_fastboot(struct i2c_client *client) | ||
487 | { | ||
488 | const u8 boot_cmd[] = { 0x4D, 0x61, 0x69, 0x6E }; | ||
489 | int error; | ||
490 | |||
491 | error = elants_i2c_send(client, boot_cmd, sizeof(boot_cmd)); | ||
492 | if (error) { | ||
493 | dev_err(&client->dev, "boot failed: %d\n", error); | ||
494 | return error; | ||
495 | } | ||
496 | |||
497 | dev_dbg(&client->dev, "boot success -- 0x%x\n", client->addr); | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int elants_i2c_initialize(struct elants_data *ts) | ||
502 | { | ||
503 | struct i2c_client *client = ts->client; | ||
504 | int error, retry_cnt; | ||
505 | const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; | ||
506 | const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; | ||
507 | u8 buf[HEADER_SIZE]; | ||
508 | |||
509 | for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { | ||
510 | error = elants_i2c_sw_reset(client); | ||
511 | if (error) { | ||
512 | /* Continue initializing if it's the last try */ | ||
513 | if (retry_cnt < MAX_RETRIES - 1) | ||
514 | continue; | ||
515 | } | ||
516 | |||
517 | error = elants_i2c_fastboot(client); | ||
518 | if (error) { | ||
519 | /* Continue initializing if it's the last try */ | ||
520 | if (retry_cnt < MAX_RETRIES - 1) | ||
521 | continue; | ||
522 | } | ||
523 | |||
524 | /* Wait for Hello packet */ | ||
525 | msleep(BOOT_TIME_DELAY_MS); | ||
526 | |||
527 | error = elants_i2c_read(client, buf, sizeof(buf)); | ||
528 | if (error) { | ||
529 | dev_err(&client->dev, | ||
530 | "failed to read 'hello' packet: %d\n", error); | ||
531 | } else if (!memcmp(buf, hello_packet, sizeof(hello_packet))) { | ||
532 | ts->iap_mode = ELAN_IAP_OPERATIONAL; | ||
533 | break; | ||
534 | } else if (!memcmp(buf, recov_packet, sizeof(recov_packet))) { | ||
535 | /* | ||
536 | * Setting error code will mark device | ||
537 | * in recovery mode below. | ||
538 | */ | ||
539 | error = -EIO; | ||
540 | break; | ||
541 | } else { | ||
542 | error = -EINVAL; | ||
543 | dev_err(&client->dev, | ||
544 | "invalid 'hello' packet: %*ph\n", | ||
545 | (int)sizeof(buf), buf); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | if (!error) | ||
550 | error = elants_i2c_query_fw_id(ts); | ||
551 | if (!error) | ||
552 | error = elants_i2c_query_fw_version(ts); | ||
553 | |||
554 | if (error) { | ||
555 | ts->iap_mode = ELAN_IAP_RECOVERY; | ||
556 | } else { | ||
557 | elants_i2c_query_test_version(ts); | ||
558 | elants_i2c_query_bc_version(ts); | ||
559 | elants_i2c_query_ts_info(ts); | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | /* | ||
566 | * Firmware update interface. | ||
567 | */ | ||
568 | |||
569 | static int elants_i2c_fw_write_page(struct i2c_client *client, | ||
570 | const void *page) | ||
571 | { | ||
572 | const u8 ack_ok[] = { 0xaa, 0xaa }; | ||
573 | u8 buf[2]; | ||
574 | int retry; | ||
575 | int error; | ||
576 | |||
577 | for (retry = 0; retry < MAX_FW_UPDATE_RETRIES; retry++) { | ||
578 | error = elants_i2c_send(client, page, ELAN_FW_PAGESIZE); | ||
579 | if (error) { | ||
580 | dev_err(&client->dev, | ||
581 | "IAP Write Page failed: %d\n", error); | ||
582 | continue; | ||
583 | } | ||
584 | |||
585 | error = elants_i2c_read(client, buf, 2); | ||
586 | if (error) { | ||
587 | dev_err(&client->dev, | ||
588 | "IAP Ack read failed: %d\n", error); | ||
589 | return error; | ||
590 | } | ||
591 | |||
592 | if (!memcmp(buf, ack_ok, sizeof(ack_ok))) | ||
593 | return 0; | ||
594 | |||
595 | error = -EIO; | ||
596 | dev_err(&client->dev, | ||
597 | "IAP Get Ack Error [%02x:%02x]\n", | ||
598 | buf[0], buf[1]); | ||
599 | } | ||
600 | |||
601 | return error; | ||
602 | } | ||
603 | |||
604 | static int elants_i2c_do_update_firmware(struct i2c_client *client, | ||
605 | const struct firmware *fw, | ||
606 | bool force) | ||
607 | { | ||
608 | const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; | ||
609 | const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; | ||
610 | const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; | ||
611 | u8 buf[HEADER_SIZE]; | ||
612 | u16 send_id; | ||
613 | int page, n_fw_pages; | ||
614 | int error; | ||
615 | |||
616 | /* Recovery mode detection! */ | ||
617 | if (force) { | ||
618 | dev_dbg(&client->dev, "Recovery mode procedure\n"); | ||
619 | error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); | ||
620 | } else { | ||
621 | /* Start IAP Procedure */ | ||
622 | dev_dbg(&client->dev, "Normal IAP procedure\n"); | ||
623 | elants_i2c_sw_reset(client); | ||
624 | |||
625 | error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); | ||
626 | } | ||
627 | |||
628 | if (error) { | ||
629 | dev_err(&client->dev, "failed to enter IAP mode: %d\n", error); | ||
630 | return error; | ||
631 | } | ||
632 | |||
633 | msleep(20); | ||
634 | |||
635 | /* check IAP state */ | ||
636 | error = elants_i2c_read(client, buf, 4); | ||
637 | if (error) { | ||
638 | dev_err(&client->dev, | ||
639 | "failed to read IAP acknowledgement: %d\n", | ||
640 | error); | ||
641 | return error; | ||
642 | } | ||
643 | |||
644 | if (memcmp(buf, iap_ack, sizeof(iap_ack))) { | ||
645 | dev_err(&client->dev, | ||
646 | "failed to enter IAP: %*ph (expected %*ph)\n", | ||
647 | (int)sizeof(buf), buf, (int)sizeof(iap_ack), iap_ack); | ||
648 | return -EIO; | ||
649 | } | ||
650 | |||
651 | dev_info(&client->dev, "successfully entered IAP mode"); | ||
652 | |||
653 | send_id = client->addr; | ||
654 | error = elants_i2c_send(client, &send_id, 1); | ||
655 | if (error) { | ||
656 | dev_err(&client->dev, "sending dummy byte failed: %d\n", | ||
657 | error); | ||
658 | return error; | ||
659 | } | ||
660 | |||
661 | /* Clear the last page of Master */ | ||
662 | error = elants_i2c_send(client, fw->data, ELAN_FW_PAGESIZE); | ||
663 | if (error) { | ||
664 | dev_err(&client->dev, "clearing of the last page failed: %d\n", | ||
665 | error); | ||
666 | return error; | ||
667 | } | ||
668 | |||
669 | error = elants_i2c_read(client, buf, 2); | ||
670 | if (error) { | ||
671 | dev_err(&client->dev, | ||
672 | "failed to read ACK for clearing the last page: %d\n", | ||
673 | error); | ||
674 | return error; | ||
675 | } | ||
676 | |||
677 | n_fw_pages = fw->size / ELAN_FW_PAGESIZE; | ||
678 | dev_dbg(&client->dev, "IAP Pages = %d\n", n_fw_pages); | ||
679 | |||
680 | for (page = 0; page < n_fw_pages; page++) { | ||
681 | error = elants_i2c_fw_write_page(client, | ||
682 | fw->data + page * ELAN_FW_PAGESIZE); | ||
683 | if (error) { | ||
684 | dev_err(&client->dev, | ||
685 | "failed to write FW page %d: %d\n", | ||
686 | page, error); | ||
687 | return error; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | /* Old iap needs to wait 200ms for WDT and rest is for hello packets */ | ||
692 | msleep(300); | ||
693 | |||
694 | dev_info(&client->dev, "firmware update completed\n"); | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int elants_i2c_fw_update(struct elants_data *ts) | ||
699 | { | ||
700 | struct i2c_client *client = ts->client; | ||
701 | const struct firmware *fw; | ||
702 | int error; | ||
703 | |||
704 | error = request_firmware(&fw, ELAN_FW_FILENAME, &client->dev); | ||
705 | if (error) { | ||
706 | dev_err(&client->dev, "failed to request firmware %s: %d\n", | ||
707 | ELAN_FW_FILENAME, error); | ||
708 | return error; | ||
709 | } | ||
710 | |||
711 | if (fw->size % ELAN_FW_PAGESIZE) { | ||
712 | dev_err(&client->dev, "invalid firmware length: %zu\n", | ||
713 | fw->size); | ||
714 | error = -EINVAL; | ||
715 | goto out; | ||
716 | } | ||
717 | |||
718 | disable_irq(client->irq); | ||
719 | |||
720 | error = elants_i2c_do_update_firmware(client, fw, | ||
721 | ts->iap_mode == ELAN_IAP_RECOVERY); | ||
722 | if (error) { | ||
723 | dev_err(&client->dev, "firmware update failed: %d\n", error); | ||
724 | ts->iap_mode = ELAN_IAP_RECOVERY; | ||
725 | goto out_enable_irq; | ||
726 | } | ||
727 | |||
728 | error = elants_i2c_initialize(ts); | ||
729 | if (error) { | ||
730 | dev_err(&client->dev, | ||
731 | "failed to initialize device after firmware update: %d\n", | ||
732 | error); | ||
733 | ts->iap_mode = ELAN_IAP_RECOVERY; | ||
734 | goto out_enable_irq; | ||
735 | } | ||
736 | |||
737 | ts->iap_mode = ELAN_IAP_OPERATIONAL; | ||
738 | |||
739 | out_enable_irq: | ||
740 | ts->state = ELAN_STATE_NORMAL; | ||
741 | enable_irq(client->irq); | ||
742 | msleep(100); | ||
743 | |||
744 | if (!error) | ||
745 | elants_i2c_calibrate(ts); | ||
746 | out: | ||
747 | release_firmware(fw); | ||
748 | return error; | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * Event reporting. | ||
753 | */ | ||
754 | |||
755 | static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) | ||
756 | { | ||
757 | struct input_dev *input = ts->input; | ||
758 | unsigned int n_fingers; | ||
759 | u16 finger_state; | ||
760 | int i; | ||
761 | |||
762 | n_fingers = buf[FW_POS_STATE + 1] & 0x0f; | ||
763 | finger_state = ((buf[FW_POS_STATE + 1] & 0x30) << 4) | | ||
764 | buf[FW_POS_STATE]; | ||
765 | |||
766 | dev_dbg(&ts->client->dev, | ||
767 | "n_fingers: %u, state: %04x\n", n_fingers, finger_state); | ||
768 | |||
769 | for (i = 0; i < MAX_CONTACT_NUM && n_fingers; i++) { | ||
770 | if (finger_state & 1) { | ||
771 | unsigned int x, y, p, w; | ||
772 | u8 *pos; | ||
773 | |||
774 | pos = &buf[FW_POS_XY + i * 3]; | ||
775 | x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; | ||
776 | y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; | ||
777 | p = buf[FW_POS_PRESSURE + i]; | ||
778 | w = buf[FW_POS_WIDTH + i]; | ||
779 | |||
780 | dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", | ||
781 | i, x, y, p, w); | ||
782 | |||
783 | input_mt_slot(input, i); | ||
784 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
785 | input_event(input, EV_ABS, ABS_MT_POSITION_X, x); | ||
786 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); | ||
787 | input_event(input, EV_ABS, ABS_MT_PRESSURE, p); | ||
788 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); | ||
789 | |||
790 | n_fingers--; | ||
791 | } | ||
792 | |||
793 | finger_state >>= 1; | ||
794 | } | ||
795 | |||
796 | input_mt_sync_frame(input); | ||
797 | input_sync(input); | ||
798 | } | ||
799 | |||
800 | static u8 elants_i2c_calculate_checksum(u8 *buf) | ||
801 | { | ||
802 | u8 checksum = 0; | ||
803 | u8 i; | ||
804 | |||
805 | for (i = 0; i < FW_POS_CHECKSUM; i++) | ||
806 | checksum += buf[i]; | ||
807 | |||
808 | return checksum; | ||
809 | } | ||
810 | |||
811 | static void elants_i2c_event(struct elants_data *ts, u8 *buf) | ||
812 | { | ||
813 | u8 checksum = elants_i2c_calculate_checksum(buf); | ||
814 | |||
815 | if (unlikely(buf[FW_POS_CHECKSUM] != checksum)) | ||
816 | dev_warn(&ts->client->dev, | ||
817 | "%s: invalid checksum for packet %02x: %02x vs. %02x\n", | ||
818 | __func__, buf[FW_POS_HEADER], | ||
819 | checksum, buf[FW_POS_CHECKSUM]); | ||
820 | else if (unlikely(buf[FW_POS_HEADER] != HEADER_REPORT_10_FINGER)) | ||
821 | dev_warn(&ts->client->dev, | ||
822 | "%s: unknown packet type: %02x\n", | ||
823 | __func__, buf[FW_POS_HEADER]); | ||
824 | else | ||
825 | elants_i2c_mt_event(ts, buf); | ||
826 | } | ||
827 | |||
828 | static irqreturn_t elants_i2c_irq(int irq, void *_dev) | ||
829 | { | ||
830 | const u8 wait_packet[] = { 0x64, 0x64, 0x64, 0x64 }; | ||
831 | struct elants_data *ts = _dev; | ||
832 | struct i2c_client *client = ts->client; | ||
833 | int report_count, report_len; | ||
834 | int i; | ||
835 | int len; | ||
836 | |||
837 | len = i2c_master_recv(client, ts->buf, sizeof(ts->buf)); | ||
838 | if (len < 0) { | ||
839 | dev_err(&client->dev, "%s: failed to read data: %d\n", | ||
840 | __func__, len); | ||
841 | goto out; | ||
842 | } | ||
843 | |||
844 | dev_dbg(&client->dev, "%s: packet %*ph\n", | ||
845 | __func__, HEADER_SIZE, ts->buf); | ||
846 | |||
847 | switch (ts->state) { | ||
848 | case ELAN_WAIT_RECALIBRATION: | ||
849 | if (ts->buf[FW_HDR_TYPE] == CMD_HEADER_REK) { | ||
850 | memcpy(ts->cmd_resp, ts->buf, sizeof(ts->cmd_resp)); | ||
851 | complete(&ts->cmd_done); | ||
852 | ts->state = ELAN_STATE_NORMAL; | ||
853 | } | ||
854 | break; | ||
855 | |||
856 | case ELAN_WAIT_QUEUE_HEADER: | ||
857 | if (ts->buf[FW_HDR_TYPE] != QUEUE_HEADER_NORMAL) | ||
858 | break; | ||
859 | |||
860 | ts->state = ELAN_STATE_NORMAL; | ||
861 | /* fall through */ | ||
862 | |||
863 | case ELAN_STATE_NORMAL: | ||
864 | |||
865 | switch (ts->buf[FW_HDR_TYPE]) { | ||
866 | case CMD_HEADER_HELLO: | ||
867 | case CMD_HEADER_RESP: | ||
868 | case CMD_HEADER_REK: | ||
869 | break; | ||
870 | |||
871 | case QUEUE_HEADER_WAIT: | ||
872 | if (memcmp(ts->buf, wait_packet, sizeof(wait_packet))) { | ||
873 | dev_err(&client->dev, | ||
874 | "invalid wait packet %*ph\n", | ||
875 | HEADER_SIZE, ts->buf); | ||
876 | } else { | ||
877 | ts->state = ELAN_WAIT_QUEUE_HEADER; | ||
878 | udelay(30); | ||
879 | } | ||
880 | break; | ||
881 | |||
882 | case QUEUE_HEADER_SINGLE: | ||
883 | elants_i2c_event(ts, &ts->buf[HEADER_SIZE]); | ||
884 | break; | ||
885 | |||
886 | case QUEUE_HEADER_NORMAL: | ||
887 | report_count = ts->buf[FW_HDR_COUNT]; | ||
888 | if (report_count > 3) { | ||
889 | dev_err(&client->dev, | ||
890 | "too large report count: %*ph\n", | ||
891 | HEADER_SIZE, ts->buf); | ||
892 | break; | ||
893 | } | ||
894 | |||
895 | report_len = ts->buf[FW_HDR_LENGTH] / report_count; | ||
896 | if (report_len != PACKET_SIZE) { | ||
897 | dev_err(&client->dev, | ||
898 | "mismatching report length: %*ph\n", | ||
899 | HEADER_SIZE, ts->buf); | ||
900 | break; | ||
901 | } | ||
902 | |||
903 | for (i = 0; i < report_count; i++) { | ||
904 | u8 *buf = ts->buf + HEADER_SIZE + | ||
905 | i * PACKET_SIZE; | ||
906 | elants_i2c_event(ts, buf); | ||
907 | } | ||
908 | break; | ||
909 | |||
910 | default: | ||
911 | dev_err(&client->dev, "unknown packet %*ph\n", | ||
912 | HEADER_SIZE, ts->buf); | ||
913 | break; | ||
914 | } | ||
915 | break; | ||
916 | } | ||
917 | |||
918 | out: | ||
919 | return IRQ_HANDLED; | ||
920 | } | ||
921 | |||
922 | /* | ||
923 | * sysfs interface | ||
924 | */ | ||
925 | static ssize_t calibrate_store(struct device *dev, | ||
926 | struct device_attribute *attr, | ||
927 | const char *buf, size_t count) | ||
928 | { | ||
929 | struct i2c_client *client = to_i2c_client(dev); | ||
930 | struct elants_data *ts = i2c_get_clientdata(client); | ||
931 | int error; | ||
932 | |||
933 | error = mutex_lock_interruptible(&ts->sysfs_mutex); | ||
934 | if (error) | ||
935 | return error; | ||
936 | |||
937 | error = elants_i2c_calibrate(ts); | ||
938 | |||
939 | mutex_unlock(&ts->sysfs_mutex); | ||
940 | return error ?: count; | ||
941 | } | ||
942 | |||
943 | static ssize_t write_update_fw(struct device *dev, | ||
944 | struct device_attribute *attr, | ||
945 | const char *buf, size_t count) | ||
946 | { | ||
947 | struct i2c_client *client = to_i2c_client(dev); | ||
948 | struct elants_data *ts = i2c_get_clientdata(client); | ||
949 | int error; | ||
950 | |||
951 | error = mutex_lock_interruptible(&ts->sysfs_mutex); | ||
952 | if (error) | ||
953 | return error; | ||
954 | |||
955 | error = elants_i2c_fw_update(ts); | ||
956 | dev_dbg(dev, "firmware update result: %d\n", error); | ||
957 | |||
958 | mutex_unlock(&ts->sysfs_mutex); | ||
959 | return error ?: count; | ||
960 | } | ||
961 | |||
962 | static ssize_t show_iap_mode(struct device *dev, | ||
963 | struct device_attribute *attr, char *buf) | ||
964 | { | ||
965 | struct i2c_client *client = to_i2c_client(dev); | ||
966 | struct elants_data *ts = i2c_get_clientdata(client); | ||
967 | |||
968 | return sprintf(buf, "%s\n", | ||
969 | ts->iap_mode == ELAN_IAP_OPERATIONAL ? | ||
970 | "Normal" : "Recovery"); | ||
971 | } | ||
972 | |||
973 | static DEVICE_ATTR(calibrate, S_IWUSR, NULL, calibrate_store); | ||
974 | static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL); | ||
975 | static DEVICE_ATTR(update_fw, S_IWUSR, NULL, write_update_fw); | ||
976 | |||
977 | struct elants_version_attribute { | ||
978 | struct device_attribute dattr; | ||
979 | size_t field_offset; | ||
980 | size_t field_size; | ||
981 | }; | ||
982 | |||
983 | #define __ELANTS_FIELD_SIZE(_field) \ | ||
984 | sizeof(((struct elants_data *)NULL)->_field) | ||
985 | #define __ELANTS_VERIFY_SIZE(_field) \ | ||
986 | (BUILD_BUG_ON_ZERO(__ELANTS_FIELD_SIZE(_field) > 2) + \ | ||
987 | __ELANTS_FIELD_SIZE(_field)) | ||
988 | #define ELANTS_VERSION_ATTR(_field) \ | ||
989 | struct elants_version_attribute elants_ver_attr_##_field = { \ | ||
990 | .dattr = __ATTR(_field, S_IRUGO, \ | ||
991 | elants_version_attribute_show, NULL), \ | ||
992 | .field_offset = offsetof(struct elants_data, _field), \ | ||
993 | .field_size = __ELANTS_VERIFY_SIZE(_field), \ | ||
994 | } | ||
995 | |||
996 | static ssize_t elants_version_attribute_show(struct device *dev, | ||
997 | struct device_attribute *dattr, | ||
998 | char *buf) | ||
999 | { | ||
1000 | struct i2c_client *client = to_i2c_client(dev); | ||
1001 | struct elants_data *ts = i2c_get_clientdata(client); | ||
1002 | struct elants_version_attribute *attr = | ||
1003 | container_of(dattr, struct elants_version_attribute, dattr); | ||
1004 | u8 *field = (u8 *)((char *)ts + attr->field_offset); | ||
1005 | unsigned int fmt_size; | ||
1006 | unsigned int val; | ||
1007 | |||
1008 | if (attr->field_size == 1) { | ||
1009 | val = *field; | ||
1010 | fmt_size = 2; /* 2 HEX digits */ | ||
1011 | } else { | ||
1012 | val = *(u16 *)field; | ||
1013 | fmt_size = 4; /* 4 HEX digits */ | ||
1014 | } | ||
1015 | |||
1016 | return sprintf(buf, "%0*x\n", fmt_size, val); | ||
1017 | } | ||
1018 | |||
1019 | static ELANTS_VERSION_ATTR(fw_version); | ||
1020 | static ELANTS_VERSION_ATTR(hw_version); | ||
1021 | static ELANTS_VERSION_ATTR(test_version); | ||
1022 | static ELANTS_VERSION_ATTR(solution_version); | ||
1023 | static ELANTS_VERSION_ATTR(bc_version); | ||
1024 | static ELANTS_VERSION_ATTR(iap_version); | ||
1025 | |||
1026 | static struct attribute *elants_attributes[] = { | ||
1027 | &dev_attr_calibrate.attr, | ||
1028 | &dev_attr_update_fw.attr, | ||
1029 | &dev_attr_iap_mode.attr, | ||
1030 | |||
1031 | &elants_ver_attr_fw_version.dattr.attr, | ||
1032 | &elants_ver_attr_hw_version.dattr.attr, | ||
1033 | &elants_ver_attr_test_version.dattr.attr, | ||
1034 | &elants_ver_attr_solution_version.dattr.attr, | ||
1035 | &elants_ver_attr_bc_version.dattr.attr, | ||
1036 | &elants_ver_attr_iap_version.dattr.attr, | ||
1037 | NULL | ||
1038 | }; | ||
1039 | |||
1040 | static struct attribute_group elants_attribute_group = { | ||
1041 | .attrs = elants_attributes, | ||
1042 | }; | ||
1043 | |||
1044 | static void elants_i2c_remove_sysfs_group(void *_data) | ||
1045 | { | ||
1046 | struct elants_data *ts = _data; | ||
1047 | |||
1048 | sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group); | ||
1049 | } | ||
1050 | |||
1051 | static int elants_i2c_probe(struct i2c_client *client, | ||
1052 | const struct i2c_device_id *id) | ||
1053 | { | ||
1054 | union i2c_smbus_data dummy; | ||
1055 | struct elants_data *ts; | ||
1056 | unsigned long irqflags; | ||
1057 | int error; | ||
1058 | |||
1059 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
1060 | dev_err(&client->dev, | ||
1061 | "%s: i2c check functionality error\n", DEVICE_NAME); | ||
1062 | return -ENXIO; | ||
1063 | } | ||
1064 | |||
1065 | /* Make sure there is something at this address */ | ||
1066 | if (i2c_smbus_xfer(client->adapter, client->addr, 0, | ||
1067 | I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { | ||
1068 | dev_err(&client->dev, "nothing at this address\n"); | ||
1069 | return -ENXIO; | ||
1070 | } | ||
1071 | |||
1072 | ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); | ||
1073 | if (!ts) | ||
1074 | return -ENOMEM; | ||
1075 | |||
1076 | mutex_init(&ts->sysfs_mutex); | ||
1077 | init_completion(&ts->cmd_done); | ||
1078 | |||
1079 | ts->client = client; | ||
1080 | i2c_set_clientdata(client, ts); | ||
1081 | |||
1082 | error = elants_i2c_initialize(ts); | ||
1083 | if (error) { | ||
1084 | dev_err(&client->dev, "failed to initialize: %d\n", error); | ||
1085 | return error; | ||
1086 | } | ||
1087 | |||
1088 | ts->input = devm_input_allocate_device(&client->dev); | ||
1089 | if (!ts->input) { | ||
1090 | dev_err(&client->dev, "Failed to allocate input device\n"); | ||
1091 | return -ENOMEM; | ||
1092 | } | ||
1093 | |||
1094 | ts->input->name = "Elan Touchscreen"; | ||
1095 | ts->input->id.bustype = BUS_I2C; | ||
1096 | |||
1097 | __set_bit(BTN_TOUCH, ts->input->keybit); | ||
1098 | __set_bit(EV_ABS, ts->input->evbit); | ||
1099 | __set_bit(EV_KEY, ts->input->evbit); | ||
1100 | |||
1101 | /* Single touch input params setup */ | ||
1102 | input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0); | ||
1103 | input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0); | ||
1104 | input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0); | ||
1105 | input_abs_set_res(ts->input, ABS_X, ts->x_res); | ||
1106 | input_abs_set_res(ts->input, ABS_Y, ts->y_res); | ||
1107 | |||
1108 | /* Multitouch input params setup */ | ||
1109 | error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, | ||
1110 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); | ||
1111 | if (error) { | ||
1112 | dev_err(&client->dev, | ||
1113 | "failed to initialize MT slots: %d\n", error); | ||
1114 | return error; | ||
1115 | } | ||
1116 | |||
1117 | input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); | ||
1118 | input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); | ||
1119 | input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); | ||
1120 | input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); | ||
1121 | input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); | ||
1122 | input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); | ||
1123 | |||
1124 | input_set_drvdata(ts->input, ts); | ||
1125 | |||
1126 | error = input_register_device(ts->input); | ||
1127 | if (error) { | ||
1128 | dev_err(&client->dev, | ||
1129 | "unable to register input device: %d\n", error); | ||
1130 | return error; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * Systems using device tree should set up interrupt via DTS, | ||
1135 | * the rest will use the default falling edge interrupts. | ||
1136 | */ | ||
1137 | irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; | ||
1138 | |||
1139 | error = devm_request_threaded_irq(&client->dev, client->irq, | ||
1140 | NULL, elants_i2c_irq, | ||
1141 | irqflags | IRQF_ONESHOT, | ||
1142 | client->name, ts); | ||
1143 | if (error) { | ||
1144 | dev_err(&client->dev, "Failed to register interrupt\n"); | ||
1145 | return error; | ||
1146 | } | ||
1147 | |||
1148 | /* | ||
1149 | * Systems using device tree should set up wakeup via DTS, | ||
1150 | * the rest will configure device as wakeup source by default. | ||
1151 | */ | ||
1152 | if (!client->dev.of_node) | ||
1153 | device_init_wakeup(&client->dev, true); | ||
1154 | |||
1155 | error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group); | ||
1156 | if (error) { | ||
1157 | dev_err(&client->dev, "failed to create sysfs attributes: %d\n", | ||
1158 | error); | ||
1159 | return error; | ||
1160 | } | ||
1161 | |||
1162 | error = devm_add_action(&client->dev, | ||
1163 | elants_i2c_remove_sysfs_group, ts); | ||
1164 | if (error) { | ||
1165 | elants_i2c_remove_sysfs_group(ts); | ||
1166 | dev_err(&client->dev, | ||
1167 | "Failed to add sysfs cleanup action: %d\n", | ||
1168 | error); | ||
1169 | return error; | ||
1170 | } | ||
1171 | |||
1172 | return 0; | ||
1173 | } | ||
1174 | |||
1175 | static int __maybe_unused elants_i2c_suspend(struct device *dev) | ||
1176 | { | ||
1177 | struct i2c_client *client = to_i2c_client(dev); | ||
1178 | struct elants_data *ts = i2c_get_clientdata(client); | ||
1179 | const u8 set_sleep_cmd[] = { 0x54, 0x50, 0x00, 0x01 }; | ||
1180 | int retry_cnt; | ||
1181 | int error; | ||
1182 | |||
1183 | /* Command not support in IAP recovery mode */ | ||
1184 | if (ts->iap_mode != ELAN_IAP_OPERATIONAL) | ||
1185 | return -EBUSY; | ||
1186 | |||
1187 | disable_irq(client->irq); | ||
1188 | |||
1189 | for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { | ||
1190 | error = elants_i2c_send(client, set_sleep_cmd, | ||
1191 | sizeof(set_sleep_cmd)); | ||
1192 | if (!error) | ||
1193 | break; | ||
1194 | |||
1195 | dev_err(&client->dev, "suspend command failed: %d\n", error); | ||
1196 | } | ||
1197 | |||
1198 | if (device_may_wakeup(dev)) | ||
1199 | ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | static int __maybe_unused elants_i2c_resume(struct device *dev) | ||
1205 | { | ||
1206 | struct i2c_client *client = to_i2c_client(dev); | ||
1207 | struct elants_data *ts = i2c_get_clientdata(client); | ||
1208 | const u8 set_active_cmd[] = { 0x54, 0x58, 0x00, 0x01 }; | ||
1209 | int retry_cnt; | ||
1210 | int error; | ||
1211 | |||
1212 | if (device_may_wakeup(dev) && ts->wake_irq_enabled) | ||
1213 | disable_irq_wake(client->irq); | ||
1214 | |||
1215 | for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { | ||
1216 | error = elants_i2c_send(client, set_active_cmd, | ||
1217 | sizeof(set_active_cmd)); | ||
1218 | if (!error) | ||
1219 | break; | ||
1220 | |||
1221 | dev_err(&client->dev, "resume command failed: %d\n", error); | ||
1222 | } | ||
1223 | |||
1224 | ts->state = ELAN_STATE_NORMAL; | ||
1225 | enable_irq(client->irq); | ||
1226 | |||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, | ||
1231 | elants_i2c_suspend, elants_i2c_resume); | ||
1232 | |||
1233 | static const struct i2c_device_id elants_i2c_id[] = { | ||
1234 | { DEVICE_NAME, 0 }, | ||
1235 | { } | ||
1236 | }; | ||
1237 | MODULE_DEVICE_TABLE(i2c, elants_i2c_id); | ||
1238 | |||
1239 | #ifdef CONFIG_ACPI | ||
1240 | static const struct acpi_device_id elants_acpi_id[] = { | ||
1241 | { "ELAN0001", 0 }, | ||
1242 | { } | ||
1243 | }; | ||
1244 | MODULE_DEVICE_TABLE(acpi, elants_acpi_id); | ||
1245 | #endif | ||
1246 | |||
1247 | #ifdef CONFIG_OF | ||
1248 | static const struct of_device_id elants_of_match[] = { | ||
1249 | { .compatible = "elan,ekth3500" }, | ||
1250 | { /* sentinel */ } | ||
1251 | }; | ||
1252 | MODULE_DEVICE_TABLE(of, elants_of_match); | ||
1253 | #endif | ||
1254 | |||
1255 | static struct i2c_driver elants_i2c_driver = { | ||
1256 | .probe = elants_i2c_probe, | ||
1257 | .id_table = elants_i2c_id, | ||
1258 | .driver = { | ||
1259 | .name = DEVICE_NAME, | ||
1260 | .owner = THIS_MODULE, | ||
1261 | .pm = &elants_i2c_pm_ops, | ||
1262 | .acpi_match_table = ACPI_PTR(elants_acpi_id), | ||
1263 | .of_match_table = of_match_ptr(elants_of_match), | ||
1264 | }, | ||
1265 | }; | ||
1266 | module_i2c_driver(elants_i2c_driver); | ||
1267 | |||
1268 | MODULE_AUTHOR("Scott Liu <scott.liu@emc.com.tw>"); | ||
1269 | MODULE_DESCRIPTION("Elan I2c Touchscreen driver"); | ||
1270 | MODULE_VERSION(DRV_VERSION); | ||
1271 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c new file mode 100644 index 000000000000..ca196689f025 --- /dev/null +++ b/drivers/input/touchscreen/goodix.c | |||
@@ -0,0 +1,395 @@ | |||
1 | /* | ||
2 | * Driver for Goodix Touchscreens | ||
3 | * | ||
4 | * Copyright (c) 2014 Red Hat Inc. | ||
5 | * | ||
6 | * This code is based on gt9xx.c authored by andrew@goodix.com: | ||
7 | * | ||
8 | * 2010 - 2012 Goodix Technology. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the Free | ||
14 | * Software Foundation; version 2 of the License. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/input/mt.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <asm/unaligned.h> | ||
27 | |||
28 | struct goodix_ts_data { | ||
29 | struct i2c_client *client; | ||
30 | struct input_dev *input_dev; | ||
31 | int abs_x_max; | ||
32 | int abs_y_max; | ||
33 | unsigned int max_touch_num; | ||
34 | unsigned int int_trigger_type; | ||
35 | }; | ||
36 | |||
37 | #define GOODIX_MAX_HEIGHT 4096 | ||
38 | #define GOODIX_MAX_WIDTH 4096 | ||
39 | #define GOODIX_INT_TRIGGER 1 | ||
40 | #define GOODIX_CONTACT_SIZE 8 | ||
41 | #define GOODIX_MAX_CONTACTS 10 | ||
42 | |||
43 | #define GOODIX_CONFIG_MAX_LENGTH 240 | ||
44 | |||
45 | /* Register defines */ | ||
46 | #define GOODIX_READ_COOR_ADDR 0x814E | ||
47 | #define GOODIX_REG_CONFIG_DATA 0x8047 | ||
48 | #define GOODIX_REG_VERSION 0x8140 | ||
49 | |||
50 | #define RESOLUTION_LOC 1 | ||
51 | #define TRIGGER_LOC 6 | ||
52 | |||
53 | static const unsigned long goodix_irq_flags[] = { | ||
54 | IRQ_TYPE_EDGE_RISING, | ||
55 | IRQ_TYPE_EDGE_FALLING, | ||
56 | IRQ_TYPE_LEVEL_LOW, | ||
57 | IRQ_TYPE_LEVEL_HIGH, | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * goodix_i2c_read - read data from a register of the i2c slave device. | ||
62 | * | ||
63 | * @client: i2c device. | ||
64 | * @reg: the register to read from. | ||
65 | * @buf: raw write data buffer. | ||
66 | * @len: length of the buffer to write | ||
67 | */ | ||
68 | static int goodix_i2c_read(struct i2c_client *client, | ||
69 | u16 reg, u8 *buf, int len) | ||
70 | { | ||
71 | struct i2c_msg msgs[2]; | ||
72 | u16 wbuf = cpu_to_be16(reg); | ||
73 | int ret; | ||
74 | |||
75 | msgs[0].flags = 0; | ||
76 | msgs[0].addr = client->addr; | ||
77 | msgs[0].len = 2; | ||
78 | msgs[0].buf = (u8 *) &wbuf; | ||
79 | |||
80 | msgs[1].flags = I2C_M_RD; | ||
81 | msgs[1].addr = client->addr; | ||
82 | msgs[1].len = len; | ||
83 | msgs[1].buf = buf; | ||
84 | |||
85 | ret = i2c_transfer(client->adapter, msgs, 2); | ||
86 | return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0); | ||
87 | } | ||
88 | |||
89 | static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) | ||
90 | { | ||
91 | int touch_num; | ||
92 | int error; | ||
93 | |||
94 | error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, data, | ||
95 | GOODIX_CONTACT_SIZE + 1); | ||
96 | if (error) { | ||
97 | dev_err(&ts->client->dev, "I2C transfer error: %d\n", error); | ||
98 | return error; | ||
99 | } | ||
100 | |||
101 | touch_num = data[0] & 0x0f; | ||
102 | if (touch_num > GOODIX_MAX_CONTACTS) | ||
103 | return -EPROTO; | ||
104 | |||
105 | if (touch_num > 1) { | ||
106 | data += 1 + GOODIX_CONTACT_SIZE; | ||
107 | error = goodix_i2c_read(ts->client, | ||
108 | GOODIX_READ_COOR_ADDR + | ||
109 | 1 + GOODIX_CONTACT_SIZE, | ||
110 | data, | ||
111 | GOODIX_CONTACT_SIZE * (touch_num - 1)); | ||
112 | if (error) | ||
113 | return error; | ||
114 | } | ||
115 | |||
116 | return touch_num; | ||
117 | } | ||
118 | |||
119 | static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) | ||
120 | { | ||
121 | int id = coor_data[0] & 0x0F; | ||
122 | int input_x = get_unaligned_le16(&coor_data[1]); | ||
123 | int input_y = get_unaligned_le16(&coor_data[3]); | ||
124 | int input_w = get_unaligned_le16(&coor_data[5]); | ||
125 | |||
126 | input_mt_slot(ts->input_dev, id); | ||
127 | input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); | ||
128 | input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x); | ||
129 | input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); | ||
130 | input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); | ||
131 | input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * goodix_process_events - Process incoming events | ||
136 | * | ||
137 | * @ts: our goodix_ts_data pointer | ||
138 | * | ||
139 | * Called when the IRQ is triggered. Read the current device state, and push | ||
140 | * the input events to the user space. | ||
141 | */ | ||
142 | static void goodix_process_events(struct goodix_ts_data *ts) | ||
143 | { | ||
144 | u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; | ||
145 | int touch_num; | ||
146 | int i; | ||
147 | |||
148 | touch_num = goodix_ts_read_input_report(ts, point_data); | ||
149 | if (touch_num < 0) | ||
150 | return; | ||
151 | |||
152 | for (i = 0; i < touch_num; i++) | ||
153 | goodix_ts_report_touch(ts, | ||
154 | &point_data[1 + GOODIX_CONTACT_SIZE * i]); | ||
155 | |||
156 | input_mt_sync_frame(ts->input_dev); | ||
157 | input_sync(ts->input_dev); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * goodix_ts_irq_handler - The IRQ handler | ||
162 | * | ||
163 | * @irq: interrupt number. | ||
164 | * @dev_id: private data pointer. | ||
165 | */ | ||
166 | static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) | ||
167 | { | ||
168 | static const u8 end_cmd[] = { | ||
169 | GOODIX_READ_COOR_ADDR >> 8, | ||
170 | GOODIX_READ_COOR_ADDR & 0xff, | ||
171 | 0 | ||
172 | }; | ||
173 | struct goodix_ts_data *ts = dev_id; | ||
174 | |||
175 | goodix_process_events(ts); | ||
176 | |||
177 | if (i2c_master_send(ts->client, end_cmd, sizeof(end_cmd)) < 0) | ||
178 | dev_err(&ts->client->dev, "I2C write end_cmd error\n"); | ||
179 | |||
180 | return IRQ_HANDLED; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * goodix_read_config - Read the embedded configuration of the panel | ||
185 | * | ||
186 | * @ts: our goodix_ts_data pointer | ||
187 | * | ||
188 | * Must be called during probe | ||
189 | */ | ||
190 | static void goodix_read_config(struct goodix_ts_data *ts) | ||
191 | { | ||
192 | u8 config[GOODIX_CONFIG_MAX_LENGTH]; | ||
193 | int error; | ||
194 | |||
195 | error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, | ||
196 | config, | ||
197 | GOODIX_CONFIG_MAX_LENGTH); | ||
198 | if (error) { | ||
199 | dev_warn(&ts->client->dev, | ||
200 | "Error reading config (%d), using defaults\n", | ||
201 | error); | ||
202 | ts->abs_x_max = GOODIX_MAX_WIDTH; | ||
203 | ts->abs_y_max = GOODIX_MAX_HEIGHT; | ||
204 | ts->int_trigger_type = GOODIX_INT_TRIGGER; | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]); | ||
209 | ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]); | ||
210 | ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; | ||
211 | if (!ts->abs_x_max || !ts->abs_y_max) { | ||
212 | dev_err(&ts->client->dev, | ||
213 | "Invalid config, using defaults\n"); | ||
214 | ts->abs_x_max = GOODIX_MAX_WIDTH; | ||
215 | ts->abs_y_max = GOODIX_MAX_HEIGHT; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | |||
220 | /** | ||
221 | * goodix_read_version - Read goodix touchscreen version | ||
222 | * | ||
223 | * @client: the i2c client | ||
224 | * @version: output buffer containing the version on success | ||
225 | */ | ||
226 | static int goodix_read_version(struct i2c_client *client, u16 *version) | ||
227 | { | ||
228 | int error; | ||
229 | u8 buf[6]; | ||
230 | |||
231 | error = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf)); | ||
232 | if (error) { | ||
233 | dev_err(&client->dev, "read version failed: %d\n", error); | ||
234 | return error; | ||
235 | } | ||
236 | |||
237 | if (version) | ||
238 | *version = get_unaligned_le16(&buf[4]); | ||
239 | |||
240 | dev_info(&client->dev, "IC VERSION: %6ph\n", buf); | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * goodix_i2c_test - I2C test function to check if the device answers. | ||
247 | * | ||
248 | * @client: the i2c client | ||
249 | */ | ||
250 | static int goodix_i2c_test(struct i2c_client *client) | ||
251 | { | ||
252 | int retry = 0; | ||
253 | int error; | ||
254 | u8 test; | ||
255 | |||
256 | while (retry++ < 2) { | ||
257 | error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA, | ||
258 | &test, 1); | ||
259 | if (!error) | ||
260 | return 0; | ||
261 | |||
262 | dev_err(&client->dev, "i2c test failed attempt %d: %d\n", | ||
263 | retry, error); | ||
264 | msleep(20); | ||
265 | } | ||
266 | |||
267 | return error; | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * goodix_request_input_dev - Allocate, populate and register the input device | ||
272 | * | ||
273 | * @ts: our goodix_ts_data pointer | ||
274 | * | ||
275 | * Must be called during probe | ||
276 | */ | ||
277 | static int goodix_request_input_dev(struct goodix_ts_data *ts) | ||
278 | { | ||
279 | int error; | ||
280 | |||
281 | ts->input_dev = devm_input_allocate_device(&ts->client->dev); | ||
282 | if (!ts->input_dev) { | ||
283 | dev_err(&ts->client->dev, "Failed to allocate input device."); | ||
284 | return -ENOMEM; | ||
285 | } | ||
286 | |||
287 | ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | | ||
288 | BIT_MASK(EV_KEY) | | ||
289 | BIT_MASK(EV_ABS); | ||
290 | |||
291 | input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, | ||
292 | ts->abs_x_max, 0, 0); | ||
293 | input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, | ||
294 | ts->abs_y_max, 0, 0); | ||
295 | input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); | ||
296 | input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); | ||
297 | |||
298 | input_mt_init_slots(ts->input_dev, GOODIX_MAX_CONTACTS, | ||
299 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); | ||
300 | |||
301 | ts->input_dev->name = "Goodix Capacitive TouchScreen"; | ||
302 | ts->input_dev->phys = "input/ts"; | ||
303 | ts->input_dev->id.bustype = BUS_I2C; | ||
304 | ts->input_dev->id.vendor = 0x0416; | ||
305 | ts->input_dev->id.product = 0x1001; | ||
306 | ts->input_dev->id.version = 10427; | ||
307 | |||
308 | error = input_register_device(ts->input_dev); | ||
309 | if (error) { | ||
310 | dev_err(&ts->client->dev, | ||
311 | "Failed to register input device: %d", error); | ||
312 | return error; | ||
313 | } | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int goodix_ts_probe(struct i2c_client *client, | ||
319 | const struct i2c_device_id *id) | ||
320 | { | ||
321 | struct goodix_ts_data *ts; | ||
322 | unsigned long irq_flags; | ||
323 | int error; | ||
324 | u16 version_info; | ||
325 | |||
326 | dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); | ||
327 | |||
328 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
329 | dev_err(&client->dev, "I2C check functionality failed.\n"); | ||
330 | return -ENXIO; | ||
331 | } | ||
332 | |||
333 | ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); | ||
334 | if (!ts) | ||
335 | return -ENOMEM; | ||
336 | |||
337 | ts->client = client; | ||
338 | i2c_set_clientdata(client, ts); | ||
339 | |||
340 | error = goodix_i2c_test(client); | ||
341 | if (error) { | ||
342 | dev_err(&client->dev, "I2C communication failure: %d\n", error); | ||
343 | return error; | ||
344 | } | ||
345 | |||
346 | error = goodix_read_version(client, &version_info); | ||
347 | if (error) { | ||
348 | dev_err(&client->dev, "Read version failed.\n"); | ||
349 | return error; | ||
350 | } | ||
351 | |||
352 | goodix_read_config(ts); | ||
353 | |||
354 | error = goodix_request_input_dev(ts); | ||
355 | if (error) | ||
356 | return error; | ||
357 | |||
358 | irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT; | ||
359 | error = devm_request_threaded_irq(&ts->client->dev, client->irq, | ||
360 | NULL, goodix_ts_irq_handler, | ||
361 | irq_flags, client->name, ts); | ||
362 | if (error) { | ||
363 | dev_err(&client->dev, "request IRQ failed: %d\n", error); | ||
364 | return error; | ||
365 | } | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static const struct i2c_device_id goodix_ts_id[] = { | ||
371 | { "GDIX1001:00", 0 }, | ||
372 | { } | ||
373 | }; | ||
374 | |||
375 | static const struct acpi_device_id goodix_acpi_match[] = { | ||
376 | { "GDIX1001", 0 }, | ||
377 | { } | ||
378 | }; | ||
379 | MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); | ||
380 | |||
381 | static struct i2c_driver goodix_ts_driver = { | ||
382 | .probe = goodix_ts_probe, | ||
383 | .id_table = goodix_ts_id, | ||
384 | .driver = { | ||
385 | .name = "Goodix-TS", | ||
386 | .owner = THIS_MODULE, | ||
387 | .acpi_match_table = goodix_acpi_match, | ||
388 | }, | ||
389 | }; | ||
390 | module_i2c_driver(goodix_ts_driver); | ||
391 | |||
392 | MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); | ||
393 | MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>"); | ||
394 | MODULE_DESCRIPTION("Goodix touchscreen driver"); | ||
395 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 2a5089139818..da6dc819c846 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c | |||
@@ -311,8 +311,7 @@ static int ili210x_i2c_remove(struct i2c_client *client) | |||
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | 313 | ||
314 | #ifdef CONFIG_PM_SLEEP | 314 | static int __maybe_unused ili210x_i2c_suspend(struct device *dev) |
315 | static int ili210x_i2c_suspend(struct device *dev) | ||
316 | { | 315 | { |
317 | struct i2c_client *client = to_i2c_client(dev); | 316 | struct i2c_client *client = to_i2c_client(dev); |
318 | 317 | ||
@@ -322,7 +321,7 @@ static int ili210x_i2c_suspend(struct device *dev) | |||
322 | return 0; | 321 | return 0; |
323 | } | 322 | } |
324 | 323 | ||
325 | static int ili210x_i2c_resume(struct device *dev) | 324 | static int __maybe_unused ili210x_i2c_resume(struct device *dev) |
326 | { | 325 | { |
327 | struct i2c_client *client = to_i2c_client(dev); | 326 | struct i2c_client *client = to_i2c_client(dev); |
328 | 327 | ||
@@ -331,7 +330,6 @@ static int ili210x_i2c_resume(struct device *dev) | |||
331 | 330 | ||
332 | return 0; | 331 | return 0; |
333 | } | 332 | } |
334 | #endif | ||
335 | 333 | ||
336 | static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, | 334 | static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, |
337 | ili210x_i2c_suspend, ili210x_i2c_resume); | 335 | ili210x_i2c_suspend, ili210x_i2c_resume); |
diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c index 62c8976e616f..33c134820ef9 100644 --- a/drivers/input/touchscreen/ipaq-micro-ts.c +++ b/drivers/input/touchscreen/ipaq-micro-ts.c | |||
@@ -122,8 +122,7 @@ static int micro_ts_probe(struct platform_device *pdev) | |||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | #ifdef CONFIG_PM_SLEEP | 125 | static int __maybe_unused micro_ts_suspend(struct device *dev) |
126 | static int micro_ts_suspend(struct device *dev) | ||
127 | { | 126 | { |
128 | struct touchscreen_data *ts = dev_get_drvdata(dev); | 127 | struct touchscreen_data *ts = dev_get_drvdata(dev); |
129 | 128 | ||
@@ -132,7 +131,7 @@ static int micro_ts_suspend(struct device *dev) | |||
132 | return 0; | 131 | return 0; |
133 | } | 132 | } |
134 | 133 | ||
135 | static int micro_ts_resume(struct device *dev) | 134 | static int __maybe_unused micro_ts_resume(struct device *dev) |
136 | { | 135 | { |
137 | struct touchscreen_data *ts = dev_get_drvdata(dev); | 136 | struct touchscreen_data *ts = dev_get_drvdata(dev); |
138 | struct input_dev *input = ts->input; | 137 | struct input_dev *input = ts->input; |
@@ -146,7 +145,6 @@ static int micro_ts_resume(struct device *dev) | |||
146 | 145 | ||
147 | return 0; | 146 | return 0; |
148 | } | 147 | } |
149 | #endif | ||
150 | 148 | ||
151 | static const struct dev_pm_ops micro_ts_dev_pm_ops = { | 149 | static const struct dev_pm_ops micro_ts_dev_pm_ops = { |
152 | SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume) | 150 | SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume) |
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 372bbf7658fe..67c0d31613d8 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c | |||
@@ -515,8 +515,7 @@ static int mms114_probe(struct i2c_client *client, | |||
515 | return 0; | 515 | return 0; |
516 | } | 516 | } |
517 | 517 | ||
518 | #ifdef CONFIG_PM_SLEEP | 518 | static int __maybe_unused mms114_suspend(struct device *dev) |
519 | static int mms114_suspend(struct device *dev) | ||
520 | { | 519 | { |
521 | struct i2c_client *client = to_i2c_client(dev); | 520 | struct i2c_client *client = to_i2c_client(dev); |
522 | struct mms114_data *data = i2c_get_clientdata(client); | 521 | struct mms114_data *data = i2c_get_clientdata(client); |
@@ -540,7 +539,7 @@ static int mms114_suspend(struct device *dev) | |||
540 | return 0; | 539 | return 0; |
541 | } | 540 | } |
542 | 541 | ||
543 | static int mms114_resume(struct device *dev) | 542 | static int __maybe_unused mms114_resume(struct device *dev) |
544 | { | 543 | { |
545 | struct i2c_client *client = to_i2c_client(dev); | 544 | struct i2c_client *client = to_i2c_client(dev); |
546 | struct mms114_data *data = i2c_get_clientdata(client); | 545 | struct mms114_data *data = i2c_get_clientdata(client); |
@@ -559,7 +558,6 @@ static int mms114_resume(struct device *dev) | |||
559 | 558 | ||
560 | return 0; | 559 | return 0; |
561 | } | 560 | } |
562 | #endif | ||
563 | 561 | ||
564 | static SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume); | 562 | static SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume); |
565 | 563 | ||
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index fc49c75317d1..4fb5537fdd42 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c | |||
@@ -347,8 +347,7 @@ static void pixcir_input_close(struct input_dev *dev) | |||
347 | pixcir_stop(ts); | 347 | pixcir_stop(ts); |
348 | } | 348 | } |
349 | 349 | ||
350 | #ifdef CONFIG_PM_SLEEP | 350 | static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev) |
351 | static int pixcir_i2c_ts_suspend(struct device *dev) | ||
352 | { | 351 | { |
353 | struct i2c_client *client = to_i2c_client(dev); | 352 | struct i2c_client *client = to_i2c_client(dev); |
354 | struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); | 353 | struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); |
@@ -377,7 +376,7 @@ unlock: | |||
377 | return ret; | 376 | return ret; |
378 | } | 377 | } |
379 | 378 | ||
380 | static int pixcir_i2c_ts_resume(struct device *dev) | 379 | static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) |
381 | { | 380 | { |
382 | struct i2c_client *client = to_i2c_client(dev); | 381 | struct i2c_client *client = to_i2c_client(dev); |
383 | struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); | 382 | struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); |
@@ -405,7 +404,6 @@ unlock: | |||
405 | 404 | ||
406 | return ret; | 405 | return ret; |
407 | } | 406 | } |
408 | #endif | ||
409 | 407 | ||
410 | static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, | 408 | static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, |
411 | pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); | 409 | pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); |
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 3c0f57efe7b1..697e26e52d54 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c | |||
@@ -243,8 +243,7 @@ static int st1232_ts_remove(struct i2c_client *client) | |||
243 | return 0; | 243 | return 0; |
244 | } | 244 | } |
245 | 245 | ||
246 | #ifdef CONFIG_PM_SLEEP | 246 | static int __maybe_unused st1232_ts_suspend(struct device *dev) |
247 | static int st1232_ts_suspend(struct device *dev) | ||
248 | { | 247 | { |
249 | struct i2c_client *client = to_i2c_client(dev); | 248 | struct i2c_client *client = to_i2c_client(dev); |
250 | struct st1232_ts_data *ts = i2c_get_clientdata(client); | 249 | struct st1232_ts_data *ts = i2c_get_clientdata(client); |
@@ -259,7 +258,7 @@ static int st1232_ts_suspend(struct device *dev) | |||
259 | return 0; | 258 | return 0; |
260 | } | 259 | } |
261 | 260 | ||
262 | static int st1232_ts_resume(struct device *dev) | 261 | static int __maybe_unused st1232_ts_resume(struct device *dev) |
263 | { | 262 | { |
264 | struct i2c_client *client = to_i2c_client(dev); | 263 | struct i2c_client *client = to_i2c_client(dev); |
265 | struct st1232_ts_data *ts = i2c_get_clientdata(client); | 264 | struct st1232_ts_data *ts = i2c_get_clientdata(client); |
@@ -274,8 +273,6 @@ static int st1232_ts_resume(struct device *dev) | |||
274 | return 0; | 273 | return 0; |
275 | } | 274 | } |
276 | 275 | ||
277 | #endif | ||
278 | |||
279 | static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops, | 276 | static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops, |
280 | st1232_ts_suspend, st1232_ts_resume); | 277 | st1232_ts_suspend, st1232_ts_resume); |
281 | 278 | ||
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 52380b68ebdf..72657c579430 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c | |||
@@ -773,8 +773,7 @@ static int tsc2005_remove(struct spi_device *spi) | |||
773 | return 0; | 773 | return 0; |
774 | } | 774 | } |
775 | 775 | ||
776 | #ifdef CONFIG_PM_SLEEP | 776 | static int __maybe_unused tsc2005_suspend(struct device *dev) |
777 | static int tsc2005_suspend(struct device *dev) | ||
778 | { | 777 | { |
779 | struct spi_device *spi = to_spi_device(dev); | 778 | struct spi_device *spi = to_spi_device(dev); |
780 | struct tsc2005 *ts = spi_get_drvdata(spi); | 779 | struct tsc2005 *ts = spi_get_drvdata(spi); |
@@ -791,7 +790,7 @@ static int tsc2005_suspend(struct device *dev) | |||
791 | return 0; | 790 | return 0; |
792 | } | 791 | } |
793 | 792 | ||
794 | static int tsc2005_resume(struct device *dev) | 793 | static int __maybe_unused tsc2005_resume(struct device *dev) |
795 | { | 794 | { |
796 | struct spi_device *spi = to_spi_device(dev); | 795 | struct spi_device *spi = to_spi_device(dev); |
797 | struct tsc2005 *ts = spi_get_drvdata(spi); | 796 | struct tsc2005 *ts = spi_get_drvdata(spi); |
@@ -807,7 +806,6 @@ static int tsc2005_resume(struct device *dev) | |||
807 | 806 | ||
808 | return 0; | 807 | return 0; |
809 | } | 808 | } |
810 | #endif | ||
811 | 809 | ||
812 | static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume); | 810 | static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume); |
813 | 811 | ||
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 0eca00da584b..c1e23cfc6155 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c | |||
@@ -406,8 +406,7 @@ static int ucb1400_ts_remove(struct platform_device *pdev) | |||
406 | return 0; | 406 | return 0; |
407 | } | 407 | } |
408 | 408 | ||
409 | #ifdef CONFIG_PM_SLEEP | 409 | static int __maybe_unused ucb1400_ts_suspend(struct device *dev) |
410 | static int ucb1400_ts_suspend(struct device *dev) | ||
411 | { | 410 | { |
412 | struct ucb1400_ts *ucb = dev_get_platdata(dev); | 411 | struct ucb1400_ts *ucb = dev_get_platdata(dev); |
413 | struct input_dev *idev = ucb->ts_idev; | 412 | struct input_dev *idev = ucb->ts_idev; |
@@ -421,7 +420,7 @@ static int ucb1400_ts_suspend(struct device *dev) | |||
421 | return 0; | 420 | return 0; |
422 | } | 421 | } |
423 | 422 | ||
424 | static int ucb1400_ts_resume(struct device *dev) | 423 | static int __maybe_unused ucb1400_ts_resume(struct device *dev) |
425 | { | 424 | { |
426 | struct ucb1400_ts *ucb = dev_get_platdata(dev); | 425 | struct ucb1400_ts *ucb = dev_get_platdata(dev); |
427 | struct input_dev *idev = ucb->ts_idev; | 426 | struct input_dev *idev = ucb->ts_idev; |
@@ -434,7 +433,6 @@ static int ucb1400_ts_resume(struct device *dev) | |||
434 | mutex_unlock(&idev->mutex); | 433 | mutex_unlock(&idev->mutex); |
435 | return 0; | 434 | return 0; |
436 | } | 435 | } |
437 | #endif | ||
438 | 436 | ||
439 | static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops, | 437 | static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops, |
440 | ucb1400_ts_suspend, ucb1400_ts_resume); | 438 | ucb1400_ts_suspend, ucb1400_ts_resume); |
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index 7ccaa1b12b05..32f8ac003936 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c | |||
@@ -242,8 +242,7 @@ static int wacom_i2c_remove(struct i2c_client *client) | |||
242 | return 0; | 242 | return 0; |
243 | } | 243 | } |
244 | 244 | ||
245 | #ifdef CONFIG_PM_SLEEP | 245 | static int __maybe_unused wacom_i2c_suspend(struct device *dev) |
246 | static int wacom_i2c_suspend(struct device *dev) | ||
247 | { | 246 | { |
248 | struct i2c_client *client = to_i2c_client(dev); | 247 | struct i2c_client *client = to_i2c_client(dev); |
249 | 248 | ||
@@ -252,7 +251,7 @@ static int wacom_i2c_suspend(struct device *dev) | |||
252 | return 0; | 251 | return 0; |
253 | } | 252 | } |
254 | 253 | ||
255 | static int wacom_i2c_resume(struct device *dev) | 254 | static int __maybe_unused wacom_i2c_resume(struct device *dev) |
256 | { | 255 | { |
257 | struct i2c_client *client = to_i2c_client(dev); | 256 | struct i2c_client *client = to_i2c_client(dev); |
258 | 257 | ||
@@ -260,7 +259,6 @@ static int wacom_i2c_resume(struct device *dev) | |||
260 | 259 | ||
261 | return 0; | 260 | return 0; |
262 | } | 261 | } |
263 | #endif | ||
264 | 262 | ||
265 | static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume); | 263 | static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume); |
266 | 264 | ||
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 8ba48f5eff7b..19880c7385e3 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c | |||
@@ -602,8 +602,7 @@ static void zforce_input_close(struct input_dev *dev) | |||
602 | return; | 602 | return; |
603 | } | 603 | } |
604 | 604 | ||
605 | #ifdef CONFIG_PM_SLEEP | 605 | static int __maybe_unused zforce_suspend(struct device *dev) |
606 | static int zforce_suspend(struct device *dev) | ||
607 | { | 606 | { |
608 | struct i2c_client *client = to_i2c_client(dev); | 607 | struct i2c_client *client = to_i2c_client(dev); |
609 | struct zforce_ts *ts = i2c_get_clientdata(client); | 608 | struct zforce_ts *ts = i2c_get_clientdata(client); |
@@ -648,7 +647,7 @@ unlock: | |||
648 | return ret; | 647 | return ret; |
649 | } | 648 | } |
650 | 649 | ||
651 | static int zforce_resume(struct device *dev) | 650 | static int __maybe_unused zforce_resume(struct device *dev) |
652 | { | 651 | { |
653 | struct i2c_client *client = to_i2c_client(dev); | 652 | struct i2c_client *client = to_i2c_client(dev); |
654 | struct zforce_ts *ts = i2c_get_clientdata(client); | 653 | struct zforce_ts *ts = i2c_get_clientdata(client); |
@@ -685,7 +684,6 @@ unlock: | |||
685 | 684 | ||
686 | return ret; | 685 | return ret; |
687 | } | 686 | } |
688 | #endif | ||
689 | 687 | ||
690 | static SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume); | 688 | static SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume); |
691 | 689 | ||