diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-07-02 12:01:31 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-07-02 12:01:31 -0400 |
| commit | 27eb2c4b3d3e13f376a359e293c212a2e9407af5 (patch) | |
| tree | 556aa7b5cd6eeb4214dec129c789515157187010 /drivers/input | |
| parent | 5705b8aca5a80141de5637ff0e23b31b26f2c5bf (diff) | |
| parent | 67bf12ca50d524f9e225347fe63533562e2004de (diff) | |
Merge branch 'next' into for-linus
Prepare first set of updates for 3.11 merge window.
Diffstat (limited to 'drivers/input')
81 files changed, 4722 insertions, 325 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index f0f8928b3c8a..d2b34fbbc42e 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -52,6 +52,82 @@ struct evdev_client { | |||
| 52 | struct input_event buffer[]; | 52 | struct input_event buffer[]; |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | /* flush queued events of type @type, caller must hold client->buffer_lock */ | ||
| 56 | static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) | ||
| 57 | { | ||
| 58 | unsigned int i, head, num; | ||
| 59 | unsigned int mask = client->bufsize - 1; | ||
| 60 | bool is_report; | ||
| 61 | struct input_event *ev; | ||
| 62 | |||
| 63 | BUG_ON(type == EV_SYN); | ||
| 64 | |||
| 65 | head = client->tail; | ||
| 66 | client->packet_head = client->tail; | ||
| 67 | |||
| 68 | /* init to 1 so a leading SYN_REPORT will not be dropped */ | ||
| 69 | num = 1; | ||
| 70 | |||
| 71 | for (i = client->tail; i != client->head; i = (i + 1) & mask) { | ||
| 72 | ev = &client->buffer[i]; | ||
| 73 | is_report = ev->type == EV_SYN && ev->code == SYN_REPORT; | ||
| 74 | |||
| 75 | if (ev->type == type) { | ||
| 76 | /* drop matched entry */ | ||
| 77 | continue; | ||
| 78 | } else if (is_report && !num) { | ||
| 79 | /* drop empty SYN_REPORT groups */ | ||
| 80 | continue; | ||
| 81 | } else if (head != i) { | ||
| 82 | /* move entry to fill the gap */ | ||
| 83 | client->buffer[head].time = ev->time; | ||
| 84 | client->buffer[head].type = ev->type; | ||
| 85 | client->buffer[head].code = ev->code; | ||
| 86 | client->buffer[head].value = ev->value; | ||
| 87 | } | ||
| 88 | |||
| 89 | num++; | ||
| 90 | head = (head + 1) & mask; | ||
| 91 | |||
| 92 | if (is_report) { | ||
| 93 | num = 0; | ||
| 94 | client->packet_head = head; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | client->head = head; | ||
| 99 | } | ||
| 100 | |||
| 101 | /* queue SYN_DROPPED event */ | ||
| 102 | static void evdev_queue_syn_dropped(struct evdev_client *client) | ||
| 103 | { | ||
| 104 | unsigned long flags; | ||
| 105 | struct input_event ev; | ||
| 106 | ktime_t time; | ||
| 107 | |||
| 108 | time = ktime_get(); | ||
| 109 | if (client->clkid != CLOCK_MONOTONIC) | ||
| 110 | time = ktime_sub(time, ktime_get_monotonic_offset()); | ||
| 111 | |||
| 112 | ev.time = ktime_to_timeval(time); | ||
| 113 | ev.type = EV_SYN; | ||
| 114 | ev.code = SYN_DROPPED; | ||
| 115 | ev.value = 0; | ||
| 116 | |||
| 117 | spin_lock_irqsave(&client->buffer_lock, flags); | ||
| 118 | |||
| 119 | client->buffer[client->head++] = ev; | ||
| 120 | client->head &= client->bufsize - 1; | ||
| 121 | |||
| 122 | if (unlikely(client->head == client->tail)) { | ||
| 123 | /* drop queue but keep our SYN_DROPPED event */ | ||
| 124 | client->tail = (client->head - 1) & (client->bufsize - 1); | ||
| 125 | client->packet_head = client->tail; | ||
| 126 | } | ||
| 127 | |||
| 128 | spin_unlock_irqrestore(&client->buffer_lock, flags); | ||
| 129 | } | ||
| 130 | |||
| 55 | static void __pass_event(struct evdev_client *client, | 131 | static void __pass_event(struct evdev_client *client, |
| 56 | const struct input_event *event) | 132 | const struct input_event *event) |
| 57 | { | 133 | { |
| @@ -650,6 +726,51 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p) | |||
| 650 | return input_set_keycode(dev, &ke); | 726 | return input_set_keycode(dev, &ke); |
| 651 | } | 727 | } |
| 652 | 728 | ||
| 729 | /* | ||
| 730 | * If we transfer state to the user, we should flush all pending events | ||
| 731 | * of the same type from the client's queue. Otherwise, they might end up | ||
| 732 | * with duplicate events, which can screw up client's state tracking. | ||
| 733 | * If bits_to_user fails after flushing the queue, we queue a SYN_DROPPED | ||
| 734 | * event so user-space will notice missing events. | ||
| 735 | * | ||
| 736 | * LOCKING: | ||
| 737 | * We need to take event_lock before buffer_lock to avoid dead-locks. But we | ||
| 738 | * need the even_lock only to guarantee consistent state. We can safely release | ||
| 739 | * it while flushing the queue. This allows input-core to handle filters while | ||
| 740 | * we flush the queue. | ||
| 741 | */ | ||
| 742 | static int evdev_handle_get_val(struct evdev_client *client, | ||
| 743 | struct input_dev *dev, unsigned int type, | ||
| 744 | unsigned long *bits, unsigned int max, | ||
| 745 | unsigned int size, void __user *p, int compat) | ||
| 746 | { | ||
| 747 | int ret; | ||
| 748 | unsigned long *mem; | ||
| 749 | |||
| 750 | mem = kmalloc(sizeof(unsigned long) * max, GFP_KERNEL); | ||
| 751 | if (!mem) | ||
| 752 | return -ENOMEM; | ||
| 753 | |||
| 754 | spin_lock_irq(&dev->event_lock); | ||
| 755 | spin_lock(&client->buffer_lock); | ||
| 756 | |||
| 757 | memcpy(mem, bits, sizeof(unsigned long) * max); | ||
| 758 | |||
| 759 | spin_unlock(&dev->event_lock); | ||
| 760 | |||
| 761 | __evdev_flush_queue(client, type); | ||
| 762 | |||
| 763 | spin_unlock_irq(&client->buffer_lock); | ||
| 764 | |||
| 765 | ret = bits_to_user(mem, max, size, p, compat); | ||
| 766 | if (ret < 0) | ||
| 767 | evdev_queue_syn_dropped(client); | ||
| 768 | |||
| 769 | kfree(mem); | ||
| 770 | |||
| 771 | return ret; | ||
| 772 | } | ||
| 773 | |||
| 653 | static int evdev_handle_mt_request(struct input_dev *dev, | 774 | static int evdev_handle_mt_request(struct input_dev *dev, |
| 654 | unsigned int size, | 775 | unsigned int size, |
| 655 | int __user *ip) | 776 | int __user *ip) |
| @@ -771,16 +892,20 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
| 771 | return evdev_handle_mt_request(dev, size, ip); | 892 | return evdev_handle_mt_request(dev, size, ip); |
| 772 | 893 | ||
| 773 | case EVIOCGKEY(0): | 894 | case EVIOCGKEY(0): |
| 774 | return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); | 895 | return evdev_handle_get_val(client, dev, EV_KEY, dev->key, |
| 896 | KEY_MAX, size, p, compat_mode); | ||
| 775 | 897 | ||
| 776 | case EVIOCGLED(0): | 898 | case EVIOCGLED(0): |
| 777 | return bits_to_user(dev->led, LED_MAX, size, p, compat_mode); | 899 | return evdev_handle_get_val(client, dev, EV_LED, dev->led, |
| 900 | LED_MAX, size, p, compat_mode); | ||
| 778 | 901 | ||
| 779 | case EVIOCGSND(0): | 902 | case EVIOCGSND(0): |
| 780 | return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode); | 903 | return evdev_handle_get_val(client, dev, EV_SND, dev->snd, |
| 904 | SND_MAX, size, p, compat_mode); | ||
| 781 | 905 | ||
| 782 | case EVIOCGSW(0): | 906 | case EVIOCGSW(0): |
| 783 | return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode); | 907 | return evdev_handle_get_val(client, dev, EV_SW, dev->sw, |
| 908 | SW_MAX, size, p, compat_mode); | ||
| 784 | 909 | ||
| 785 | case EVIOCGNAME(0): | 910 | case EVIOCGNAME(0): |
| 786 | return str_to_user(dev->name, size, p); | 911 | return str_to_user(dev->name, size, p); |
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 7cd74e29cbc8..9135606c8649 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c | |||
| @@ -158,14 +158,10 @@ static unsigned int get_time_pit(void) | |||
| 158 | #define GET_TIME(x) rdtscl(x) | 158 | #define GET_TIME(x) rdtscl(x) |
| 159 | #define DELTA(x,y) ((y)-(x)) | 159 | #define DELTA(x,y) ((y)-(x)) |
| 160 | #define TIME_NAME "TSC" | 160 | #define TIME_NAME "TSC" |
| 161 | #elif defined(__alpha__) | 161 | #elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_TILE) |
| 162 | #define GET_TIME(x) do { x = get_cycles(); } while (0) | 162 | #define GET_TIME(x) do { x = get_cycles(); } while (0) |
| 163 | #define DELTA(x,y) ((y)-(x)) | 163 | #define DELTA(x,y) ((y)-(x)) |
| 164 | #define TIME_NAME "PCC" | 164 | #define TIME_NAME "get_cycles" |
| 165 | #elif defined(CONFIG_MN10300) || defined(CONFIG_TILE) | ||
| 166 | #define GET_TIME(x) do { x = get_cycles(); } while (0) | ||
| 167 | #define DELTA(x, y) ((x) - (y)) | ||
| 168 | #define TIME_NAME "TSC" | ||
| 169 | #else | 165 | #else |
| 170 | #define FAKE_TIME | 166 | #define FAKE_TIME |
| 171 | static unsigned long analog_faketime = 0; | 167 | static unsigned long analog_faketime = 0; |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c62ca1b47a37..269d4c3658cb 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -175,7 +175,7 @@ config KEYBOARD_EP93XX | |||
| 175 | 175 | ||
| 176 | config KEYBOARD_GPIO | 176 | config KEYBOARD_GPIO |
| 177 | tristate "GPIO Buttons" | 177 | tristate "GPIO Buttons" |
| 178 | depends on GENERIC_GPIO | 178 | depends on GPIOLIB |
| 179 | help | 179 | help |
| 180 | This driver implements support for buttons connected | 180 | This driver implements support for buttons connected |
| 181 | to GPIO pins of various CPUs (and some other chips). | 181 | to GPIO pins of various CPUs (and some other chips). |
| @@ -190,7 +190,7 @@ config KEYBOARD_GPIO | |||
| 190 | 190 | ||
| 191 | config KEYBOARD_GPIO_POLLED | 191 | config KEYBOARD_GPIO_POLLED |
| 192 | tristate "Polled GPIO buttons" | 192 | tristate "Polled GPIO buttons" |
| 193 | depends on GENERIC_GPIO | 193 | depends on GPIOLIB |
| 194 | select INPUT_POLLDEV | 194 | select INPUT_POLLDEV |
| 195 | help | 195 | help |
| 196 | This driver implements support for buttons connected | 196 | This driver implements support for buttons connected |
| @@ -241,7 +241,7 @@ config KEYBOARD_TCA8418 | |||
| 241 | 241 | ||
| 242 | config KEYBOARD_MATRIX | 242 | config KEYBOARD_MATRIX |
| 243 | tristate "GPIO driven matrix keypad support" | 243 | tristate "GPIO driven matrix keypad support" |
| 244 | depends on GENERIC_GPIO | 244 | depends on GPIOLIB |
| 245 | select INPUT_MATRIXKMAP | 245 | select INPUT_MATRIXKMAP |
| 246 | help | 246 | help |
| 247 | Enable support for GPIO driven matrix keypad. | 247 | Enable support for GPIO driven matrix keypad. |
| @@ -418,6 +418,16 @@ config KEYBOARD_NOMADIK | |||
| 418 | To compile this driver as a module, choose M here: the | 418 | To compile this driver as a module, choose M here: the |
| 419 | module will be called nmk-ske-keypad. | 419 | module will be called nmk-ske-keypad. |
| 420 | 420 | ||
| 421 | config KEYBOARD_NSPIRE | ||
| 422 | tristate "TI-NSPIRE built-in keyboard" | ||
| 423 | depends on ARCH_NSPIRE && OF | ||
| 424 | select INPUT_MATRIXKMAP | ||
| 425 | help | ||
| 426 | Say Y here if you want to use the built-in keypad on TI-NSPIRE. | ||
| 427 | |||
| 428 | To compile this driver as a module, choose M here: the | ||
| 429 | module will be called nspire-keypad. | ||
| 430 | |||
| 421 | config KEYBOARD_TEGRA | 431 | config KEYBOARD_TEGRA |
| 422 | tristate "NVIDIA Tegra internal matrix keyboard controller support" | 432 | tristate "NVIDIA Tegra internal matrix keyboard controller support" |
| 423 | depends on ARCH_TEGRA && OF | 433 | depends on ARCH_TEGRA && OF |
| @@ -442,6 +452,7 @@ config KEYBOARD_OPENCORES | |||
| 442 | config KEYBOARD_PXA27x | 452 | config KEYBOARD_PXA27x |
| 443 | tristate "PXA27x/PXA3xx keypad support" | 453 | tristate "PXA27x/PXA3xx keypad support" |
| 444 | depends on PXA27x || PXA3xx || ARCH_MMP | 454 | depends on PXA27x || PXA3xx || ARCH_MMP |
| 455 | select INPUT_MATRIXKMAP | ||
| 445 | help | 456 | help |
| 446 | Enable support for PXA27x/PXA3xx keypad controller. | 457 | Enable support for PXA27x/PXA3xx keypad controller. |
| 447 | 458 | ||
| @@ -629,4 +640,16 @@ config KEYBOARD_W90P910 | |||
| 629 | To compile this driver as a module, choose M here: the | 640 | To compile this driver as a module, choose M here: the |
| 630 | module will be called w90p910_keypad. | 641 | module will be called w90p910_keypad. |
| 631 | 642 | ||
| 643 | config KEYBOARD_CROS_EC | ||
| 644 | tristate "ChromeOS EC keyboard" | ||
| 645 | select INPUT_MATRIXKMAP | ||
| 646 | depends on MFD_CROS_EC | ||
| 647 | help | ||
| 648 | Say Y here to enable the matrix keyboard used by ChromeOS devices | ||
| 649 | and implemented on the ChromeOS EC. You must enable one bus option | ||
| 650 | (MFD_CROS_EC_I2C or MFD_CROS_EC_SPI) to use this. | ||
| 651 | |||
| 652 | To compile this driver as a module, choose M here: the | ||
| 653 | module will be called cros_ec_keyb. | ||
| 654 | |||
| 632 | endif | 655 | endif |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 49b16453d00e..a699b6172303 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o | |||
| 11 | obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o | 11 | obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o |
| 12 | obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o | 12 | obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o |
| 13 | obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o | 13 | obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o |
| 14 | obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o | ||
| 14 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o | 15 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o |
| 15 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o | 16 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o |
| 16 | obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o | 17 | obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o |
| @@ -35,6 +36,7 @@ obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o | |||
| 35 | obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o | 36 | obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o |
| 36 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o | 37 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o |
| 37 | obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o | 38 | obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o |
| 39 | obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o | ||
| 38 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o | 40 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o |
| 39 | obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o | 41 | obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o |
| 40 | obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o | 42 | obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o |
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index ba0b36f7daea..096d6067ae1f 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c | |||
| @@ -246,7 +246,6 @@ static int __exit amikbd_remove(struct platform_device *pdev) | |||
| 246 | { | 246 | { |
| 247 | struct input_dev *dev = platform_get_drvdata(pdev); | 247 | struct input_dev *dev = platform_get_drvdata(pdev); |
| 248 | 248 | ||
| 249 | platform_set_drvdata(pdev, NULL); | ||
| 250 | free_irq(IRQ_AMIGA_CIAA_SP, dev); | 249 | free_irq(IRQ_AMIGA_CIAA_SP, dev); |
| 251 | input_unregister_device(dev); | 250 | input_unregister_device(dev); |
| 252 | return 0; | 251 | return 0; |
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index 20b9fa91fb9e..fc88fb48d70d 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c | |||
| @@ -326,7 +326,6 @@ out0: | |||
| 326 | kfree(bf54x_kpad->keycode); | 326 | kfree(bf54x_kpad->keycode); |
| 327 | out: | 327 | out: |
| 328 | kfree(bf54x_kpad); | 328 | kfree(bf54x_kpad); |
| 329 | platform_set_drvdata(pdev, NULL); | ||
| 330 | 329 | ||
| 331 | return error; | 330 | return error; |
| 332 | } | 331 | } |
| @@ -346,7 +345,6 @@ static int bfin_kpad_remove(struct platform_device *pdev) | |||
| 346 | 345 | ||
| 347 | kfree(bf54x_kpad->keycode); | 346 | kfree(bf54x_kpad->keycode); |
| 348 | kfree(bf54x_kpad); | 347 | kfree(bf54x_kpad); |
| 349 | platform_set_drvdata(pdev, NULL); | ||
| 350 | 348 | ||
| 351 | return 0; | 349 | return 0; |
| 352 | } | 350 | } |
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c new file mode 100644 index 000000000000..49557f27bfa6 --- /dev/null +++ b/drivers/input/keyboard/cros_ec_keyb.c | |||
| @@ -0,0 +1,334 @@ | |||
| 1 | /* | ||
| 2 | * ChromeOS EC keyboard driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Google, Inc | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the Chrome OS EC byte-level message-based protocol for | ||
| 16 | * communicating the keyboard state (which keys are pressed) from a keyboard EC | ||
| 17 | * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, | ||
| 18 | * but everything else (including deghosting) is done here. The main | ||
| 19 | * motivation for this is to keep the EC firmware as simple as possible, since | ||
| 20 | * it cannot be easily upgraded and EC flash/IRAM space is relatively | ||
| 21 | * expensive. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/input.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/notifier.h> | ||
| 29 | #include <linux/platform_device.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/input/matrix_keypad.h> | ||
| 32 | #include <linux/mfd/cros_ec.h> | ||
| 33 | #include <linux/mfd/cros_ec_commands.h> | ||
| 34 | |||
| 35 | /* | ||
| 36 | * @rows: Number of rows in the keypad | ||
| 37 | * @cols: Number of columns in the keypad | ||
| 38 | * @row_shift: log2 or number of rows, rounded up | ||
| 39 | * @keymap_data: Matrix keymap data used to convert to keyscan values | ||
| 40 | * @ghost_filter: true to enable the matrix key-ghosting filter | ||
| 41 | * @dev: Device pointer | ||
| 42 | * @idev: Input device | ||
| 43 | * @ec: Top level ChromeOS device to use to talk to EC | ||
| 44 | * @event_notifier: interrupt event notifier for transport devices | ||
| 45 | */ | ||
| 46 | struct cros_ec_keyb { | ||
| 47 | unsigned int rows; | ||
| 48 | unsigned int cols; | ||
| 49 | int row_shift; | ||
| 50 | const struct matrix_keymap_data *keymap_data; | ||
| 51 | bool ghost_filter; | ||
| 52 | |||
| 53 | struct device *dev; | ||
| 54 | struct input_dev *idev; | ||
| 55 | struct cros_ec_device *ec; | ||
| 56 | struct notifier_block notifier; | ||
| 57 | }; | ||
| 58 | |||
| 59 | |||
| 60 | static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev, | ||
| 61 | uint8_t *buf, int row) | ||
| 62 | { | ||
| 63 | int pressed_in_row = 0; | ||
| 64 | int row_has_teeth = 0; | ||
| 65 | int col, mask; | ||
| 66 | |||
| 67 | mask = 1 << row; | ||
| 68 | for (col = 0; col < ckdev->cols; col++) { | ||
| 69 | if (buf[col] & mask) { | ||
| 70 | pressed_in_row++; | ||
| 71 | row_has_teeth |= buf[col] & ~mask; | ||
| 72 | if (pressed_in_row > 1 && row_has_teeth) { | ||
| 73 | /* ghosting */ | ||
| 74 | dev_dbg(ckdev->dev, | ||
| 75 | "ghost found at: r%d c%d, pressed %d, teeth 0x%x\n", | ||
| 76 | row, col, pressed_in_row, | ||
| 77 | row_has_teeth); | ||
| 78 | return true; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | return false; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Returns true when there is at least one combination of pressed keys that | ||
| 88 | * results in ghosting. | ||
| 89 | */ | ||
| 90 | static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) | ||
| 91 | { | ||
| 92 | int row; | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Ghosting happens if for any pressed key X there are other keys | ||
| 96 | * pressed both in the same row and column of X as, for instance, | ||
| 97 | * in the following diagram: | ||
| 98 | * | ||
| 99 | * . . Y . g . | ||
| 100 | * . . . . . . | ||
| 101 | * . . . . . . | ||
| 102 | * . . X . Z . | ||
| 103 | * | ||
| 104 | * In this case only X, Y, and Z are pressed, but g appears to be | ||
| 105 | * pressed too (see Wikipedia). | ||
| 106 | * | ||
| 107 | * We can detect ghosting in a single pass (*) over the keyboard state | ||
| 108 | * by maintaining two arrays. pressed_in_row counts how many pressed | ||
| 109 | * keys we have found in a row. row_has_teeth is true if any of the | ||
| 110 | * pressed keys for this row has other pressed keys in its column. If | ||
| 111 | * at any point of the scan we find that a row has multiple pressed | ||
| 112 | * keys, and at least one of them is at the intersection with a column | ||
| 113 | * with multiple pressed keys, we're sure there is ghosting. | ||
| 114 | * Conversely, if there is ghosting, we will detect such situation for | ||
| 115 | * at least one key during the pass. | ||
| 116 | * | ||
| 117 | * (*) This looks linear in the number of keys, but it's not. We can | ||
| 118 | * cheat because the number of rows is small. | ||
| 119 | */ | ||
| 120 | for (row = 0; row < ckdev->rows; row++) | ||
| 121 | if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row)) | ||
| 122 | return true; | ||
| 123 | |||
| 124 | return false; | ||
| 125 | } | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Compares the new keyboard state to the old one and produces key | ||
| 129 | * press/release events accordingly. The keyboard state is 13 bytes (one byte | ||
| 130 | * per column) | ||
| 131 | */ | ||
| 132 | static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, | ||
| 133 | uint8_t *kb_state, int len) | ||
| 134 | { | ||
| 135 | struct input_dev *idev = ckdev->idev; | ||
| 136 | int col, row; | ||
| 137 | int new_state; | ||
| 138 | int num_cols; | ||
| 139 | |||
| 140 | num_cols = len; | ||
| 141 | |||
| 142 | if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) { | ||
| 143 | /* | ||
| 144 | * Simple-minded solution: ignore this state. The obvious | ||
| 145 | * improvement is to only ignore changes to keys involved in | ||
| 146 | * the ghosting, but process the other changes. | ||
| 147 | */ | ||
| 148 | dev_dbg(ckdev->dev, "ghosting found\n"); | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | |||
| 152 | for (col = 0; col < ckdev->cols; col++) { | ||
| 153 | for (row = 0; row < ckdev->rows; row++) { | ||
| 154 | int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); | ||
| 155 | const unsigned short *keycodes = idev->keycode; | ||
| 156 | int code; | ||
| 157 | |||
| 158 | code = keycodes[pos]; | ||
| 159 | new_state = kb_state[col] & (1 << row); | ||
| 160 | if (!!new_state != test_bit(code, idev->key)) { | ||
| 161 | dev_dbg(ckdev->dev, | ||
| 162 | "changed: [r%d c%d]: byte %02x\n", | ||
| 163 | row, col, new_state); | ||
| 164 | |||
| 165 | input_report_key(idev, code, new_state); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | input_sync(ckdev->idev); | ||
| 170 | } | ||
| 171 | |||
| 172 | static int cros_ec_keyb_open(struct input_dev *dev) | ||
| 173 | { | ||
| 174 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); | ||
| 175 | |||
| 176 | return blocking_notifier_chain_register(&ckdev->ec->event_notifier, | ||
| 177 | &ckdev->notifier); | ||
| 178 | } | ||
| 179 | |||
| 180 | static void cros_ec_keyb_close(struct input_dev *dev) | ||
| 181 | { | ||
| 182 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); | ||
| 183 | |||
| 184 | blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, | ||
| 185 | &ckdev->notifier); | ||
| 186 | } | ||
| 187 | |||
| 188 | static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) | ||
| 189 | { | ||
| 190 | return ckdev->ec->command_recv(ckdev->ec, EC_CMD_MKBP_STATE, | ||
| 191 | kb_state, ckdev->cols); | ||
| 192 | } | ||
| 193 | |||
| 194 | static int cros_ec_keyb_work(struct notifier_block *nb, | ||
| 195 | unsigned long state, void *_notify) | ||
| 196 | { | ||
| 197 | int ret; | ||
| 198 | struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, | ||
| 199 | notifier); | ||
| 200 | uint8_t kb_state[ckdev->cols]; | ||
| 201 | |||
| 202 | ret = cros_ec_keyb_get_state(ckdev, kb_state); | ||
| 203 | if (ret >= 0) | ||
| 204 | cros_ec_keyb_process(ckdev, kb_state, ret); | ||
| 205 | |||
| 206 | return NOTIFY_DONE; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* Clear any keys in the buffer */ | ||
| 210 | static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev) | ||
| 211 | { | ||
| 212 | uint8_t old_state[ckdev->cols]; | ||
| 213 | uint8_t new_state[ckdev->cols]; | ||
| 214 | unsigned long duration; | ||
| 215 | int i, ret; | ||
| 216 | |||
| 217 | /* | ||
| 218 | * Keep reading until we see that the scan state does not change. | ||
| 219 | * That indicates that we are done. | ||
| 220 | * | ||
| 221 | * Assume that the EC keyscan buffer is at most 32 deep. | ||
| 222 | */ | ||
| 223 | duration = jiffies; | ||
| 224 | ret = cros_ec_keyb_get_state(ckdev, new_state); | ||
| 225 | for (i = 1; !ret && i < 32; i++) { | ||
| 226 | memcpy(old_state, new_state, sizeof(old_state)); | ||
| 227 | ret = cros_ec_keyb_get_state(ckdev, new_state); | ||
| 228 | if (0 == memcmp(old_state, new_state, sizeof(old_state))) | ||
| 229 | break; | ||
| 230 | } | ||
| 231 | duration = jiffies - duration; | ||
| 232 | dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i, | ||
| 233 | jiffies_to_usecs(duration)); | ||
| 234 | } | ||
| 235 | |||
| 236 | static int cros_ec_keyb_probe(struct platform_device *pdev) | ||
| 237 | { | ||
| 238 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | ||
| 239 | struct device *dev = ec->dev; | ||
| 240 | struct cros_ec_keyb *ckdev; | ||
| 241 | struct input_dev *idev; | ||
| 242 | struct device_node *np; | ||
| 243 | int err; | ||
| 244 | |||
| 245 | np = pdev->dev.of_node; | ||
| 246 | if (!np) | ||
| 247 | return -ENODEV; | ||
| 248 | |||
| 249 | ckdev = devm_kzalloc(&pdev->dev, sizeof(*ckdev), GFP_KERNEL); | ||
| 250 | if (!ckdev) | ||
| 251 | return -ENOMEM; | ||
| 252 | err = matrix_keypad_parse_of_params(&pdev->dev, &ckdev->rows, | ||
| 253 | &ckdev->cols); | ||
| 254 | if (err) | ||
| 255 | return err; | ||
| 256 | |||
| 257 | idev = devm_input_allocate_device(&pdev->dev); | ||
| 258 | if (!idev) | ||
| 259 | return -ENOMEM; | ||
| 260 | |||
| 261 | ckdev->ec = ec; | ||
| 262 | ckdev->notifier.notifier_call = cros_ec_keyb_work; | ||
| 263 | ckdev->dev = dev; | ||
| 264 | dev_set_drvdata(&pdev->dev, ckdev); | ||
| 265 | |||
| 266 | idev->name = ec->ec_name; | ||
| 267 | idev->phys = ec->phys_name; | ||
| 268 | __set_bit(EV_REP, idev->evbit); | ||
| 269 | |||
| 270 | idev->id.bustype = BUS_VIRTUAL; | ||
| 271 | idev->id.version = 1; | ||
| 272 | idev->id.product = 0; | ||
| 273 | idev->dev.parent = &pdev->dev; | ||
| 274 | idev->open = cros_ec_keyb_open; | ||
| 275 | idev->close = cros_ec_keyb_close; | ||
| 276 | |||
| 277 | ckdev->ghost_filter = of_property_read_bool(np, | ||
| 278 | "google,needs-ghost-filter"); | ||
| 279 | |||
| 280 | err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, | ||
| 281 | NULL, idev); | ||
| 282 | if (err) { | ||
| 283 | dev_err(dev, "cannot build key matrix\n"); | ||
| 284 | return err; | ||
| 285 | } | ||
| 286 | |||
| 287 | ckdev->row_shift = get_count_order(ckdev->cols); | ||
| 288 | |||
| 289 | input_set_capability(idev, EV_MSC, MSC_SCAN); | ||
| 290 | input_set_drvdata(idev, ckdev); | ||
| 291 | ckdev->idev = idev; | ||
| 292 | err = input_register_device(ckdev->idev); | ||
| 293 | if (err) { | ||
| 294 | dev_err(dev, "cannot register input device\n"); | ||
| 295 | return err; | ||
| 296 | } | ||
| 297 | |||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | #ifdef CONFIG_PM_SLEEP | ||
| 302 | static int cros_ec_keyb_resume(struct device *dev) | ||
| 303 | { | ||
| 304 | struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); | ||
| 305 | |||
| 306 | /* | ||
| 307 | * When the EC is not a wake source, then it could not have caused the | ||
| 308 | * resume, so we clear the EC's key scan buffer. If the EC was a | ||
| 309 | * wake source (e.g. the lid is open and the user might press a key to | ||
| 310 | * wake) then the key scan buffer should be preserved. | ||
| 311 | */ | ||
| 312 | if (ckdev->ec->was_wake_device) | ||
| 313 | cros_ec_keyb_clear_keyboard(ckdev); | ||
| 314 | |||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | |||
| 318 | #endif | ||
| 319 | |||
| 320 | static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); | ||
| 321 | |||
| 322 | static struct platform_driver cros_ec_keyb_driver = { | ||
| 323 | .probe = cros_ec_keyb_probe, | ||
| 324 | .driver = { | ||
| 325 | .name = "cros-ec-keyb", | ||
| 326 | .pm = &cros_ec_keyb_pm_ops, | ||
| 327 | }, | ||
| 328 | }; | ||
| 329 | |||
| 330 | module_platform_driver(cros_ec_keyb_driver); | ||
| 331 | |||
| 332 | MODULE_LICENSE("GPL"); | ||
| 333 | MODULE_DESCRIPTION("ChromeOS EC keyboard driver"); | ||
| 334 | MODULE_ALIAS("platform:cros-ec-keyb"); | ||
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index 829753702b62..d15977a8361e 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c | |||
| @@ -314,8 +314,6 @@ static int davinci_ks_remove(struct platform_device *pdev) | |||
| 314 | iounmap(davinci_ks->base); | 314 | iounmap(davinci_ks->base); |
| 315 | release_mem_region(davinci_ks->pbase, davinci_ks->base_size); | 315 | release_mem_region(davinci_ks->pbase, davinci_ks->base_size); |
| 316 | 316 | ||
| 317 | platform_set_drvdata(pdev, NULL); | ||
| 318 | |||
| 319 | kfree(davinci_ks); | 317 | kfree(davinci_ks); |
| 320 | 318 | ||
| 321 | return 0; | 319 | return 0; |
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 9857e8fd0987..47206bdba411 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c | |||
| @@ -329,8 +329,7 @@ static int ep93xx_keypad_probe(struct platform_device *pdev) | |||
| 329 | return 0; | 329 | return 0; |
| 330 | 330 | ||
| 331 | failed_free_irq: | 331 | failed_free_irq: |
| 332 | free_irq(keypad->irq, pdev); | 332 | free_irq(keypad->irq, keypad); |
| 333 | platform_set_drvdata(pdev, NULL); | ||
| 334 | failed_free_dev: | 333 | failed_free_dev: |
| 335 | input_free_device(input_dev); | 334 | input_free_device(input_dev); |
| 336 | failed_put_clk: | 335 | failed_put_clk: |
| @@ -351,9 +350,7 @@ static int ep93xx_keypad_remove(struct platform_device *pdev) | |||
| 351 | struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); | 350 | struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); |
| 352 | struct resource *res; | 351 | struct resource *res; |
| 353 | 352 | ||
| 354 | free_irq(keypad->irq, pdev); | 353 | free_irq(keypad->irq, keypad); |
| 355 | |||
| 356 | platform_set_drvdata(pdev, NULL); | ||
| 357 | 354 | ||
| 358 | if (keypad->enabled) | 355 | if (keypad->enabled) |
| 359 | clk_disable(keypad->clk); | 356 | clk_disable(keypad->clk); |
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index b29ca651a395..440ce32462ba 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c | |||
| @@ -767,7 +767,6 @@ static int gpio_keys_probe(struct platform_device *pdev) | |||
| 767 | while (--i >= 0) | 767 | while (--i >= 0) |
| 768 | gpio_remove_key(&ddata->data[i]); | 768 | gpio_remove_key(&ddata->data[i]); |
| 769 | 769 | ||
| 770 | platform_set_drvdata(pdev, NULL); | ||
| 771 | fail1: | 770 | fail1: |
| 772 | input_free_device(input); | 771 | input_free_device(input); |
| 773 | kfree(ddata); | 772 | kfree(ddata); |
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 21147164874d..cd5ed9e22168 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c | |||
| @@ -324,7 +324,6 @@ err_free_gpio: | |||
| 324 | 324 | ||
| 325 | err_free_bdev: | 325 | err_free_bdev: |
| 326 | kfree(bdev); | 326 | kfree(bdev); |
| 327 | platform_set_drvdata(pdev, NULL); | ||
| 328 | 327 | ||
| 329 | err_free_pdata: | 328 | err_free_pdata: |
| 330 | /* If we have no platform_data, we allocated pdata dynamically. */ | 329 | /* If we have no platform_data, we allocated pdata dynamically. */ |
| @@ -355,7 +354,6 @@ static int gpio_keys_polled_remove(struct platform_device *pdev) | |||
| 355 | kfree(pdata); | 354 | kfree(pdata); |
| 356 | 355 | ||
| 357 | kfree(bdev); | 356 | kfree(bdev); |
| 358 | platform_set_drvdata(pdev, NULL); | ||
| 359 | 357 | ||
| 360 | return 0; | 358 | return 0; |
| 361 | } | 359 | } |
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index 74e75a6e8deb..a2a034c25f0b 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c | |||
| @@ -233,7 +233,6 @@ static int jornada680kbd_probe(struct platform_device *pdev) | |||
| 233 | failed: | 233 | failed: |
| 234 | printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n", | 234 | printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n", |
| 235 | error); | 235 | error); |
| 236 | platform_set_drvdata(pdev, NULL); | ||
| 237 | input_free_polled_device(poll_dev); | 236 | input_free_polled_device(poll_dev); |
| 238 | kfree(jornadakbd); | 237 | kfree(jornadakbd); |
| 239 | return error; | 238 | return error; |
| @@ -244,7 +243,6 @@ static int jornada680kbd_remove(struct platform_device *pdev) | |||
| 244 | { | 243 | { |
| 245 | struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); | 244 | struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); |
| 246 | 245 | ||
| 247 | platform_set_drvdata(pdev, NULL); | ||
| 248 | input_unregister_polled_device(jornadakbd->poll_dev); | 246 | input_unregister_polled_device(jornadakbd->poll_dev); |
| 249 | input_free_polled_device(jornadakbd->poll_dev); | 247 | input_free_polled_device(jornadakbd->poll_dev); |
| 250 | kfree(jornadakbd); | 248 | kfree(jornadakbd); |
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 5ceef636df2f..b0ad457ca9d8 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c | |||
| @@ -146,7 +146,6 @@ static int jornada720_kbd_probe(struct platform_device *pdev) | |||
| 146 | fail2: /* IRQ, DEVICE, MEMORY */ | 146 | fail2: /* IRQ, DEVICE, MEMORY */ |
| 147 | free_irq(IRQ_GPIO0, pdev); | 147 | free_irq(IRQ_GPIO0, pdev); |
| 148 | fail1: /* DEVICE, MEMORY */ | 148 | fail1: /* DEVICE, MEMORY */ |
| 149 | platform_set_drvdata(pdev, NULL); | ||
| 150 | input_free_device(input_dev); | 149 | input_free_device(input_dev); |
| 151 | kfree(jornadakbd); | 150 | kfree(jornadakbd); |
| 152 | return err; | 151 | return err; |
| @@ -157,7 +156,6 @@ static int jornada720_kbd_remove(struct platform_device *pdev) | |||
| 157 | struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); | 156 | struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); |
| 158 | 157 | ||
| 159 | free_irq(IRQ_GPIO0, pdev); | 158 | free_irq(IRQ_GPIO0, pdev); |
| 160 | platform_set_drvdata(pdev, NULL); | ||
| 161 | input_unregister_device(jornadakbd->input); | 159 | input_unregister_device(jornadakbd->input); |
| 162 | kfree(jornadakbd); | 160 | kfree(jornadakbd); |
| 163 | 161 | ||
diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 1b8add6cfb9d..42181435fe67 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c | |||
| @@ -144,12 +144,13 @@ static int lpc32xx_parse_dt(struct device *dev, | |||
| 144 | { | 144 | { |
| 145 | struct device_node *np = dev->of_node; | 145 | struct device_node *np = dev->of_node; |
| 146 | u32 rows = 0, columns = 0; | 146 | u32 rows = 0, columns = 0; |
| 147 | int err; | ||
| 147 | 148 | ||
| 148 | of_property_read_u32(np, "keypad,num-rows", &rows); | 149 | err = matrix_keypad_parse_of_params(dev, &rows, &columns); |
| 149 | of_property_read_u32(np, "keypad,num-columns", &columns); | 150 | if (err) |
| 150 | if (!rows || rows != columns) { | 151 | return err; |
| 151 | dev_err(dev, | 152 | if (rows != columns) { |
| 152 | "rows and columns must be specified and be equal!\n"); | 153 | dev_err(dev, "rows and columns must be equal!\n"); |
| 153 | return -EINVAL; | 154 | return -EINVAL; |
| 154 | } | 155 | } |
| 155 | 156 | ||
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 71d77192ac1e..90ff73ace424 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c | |||
| @@ -549,8 +549,6 @@ static int matrix_keypad_remove(struct platform_device *pdev) | |||
| 549 | input_unregister_device(keypad->input_dev); | 549 | input_unregister_device(keypad->input_dev); |
| 550 | kfree(keypad); | 550 | kfree(keypad); |
| 551 | 551 | ||
| 552 | platform_set_drvdata(pdev, NULL); | ||
| 553 | |||
| 554 | return 0; | 552 | return 0; |
| 555 | } | 553 | } |
| 556 | 554 | ||
diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c new file mode 100644 index 000000000000..e0a1339e40e6 --- /dev/null +++ b/drivers/input/keyboard/nspire-keypad.c | |||
| @@ -0,0 +1,283 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2, as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/input/matrix_keypad.h> | ||
| 10 | #include <linux/platform_device.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/io.h> | ||
| 13 | #include <linux/delay.h> | ||
| 14 | #include <linux/input.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/clk.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | |||
| 20 | #define KEYPAD_SCAN_MODE 0x00 | ||
| 21 | #define KEYPAD_CNTL 0x04 | ||
| 22 | #define KEYPAD_INT 0x08 | ||
| 23 | #define KEYPAD_INTMSK 0x0C | ||
| 24 | |||
| 25 | #define KEYPAD_DATA 0x10 | ||
| 26 | #define KEYPAD_GPIO 0x30 | ||
| 27 | |||
| 28 | #define KEYPAD_UNKNOWN_INT 0x40 | ||
| 29 | #define KEYPAD_UNKNOWN_INT_STS 0x44 | ||
| 30 | |||
| 31 | #define KEYPAD_BITMASK_COLS 11 | ||
| 32 | #define KEYPAD_BITMASK_ROWS 8 | ||
| 33 | |||
| 34 | struct nspire_keypad { | ||
| 35 | void __iomem *reg_base; | ||
| 36 | u32 int_mask; | ||
| 37 | |||
| 38 | struct input_dev *input; | ||
| 39 | struct clk *clk; | ||
| 40 | |||
| 41 | struct matrix_keymap_data *keymap; | ||
| 42 | int row_shift; | ||
| 43 | |||
| 44 | /* Maximum delay estimated assuming 33MHz APB */ | ||
| 45 | u32 scan_interval; /* In microseconds (~2000us max) */ | ||
| 46 | u32 row_delay; /* In microseconds (~500us max) */ | ||
| 47 | |||
| 48 | u16 state[KEYPAD_BITMASK_ROWS]; | ||
| 49 | |||
| 50 | bool active_low; | ||
| 51 | }; | ||
| 52 | |||
| 53 | static irqreturn_t nspire_keypad_irq(int irq, void *dev_id) | ||
| 54 | { | ||
| 55 | struct nspire_keypad *keypad = dev_id; | ||
| 56 | struct input_dev *input = keypad->input; | ||
| 57 | unsigned short *keymap = input->keycode; | ||
| 58 | unsigned int code; | ||
| 59 | int row, col; | ||
| 60 | u32 int_sts; | ||
| 61 | u16 state[8]; | ||
| 62 | u16 bits, changed; | ||
| 63 | |||
| 64 | int_sts = readl(keypad->reg_base + KEYPAD_INT) & keypad->int_mask; | ||
| 65 | if (!int_sts) | ||
| 66 | return IRQ_NONE; | ||
| 67 | |||
| 68 | memcpy_fromio(state, keypad->reg_base + KEYPAD_DATA, sizeof(state)); | ||
| 69 | |||
| 70 | for (row = 0; row < KEYPAD_BITMASK_ROWS; row++) { | ||
| 71 | bits = state[row]; | ||
| 72 | if (keypad->active_low) | ||
| 73 | bits = ~bits; | ||
| 74 | |||
| 75 | changed = bits ^ keypad->state[row]; | ||
| 76 | if (!changed) | ||
| 77 | continue; | ||
| 78 | |||
| 79 | keypad->state[row] = bits; | ||
| 80 | |||
| 81 | for (col = 0; col < KEYPAD_BITMASK_COLS; col++) { | ||
| 82 | if (!(changed & (1U << col))) | ||
| 83 | continue; | ||
| 84 | |||
| 85 | code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); | ||
| 86 | input_event(input, EV_MSC, MSC_SCAN, code); | ||
| 87 | input_report_key(input, keymap[code], | ||
| 88 | bits & (1U << col)); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | input_sync(input); | ||
| 93 | |||
| 94 | writel(0x3, keypad->reg_base + KEYPAD_INT); | ||
| 95 | |||
| 96 | return IRQ_HANDLED; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int nspire_keypad_chip_init(struct nspire_keypad *keypad) | ||
| 100 | { | ||
| 101 | unsigned long val = 0, cycles_per_us, delay_cycles, row_delay_cycles; | ||
| 102 | |||
| 103 | cycles_per_us = (clk_get_rate(keypad->clk) / 1000000); | ||
| 104 | if (cycles_per_us == 0) | ||
| 105 | cycles_per_us = 1; | ||
| 106 | |||
| 107 | delay_cycles = cycles_per_us * keypad->scan_interval; | ||
| 108 | WARN_ON(delay_cycles >= (1 << 16)); /* Overflow */ | ||
| 109 | delay_cycles &= 0xffff; | ||
| 110 | |||
| 111 | row_delay_cycles = cycles_per_us * keypad->row_delay; | ||
| 112 | WARN_ON(row_delay_cycles >= (1 << 14)); /* Overflow */ | ||
| 113 | row_delay_cycles &= 0x3fff; | ||
| 114 | |||
| 115 | val |= 3 << 0; /* Set scan mode to 3 (continuous scan) */ | ||
| 116 | val |= row_delay_cycles << 2; /* Delay between scanning each row */ | ||
| 117 | val |= delay_cycles << 16; /* Delay between scans */ | ||
| 118 | writel(val, keypad->reg_base + KEYPAD_SCAN_MODE); | ||
| 119 | |||
| 120 | val = (KEYPAD_BITMASK_ROWS & 0xff) | (KEYPAD_BITMASK_COLS & 0xff)<<8; | ||
| 121 | writel(val, keypad->reg_base + KEYPAD_CNTL); | ||
| 122 | |||
| 123 | /* Enable interrupts */ | ||
| 124 | keypad->int_mask = 1 << 1; | ||
| 125 | writel(keypad->int_mask, keypad->reg_base + 0xc); | ||
| 126 | |||
| 127 | /* Disable GPIO interrupts to prevent hanging on touchpad */ | ||
| 128 | /* Possibly used to detect touchpad events */ | ||
| 129 | writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT); | ||
| 130 | /* Acknowledge existing interrupts */ | ||
| 131 | writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS); | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | static int nspire_keypad_open(struct input_dev *input) | ||
| 137 | { | ||
| 138 | struct nspire_keypad *keypad = input_get_drvdata(input); | ||
| 139 | int error; | ||
| 140 | |||
| 141 | error = clk_prepare_enable(keypad->clk); | ||
| 142 | if (error) | ||
| 143 | return error; | ||
| 144 | |||
| 145 | error = nspire_keypad_chip_init(keypad); | ||
| 146 | if (error) | ||
| 147 | return error; | ||
| 148 | |||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | static void nspire_keypad_close(struct input_dev *input) | ||
| 153 | { | ||
| 154 | struct nspire_keypad *keypad = input_get_drvdata(input); | ||
| 155 | |||
| 156 | clk_disable_unprepare(keypad->clk); | ||
| 157 | } | ||
| 158 | |||
| 159 | static int nspire_keypad_probe(struct platform_device *pdev) | ||
| 160 | { | ||
| 161 | const struct device_node *of_node = pdev->dev.of_node; | ||
| 162 | struct nspire_keypad *keypad; | ||
| 163 | struct input_dev *input; | ||
| 164 | struct resource *res; | ||
| 165 | int irq; | ||
| 166 | int error; | ||
| 167 | |||
| 168 | irq = platform_get_irq(pdev, 0); | ||
| 169 | if (irq < 0) { | ||
| 170 | dev_err(&pdev->dev, "failed to get keypad irq\n"); | ||
| 171 | return -EINVAL; | ||
| 172 | } | ||
| 173 | |||
| 174 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 175 | if (!res) { | ||
| 176 | dev_err(&pdev->dev, "missing platform resources\n"); | ||
| 177 | return -EINVAL; | ||
| 178 | } | ||
| 179 | |||
| 180 | keypad = devm_kzalloc(&pdev->dev, sizeof(struct nspire_keypad), | ||
| 181 | GFP_KERNEL); | ||
| 182 | if (!keypad) { | ||
| 183 | dev_err(&pdev->dev, "failed to allocate keypad memory\n"); | ||
| 184 | return -ENOMEM; | ||
| 185 | } | ||
| 186 | |||
| 187 | keypad->row_shift = get_count_order(KEYPAD_BITMASK_COLS); | ||
| 188 | |||
| 189 | error = of_property_read_u32(of_node, "scan-interval", | ||
| 190 | &keypad->scan_interval); | ||
| 191 | if (error) { | ||
| 192 | dev_err(&pdev->dev, "failed to get scan-interval\n"); | ||
| 193 | return error; | ||
| 194 | } | ||
| 195 | |||
| 196 | error = of_property_read_u32(of_node, "row-delay", | ||
| 197 | &keypad->row_delay); | ||
| 198 | if (error) { | ||
| 199 | dev_err(&pdev->dev, "failed to get row-delay\n"); | ||
| 200 | return error; | ||
| 201 | } | ||
| 202 | |||
| 203 | keypad->active_low = of_property_read_bool(of_node, "active-low"); | ||
| 204 | |||
| 205 | keypad->clk = devm_clk_get(&pdev->dev, NULL); | ||
| 206 | if (IS_ERR(keypad->clk)) { | ||
| 207 | dev_err(&pdev->dev, "unable to get clock\n"); | ||
| 208 | return PTR_ERR(keypad->clk); | ||
| 209 | } | ||
| 210 | |||
| 211 | keypad->reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
| 212 | if (IS_ERR(keypad->reg_base)) | ||
| 213 | return PTR_ERR(keypad->reg_base); | ||
| 214 | |||
| 215 | keypad->input = input = devm_input_allocate_device(&pdev->dev); | ||
| 216 | if (!input) { | ||
| 217 | dev_err(&pdev->dev, "failed to allocate input device\n"); | ||
| 218 | return -ENOMEM; | ||
| 219 | } | ||
| 220 | |||
| 221 | input_set_drvdata(input, keypad); | ||
| 222 | |||
| 223 | input->id.bustype = BUS_HOST; | ||
| 224 | input->name = "nspire-keypad"; | ||
| 225 | input->open = nspire_keypad_open; | ||
| 226 | input->close = nspire_keypad_close; | ||
| 227 | |||
| 228 | __set_bit(EV_KEY, input->evbit); | ||
| 229 | __set_bit(EV_REP, input->evbit); | ||
| 230 | input_set_capability(input, EV_MSC, MSC_SCAN); | ||
| 231 | |||
| 232 | error = matrix_keypad_build_keymap(NULL, NULL, | ||
| 233 | KEYPAD_BITMASK_ROWS, | ||
| 234 | KEYPAD_BITMASK_COLS, | ||
| 235 | NULL, input); | ||
| 236 | if (error) { | ||
| 237 | dev_err(&pdev->dev, "building keymap failed\n"); | ||
| 238 | return error; | ||
| 239 | } | ||
| 240 | |||
| 241 | error = devm_request_irq(&pdev->dev, irq, nspire_keypad_irq, 0, | ||
| 242 | "nspire_keypad", keypad); | ||
| 243 | if (error) { | ||
| 244 | dev_err(&pdev->dev, "allocate irq %d failed\n", irq); | ||
| 245 | return error; | ||
| 246 | } | ||
| 247 | |||
| 248 | error = input_register_device(input); | ||
| 249 | if (error) { | ||
| 250 | dev_err(&pdev->dev, | ||
| 251 | "unable to register input device: %d\n", error); | ||
| 252 | return error; | ||
| 253 | } | ||
| 254 | |||
| 255 | platform_set_drvdata(pdev, keypad); | ||
| 256 | |||
| 257 | dev_dbg(&pdev->dev, | ||
| 258 | "TI-NSPIRE keypad at %pR (scan_interval=%uus, row_delay=%uus%s)\n", | ||
| 259 | res, keypad->row_delay, keypad->scan_interval, | ||
| 260 | keypad->active_low ? ", active_low" : ""); | ||
| 261 | |||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | static const struct of_device_id nspire_keypad_dt_match[] = { | ||
| 266 | { .compatible = "ti,nspire-keypad" }, | ||
| 267 | { }, | ||
| 268 | }; | ||
| 269 | MODULE_DEVICE_TABLE(of, nspire_keypad_dt_match); | ||
| 270 | |||
| 271 | static struct platform_driver nspire_keypad_driver = { | ||
| 272 | .driver = { | ||
| 273 | .name = "nspire-keypad", | ||
| 274 | .owner = THIS_MODULE, | ||
| 275 | .of_match_table = of_match_ptr(nspire_keypad_dt_match), | ||
| 276 | }, | ||
| 277 | .probe = nspire_keypad_probe, | ||
| 278 | }; | ||
| 279 | |||
| 280 | module_platform_driver(nspire_keypad_driver); | ||
| 281 | |||
| 282 | MODULE_LICENSE("GPL"); | ||
| 283 | MODULE_DESCRIPTION("TI-NSPIRE Keypad Driver"); | ||
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index e25b022692cd..f4aa53a1fd69 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c | |||
| @@ -215,18 +215,12 @@ static int omap4_keypad_parse_dt(struct device *dev, | |||
| 215 | struct omap4_keypad *keypad_data) | 215 | struct omap4_keypad *keypad_data) |
| 216 | { | 216 | { |
| 217 | struct device_node *np = dev->of_node; | 217 | struct device_node *np = dev->of_node; |
| 218 | int err; | ||
| 218 | 219 | ||
| 219 | if (!np) { | 220 | err = matrix_keypad_parse_of_params(dev, &keypad_data->rows, |
| 220 | dev_err(dev, "missing DT data"); | 221 | &keypad_data->cols); |
| 221 | return -EINVAL; | 222 | if (err) |
| 222 | } | 223 | return err; |
| 223 | |||
| 224 | of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows); | ||
| 225 | of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols); | ||
| 226 | if (!keypad_data->rows || !keypad_data->cols) { | ||
| 227 | dev_err(dev, "number of keypad rows/columns not specified\n"); | ||
| 228 | return -EINVAL; | ||
| 229 | } | ||
| 230 | 224 | ||
| 231 | if (of_get_property(np, "linux,input-no-autorepeat", NULL)) | 225 | if (of_get_property(np, "linux,input-no-autorepeat", NULL)) |
| 232 | keypad_data->no_autorepeat = true; | 226 | keypad_data->no_autorepeat = true; |
| @@ -425,8 +419,6 @@ static int omap4_keypad_remove(struct platform_device *pdev) | |||
| 425 | kfree(keypad_data->keymap); | 419 | kfree(keypad_data->keymap); |
| 426 | kfree(keypad_data); | 420 | kfree(keypad_data); |
| 427 | 421 | ||
| 428 | platform_set_drvdata(pdev, NULL); | ||
| 429 | |||
| 430 | return 0; | 422 | return 0; |
| 431 | } | 423 | } |
| 432 | 424 | ||
diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index 7ac5f174c6f7..7b9b44158ad1 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c | |||
| @@ -151,8 +151,6 @@ static int opencores_kbd_remove(struct platform_device *pdev) | |||
| 151 | input_unregister_device(opencores_kbd->input); | 151 | input_unregister_device(opencores_kbd->input); |
| 152 | kfree(opencores_kbd); | 152 | kfree(opencores_kbd); |
| 153 | 153 | ||
| 154 | platform_set_drvdata(pdev, NULL); | ||
| 155 | |||
| 156 | return 0; | 154 | return 0; |
| 157 | } | 155 | } |
| 158 | 156 | ||
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 74339e139d43..2c9f19ac35ea 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c | |||
| @@ -707,7 +707,6 @@ err_gpio_config: | |||
| 707 | err_get_irq: | 707 | err_get_irq: |
| 708 | input_free_device(kp->input); | 708 | input_free_device(kp->input); |
| 709 | err_alloc_device: | 709 | err_alloc_device: |
| 710 | platform_set_drvdata(pdev, NULL); | ||
| 711 | kfree(kp); | 710 | kfree(kp); |
| 712 | return rc; | 711 | return rc; |
| 713 | } | 712 | } |
| @@ -722,7 +721,6 @@ static int pmic8xxx_kp_remove(struct platform_device *pdev) | |||
| 722 | input_unregister_device(kp->input); | 721 | input_unregister_device(kp->input); |
| 723 | kfree(kp); | 722 | kfree(kp); |
| 724 | 723 | ||
| 725 | platform_set_drvdata(pdev, NULL); | ||
| 726 | return 0; | 724 | return 0; |
| 727 | } | 725 | } |
| 728 | 726 | ||
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 5330d8fbf6c0..134c3b404a54 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c | |||
| @@ -100,7 +100,7 @@ | |||
| 100 | #define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM) | 100 | #define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM) |
| 101 | 101 | ||
| 102 | struct pxa27x_keypad { | 102 | struct pxa27x_keypad { |
| 103 | struct pxa27x_keypad_platform_data *pdata; | 103 | const struct pxa27x_keypad_platform_data *pdata; |
| 104 | 104 | ||
| 105 | struct clk *clk; | 105 | struct clk *clk; |
| 106 | struct input_dev *input_dev; | 106 | struct input_dev *input_dev; |
| @@ -118,25 +118,254 @@ struct pxa27x_keypad { | |||
| 118 | unsigned int direct_key_mask; | 118 | unsigned int direct_key_mask; |
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) | 121 | #ifdef CONFIG_OF |
| 122 | static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad, | ||
| 123 | struct pxa27x_keypad_platform_data *pdata) | ||
| 122 | { | 124 | { |
| 123 | struct pxa27x_keypad_platform_data *pdata = keypad->pdata; | ||
| 124 | struct input_dev *input_dev = keypad->input_dev; | 125 | struct input_dev *input_dev = keypad->input_dev; |
| 125 | unsigned short keycode; | 126 | struct device *dev = input_dev->dev.parent; |
| 127 | u32 rows, cols; | ||
| 128 | int error; | ||
| 129 | |||
| 130 | error = matrix_keypad_parse_of_params(dev, &rows, &cols); | ||
| 131 | if (error) | ||
| 132 | return error; | ||
| 133 | |||
| 134 | if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) { | ||
| 135 | dev_err(dev, "rows or cols exceeds maximum value\n"); | ||
| 136 | return -EINVAL; | ||
| 137 | } | ||
| 138 | |||
| 139 | pdata->matrix_key_rows = rows; | ||
| 140 | pdata->matrix_key_cols = cols; | ||
| 141 | |||
| 142 | error = matrix_keypad_build_keymap(NULL, NULL, | ||
| 143 | pdata->matrix_key_rows, | ||
| 144 | pdata->matrix_key_cols, | ||
| 145 | keypad->keycodes, input_dev); | ||
| 146 | if (error) | ||
| 147 | return error; | ||
| 148 | |||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad, | ||
| 153 | struct pxa27x_keypad_platform_data *pdata) | ||
| 154 | { | ||
| 155 | struct input_dev *input_dev = keypad->input_dev; | ||
| 156 | struct device *dev = input_dev->dev.parent; | ||
| 157 | struct device_node *np = dev->of_node; | ||
| 158 | const __be16 *prop; | ||
| 159 | unsigned short code; | ||
| 160 | unsigned int proplen, size; | ||
| 126 | int i; | 161 | int i; |
| 162 | int error; | ||
| 127 | 163 | ||
| 128 | for (i = 0; i < pdata->matrix_key_map_size; i++) { | 164 | error = of_property_read_u32(np, "marvell,direct-key-count", |
| 129 | unsigned int key = pdata->matrix_key_map[i]; | 165 | &pdata->direct_key_num); |
| 130 | unsigned int row = KEY_ROW(key); | 166 | if (error) { |
| 131 | unsigned int col = KEY_COL(key); | 167 | /* |
| 132 | unsigned int scancode = MATRIX_SCAN_CODE(row, col, | 168 | * If do not have marvel,direct-key-count defined, |
| 133 | MATRIX_ROW_SHIFT); | 169 | * it means direct key is not supported. |
| 170 | */ | ||
| 171 | return error == -EINVAL ? 0 : error; | ||
| 172 | } | ||
| 134 | 173 | ||
| 135 | keycode = KEY_VAL(key); | 174 | error = of_property_read_u32(np, "marvell,direct-key-mask", |
| 136 | keypad->keycodes[scancode] = keycode; | 175 | &pdata->direct_key_mask); |
| 137 | __set_bit(keycode, input_dev->keybit); | 176 | if (error) { |
| 177 | if (error != -EINVAL) | ||
| 178 | return error; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * If marvell,direct-key-mask is not defined, driver will use | ||
| 182 | * default value. Default value is set when configure the keypad. | ||
| 183 | */ | ||
| 184 | pdata->direct_key_mask = 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | pdata->direct_key_low_active = of_property_read_bool(np, | ||
| 188 | "marvell,direct-key-low-active"); | ||
| 189 | |||
| 190 | prop = of_get_property(np, "marvell,direct-key-map", &proplen); | ||
| 191 | if (!prop) | ||
| 192 | return -EINVAL; | ||
| 193 | |||
| 194 | if (proplen % sizeof(u16)) | ||
| 195 | return -EINVAL; | ||
| 196 | |||
| 197 | size = proplen / sizeof(u16); | ||
| 198 | |||
| 199 | /* Only MAX_DIRECT_KEY_NUM is accepted.*/ | ||
| 200 | if (size > MAX_DIRECT_KEY_NUM) | ||
| 201 | return -EINVAL; | ||
| 202 | |||
| 203 | for (i = 0; i < size; i++) { | ||
| 204 | code = be16_to_cpup(prop + i); | ||
| 205 | keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code; | ||
| 206 | __set_bit(code, input_dev->keybit); | ||
| 207 | } | ||
| 208 | |||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad, | ||
| 213 | struct pxa27x_keypad_platform_data *pdata) | ||
| 214 | { | ||
| 215 | const __be32 *prop; | ||
| 216 | int i, relkey_ret; | ||
| 217 | unsigned int code, proplen; | ||
| 218 | const char *rotaryname[2] = { | ||
| 219 | "marvell,rotary0", "marvell,rotary1"}; | ||
| 220 | const char relkeyname[] = {"marvell,rotary-rel-key"}; | ||
| 221 | struct input_dev *input_dev = keypad->input_dev; | ||
| 222 | struct device *dev = input_dev->dev.parent; | ||
| 223 | struct device_node *np = dev->of_node; | ||
| 224 | |||
| 225 | relkey_ret = of_property_read_u32(np, relkeyname, &code); | ||
| 226 | /* if can read correct rotary key-code, we do not need this. */ | ||
| 227 | if (relkey_ret == 0) { | ||
| 228 | unsigned short relcode; | ||
| 229 | |||
| 230 | /* rotary0 taks lower half, rotary1 taks upper half. */ | ||
| 231 | relcode = code & 0xffff; | ||
| 232 | pdata->rotary0_rel_code = (code & 0xffff); | ||
| 233 | __set_bit(relcode, input_dev->relbit); | ||
| 234 | |||
| 235 | relcode = code >> 16; | ||
| 236 | pdata->rotary1_rel_code = relcode; | ||
| 237 | __set_bit(relcode, input_dev->relbit); | ||
| 238 | } | ||
| 239 | |||
| 240 | for (i = 0; i < 2; i++) { | ||
| 241 | prop = of_get_property(np, rotaryname[i], &proplen); | ||
| 242 | /* | ||
| 243 | * If the prop is not set, it means keypad does not need | ||
| 244 | * initialize the rotaryX. | ||
| 245 | */ | ||
| 246 | if (!prop) | ||
| 247 | continue; | ||
| 248 | |||
| 249 | code = be32_to_cpup(prop); | ||
| 250 | /* | ||
| 251 | * Not all up/down key code are valid. | ||
| 252 | * Now we depends on direct-rel-code. | ||
| 253 | */ | ||
| 254 | if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) { | ||
| 255 | return relkey_ret; | ||
| 256 | } else { | ||
| 257 | unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1); | ||
| 258 | unsigned short keycode; | ||
| 259 | |||
| 260 | keycode = code & 0xffff; | ||
| 261 | keypad->keycodes[n] = keycode; | ||
| 262 | __set_bit(keycode, input_dev->keybit); | ||
| 263 | |||
| 264 | keycode = code >> 16; | ||
| 265 | keypad->keycodes[n + 1] = keycode; | ||
| 266 | __set_bit(keycode, input_dev->keybit); | ||
| 267 | |||
| 268 | if (i == 0) | ||
| 269 | pdata->rotary0_rel_code = -1; | ||
| 270 | else | ||
| 271 | pdata->rotary1_rel_code = -1; | ||
| 272 | } | ||
| 273 | if (i == 0) | ||
| 274 | pdata->enable_rotary0 = 1; | ||
| 275 | else | ||
| 276 | pdata->enable_rotary1 = 1; | ||
| 277 | } | ||
| 278 | |||
| 279 | keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; | ||
| 280 | keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; | ||
| 281 | |||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) | ||
| 286 | { | ||
| 287 | struct input_dev *input_dev = keypad->input_dev; | ||
| 288 | struct device *dev = input_dev->dev.parent; | ||
| 289 | struct device_node *np = dev->of_node; | ||
| 290 | struct pxa27x_keypad_platform_data *pdata; | ||
| 291 | int error; | ||
| 292 | |||
| 293 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||
| 294 | if (!pdata) { | ||
| 295 | dev_err(dev, "failed to allocate memory for pdata\n"); | ||
| 296 | return -ENOMEM; | ||
| 297 | } | ||
| 298 | |||
| 299 | error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata); | ||
| 300 | if (error) { | ||
| 301 | dev_err(dev, "failed to parse matrix key\n"); | ||
| 302 | return error; | ||
| 303 | } | ||
| 304 | |||
| 305 | error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata); | ||
| 306 | if (error) { | ||
| 307 | dev_err(dev, "failed to parse direct key\n"); | ||
| 308 | return error; | ||
| 309 | } | ||
| 310 | |||
| 311 | error = pxa27x_keypad_rotary_parse_dt(keypad, pdata); | ||
| 312 | if (error) { | ||
| 313 | dev_err(dev, "failed to parse rotary key\n"); | ||
| 314 | return error; | ||
| 315 | } | ||
| 316 | |||
| 317 | error = of_property_read_u32(np, "marvell,debounce-interval", | ||
| 318 | &pdata->debounce_interval); | ||
| 319 | if (error) { | ||
| 320 | dev_err(dev, "failed to parse debpunce-interval\n"); | ||
| 321 | return error; | ||
| 138 | } | 322 | } |
| 139 | 323 | ||
| 324 | /* | ||
| 325 | * The keycodes may not only includes matrix key but also the direct | ||
| 326 | * key or rotary key. | ||
| 327 | */ | ||
| 328 | input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); | ||
| 329 | |||
| 330 | keypad->pdata = pdata; | ||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | #else | ||
| 335 | |||
| 336 | static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) | ||
| 337 | { | ||
| 338 | dev_info(keypad->input_dev->dev.parent, "missing platform data\n"); | ||
| 339 | |||
| 340 | return -EINVAL; | ||
| 341 | } | ||
| 342 | |||
| 343 | #endif | ||
| 344 | |||
| 345 | static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) | ||
| 346 | { | ||
| 347 | const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; | ||
| 348 | struct input_dev *input_dev = keypad->input_dev; | ||
| 349 | const struct matrix_keymap_data *keymap_data = | ||
| 350 | pdata ? pdata->matrix_keymap_data : NULL; | ||
| 351 | unsigned short keycode; | ||
| 352 | int i; | ||
| 353 | int error; | ||
| 354 | |||
| 355 | error = matrix_keypad_build_keymap(keymap_data, NULL, | ||
| 356 | pdata->matrix_key_rows, | ||
| 357 | pdata->matrix_key_cols, | ||
| 358 | keypad->keycodes, input_dev); | ||
| 359 | if (error) | ||
| 360 | return error; | ||
| 361 | |||
| 362 | /* | ||
| 363 | * The keycodes may not only include matrix keys but also the direct | ||
| 364 | * or rotary keys. | ||
| 365 | */ | ||
| 366 | input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); | ||
| 367 | |||
| 368 | /* For direct keys. */ | ||
| 140 | for (i = 0; i < pdata->direct_key_num; i++) { | 369 | for (i = 0; i < pdata->direct_key_num; i++) { |
| 141 | keycode = pdata->direct_key_map[i]; | 370 | keycode = pdata->direct_key_map[i]; |
| 142 | keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode; | 371 | keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode; |
| @@ -178,11 +407,13 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) | |||
| 178 | } | 407 | } |
| 179 | 408 | ||
| 180 | __clear_bit(KEY_RESERVED, input_dev->keybit); | 409 | __clear_bit(KEY_RESERVED, input_dev->keybit); |
| 410 | |||
| 411 | return 0; | ||
| 181 | } | 412 | } |
| 182 | 413 | ||
| 183 | static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) | 414 | static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) |
| 184 | { | 415 | { |
| 185 | struct pxa27x_keypad_platform_data *pdata = keypad->pdata; | 416 | const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; |
| 186 | struct input_dev *input_dev = keypad->input_dev; | 417 | struct input_dev *input_dev = keypad->input_dev; |
| 187 | int row, col, num_keys_pressed = 0; | 418 | int row, col, num_keys_pressed = 0; |
| 188 | uint32_t new_state[MAX_MATRIX_KEY_COLS]; | 419 | uint32_t new_state[MAX_MATRIX_KEY_COLS]; |
| @@ -284,7 +515,7 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) | |||
| 284 | 515 | ||
| 285 | static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) | 516 | static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) |
| 286 | { | 517 | { |
| 287 | struct pxa27x_keypad_platform_data *pdata = keypad->pdata; | 518 | const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; |
| 288 | uint32_t kprec; | 519 | uint32_t kprec; |
| 289 | 520 | ||
| 290 | /* read and reset to default count value */ | 521 | /* read and reset to default count value */ |
| @@ -300,7 +531,7 @@ static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) | |||
| 300 | 531 | ||
| 301 | static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) | 532 | static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) |
| 302 | { | 533 | { |
| 303 | struct pxa27x_keypad_platform_data *pdata = keypad->pdata; | 534 | const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; |
| 304 | struct input_dev *input_dev = keypad->input_dev; | 535 | struct input_dev *input_dev = keypad->input_dev; |
| 305 | unsigned int new_state; | 536 | unsigned int new_state; |
| 306 | uint32_t kpdk, bits_changed; | 537 | uint32_t kpdk, bits_changed; |
| @@ -340,7 +571,7 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) | |||
| 340 | 571 | ||
| 341 | static void clear_wakeup_event(struct pxa27x_keypad *keypad) | 572 | static void clear_wakeup_event(struct pxa27x_keypad *keypad) |
| 342 | { | 573 | { |
| 343 | struct pxa27x_keypad_platform_data *pdata = keypad->pdata; | 574 | const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; |
| 344 | 575 | ||
| 345 | if (pdata->clear_wakeup_event) | 576 | if (pdata->clear_wakeup_event) |
| 346 | (pdata->clear_wakeup_event)(); | 577 | (pdata->clear_wakeup_event)(); |
| @@ -364,7 +595,7 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) | |||
| 364 | 595 | ||
| 365 | static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) | 596 | static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) |
| 366 | { | 597 | { |
| 367 | struct pxa27x_keypad_platform_data *pdata = keypad->pdata; | 598 | const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; |
| 368 | unsigned int mask = 0, direct_key_num = 0; | 599 | unsigned int mask = 0, direct_key_num = 0; |
| 369 | unsigned long kpc = 0; | 600 | unsigned long kpc = 0; |
| 370 | 601 | ||
| @@ -431,7 +662,7 @@ static void pxa27x_keypad_close(struct input_dev *dev) | |||
| 431 | clk_disable_unprepare(keypad->clk); | 662 | clk_disable_unprepare(keypad->clk); |
| 432 | } | 663 | } |
| 433 | 664 | ||
| 434 | #ifdef CONFIG_PM | 665 | #ifdef CONFIG_PM_SLEEP |
| 435 | static int pxa27x_keypad_suspend(struct device *dev) | 666 | static int pxa27x_keypad_suspend(struct device *dev) |
| 436 | { | 667 | { |
| 437 | struct platform_device *pdev = to_platform_device(dev); | 668 | struct platform_device *pdev = to_platform_device(dev); |
| @@ -475,25 +706,25 @@ static int pxa27x_keypad_resume(struct device *dev) | |||
| 475 | 706 | ||
| 476 | return 0; | 707 | return 0; |
| 477 | } | 708 | } |
| 478 | |||
| 479 | static const struct dev_pm_ops pxa27x_keypad_pm_ops = { | ||
| 480 | .suspend = pxa27x_keypad_suspend, | ||
| 481 | .resume = pxa27x_keypad_resume, | ||
| 482 | }; | ||
| 483 | #endif | 709 | #endif |
| 484 | 710 | ||
| 711 | static SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops, | ||
| 712 | pxa27x_keypad_suspend, pxa27x_keypad_resume); | ||
| 713 | |||
| 714 | |||
| 485 | static int pxa27x_keypad_probe(struct platform_device *pdev) | 715 | static int pxa27x_keypad_probe(struct platform_device *pdev) |
| 486 | { | 716 | { |
| 487 | struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; | 717 | const struct pxa27x_keypad_platform_data *pdata = |
| 718 | dev_get_platdata(&pdev->dev); | ||
| 719 | struct device_node *np = pdev->dev.of_node; | ||
| 488 | struct pxa27x_keypad *keypad; | 720 | struct pxa27x_keypad *keypad; |
| 489 | struct input_dev *input_dev; | 721 | struct input_dev *input_dev; |
| 490 | struct resource *res; | 722 | struct resource *res; |
| 491 | int irq, error; | 723 | int irq, error; |
| 492 | 724 | ||
| 493 | if (pdata == NULL) { | 725 | /* Driver need build keycode from device tree or pdata */ |
| 494 | dev_err(&pdev->dev, "no platform data defined\n"); | 726 | if (!np && !pdata) |
| 495 | return -EINVAL; | 727 | return -EINVAL; |
| 496 | } | ||
| 497 | 728 | ||
| 498 | irq = platform_get_irq(pdev, 0); | 729 | irq = platform_get_irq(pdev, 0); |
| 499 | if (irq < 0) { | 730 | if (irq < 0) { |
| @@ -555,7 +786,14 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) | |||
| 555 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); | 786 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); |
| 556 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | 787 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); |
| 557 | 788 | ||
| 558 | pxa27x_keypad_build_keycode(keypad); | 789 | if (pdata) |
| 790 | error = pxa27x_keypad_build_keycode(keypad); | ||
| 791 | else | ||
| 792 | error = pxa27x_keypad_build_keycode_from_dt(keypad); | ||
| 793 | if (error) { | ||
| 794 | dev_err(&pdev->dev, "failed to build keycode\n"); | ||
| 795 | goto failed_put_clk; | ||
| 796 | } | ||
| 559 | 797 | ||
| 560 | if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) || | 798 | if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) || |
| 561 | (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) { | 799 | (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) { |
| @@ -582,7 +820,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) | |||
| 582 | return 0; | 820 | return 0; |
| 583 | 821 | ||
| 584 | failed_free_irq: | 822 | failed_free_irq: |
| 585 | free_irq(irq, pdev); | 823 | free_irq(irq, keypad); |
| 586 | failed_put_clk: | 824 | failed_put_clk: |
| 587 | clk_put(keypad->clk); | 825 | clk_put(keypad->clk); |
| 588 | failed_free_io: | 826 | failed_free_io: |
| @@ -600,7 +838,7 @@ static int pxa27x_keypad_remove(struct platform_device *pdev) | |||
| 600 | struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); | 838 | struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); |
| 601 | struct resource *res; | 839 | struct resource *res; |
| 602 | 840 | ||
| 603 | free_irq(keypad->irq, pdev); | 841 | free_irq(keypad->irq, keypad); |
| 604 | clk_put(keypad->clk); | 842 | clk_put(keypad->clk); |
| 605 | 843 | ||
| 606 | input_unregister_device(keypad->input_dev); | 844 | input_unregister_device(keypad->input_dev); |
| @@ -609,7 +847,6 @@ static int pxa27x_keypad_remove(struct platform_device *pdev) | |||
| 609 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 847 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 610 | release_mem_region(res->start, resource_size(res)); | 848 | release_mem_region(res->start, resource_size(res)); |
| 611 | 849 | ||
| 612 | platform_set_drvdata(pdev, NULL); | ||
| 613 | kfree(keypad); | 850 | kfree(keypad); |
| 614 | 851 | ||
| 615 | return 0; | 852 | return 0; |
| @@ -618,15 +855,22 @@ static int pxa27x_keypad_remove(struct platform_device *pdev) | |||
| 618 | /* work with hotplug and coldplug */ | 855 | /* work with hotplug and coldplug */ |
| 619 | MODULE_ALIAS("platform:pxa27x-keypad"); | 856 | MODULE_ALIAS("platform:pxa27x-keypad"); |
| 620 | 857 | ||
| 858 | #ifdef CONFIG_OF | ||
| 859 | static const struct of_device_id pxa27x_keypad_dt_match[] = { | ||
| 860 | { .compatible = "marvell,pxa27x-keypad" }, | ||
| 861 | {}, | ||
| 862 | }; | ||
| 863 | MODULE_DEVICE_TABLE(of, pxa27x_keypad_dt_match); | ||
| 864 | #endif | ||
| 865 | |||
| 621 | static struct platform_driver pxa27x_keypad_driver = { | 866 | static struct platform_driver pxa27x_keypad_driver = { |
| 622 | .probe = pxa27x_keypad_probe, | 867 | .probe = pxa27x_keypad_probe, |
| 623 | .remove = pxa27x_keypad_remove, | 868 | .remove = pxa27x_keypad_remove, |
| 624 | .driver = { | 869 | .driver = { |
| 625 | .name = "pxa27x-keypad", | 870 | .name = "pxa27x-keypad", |
| 871 | .of_match_table = of_match_ptr(pxa27x_keypad_dt_match), | ||
| 626 | .owner = THIS_MODULE, | 872 | .owner = THIS_MODULE, |
| 627 | #ifdef CONFIG_PM | ||
| 628 | .pm = &pxa27x_keypad_pm_ops, | 873 | .pm = &pxa27x_keypad_pm_ops, |
| 629 | #endif | ||
| 630 | }, | 874 | }, |
| 631 | }; | 875 | }; |
| 632 | module_platform_driver(pxa27x_keypad_driver); | 876 | module_platform_driver(pxa27x_keypad_driver); |
diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index bcad95be73aa..248cdcf95296 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c | |||
| @@ -181,7 +181,6 @@ static int pxa930_rotary_remove(struct platform_device *pdev) | |||
| 181 | free_irq(platform_get_irq(pdev, 0), r); | 181 | free_irq(platform_get_irq(pdev, 0), r); |
| 182 | input_unregister_device(r->input_dev); | 182 | input_unregister_device(r->input_dev); |
| 183 | iounmap(r->mmio_base); | 183 | iounmap(r->mmio_base); |
| 184 | platform_set_drvdata(pdev, NULL); | ||
| 185 | kfree(r); | 184 | kfree(r); |
| 186 | 185 | ||
| 187 | return 0; | 186 | return 0; |
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 03bdad771d2d..ac43a486c775 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c | |||
| @@ -439,7 +439,6 @@ static int samsung_keypad_probe(struct platform_device *pdev) | |||
| 439 | err_disable_runtime_pm: | 439 | err_disable_runtime_pm: |
| 440 | pm_runtime_disable(&pdev->dev); | 440 | pm_runtime_disable(&pdev->dev); |
| 441 | device_init_wakeup(&pdev->dev, 0); | 441 | device_init_wakeup(&pdev->dev, 0); |
| 442 | platform_set_drvdata(pdev, NULL); | ||
| 443 | err_unprepare_clk: | 442 | err_unprepare_clk: |
| 444 | clk_unprepare(keypad->clk); | 443 | clk_unprepare(keypad->clk); |
| 445 | return error; | 444 | return error; |
| @@ -451,7 +450,6 @@ static int samsung_keypad_remove(struct platform_device *pdev) | |||
| 451 | 450 | ||
| 452 | pm_runtime_disable(&pdev->dev); | 451 | pm_runtime_disable(&pdev->dev); |
| 453 | device_init_wakeup(&pdev->dev, 0); | 452 | device_init_wakeup(&pdev->dev, 0); |
| 454 | platform_set_drvdata(pdev, NULL); | ||
| 455 | 453 | ||
| 456 | input_unregister_device(keypad->input_dev); | 454 | input_unregister_device(keypad->input_dev); |
| 457 | 455 | ||
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index fdb9eb2df380..fe0e498d2479 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c | |||
| @@ -266,7 +266,6 @@ static int sh_keysc_probe(struct platform_device *pdev) | |||
| 266 | err2: | 266 | err2: |
| 267 | iounmap(priv->iomem_base); | 267 | iounmap(priv->iomem_base); |
| 268 | err1: | 268 | err1: |
| 269 | platform_set_drvdata(pdev, NULL); | ||
| 270 | kfree(priv); | 269 | kfree(priv); |
| 271 | err0: | 270 | err0: |
| 272 | return error; | 271 | return error; |
| @@ -285,7 +284,6 @@ static int sh_keysc_remove(struct platform_device *pdev) | |||
| 285 | pm_runtime_put_sync(&pdev->dev); | 284 | pm_runtime_put_sync(&pdev->dev); |
| 286 | pm_runtime_disable(&pdev->dev); | 285 | pm_runtime_disable(&pdev->dev); |
| 287 | 286 | ||
| 288 | platform_set_drvdata(pdev, NULL); | ||
| 289 | kfree(priv); | 287 | kfree(priv); |
| 290 | 288 | ||
| 291 | return 0; | 289 | return 0; |
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index cb1e8f614631..7111124b5362 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c | |||
| @@ -290,7 +290,6 @@ static int spear_kbd_remove(struct platform_device *pdev) | |||
| 290 | clk_unprepare(kbd->clk); | 290 | clk_unprepare(kbd->clk); |
| 291 | 291 | ||
| 292 | device_init_wakeup(&pdev->dev, 0); | 292 | device_init_wakeup(&pdev->dev, 0); |
| 293 | platform_set_drvdata(pdev, NULL); | ||
| 294 | 293 | ||
| 295 | return 0; | 294 | return 0; |
| 296 | } | 295 | } |
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index a34cc6714e5b..55c15304ddbc 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c | |||
| @@ -288,8 +288,11 @@ static int tca8418_keypad_probe(struct i2c_client *client, | |||
| 288 | irq_is_gpio = pdata->irq_is_gpio; | 288 | irq_is_gpio = pdata->irq_is_gpio; |
| 289 | } else { | 289 | } else { |
| 290 | struct device_node *np = dev->of_node; | 290 | struct device_node *np = dev->of_node; |
| 291 | of_property_read_u32(np, "keypad,num-rows", &rows); | 291 | int err; |
| 292 | of_property_read_u32(np, "keypad,num-columns", &cols); | 292 | |
| 293 | err = matrix_keypad_parse_of_params(dev, &rows, &cols); | ||
| 294 | if (err) | ||
| 295 | return err; | ||
| 293 | rep = of_property_read_bool(np, "keypad,autorepeat"); | 296 | rep = of_property_read_bool(np, "keypad,autorepeat"); |
| 294 | } | 297 | } |
| 295 | 298 | ||
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c index ee1635011292..5f7b427dd7ed 100644 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ b/drivers/input/keyboard/tnetv107x-keypad.c | |||
| @@ -296,7 +296,6 @@ error_clk: | |||
| 296 | error_map: | 296 | error_map: |
| 297 | release_mem_region(kp->res->start, resource_size(kp->res)); | 297 | release_mem_region(kp->res->start, resource_size(kp->res)); |
| 298 | error_res: | 298 | error_res: |
| 299 | platform_set_drvdata(pdev, NULL); | ||
| 300 | kfree(kp); | 299 | kfree(kp); |
| 301 | return error; | 300 | return error; |
| 302 | } | 301 | } |
| @@ -311,7 +310,6 @@ static int keypad_remove(struct platform_device *pdev) | |||
| 311 | clk_put(kp->clk); | 310 | clk_put(kp->clk); |
| 312 | iounmap(kp->regs); | 311 | iounmap(kp->regs); |
| 313 | release_mem_region(kp->res->start, resource_size(kp->res)); | 312 | release_mem_region(kp->res->start, resource_size(kp->res)); |
| 314 | platform_set_drvdata(pdev, NULL); | ||
| 315 | kfree(kp); | 313 | kfree(kp); |
| 316 | 314 | ||
| 317 | return 0; | 315 | return 0; |
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 04f84fd57173..d2d178c84ea7 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c | |||
| @@ -422,7 +422,7 @@ static int twl4030_kp_probe(struct platform_device *pdev) | |||
| 422 | err3: | 422 | err3: |
| 423 | /* mask all events - we don't care about the result */ | 423 | /* mask all events - we don't care about the result */ |
| 424 | (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); | 424 | (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); |
| 425 | free_irq(kp->irq, NULL); | 425 | free_irq(kp->irq, kp); |
| 426 | err2: | 426 | err2: |
| 427 | input_unregister_device(input); | 427 | input_unregister_device(input); |
| 428 | input = NULL; | 428 | input = NULL; |
| @@ -438,7 +438,6 @@ static int twl4030_kp_remove(struct platform_device *pdev) | |||
| 438 | 438 | ||
| 439 | free_irq(kp->irq, kp); | 439 | free_irq(kp->irq, kp); |
| 440 | input_unregister_device(kp->input); | 440 | input_unregister_device(kp->input); |
| 441 | platform_set_drvdata(pdev, NULL); | ||
| 442 | kfree(kp); | 441 | kfree(kp); |
| 443 | 442 | ||
| 444 | return 0; | 443 | return 0; |
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index ee163bee8cce..7b039162a3f8 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c | |||
| @@ -221,7 +221,7 @@ static int w90p910_keypad_probe(struct platform_device *pdev) | |||
| 221 | return 0; | 221 | return 0; |
| 222 | 222 | ||
| 223 | failed_free_irq: | 223 | failed_free_irq: |
| 224 | free_irq(irq, pdev); | 224 | free_irq(irq, keypad); |
| 225 | failed_put_clk: | 225 | failed_put_clk: |
| 226 | clk_put(keypad->clk); | 226 | clk_put(keypad->clk); |
| 227 | failed_free_io: | 227 | failed_free_io: |
| @@ -239,7 +239,7 @@ static int w90p910_keypad_remove(struct platform_device *pdev) | |||
| 239 | struct w90p910_keypad *keypad = platform_get_drvdata(pdev); | 239 | struct w90p910_keypad *keypad = platform_get_drvdata(pdev); |
| 240 | struct resource *res; | 240 | struct resource *res; |
| 241 | 241 | ||
| 242 | free_irq(keypad->irq, pdev); | 242 | free_irq(keypad->irq, keypad); |
| 243 | 243 | ||
| 244 | clk_put(keypad->clk); | 244 | clk_put(keypad->clk); |
| 245 | 245 | ||
| @@ -249,7 +249,6 @@ static int w90p910_keypad_remove(struct platform_device *pdev) | |||
| 249 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 249 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 250 | release_mem_region(res->start, resource_size(res)); | 250 | release_mem_region(res->start, resource_size(res)); |
| 251 | 251 | ||
| 252 | platform_set_drvdata(pdev, NULL); | ||
| 253 | kfree(keypad); | 252 | kfree(keypad); |
| 254 | 253 | ||
| 255 | return 0; | 254 | return 0; |
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c index 3ae496ea5fe6..08b61f506db6 100644 --- a/drivers/input/matrix-keymap.c +++ b/drivers/input/matrix-keymap.c | |||
| @@ -50,6 +50,26 @@ static bool matrix_keypad_map_key(struct input_dev *input_dev, | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | #ifdef CONFIG_OF | 52 | #ifdef CONFIG_OF |
| 53 | int matrix_keypad_parse_of_params(struct device *dev, | ||
| 54 | unsigned int *rows, unsigned int *cols) | ||
| 55 | { | ||
| 56 | struct device_node *np = dev->of_node; | ||
| 57 | |||
| 58 | if (!np) { | ||
| 59 | dev_err(dev, "missing DT data"); | ||
| 60 | return -EINVAL; | ||
| 61 | } | ||
| 62 | of_property_read_u32(np, "keypad,num-rows", rows); | ||
| 63 | of_property_read_u32(np, "keypad,num-columns", cols); | ||
| 64 | if (!*rows || !*cols) { | ||
| 65 | dev_err(dev, "number of keypad rows/columns not specified\n"); | ||
| 66 | return -EINVAL; | ||
| 67 | } | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | EXPORT_SYMBOL_GPL(matrix_keypad_parse_of_params); | ||
| 72 | |||
| 53 | static int matrix_keypad_parse_of_keymap(const char *propname, | 73 | static int matrix_keypad_parse_of_keymap(const char *propname, |
| 54 | unsigned int rows, unsigned int cols, | 74 | unsigned int rows, unsigned int cols, |
| 55 | struct input_dev *input_dev) | 75 | struct input_dev *input_dev) |
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index af80928a46b4..0b541cdf9b8e 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
| @@ -214,7 +214,7 @@ config INPUT_APANEL | |||
| 214 | config INPUT_GP2A | 214 | config INPUT_GP2A |
| 215 | tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver" | 215 | tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver" |
| 216 | depends on I2C | 216 | depends on I2C |
| 217 | depends on GENERIC_GPIO | 217 | depends on GPIOLIB |
| 218 | help | 218 | help |
| 219 | Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip | 219 | Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip |
| 220 | hooked to an I2C bus. | 220 | hooked to an I2C bus. |
| @@ -224,7 +224,7 @@ config INPUT_GP2A | |||
| 224 | 224 | ||
| 225 | config INPUT_GPIO_TILT_POLLED | 225 | config INPUT_GPIO_TILT_POLLED |
| 226 | tristate "Polled GPIO tilt switch" | 226 | tristate "Polled GPIO tilt switch" |
| 227 | depends on GENERIC_GPIO | 227 | depends on GPIOLIB |
| 228 | select INPUT_POLLDEV | 228 | select INPUT_POLLDEV |
| 229 | help | 229 | help |
| 230 | This driver implements support for tilt switches connected | 230 | This driver implements support for tilt switches connected |
| @@ -472,7 +472,7 @@ config INPUT_PWM_BEEPER | |||
| 472 | 472 | ||
| 473 | config INPUT_GPIO_ROTARY_ENCODER | 473 | config INPUT_GPIO_ROTARY_ENCODER |
| 474 | tristate "Rotary encoders connected to GPIO pins" | 474 | tristate "Rotary encoders connected to GPIO pins" |
| 475 | depends on GPIOLIB && GENERIC_GPIO | 475 | depends on GPIOLIB |
| 476 | help | 476 | help |
| 477 | Say Y here to add support for rotary encoders connected to GPIO lines. | 477 | Say Y here to add support for rotary encoders connected to GPIO lines. |
| 478 | Check file:Documentation/input/rotary-encoder.txt for more | 478 | Check file:Documentation/input/rotary-encoder.txt for more |
| @@ -484,7 +484,7 @@ config INPUT_GPIO_ROTARY_ENCODER | |||
| 484 | config INPUT_RB532_BUTTON | 484 | config INPUT_RB532_BUTTON |
| 485 | tristate "Mikrotik Routerboard 532 button interface" | 485 | tristate "Mikrotik Routerboard 532 button interface" |
| 486 | depends on MIKROTIK_RB532 | 486 | depends on MIKROTIK_RB532 |
| 487 | depends on GPIOLIB && GENERIC_GPIO | 487 | depends on GPIOLIB |
| 488 | select INPUT_POLLDEV | 488 | select INPUT_POLLDEV |
| 489 | help | 489 | help |
| 490 | Say Y here if you want support for the S1 button built into | 490 | Say Y here if you want support for the S1 button built into |
| @@ -637,4 +637,14 @@ config INPUT_XEN_KBDDEV_FRONTEND | |||
| 637 | To compile this driver as a module, choose M here: the | 637 | To compile this driver as a module, choose M here: the |
| 638 | module will be called xen-kbdfront. | 638 | module will be called xen-kbdfront. |
| 639 | 639 | ||
| 640 | config INPUT_SIRFSOC_ONKEY | ||
| 641 | bool "CSR SiRFSoC power on/off/suspend key support" | ||
| 642 | depends on ARCH_SIRF && OF | ||
| 643 | default y | ||
| 644 | help | ||
| 645 | Say Y here if you want to support for the SiRFSoC power on/off/suspend key | ||
| 646 | in Linux, after you press the onkey, system will suspend. | ||
| 647 | |||
| 648 | If unsure, say N. | ||
| 649 | |||
| 640 | endif | 650 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index d7fc17f11d77..829de43a2427 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
| @@ -51,6 +51,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o | |||
| 51 | obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o | 51 | obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o |
| 52 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o | 52 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o |
| 53 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o | 53 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o |
| 54 | obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o | ||
| 54 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | 55 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o |
| 55 | obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o | 56 | obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o |
| 56 | obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o | 57 | obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o |
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index 2f090b46e716..f2fbdd88ed20 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c | |||
| @@ -127,8 +127,6 @@ static int ab8500_ponkey_remove(struct platform_device *pdev) | |||
| 127 | input_unregister_device(ponkey->idev); | 127 | input_unregister_device(ponkey->idev); |
| 128 | kfree(ponkey); | 128 | kfree(ponkey); |
| 129 | 129 | ||
| 130 | platform_set_drvdata(pdev, NULL); | ||
| 131 | |||
| 132 | return 0; | 130 | return 0; |
| 133 | } | 131 | } |
| 134 | 132 | ||
diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c index a6666e142a91..cd139cb17e32 100644 --- a/drivers/input/misc/bfin_rotary.c +++ b/drivers/input/misc/bfin_rotary.c | |||
| @@ -208,7 +208,6 @@ static int bfin_rotary_remove(struct platform_device *pdev) | |||
| 208 | peripheral_free_list(per_cnt); | 208 | peripheral_free_list(per_cnt); |
| 209 | 209 | ||
| 210 | kfree(rotary); | 210 | kfree(rotary); |
| 211 | platform_set_drvdata(pdev, NULL); | ||
| 212 | 211 | ||
| 213 | return 0; | 212 | return 0; |
| 214 | } | 213 | } |
diff --git a/drivers/input/misc/gpio_tilt_polled.c b/drivers/input/misc/gpio_tilt_polled.c index da05cca8b562..714c68369134 100644 --- a/drivers/input/misc/gpio_tilt_polled.c +++ b/drivers/input/misc/gpio_tilt_polled.c | |||
| @@ -184,8 +184,6 @@ static int gpio_tilt_polled_remove(struct platform_device *pdev) | |||
| 184 | struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev); | 184 | struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev); |
| 185 | const struct gpio_tilt_platform_data *pdata = tdev->pdata; | 185 | const struct gpio_tilt_platform_data *pdata = tdev->pdata; |
| 186 | 186 | ||
| 187 | platform_set_drvdata(pdev, NULL); | ||
| 188 | |||
| 189 | input_unregister_polled_device(tdev->poll_dev); | 187 | input_unregister_polled_device(tdev->poll_dev); |
| 190 | input_free_polled_device(tdev->poll_dev); | 188 | input_free_polled_device(tdev->poll_dev); |
| 191 | 189 | ||
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 2e3334b8f82d..86b822806e95 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <linux/time.h> | 41 | #include <linux/time.h> |
| 42 | #include <linux/miscdevice.h> | 42 | #include <linux/miscdevice.h> |
| 43 | #include <linux/proc_fs.h> | 43 | #include <linux/proc_fs.h> |
| 44 | #include <linux/seq_file.h> | ||
| 44 | #include <linux/poll.h> | 45 | #include <linux/poll.h> |
| 45 | #include <linux/rtc.h> | 46 | #include <linux/rtc.h> |
| 46 | #include <linux/mutex.h> | 47 | #include <linux/mutex.h> |
| @@ -74,9 +75,6 @@ static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait); | |||
| 74 | static int hp_sdc_rtc_open(struct inode *inode, struct file *file); | 75 | static int hp_sdc_rtc_open(struct inode *inode, struct file *file); |
| 75 | static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on); | 76 | static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on); |
| 76 | 77 | ||
| 77 | static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off, | ||
| 78 | int count, int *eof, void *data); | ||
| 79 | |||
| 80 | static void hp_sdc_rtc_isr (int irq, void *dev_id, | 78 | static void hp_sdc_rtc_isr (int irq, void *dev_id, |
| 81 | uint8_t status, uint8_t data) | 79 | uint8_t status, uint8_t data) |
| 82 | { | 80 | { |
| @@ -427,22 +425,19 @@ static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on) | |||
| 427 | return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue); | 425 | return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue); |
| 428 | } | 426 | } |
| 429 | 427 | ||
| 430 | static int hp_sdc_rtc_proc_output (char *buf) | 428 | static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) |
| 431 | { | 429 | { |
| 432 | #define YN(bit) ("no") | 430 | #define YN(bit) ("no") |
| 433 | #define NY(bit) ("yes") | 431 | #define NY(bit) ("yes") |
| 434 | char *p; | ||
| 435 | struct rtc_time tm; | 432 | struct rtc_time tm; |
| 436 | struct timeval tv; | 433 | struct timeval tv; |
| 437 | 434 | ||
| 438 | memset(&tm, 0, sizeof(struct rtc_time)); | 435 | memset(&tm, 0, sizeof(struct rtc_time)); |
| 439 | 436 | ||
| 440 | p = buf; | ||
| 441 | |||
| 442 | if (hp_sdc_rtc_read_bbrtc(&tm)) { | 437 | if (hp_sdc_rtc_read_bbrtc(&tm)) { |
| 443 | p += sprintf(p, "BBRTC\t\t: READ FAILED!\n"); | 438 | seq_puts(m, "BBRTC\t\t: READ FAILED!\n"); |
| 444 | } else { | 439 | } else { |
| 445 | p += sprintf(p, | 440 | seq_printf(m, |
| 446 | "rtc_time\t: %02d:%02d:%02d\n" | 441 | "rtc_time\t: %02d:%02d:%02d\n" |
| 447 | "rtc_date\t: %04d-%02d-%02d\n" | 442 | "rtc_date\t: %04d-%02d-%02d\n" |
| 448 | "rtc_epoch\t: %04lu\n", | 443 | "rtc_epoch\t: %04lu\n", |
| @@ -452,41 +447,41 @@ static int hp_sdc_rtc_proc_output (char *buf) | |||
| 452 | } | 447 | } |
| 453 | 448 | ||
| 454 | if (hp_sdc_rtc_read_rt(&tv)) { | 449 | if (hp_sdc_rtc_read_rt(&tv)) { |
| 455 | p += sprintf(p, "i8042 rtc\t: READ FAILED!\n"); | 450 | seq_puts(m, "i8042 rtc\t: READ FAILED!\n"); |
| 456 | } else { | 451 | } else { |
| 457 | p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n", | 452 | seq_printf(m, "i8042 rtc\t: %ld.%02d seconds\n", |
| 458 | tv.tv_sec, (int)tv.tv_usec/1000); | 453 | tv.tv_sec, (int)tv.tv_usec/1000); |
| 459 | } | 454 | } |
| 460 | 455 | ||
| 461 | if (hp_sdc_rtc_read_fhs(&tv)) { | 456 | if (hp_sdc_rtc_read_fhs(&tv)) { |
| 462 | p += sprintf(p, "handshake\t: READ FAILED!\n"); | 457 | seq_puts(m, "handshake\t: READ FAILED!\n"); |
| 463 | } else { | 458 | } else { |
| 464 | p += sprintf(p, "handshake\t: %ld.%02d seconds\n", | 459 | seq_printf(m, "handshake\t: %ld.%02d seconds\n", |
| 465 | tv.tv_sec, (int)tv.tv_usec/1000); | 460 | tv.tv_sec, (int)tv.tv_usec/1000); |
| 466 | } | 461 | } |
| 467 | 462 | ||
| 468 | if (hp_sdc_rtc_read_mt(&tv)) { | 463 | if (hp_sdc_rtc_read_mt(&tv)) { |
| 469 | p += sprintf(p, "alarm\t\t: READ FAILED!\n"); | 464 | seq_puts(m, "alarm\t\t: READ FAILED!\n"); |
| 470 | } else { | 465 | } else { |
| 471 | p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n", | 466 | seq_printf(m, "alarm\t\t: %ld.%02d seconds\n", |
| 472 | tv.tv_sec, (int)tv.tv_usec/1000); | 467 | tv.tv_sec, (int)tv.tv_usec/1000); |
| 473 | } | 468 | } |
| 474 | 469 | ||
| 475 | if (hp_sdc_rtc_read_dt(&tv)) { | 470 | if (hp_sdc_rtc_read_dt(&tv)) { |
| 476 | p += sprintf(p, "delay\t\t: READ FAILED!\n"); | 471 | seq_puts(m, "delay\t\t: READ FAILED!\n"); |
| 477 | } else { | 472 | } else { |
| 478 | p += sprintf(p, "delay\t\t: %ld.%02d seconds\n", | 473 | seq_printf(m, "delay\t\t: %ld.%02d seconds\n", |
| 479 | tv.tv_sec, (int)tv.tv_usec/1000); | 474 | tv.tv_sec, (int)tv.tv_usec/1000); |
| 480 | } | 475 | } |
| 481 | 476 | ||
| 482 | if (hp_sdc_rtc_read_ct(&tv)) { | 477 | if (hp_sdc_rtc_read_ct(&tv)) { |
| 483 | p += sprintf(p, "periodic\t: READ FAILED!\n"); | 478 | seq_puts(m, "periodic\t: READ FAILED!\n"); |
| 484 | } else { | 479 | } else { |
| 485 | p += sprintf(p, "periodic\t: %ld.%02d seconds\n", | 480 | seq_printf(m, "periodic\t: %ld.%02d seconds\n", |
| 486 | tv.tv_sec, (int)tv.tv_usec/1000); | 481 | tv.tv_sec, (int)tv.tv_usec/1000); |
| 487 | } | 482 | } |
| 488 | 483 | ||
| 489 | p += sprintf(p, | 484 | seq_printf(m, |
| 490 | "DST_enable\t: %s\n" | 485 | "DST_enable\t: %s\n" |
| 491 | "BCD\t\t: %s\n" | 486 | "BCD\t\t: %s\n" |
| 492 | "24hr\t\t: %s\n" | 487 | "24hr\t\t: %s\n" |
| @@ -506,23 +501,23 @@ static int hp_sdc_rtc_proc_output (char *buf) | |||
| 506 | 1UL, | 501 | 1UL, |
| 507 | 1 ? "okay" : "dead"); | 502 | 1 ? "okay" : "dead"); |
| 508 | 503 | ||
| 509 | return p - buf; | 504 | return 0; |
| 510 | #undef YN | 505 | #undef YN |
| 511 | #undef NY | 506 | #undef NY |
| 512 | } | 507 | } |
| 513 | 508 | ||
| 514 | static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off, | 509 | static int hp_sdc_rtc_proc_open(struct inode *inode, struct file *file) |
| 515 | int count, int *eof, void *data) | ||
| 516 | { | 510 | { |
| 517 | int len = hp_sdc_rtc_proc_output (page); | 511 | return single_open(file, hp_sdc_rtc_proc_show, NULL); |
| 518 | if (len <= off+count) *eof = 1; | ||
| 519 | *start = page + off; | ||
| 520 | len -= off; | ||
| 521 | if (len>count) len = count; | ||
| 522 | if (len<0) len = 0; | ||
| 523 | return len; | ||
| 524 | } | 512 | } |
| 525 | 513 | ||
| 514 | static const struct file_operations hp_sdc_rtc_proc_fops = { | ||
| 515 | .open = hp_sdc_rtc_proc_open, | ||
| 516 | .read = seq_read, | ||
| 517 | .llseek = seq_lseek, | ||
| 518 | .release = single_release, | ||
| 519 | }; | ||
| 520 | |||
| 526 | static int hp_sdc_rtc_ioctl(struct file *file, | 521 | static int hp_sdc_rtc_ioctl(struct file *file, |
| 527 | unsigned int cmd, unsigned long arg) | 522 | unsigned int cmd, unsigned long arg) |
| 528 | { | 523 | { |
| @@ -715,8 +710,7 @@ static int __init hp_sdc_rtc_init(void) | |||
| 715 | if (misc_register(&hp_sdc_rtc_dev) != 0) | 710 | if (misc_register(&hp_sdc_rtc_dev) != 0) |
| 716 | printk(KERN_INFO "Could not register misc. dev for i8042 rtc\n"); | 711 | printk(KERN_INFO "Could not register misc. dev for i8042 rtc\n"); |
| 717 | 712 | ||
| 718 | create_proc_read_entry ("driver/rtc", 0, NULL, | 713 | proc_create("driver/rtc", 0, NULL, &hp_sdc_rtc_proc_fops); |
| 719 | hp_sdc_rtc_read_proc, NULL); | ||
| 720 | 714 | ||
| 721 | printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " | 715 | printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " |
| 722 | "(RTC v " RTC_VERSION ")\n"); | 716 | "(RTC v " RTC_VERSION ")\n"); |
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 6ab3decc86e6..f34beb228d36 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c | |||
| @@ -125,7 +125,7 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) | |||
| 125 | return 0; | 125 | return 0; |
| 126 | 126 | ||
| 127 | err_free_irq: | 127 | err_free_irq: |
| 128 | free_irq(IRQ_IXP4XX_TIMER2, dev); | 128 | free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); |
| 129 | err_free_device: | 129 | err_free_device: |
| 130 | input_free_device(input_dev); | 130 | input_free_device(input_dev); |
| 131 | 131 | ||
| @@ -138,13 +138,12 @@ static int ixp4xx_spkr_remove(struct platform_device *dev) | |||
| 138 | unsigned int pin = (unsigned int) input_get_drvdata(input_dev); | 138 | unsigned int pin = (unsigned int) input_get_drvdata(input_dev); |
| 139 | 139 | ||
| 140 | input_unregister_device(input_dev); | 140 | input_unregister_device(input_dev); |
| 141 | platform_set_drvdata(dev, NULL); | ||
| 142 | 141 | ||
| 143 | /* turn the speaker off */ | 142 | /* turn the speaker off */ |
| 144 | disable_irq(IRQ_IXP4XX_TIMER2); | 143 | disable_irq(IRQ_IXP4XX_TIMER2); |
| 145 | ixp4xx_spkr_control(pin, 0); | 144 | ixp4xx_spkr_control(pin, 0); |
| 146 | 145 | ||
| 147 | free_irq(IRQ_IXP4XX_TIMER2, dev); | 146 | free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); |
| 148 | 147 | ||
| 149 | return 0; | 148 | return 0; |
| 150 | } | 149 | } |
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index b40ee4b47f4f..def21dc84522 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c | |||
| @@ -85,7 +85,6 @@ static int m68kspkr_remove(struct platform_device *dev) | |||
| 85 | struct input_dev *input_dev = platform_get_drvdata(dev); | 85 | struct input_dev *input_dev = platform_get_drvdata(dev); |
| 86 | 86 | ||
| 87 | input_unregister_device(input_dev); | 87 | input_unregister_device(input_dev); |
| 88 | platform_set_drvdata(dev, NULL); | ||
| 89 | /* turn off the speaker */ | 88 | /* turn off the speaker */ |
| 90 | m68kspkr_event(NULL, EV_SND, SND_BELL, 0); | 89 | m68kspkr_event(NULL, EV_SND, SND_BELL, 0); |
| 91 | 90 | ||
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c index f9179b2585a9..eef41cfc054d 100644 --- a/drivers/input/misc/max8925_onkey.c +++ b/drivers/input/misc/max8925_onkey.c | |||
| @@ -148,8 +148,6 @@ static int max8925_onkey_remove(struct platform_device *pdev) | |||
| 148 | input_unregister_device(info->idev); | 148 | input_unregister_device(info->idev); |
| 149 | kfree(info); | 149 | kfree(info); |
| 150 | 150 | ||
| 151 | platform_set_drvdata(pdev, NULL); | ||
| 152 | |||
| 153 | return 0; | 151 | return 0; |
| 154 | } | 152 | } |
| 155 | 153 | ||
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index 0906ca593d5f..d0277a7b1579 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c | |||
| @@ -250,7 +250,6 @@ static int mc13783_pwrbutton_remove(struct platform_device *pdev) | |||
| 250 | 250 | ||
| 251 | input_unregister_device(priv->pwr); | 251 | input_unregister_device(priv->pwr); |
| 252 | kfree(priv); | 252 | kfree(priv); |
| 253 | platform_set_drvdata(pdev, NULL); | ||
| 254 | 253 | ||
| 255 | return 0; | 254 | return 0; |
| 256 | } | 255 | } |
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 199db78acc4f..7288b267613d 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c | |||
| @@ -100,7 +100,6 @@ static int pcspkr_remove(struct platform_device *dev) | |||
| 100 | struct input_dev *pcspkr_dev = platform_get_drvdata(dev); | 100 | struct input_dev *pcspkr_dev = platform_get_drvdata(dev); |
| 101 | 101 | ||
| 102 | input_unregister_device(pcspkr_dev); | 102 | input_unregister_device(pcspkr_dev); |
| 103 | platform_set_drvdata(dev, NULL); | ||
| 104 | /* turn off the speaker */ | 103 | /* turn off the speaker */ |
| 105 | pcspkr_event(NULL, EV_SND, SND_BELL, 0); | 104 | pcspkr_event(NULL, EV_SND, SND_BELL, 0); |
| 106 | 105 | ||
diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index a9da65e41c5b..ec086f6f3cc3 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c | |||
| @@ -249,8 +249,6 @@ static int pm8xxx_vib_remove(struct platform_device *pdev) | |||
| 249 | input_unregister_device(vib->vib_input_dev); | 249 | input_unregister_device(vib->vib_input_dev); |
| 250 | kfree(vib); | 250 | kfree(vib); |
| 251 | 251 | ||
| 252 | platform_set_drvdata(pdev, NULL); | ||
| 253 | |||
| 254 | return 0; | 252 | return 0; |
| 255 | } | 253 | } |
| 256 | 254 | ||
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 4b811be73974..b49b738aa9c6 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c | |||
| @@ -175,9 +175,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) | |||
| 175 | return 0; | 175 | return 0; |
| 176 | 176 | ||
| 177 | free_press_irq: | 177 | free_press_irq: |
| 178 | free_irq(key_press_irq, NULL); | 178 | free_irq(key_press_irq, pwrkey); |
| 179 | unreg_input_dev: | 179 | unreg_input_dev: |
| 180 | platform_set_drvdata(pdev, NULL); | ||
| 181 | input_unregister_device(pwr); | 180 | input_unregister_device(pwr); |
| 182 | pwr = NULL; | 181 | pwr = NULL; |
| 183 | free_input_dev: | 182 | free_input_dev: |
| @@ -198,7 +197,6 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev) | |||
| 198 | free_irq(key_press_irq, pwrkey); | 197 | free_irq(key_press_irq, pwrkey); |
| 199 | free_irq(key_release_irq, pwrkey); | 198 | free_irq(key_release_irq, pwrkey); |
| 200 | input_unregister_device(pwrkey->pwr); | 199 | input_unregister_device(pwrkey->pwr); |
| 201 | platform_set_drvdata(pdev, NULL); | ||
| 202 | kfree(pwrkey); | 200 | kfree(pwrkey); |
| 203 | 201 | ||
| 204 | return 0; | 202 | return 0; |
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 0808868461de..a37f0c909aba 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c | |||
| @@ -133,7 +133,6 @@ static int pwm_beeper_remove(struct platform_device *pdev) | |||
| 133 | { | 133 | { |
| 134 | struct pwm_beeper *beeper = platform_get_drvdata(pdev); | 134 | struct pwm_beeper *beeper = platform_get_drvdata(pdev); |
| 135 | 135 | ||
| 136 | platform_set_drvdata(pdev, NULL); | ||
| 137 | input_unregister_device(beeper->input); | 136 | input_unregister_device(beeper->input); |
| 138 | 137 | ||
| 139 | pwm_disable(beeper->pwm); | 138 | pwm_disable(beeper->pwm); |
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index aff47b2c38ff..5b1aff825138 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c | |||
| @@ -317,8 +317,6 @@ static int rotary_encoder_remove(struct platform_device *pdev) | |||
| 317 | if (!dev_get_platdata(&pdev->dev)) | 317 | if (!dev_get_platdata(&pdev->dev)) |
| 318 | kfree(pdata); | 318 | kfree(pdata); |
| 319 | 319 | ||
| 320 | platform_set_drvdata(pdev, NULL); | ||
| 321 | |||
| 322 | return 0; | 320 | return 0; |
| 323 | } | 321 | } |
| 324 | 322 | ||
diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c index ad6415ceaf5f..95cf299ef9a3 100644 --- a/drivers/input/misc/sgi_btns.c +++ b/drivers/input/misc/sgi_btns.c | |||
| @@ -128,7 +128,7 @@ static int sgi_buttons_probe(struct platform_device *pdev) | |||
| 128 | __clear_bit(KEY_RESERVED, input->keybit); | 128 | __clear_bit(KEY_RESERVED, input->keybit); |
| 129 | 129 | ||
| 130 | bdev->poll_dev = poll_dev; | 130 | bdev->poll_dev = poll_dev; |
| 131 | dev_set_drvdata(&pdev->dev, bdev); | 131 | platform_set_drvdata(pdev, bdev); |
| 132 | 132 | ||
| 133 | error = input_register_polled_device(poll_dev); | 133 | error = input_register_polled_device(poll_dev); |
| 134 | if (error) | 134 | if (error) |
| @@ -139,19 +139,16 @@ static int sgi_buttons_probe(struct platform_device *pdev) | |||
| 139 | err_free_mem: | 139 | err_free_mem: |
| 140 | input_free_polled_device(poll_dev); | 140 | input_free_polled_device(poll_dev); |
| 141 | kfree(bdev); | 141 | kfree(bdev); |
| 142 | dev_set_drvdata(&pdev->dev, NULL); | ||
| 143 | return error; | 142 | return error; |
| 144 | } | 143 | } |
| 145 | 144 | ||
| 146 | static int sgi_buttons_remove(struct platform_device *pdev) | 145 | static int sgi_buttons_remove(struct platform_device *pdev) |
| 147 | { | 146 | { |
| 148 | struct device *dev = &pdev->dev; | 147 | struct buttons_dev *bdev = platform_get_drvdata(pdev); |
| 149 | struct buttons_dev *bdev = dev_get_drvdata(dev); | ||
| 150 | 148 | ||
| 151 | input_unregister_polled_device(bdev->poll_dev); | 149 | input_unregister_polled_device(bdev->poll_dev); |
| 152 | input_free_polled_device(bdev->poll_dev); | 150 | input_free_polled_device(bdev->poll_dev); |
| 153 | kfree(bdev); | 151 | kfree(bdev); |
| 154 | dev_set_drvdata(dev, NULL); | ||
| 155 | 152 | ||
| 156 | return 0; | 153 | return 0; |
| 157 | } | 154 | } |
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c new file mode 100644 index 000000000000..0621c367049a --- /dev/null +++ b/drivers/input/misc/sirfsoc-onkey.c | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | /* | ||
| 2 | * Power key driver for SiRF PrimaII | ||
| 3 | * | ||
| 4 | * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/input.h> | ||
| 15 | #include <linux/rtc/sirfsoc_rtciobrg.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | |||
| 18 | struct sirfsoc_pwrc_drvdata { | ||
| 19 | u32 pwrc_base; | ||
| 20 | struct input_dev *input; | ||
| 21 | }; | ||
| 22 | |||
| 23 | #define PWRC_ON_KEY_BIT (1 << 0) | ||
| 24 | |||
| 25 | #define PWRC_INT_STATUS 0xc | ||
| 26 | #define PWRC_INT_MASK 0x10 | ||
| 27 | |||
| 28 | static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id) | ||
| 29 | { | ||
| 30 | struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id; | ||
| 31 | u32 int_status; | ||
| 32 | |||
| 33 | int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + | ||
| 34 | PWRC_INT_STATUS); | ||
| 35 | sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT, | ||
| 36 | pwrcdrv->pwrc_base + PWRC_INT_STATUS); | ||
| 37 | |||
| 38 | /* | ||
| 39 | * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c | ||
| 40 | * to queue a SUSPEND APM event | ||
| 41 | */ | ||
| 42 | input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1); | ||
| 43 | input_sync(pwrcdrv->input); | ||
| 44 | |||
| 45 | /* | ||
| 46 | * Todo: report KEY_POWER event for Android platforms, Android PowerManager | ||
| 47 | * will handle the suspend and powerdown/hibernation | ||
| 48 | */ | ||
| 49 | |||
| 50 | return IRQ_HANDLED; | ||
| 51 | } | ||
| 52 | |||
| 53 | static const struct of_device_id sirfsoc_pwrc_of_match[] = { | ||
| 54 | { .compatible = "sirf,prima2-pwrc" }, | ||
| 55 | {}, | ||
| 56 | } | ||
| 57 | MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match); | ||
| 58 | |||
| 59 | static int sirfsoc_pwrc_probe(struct platform_device *pdev) | ||
| 60 | { | ||
| 61 | struct device_node *np = pdev->dev.of_node; | ||
| 62 | struct sirfsoc_pwrc_drvdata *pwrcdrv; | ||
| 63 | int irq; | ||
| 64 | int error; | ||
| 65 | |||
| 66 | pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata), | ||
| 67 | GFP_KERNEL); | ||
| 68 | if (!pwrcdrv) { | ||
| 69 | dev_info(&pdev->dev, "Not enough memory for the device data\n"); | ||
| 70 | return -ENOMEM; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* | ||
| 74 | * we can't use of_iomap because pwrc is not mapped in memory, | ||
| 75 | * the so-called base address is only offset in rtciobrg | ||
| 76 | */ | ||
| 77 | error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base); | ||
| 78 | if (error) { | ||
| 79 | dev_err(&pdev->dev, | ||
| 80 | "unable to find base address of pwrc node in dtb\n"); | ||
| 81 | return error; | ||
| 82 | } | ||
| 83 | |||
| 84 | pwrcdrv->input = devm_input_allocate_device(&pdev->dev); | ||
| 85 | if (!pwrcdrv->input) | ||
| 86 | return -ENOMEM; | ||
| 87 | |||
| 88 | pwrcdrv->input->name = "sirfsoc pwrckey"; | ||
| 89 | pwrcdrv->input->phys = "pwrc/input0"; | ||
| 90 | pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR); | ||
| 91 | |||
| 92 | irq = platform_get_irq(pdev, 0); | ||
| 93 | error = devm_request_irq(&pdev->dev, irq, | ||
| 94 | sirfsoc_pwrc_isr, IRQF_SHARED, | ||
| 95 | "sirfsoc_pwrc_int", pwrcdrv); | ||
| 96 | if (error) { | ||
| 97 | dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n", | ||
| 98 | irq, error); | ||
| 99 | return error; | ||
| 100 | } | ||
| 101 | |||
| 102 | sirfsoc_rtc_iobrg_writel( | ||
| 103 | sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) | | ||
| 104 | PWRC_ON_KEY_BIT, | ||
| 105 | pwrcdrv->pwrc_base + PWRC_INT_MASK); | ||
| 106 | |||
| 107 | error = input_register_device(pwrcdrv->input); | ||
| 108 | if (error) { | ||
| 109 | dev_err(&pdev->dev, | ||
| 110 | "unable to register input device, error: %d\n", | ||
| 111 | error); | ||
| 112 | return error; | ||
| 113 | } | ||
| 114 | |||
| 115 | platform_set_drvdata(pdev, pwrcdrv); | ||
| 116 | device_init_wakeup(&pdev->dev, 1); | ||
| 117 | |||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static int sirfsoc_pwrc_remove(struct platform_device *pdev) | ||
| 122 | { | ||
| 123 | device_init_wakeup(&pdev->dev, 0); | ||
| 124 | |||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | #ifdef CONFIG_PM_SLEEP | ||
| 129 | static int pwrc_resume(struct device *dev) | ||
| 130 | { | ||
| 131 | struct platform_device *pdev = to_platform_device(dev); | ||
| 132 | struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev); | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Do not mask pwrc interrupt as we want pwrc work as a wakeup source | ||
| 136 | * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c | ||
| 137 | */ | ||
| 138 | sirfsoc_rtc_iobrg_writel( | ||
| 139 | sirfsoc_rtc_iobrg_readl( | ||
| 140 | pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT, | ||
| 141 | pwrcdrv->pwrc_base + PWRC_INT_MASK); | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | #endif | ||
| 146 | |||
| 147 | static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume); | ||
| 148 | |||
| 149 | static struct platform_driver sirfsoc_pwrc_driver = { | ||
| 150 | .probe = sirfsoc_pwrc_probe, | ||
| 151 | .remove = sirfsoc_pwrc_remove, | ||
| 152 | .driver = { | ||
| 153 | .name = "sirfsoc-pwrc", | ||
| 154 | .owner = THIS_MODULE, | ||
| 155 | .pm = &sirfsoc_pwrc_pm_ops, | ||
| 156 | .of_match_table = of_match_ptr(sirfsoc_pwrc_of_match), | ||
| 157 | } | ||
| 158 | }; | ||
| 159 | |||
| 160 | module_platform_driver(sirfsoc_pwrc_driver); | ||
| 161 | |||
| 162 | MODULE_LICENSE("GPLv2"); | ||
| 163 | MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>"); | ||
| 164 | MODULE_DESCRIPTION("CSR Prima2 PWRC Driver"); | ||
| 165 | MODULE_ALIAS("platform:sirfsoc-pwrc"); | ||
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index a53586a7fbdb..65fd3150919b 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c | |||
| @@ -175,7 +175,7 @@ static int sparcspkr_probe(struct device *dev) | |||
| 175 | 175 | ||
| 176 | static void sparcspkr_shutdown(struct platform_device *dev) | 176 | static void sparcspkr_shutdown(struct platform_device *dev) |
| 177 | { | 177 | { |
| 178 | struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); | 178 | struct sparcspkr_state *state = platform_get_drvdata(dev); |
| 179 | struct input_dev *input_dev = state->input_dev; | 179 | struct input_dev *input_dev = state->input_dev; |
| 180 | 180 | ||
| 181 | /* turn off the speaker */ | 181 | /* turn off the speaker */ |
| @@ -211,7 +211,7 @@ static int bbc_beep_probe(struct platform_device *op) | |||
| 211 | if (!info->regs) | 211 | if (!info->regs) |
| 212 | goto out_free; | 212 | goto out_free; |
| 213 | 213 | ||
| 214 | dev_set_drvdata(&op->dev, state); | 214 | platform_set_drvdata(op, state); |
| 215 | 215 | ||
| 216 | err = sparcspkr_probe(&op->dev); | 216 | err = sparcspkr_probe(&op->dev); |
| 217 | if (err) | 217 | if (err) |
| @@ -220,7 +220,6 @@ static int bbc_beep_probe(struct platform_device *op) | |||
| 220 | return 0; | 220 | return 0; |
| 221 | 221 | ||
| 222 | out_clear_drvdata: | 222 | out_clear_drvdata: |
| 223 | dev_set_drvdata(&op->dev, NULL); | ||
| 224 | of_iounmap(&op->resource[0], info->regs, 6); | 223 | of_iounmap(&op->resource[0], info->regs, 6); |
| 225 | 224 | ||
| 226 | out_free: | 225 | out_free: |
| @@ -231,7 +230,7 @@ out_err: | |||
| 231 | 230 | ||
| 232 | static int bbc_remove(struct platform_device *op) | 231 | static int bbc_remove(struct platform_device *op) |
| 233 | { | 232 | { |
| 234 | struct sparcspkr_state *state = dev_get_drvdata(&op->dev); | 233 | struct sparcspkr_state *state = platform_get_drvdata(op); |
| 235 | struct input_dev *input_dev = state->input_dev; | 234 | struct input_dev *input_dev = state->input_dev; |
| 236 | struct bbc_beep_info *info = &state->u.bbc; | 235 | struct bbc_beep_info *info = &state->u.bbc; |
| 237 | 236 | ||
| @@ -242,7 +241,6 @@ static int bbc_remove(struct platform_device *op) | |||
| 242 | 241 | ||
| 243 | of_iounmap(&op->resource[0], info->regs, 6); | 242 | of_iounmap(&op->resource[0], info->regs, 6); |
| 244 | 243 | ||
| 245 | dev_set_drvdata(&op->dev, NULL); | ||
| 246 | kfree(state); | 244 | kfree(state); |
| 247 | 245 | ||
| 248 | return 0; | 246 | return 0; |
| @@ -290,7 +288,7 @@ static int grover_beep_probe(struct platform_device *op) | |||
| 290 | if (!info->enable_reg) | 288 | if (!info->enable_reg) |
| 291 | goto out_unmap_freq_regs; | 289 | goto out_unmap_freq_regs; |
| 292 | 290 | ||
| 293 | dev_set_drvdata(&op->dev, state); | 291 | platform_set_drvdata(op, state); |
| 294 | 292 | ||
| 295 | err = sparcspkr_probe(&op->dev); | 293 | err = sparcspkr_probe(&op->dev); |
| 296 | if (err) | 294 | if (err) |
| @@ -299,7 +297,6 @@ static int grover_beep_probe(struct platform_device *op) | |||
| 299 | return 0; | 297 | return 0; |
| 300 | 298 | ||
| 301 | out_clear_drvdata: | 299 | out_clear_drvdata: |
| 302 | dev_set_drvdata(&op->dev, NULL); | ||
| 303 | of_iounmap(&op->resource[3], info->enable_reg, 1); | 300 | of_iounmap(&op->resource[3], info->enable_reg, 1); |
| 304 | 301 | ||
| 305 | out_unmap_freq_regs: | 302 | out_unmap_freq_regs: |
| @@ -312,7 +309,7 @@ out_err: | |||
| 312 | 309 | ||
| 313 | static int grover_remove(struct platform_device *op) | 310 | static int grover_remove(struct platform_device *op) |
| 314 | { | 311 | { |
| 315 | struct sparcspkr_state *state = dev_get_drvdata(&op->dev); | 312 | struct sparcspkr_state *state = platform_get_drvdata(op); |
| 316 | struct grover_beep_info *info = &state->u.grover; | 313 | struct grover_beep_info *info = &state->u.grover; |
| 317 | struct input_dev *input_dev = state->input_dev; | 314 | struct input_dev *input_dev = state->input_dev; |
| 318 | 315 | ||
| @@ -324,7 +321,6 @@ static int grover_remove(struct platform_device *op) | |||
| 324 | of_iounmap(&op->resource[3], info->enable_reg, 1); | 321 | of_iounmap(&op->resource[3], info->enable_reg, 1); |
| 325 | of_iounmap(&op->resource[2], info->freq_regs, 2); | 322 | of_iounmap(&op->resource[2], info->freq_regs, 2); |
| 326 | 323 | ||
| 327 | dev_set_drvdata(&op->dev, NULL); | ||
| 328 | kfree(state); | 324 | kfree(state); |
| 329 | 325 | ||
| 330 | return 0; | 326 | return 0; |
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 802bd6a72d73..effa9c5f2c5c 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
| @@ -295,7 +295,7 @@ config MOUSE_VSXXXAA | |||
| 295 | 295 | ||
| 296 | config MOUSE_GPIO | 296 | config MOUSE_GPIO |
| 297 | tristate "GPIO mouse" | 297 | tristate "GPIO mouse" |
| 298 | depends on GENERIC_GPIO | 298 | depends on GPIOLIB |
| 299 | select INPUT_POLLDEV | 299 | select INPUT_POLLDEV |
| 300 | help | 300 | help |
| 301 | This driver simulates a mouse on GPIO lines of various CPUs (and some | 301 | This driver simulates a mouse on GPIO lines of various CPUs (and some |
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index b55d5af217a7..62ec52b2e347 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c | |||
| @@ -133,7 +133,6 @@ static int __exit amimouse_remove(struct platform_device *pdev) | |||
| 133 | { | 133 | { |
| 134 | struct input_dev *dev = platform_get_drvdata(pdev); | 134 | struct input_dev *dev = platform_get_drvdata(pdev); |
| 135 | 135 | ||
| 136 | platform_set_drvdata(pdev, NULL); | ||
| 137 | input_unregister_device(dev); | 136 | input_unregister_device(dev); |
| 138 | return 0; | 137 | return 0; |
| 139 | } | 138 | } |
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index 532eaca4cc56..6b44413f54e3 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c | |||
| @@ -138,7 +138,6 @@ static int gpio_mouse_probe(struct platform_device *pdev) | |||
| 138 | 138 | ||
| 139 | out_free_polldev: | 139 | out_free_polldev: |
| 140 | input_free_polled_device(input_poll); | 140 | input_free_polled_device(input_poll); |
| 141 | platform_set_drvdata(pdev, NULL); | ||
| 142 | 141 | ||
| 143 | out_free_gpios: | 142 | out_free_gpios: |
| 144 | while (--i >= 0) { | 143 | while (--i >= 0) { |
| @@ -165,8 +164,6 @@ static int gpio_mouse_remove(struct platform_device *pdev) | |||
| 165 | gpio_free(pin); | 164 | gpio_free(pin); |
| 166 | } | 165 | } |
| 167 | 166 | ||
| 168 | platform_set_drvdata(pdev, NULL); | ||
| 169 | |||
| 170 | return 0; | 167 | return 0; |
| 171 | } | 168 | } |
| 172 | 169 | ||
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index 8e1b98ea5648..0b8d33591dee 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c | |||
| @@ -287,7 +287,7 @@ static int navpoint_probe(struct platform_device *pdev) | |||
| 287 | return 0; | 287 | return 0; |
| 288 | 288 | ||
| 289 | err_free_irq: | 289 | err_free_irq: |
| 290 | free_irq(ssp->irq, &pdev->dev); | 290 | free_irq(ssp->irq, navpoint); |
| 291 | err_free_mem: | 291 | err_free_mem: |
| 292 | input_free_device(input); | 292 | input_free_device(input); |
| 293 | kfree(navpoint); | 293 | kfree(navpoint); |
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 1bda828f4b55..94c17c28d268 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig | |||
| @@ -256,4 +256,14 @@ config SERIO_APBPS2 | |||
| 256 | To compile this driver as a module, choose M here: the module will | 256 | To compile this driver as a module, choose M here: the module will |
| 257 | be called apbps2. | 257 | be called apbps2. |
| 258 | 258 | ||
| 259 | config SERIO_OLPC_APSP | ||
| 260 | tristate "OLPC AP-SP input support" | ||
| 261 | depends on OF | ||
| 262 | help | ||
| 263 | Say Y here if you want support for the keyboard and touchpad included | ||
| 264 | in the OLPC XO-1.75 and XO-4 laptops. | ||
| 265 | |||
| 266 | To compile this driver as a module, choose M here: the module will | ||
| 267 | be called olpc_apsp. | ||
| 268 | |||
| 259 | endif | 269 | endif |
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 8edb36c2cdb4..12298b1c0e71 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile | |||
| @@ -27,3 +27,4 @@ obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o | |||
| 27 | obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o | 27 | obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o |
| 28 | obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o | 28 | obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o |
| 29 | obj-$(CONFIG_SERIO_APBPS2) += apbps2.o | 29 | obj-$(CONFIG_SERIO_APBPS2) += apbps2.o |
| 30 | obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o | ||
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index 479ce5fe8955..a0a2657e31ff 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c | |||
| @@ -163,7 +163,6 @@ static int altera_ps2_remove(struct platform_device *pdev) | |||
| 163 | { | 163 | { |
| 164 | struct ps2if *ps2if = platform_get_drvdata(pdev); | 164 | struct ps2if *ps2if = platform_get_drvdata(pdev); |
| 165 | 165 | ||
| 166 | platform_set_drvdata(pdev, NULL); | ||
| 167 | serio_unregister_port(ps2if->io); | 166 | serio_unregister_port(ps2if->io); |
| 168 | free_irq(ps2if->irq, ps2if); | 167 | free_irq(ps2if->irq, ps2if); |
| 169 | iounmap(ps2if->base); | 168 | iounmap(ps2if->base); |
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c index 190ce35af7df..3290b287ac4b 100644 --- a/drivers/input/serio/at32psif.c +++ b/drivers/input/serio/at32psif.c | |||
| @@ -314,8 +314,6 @@ static int __exit psif_remove(struct platform_device *pdev) | |||
| 314 | clk_put(psif->pclk); | 314 | clk_put(psif->pclk); |
| 315 | kfree(psif); | 315 | kfree(psif); |
| 316 | 316 | ||
| 317 | platform_set_drvdata(pdev, NULL); | ||
| 318 | |||
| 319 | return 0; | 317 | return 0; |
| 320 | } | 318 | } |
| 321 | 319 | ||
diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c new file mode 100644 index 000000000000..818aa466b5d2 --- /dev/null +++ b/drivers/input/serio/olpc_apsp.c | |||
| @@ -0,0 +1,287 @@ | |||
| 1 | /* | ||
| 2 | * OLPC serio driver for multiplexed input from Marvell MMP security processor | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011-2013 One Laptop Per Child | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/interrupt.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/serio.h> | ||
| 21 | #include <linux/err.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/io.h> | ||
| 24 | #include <linux/of.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | |||
| 28 | /* | ||
| 29 | * The OLPC XO-1.75 and XO-4 laptops do not have a hardware PS/2 controller. | ||
| 30 | * Instead, the OLPC firmware runs a bit-banging PS/2 implementation on an | ||
| 31 | * otherwise-unused slow processor which is included in the Marvell MMP2/MMP3 | ||
| 32 | * SoC, known as the "Security Processor" (SP) or "Wireless Trusted Module" | ||
| 33 | * (WTM). This firmware then reports its results via the WTM registers, | ||
| 34 | * which we read from the Application Processor (AP, i.e. main CPU) in this | ||
| 35 | * driver. | ||
| 36 | * | ||
| 37 | * On the hardware side we have a PS/2 mouse and an AT keyboard, the data | ||
| 38 | * is multiplexed through this system. We create a serio port for each one, | ||
| 39 | * and demultiplex the data accordingly. | ||
| 40 | */ | ||
| 41 | |||
| 42 | /* WTM register offsets */ | ||
| 43 | #define SECURE_PROCESSOR_COMMAND 0x40 | ||
| 44 | #define COMMAND_RETURN_STATUS 0x80 | ||
| 45 | #define COMMAND_FIFO_STATUS 0xc4 | ||
| 46 | #define PJ_RST_INTERRUPT 0xc8 | ||
| 47 | #define PJ_INTERRUPT_MASK 0xcc | ||
| 48 | |||
| 49 | /* | ||
| 50 | * The upper byte of SECURE_PROCESSOR_COMMAND and COMMAND_RETURN_STATUS is | ||
| 51 | * used to identify which port (device) is being talked to. The lower byte | ||
| 52 | * is the data being sent/received. | ||
| 53 | */ | ||
| 54 | #define PORT_MASK 0xff00 | ||
| 55 | #define DATA_MASK 0x00ff | ||
| 56 | #define PORT_SHIFT 8 | ||
| 57 | #define KEYBOARD_PORT 0 | ||
| 58 | #define TOUCHPAD_PORT 1 | ||
| 59 | |||
| 60 | /* COMMAND_FIFO_STATUS */ | ||
| 61 | #define CMD_CNTR_MASK 0x7 /* Number of pending/unprocessed commands */ | ||
| 62 | #define MAX_PENDING_CMDS 4 /* from device specs */ | ||
| 63 | |||
| 64 | /* PJ_RST_INTERRUPT */ | ||
| 65 | #define SP_COMMAND_COMPLETE_RESET 0x1 | ||
| 66 | |||
| 67 | /* PJ_INTERRUPT_MASK */ | ||
| 68 | #define INT_0 (1 << 0) | ||
| 69 | |||
| 70 | /* COMMAND_FIFO_STATUS */ | ||
| 71 | #define CMD_STS_MASK 0x100 | ||
| 72 | |||
| 73 | struct olpc_apsp { | ||
| 74 | struct device *dev; | ||
| 75 | struct serio *kbio; | ||
| 76 | struct serio *padio; | ||
| 77 | void __iomem *base; | ||
| 78 | int open_count; | ||
| 79 | int irq; | ||
| 80 | }; | ||
| 81 | |||
| 82 | static int olpc_apsp_write(struct serio *port, unsigned char val) | ||
| 83 | { | ||
| 84 | struct olpc_apsp *priv = port->port_data; | ||
| 85 | unsigned int i; | ||
| 86 | u32 which = 0; | ||
| 87 | |||
| 88 | if (port == priv->padio) | ||
| 89 | which = TOUCHPAD_PORT << PORT_SHIFT; | ||
| 90 | else | ||
| 91 | which = KEYBOARD_PORT << PORT_SHIFT; | ||
| 92 | |||
| 93 | dev_dbg(priv->dev, "olpc_apsp_write which=%x val=%x\n", which, val); | ||
| 94 | for (i = 0; i < 50; i++) { | ||
| 95 | u32 sts = readl(priv->base + COMMAND_FIFO_STATUS); | ||
| 96 | if ((sts & CMD_CNTR_MASK) < MAX_PENDING_CMDS) { | ||
| 97 | writel(which | val, | ||
| 98 | priv->base + SECURE_PROCESSOR_COMMAND); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | /* SP busy. This has not been seen in practice. */ | ||
| 102 | mdelay(1); | ||
| 103 | } | ||
| 104 | |||
| 105 | dev_dbg(priv->dev, "olpc_apsp_write timeout, status=%x\n", | ||
| 106 | readl(priv->base + COMMAND_FIFO_STATUS)); | ||
| 107 | |||
| 108 | return -ETIMEDOUT; | ||
| 109 | } | ||
| 110 | |||
| 111 | static irqreturn_t olpc_apsp_rx(int irq, void *dev_id) | ||
| 112 | { | ||
| 113 | struct olpc_apsp *priv = dev_id; | ||
| 114 | unsigned int w, tmp; | ||
| 115 | struct serio *serio; | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Write 1 to PJ_RST_INTERRUPT to acknowledge and clear the interrupt | ||
| 119 | * Write 0xff00 to SECURE_PROCESSOR_COMMAND. | ||
| 120 | */ | ||
| 121 | tmp = readl(priv->base + PJ_RST_INTERRUPT); | ||
| 122 | if (!(tmp & SP_COMMAND_COMPLETE_RESET)) { | ||
| 123 | dev_warn(priv->dev, "spurious interrupt?\n"); | ||
| 124 | return IRQ_NONE; | ||
| 125 | } | ||
| 126 | |||
| 127 | w = readl(priv->base + COMMAND_RETURN_STATUS); | ||
| 128 | dev_dbg(priv->dev, "olpc_apsp_rx %x\n", w); | ||
| 129 | |||
| 130 | if (w >> PORT_SHIFT == KEYBOARD_PORT) | ||
| 131 | serio = priv->kbio; | ||
| 132 | else | ||
| 133 | serio = priv->padio; | ||
| 134 | |||
| 135 | serio_interrupt(serio, w & DATA_MASK, 0); | ||
| 136 | |||
| 137 | /* Ack and clear interrupt */ | ||
| 138 | writel(tmp | SP_COMMAND_COMPLETE_RESET, priv->base + PJ_RST_INTERRUPT); | ||
| 139 | writel(PORT_MASK, priv->base + SECURE_PROCESSOR_COMMAND); | ||
| 140 | |||
| 141 | pm_wakeup_event(priv->dev, 1000); | ||
| 142 | return IRQ_HANDLED; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int olpc_apsp_open(struct serio *port) | ||
| 146 | { | ||
| 147 | struct olpc_apsp *priv = port->port_data; | ||
| 148 | unsigned int tmp; | ||
| 149 | |||
| 150 | if (priv->open_count++ == 0) { | ||
| 151 | /* Enable interrupt 0 by clearing its bit */ | ||
| 152 | tmp = readl(priv->base + PJ_INTERRUPT_MASK); | ||
| 153 | writel(tmp & ~INT_0, priv->base + PJ_INTERRUPT_MASK); | ||
| 154 | } | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | static void olpc_apsp_close(struct serio *port) | ||
| 160 | { | ||
| 161 | struct olpc_apsp *priv = port->port_data; | ||
| 162 | unsigned int tmp; | ||
| 163 | |||
| 164 | if (--priv->open_count == 0) { | ||
| 165 | /* Disable interrupt 0 */ | ||
| 166 | tmp = readl(priv->base + PJ_INTERRUPT_MASK); | ||
| 167 | writel(tmp | INT_0, priv->base + PJ_INTERRUPT_MASK); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | static int olpc_apsp_probe(struct platform_device *pdev) | ||
| 172 | { | ||
| 173 | struct serio *kb_serio, *pad_serio; | ||
| 174 | struct olpc_apsp *priv; | ||
| 175 | struct resource *res; | ||
| 176 | struct device_node *np; | ||
| 177 | unsigned long l; | ||
| 178 | int error; | ||
| 179 | |||
| 180 | priv = devm_kzalloc(&pdev->dev, sizeof(struct olpc_apsp), GFP_KERNEL); | ||
| 181 | if (!priv) | ||
| 182 | return -ENOMEM; | ||
| 183 | |||
| 184 | np = pdev->dev.of_node; | ||
| 185 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 186 | if (!res) | ||
| 187 | return -ENOENT; | ||
| 188 | |||
| 189 | priv->base = devm_ioremap_resource(&pdev->dev, res); | ||
| 190 | if (IS_ERR(priv->base)) { | ||
| 191 | dev_err(&pdev->dev, "Failed to map WTM registers\n"); | ||
| 192 | return PTR_ERR(priv->base); | ||
| 193 | } | ||
| 194 | |||
| 195 | priv->irq = platform_get_irq(pdev, 0); | ||
| 196 | if (priv->irq < 0) | ||
| 197 | return priv->irq; | ||
| 198 | |||
| 199 | l = readl(priv->base + COMMAND_FIFO_STATUS); | ||
| 200 | if (!(l & CMD_STS_MASK)) { | ||
| 201 | dev_err(&pdev->dev, "SP cannot accept commands.\n"); | ||
| 202 | return -EIO; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* KEYBOARD */ | ||
| 206 | kb_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | ||
| 207 | if (!kb_serio) | ||
| 208 | return -ENOMEM; | ||
| 209 | kb_serio->id.type = SERIO_8042_XL; | ||
| 210 | kb_serio->write = olpc_apsp_write; | ||
| 211 | kb_serio->open = olpc_apsp_open; | ||
| 212 | kb_serio->close = olpc_apsp_close; | ||
| 213 | kb_serio->port_data = priv; | ||
| 214 | kb_serio->dev.parent = &pdev->dev; | ||
| 215 | strlcpy(kb_serio->name, "sp keyboard", sizeof(kb_serio->name)); | ||
| 216 | strlcpy(kb_serio->phys, "sp/serio0", sizeof(kb_serio->phys)); | ||
| 217 | priv->kbio = kb_serio; | ||
| 218 | serio_register_port(kb_serio); | ||
| 219 | |||
| 220 | /* TOUCHPAD */ | ||
| 221 | pad_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | ||
| 222 | if (!pad_serio) { | ||
| 223 | error = -ENOMEM; | ||
| 224 | goto err_pad; | ||
| 225 | } | ||
| 226 | pad_serio->id.type = SERIO_8042; | ||
| 227 | pad_serio->write = olpc_apsp_write; | ||
| 228 | pad_serio->open = olpc_apsp_open; | ||
| 229 | pad_serio->close = olpc_apsp_close; | ||
| 230 | pad_serio->port_data = priv; | ||
| 231 | pad_serio->dev.parent = &pdev->dev; | ||
| 232 | strlcpy(pad_serio->name, "sp touchpad", sizeof(pad_serio->name)); | ||
| 233 | strlcpy(pad_serio->phys, "sp/serio1", sizeof(pad_serio->phys)); | ||
| 234 | priv->padio = pad_serio; | ||
| 235 | serio_register_port(pad_serio); | ||
| 236 | |||
| 237 | error = request_irq(priv->irq, olpc_apsp_rx, 0, "olpc-apsp", priv); | ||
| 238 | if (error) { | ||
| 239 | dev_err(&pdev->dev, "Failed to request IRQ\n"); | ||
| 240 | goto err_irq; | ||
| 241 | } | ||
| 242 | |||
| 243 | priv->dev = &pdev->dev; | ||
| 244 | device_init_wakeup(priv->dev, 1); | ||
| 245 | platform_set_drvdata(pdev, priv); | ||
| 246 | |||
| 247 | dev_dbg(&pdev->dev, "probed successfully.\n"); | ||
| 248 | return 0; | ||
| 249 | |||
| 250 | err_irq: | ||
| 251 | serio_unregister_port(pad_serio); | ||
| 252 | err_pad: | ||
| 253 | serio_unregister_port(kb_serio); | ||
| 254 | return error; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int olpc_apsp_remove(struct platform_device *pdev) | ||
| 258 | { | ||
| 259 | struct olpc_apsp *priv = platform_get_drvdata(pdev); | ||
| 260 | |||
| 261 | free_irq(priv->irq, priv); | ||
| 262 | |||
| 263 | serio_unregister_port(priv->kbio); | ||
| 264 | serio_unregister_port(priv->padio); | ||
| 265 | |||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | static struct of_device_id olpc_apsp_dt_ids[] = { | ||
| 270 | { .compatible = "olpc,ap-sp", }, | ||
| 271 | {} | ||
| 272 | }; | ||
| 273 | MODULE_DEVICE_TABLE(of, olpc_apsp_dt_ids); | ||
| 274 | |||
| 275 | static struct platform_driver olpc_apsp_driver = { | ||
| 276 | .probe = olpc_apsp_probe, | ||
| 277 | .remove = olpc_apsp_remove, | ||
| 278 | .driver = { | ||
| 279 | .name = "olpc-apsp", | ||
| 280 | .owner = THIS_MODULE, | ||
| 281 | .of_match_table = olpc_apsp_dt_ids, | ||
| 282 | }, | ||
| 283 | }; | ||
| 284 | |||
| 285 | MODULE_DESCRIPTION("OLPC AP-SP serio driver"); | ||
| 286 | MODULE_LICENSE("GPL"); | ||
| 287 | module_platform_driver(olpc_apsp_driver); | ||
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 436a3433f8e5..7a65a1bc5226 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c | |||
| @@ -181,7 +181,6 @@ static int q40kbd_remove(struct platform_device *pdev) | |||
| 181 | free_irq(Q40_IRQ_KEYBOARD, q40kbd); | 181 | free_irq(Q40_IRQ_KEYBOARD, q40kbd); |
| 182 | kfree(q40kbd); | 182 | kfree(q40kbd); |
| 183 | 183 | ||
| 184 | platform_set_drvdata(pdev, NULL); | ||
| 185 | return 0; | 184 | return 0; |
| 186 | } | 185 | } |
| 187 | 186 | ||
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 17be85948ffd..4b7662a17ae9 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c | |||
| @@ -349,8 +349,6 @@ static int xps2_of_remove(struct platform_device *of_dev) | |||
| 349 | 349 | ||
| 350 | kfree(drvdata); | 350 | kfree(drvdata); |
| 351 | 351 | ||
| 352 | platform_set_drvdata(of_dev, NULL); | ||
| 353 | |||
| 354 | return 0; | 352 | return 0; |
| 355 | } | 353 | } |
| 356 | 354 | ||
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index c7068942ebe8..f7de14a268bf 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c | |||
| @@ -237,7 +237,7 @@ static int pm860x_touch_probe(struct platform_device *pdev) | |||
| 237 | touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); | 237 | touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); |
| 238 | if (touch == NULL) | 238 | if (touch == NULL) |
| 239 | return -ENOMEM; | 239 | return -ENOMEM; |
| 240 | dev_set_drvdata(&pdev->dev, touch); | 240 | platform_set_drvdata(pdev, touch); |
| 241 | 241 | ||
| 242 | touch->idev = input_allocate_device(); | 242 | touch->idev = input_allocate_device(); |
| 243 | if (touch->idev == NULL) { | 243 | if (touch->idev == NULL) { |
| @@ -299,7 +299,6 @@ static int pm860x_touch_remove(struct platform_device *pdev) | |||
| 299 | 299 | ||
| 300 | input_unregister_device(touch->idev); | 300 | input_unregister_device(touch->idev); |
| 301 | free_irq(touch->irq, touch); | 301 | free_irq(touch->irq, touch); |
| 302 | platform_set_drvdata(pdev, NULL); | ||
| 303 | kfree(touch); | 302 | kfree(touch); |
| 304 | return 0; | 303 | return 0; |
| 305 | } | 304 | } |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f9a5fd89bc02..2d70089c1183 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
| @@ -167,6 +167,36 @@ config TOUCHSCREEN_CYTTSP_SPI | |||
| 167 | To compile this driver as a module, choose M here: the | 167 | To compile this driver as a module, choose M here: the |
| 168 | module will be called cyttsp_spi. | 168 | module will be called cyttsp_spi. |
| 169 | 169 | ||
| 170 | config TOUCHSCREEN_CYTTSP4_CORE | ||
| 171 | tristate "Cypress TrueTouch Gen4 Touchscreen Driver" | ||
| 172 | help | ||
| 173 | Core driver for Cypress TrueTouch(tm) Standard Product | ||
| 174 | Generation4 touchscreen controllers. | ||
| 175 | |||
| 176 | Say Y here if you have a Cypress Gen4 touchscreen. | ||
| 177 | |||
| 178 | If unsure, say N. | ||
| 179 | |||
| 180 | To compile this driver as a module, choose M here. | ||
| 181 | |||
| 182 | config TOUCHSCREEN_CYTTSP4_I2C | ||
| 183 | tristate "support I2C bus connection" | ||
| 184 | depends on TOUCHSCREEN_CYTTSP4_CORE && I2C | ||
| 185 | help | ||
| 186 | Say Y here if the touchscreen is connected via I2C bus. | ||
| 187 | |||
| 188 | To compile this driver as a module, choose M here: the | ||
| 189 | module will be called cyttsp4_i2c. | ||
| 190 | |||
| 191 | config TOUCHSCREEN_CYTTSP4_SPI | ||
| 192 | tristate "support SPI bus connection" | ||
| 193 | depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER | ||
| 194 | help | ||
| 195 | Say Y here if the touchscreen is connected via SPI bus. | ||
| 196 | |||
| 197 | To compile this driver as a module, choose M here: the | ||
| 198 | module will be called cyttsp4_spi. | ||
| 199 | |||
| 170 | config TOUCHSCREEN_DA9034 | 200 | config TOUCHSCREEN_DA9034 |
| 171 | tristate "Touchscreen support for Dialog Semiconductor DA9034" | 201 | tristate "Touchscreen support for Dialog Semiconductor DA9034" |
| 172 | depends on PMIC_DA903X | 202 | depends on PMIC_DA903X |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 6bfbeab67c9f..f5216c1bf53e 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
| @@ -18,8 +18,11 @@ obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o | |||
| 18 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o | 18 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o |
| 19 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o | 19 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o |
| 20 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o | 20 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o |
| 21 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o | 21 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o |
| 22 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o | 22 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o |
| 23 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o | ||
| 24 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o | ||
| 25 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o | ||
| 23 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o | 26 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o |
| 24 | obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o | 27 | obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o |
| 25 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o | 28 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o |
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 2c1e46b7e45b..268a35e55d7f 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c | |||
| @@ -372,7 +372,6 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev) | |||
| 372 | err_irq: | 372 | err_irq: |
| 373 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); | 373 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); |
| 374 | err: | 374 | err: |
| 375 | platform_set_drvdata(pdev, NULL); | ||
| 376 | kfree(atmel_wm97xx); | 375 | kfree(atmel_wm97xx); |
| 377 | return ret; | 376 | return ret; |
| 378 | } | 377 | } |
| @@ -386,7 +385,6 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev) | |||
| 386 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); | 385 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); |
| 387 | del_timer_sync(&atmel_wm97xx->pen_timer); | 386 | del_timer_sync(&atmel_wm97xx->pen_timer); |
| 388 | wm97xx_unregister_mach_ops(wm); | 387 | wm97xx_unregister_mach_ops(wm); |
| 389 | platform_set_drvdata(pdev, NULL); | ||
| 390 | kfree(atmel_wm97xx); | 388 | kfree(atmel_wm97xx); |
| 391 | 389 | ||
| 392 | return 0; | 390 | return 0; |
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 95f6785a94b0..bddabc595077 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c | |||
| @@ -183,10 +183,13 @@ static int atmel_tsadcc_probe(struct platform_device *pdev) | |||
| 183 | struct input_dev *input_dev; | 183 | struct input_dev *input_dev; |
| 184 | struct resource *res; | 184 | struct resource *res; |
| 185 | struct at91_tsadcc_data *pdata = pdev->dev.platform_data; | 185 | struct at91_tsadcc_data *pdata = pdev->dev.platform_data; |
| 186 | int err = 0; | 186 | int err; |
| 187 | unsigned int prsc; | 187 | unsigned int prsc; |
| 188 | unsigned int reg; | 188 | unsigned int reg; |
| 189 | 189 | ||
| 190 | if (!pdata) | ||
| 191 | return -EINVAL; | ||
| 192 | |||
| 190 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 193 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 191 | if (!res) { | 194 | if (!res) { |
| 192 | dev_err(&pdev->dev, "no mmio resource defined.\n"); | 195 | dev_err(&pdev->dev, "no mmio resource defined.\n"); |
| @@ -265,9 +268,6 @@ static int atmel_tsadcc_probe(struct platform_device *pdev) | |||
| 265 | prsc = clk_get_rate(ts_dev->clk); | 268 | prsc = clk_get_rate(ts_dev->clk); |
| 266 | dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); | 269 | dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); |
| 267 | 270 | ||
| 268 | if (!pdata) | ||
| 269 | goto err_fail; | ||
| 270 | |||
| 271 | if (!pdata->adc_clock) | 271 | if (!pdata->adc_clock) |
| 272 | pdata->adc_clock = ADC_DEFAULT_CLOCK; | 272 | pdata->adc_clock = ADC_DEFAULT_CLOCK; |
| 273 | 273 | ||
| @@ -325,7 +325,7 @@ err_free_mem: | |||
| 325 | 325 | ||
| 326 | static int atmel_tsadcc_remove(struct platform_device *pdev) | 326 | static int atmel_tsadcc_remove(struct platform_device *pdev) |
| 327 | { | 327 | { |
| 328 | struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); | 328 | struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev); |
| 329 | struct resource *res; | 329 | struct resource *res; |
| 330 | 330 | ||
| 331 | free_irq(ts_dev->irq, ts_dev); | 331 | free_irq(ts_dev->irq, ts_dev); |
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c new file mode 100644 index 000000000000..963da052c15e --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_core.c | |||
| @@ -0,0 +1,2169 @@ | |||
| 1 | /* | ||
| 2 | * cyttsp4_core.c | ||
| 3 | * Cypress TrueTouch(TM) Standard Product V4 Core driver module. | ||
| 4 | * For use with Cypress Txx4xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * TMA4XX | ||
| 7 | * TMA1036 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2012 Cypress Semiconductor | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU General Public License | ||
| 13 | * version 2, and only version 2, as published by the | ||
| 14 | * Free Software Foundation. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "cyttsp4_core.h" | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/gpio.h> | ||
| 28 | #include <linux/input/mt.h> | ||
| 29 | #include <linux/interrupt.h> | ||
| 30 | #include <linux/pm_runtime.h> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | |||
| 34 | /* Timeout in ms. */ | ||
| 35 | #define CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT 500 | ||
| 36 | #define CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT 5000 | ||
| 37 | #define CY_CORE_MODE_CHANGE_TIMEOUT 1000 | ||
| 38 | #define CY_CORE_RESET_AND_WAIT_TIMEOUT 500 | ||
| 39 | #define CY_CORE_WAKEUP_TIMEOUT 500 | ||
| 40 | |||
| 41 | #define CY_CORE_STARTUP_RETRY_COUNT 3 | ||
| 42 | |||
| 43 | static const u8 ldr_exit[] = { | ||
| 44 | 0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17 | ||
| 45 | }; | ||
| 46 | |||
| 47 | static const u8 ldr_err_app[] = { | ||
| 48 | 0x01, 0x02, 0x00, 0x00, 0x55, 0xDD, 0x17 | ||
| 49 | }; | ||
| 50 | |||
| 51 | static inline size_t merge_bytes(u8 high, u8 low) | ||
| 52 | { | ||
| 53 | return (high << 8) + low; | ||
| 54 | } | ||
| 55 | |||
| 56 | #ifdef VERBOSE_DEBUG | ||
| 57 | static void cyttsp4_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size, | ||
| 58 | const char *data_name) | ||
| 59 | { | ||
| 60 | int i, k; | ||
| 61 | const char fmt[] = "%02X "; | ||
| 62 | int max; | ||
| 63 | |||
| 64 | if (!size) | ||
| 65 | return; | ||
| 66 | |||
| 67 | max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED); | ||
| 68 | |||
| 69 | pr_buf[0] = 0; | ||
| 70 | for (i = k = 0; i < size && k < max; i++, k += 3) | ||
| 71 | scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]); | ||
| 72 | |||
| 73 | dev_vdbg(dev, "%s: %s[0..%d]=%s%s\n", __func__, data_name, size - 1, | ||
| 74 | pr_buf, size <= max ? "" : CY_PR_TRUNCATED); | ||
| 75 | } | ||
| 76 | #else | ||
| 77 | #define cyttsp4_pr_buf(dev, pr_buf, dptr, size, data_name) do { } while (0) | ||
| 78 | #endif | ||
| 79 | |||
| 80 | static int cyttsp4_load_status_regs(struct cyttsp4 *cd) | ||
| 81 | { | ||
| 82 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 83 | struct device *dev = cd->dev; | ||
| 84 | int rc; | ||
| 85 | |||
| 86 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, si->si_ofs.mode_size, | ||
| 87 | si->xy_mode); | ||
| 88 | if (rc < 0) | ||
| 89 | dev_err(dev, "%s: fail read mode regs r=%d\n", | ||
| 90 | __func__, rc); | ||
| 91 | else | ||
| 92 | cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_mode, | ||
| 93 | si->si_ofs.mode_size, "xy_mode"); | ||
| 94 | |||
| 95 | return rc; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int cyttsp4_handshake(struct cyttsp4 *cd, u8 mode) | ||
| 99 | { | ||
| 100 | u8 cmd = mode ^ CY_HST_TOGGLE; | ||
| 101 | int rc; | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Mode change issued, handshaking now will cause endless mode change | ||
| 105 | * requests, for sync mode modechange will do same with handshake | ||
| 106 | * */ | ||
| 107 | if (mode & CY_HST_MODE_CHANGE) | ||
| 108 | return 0; | ||
| 109 | |||
| 110 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd); | ||
| 111 | if (rc < 0) | ||
| 112 | dev_err(cd->dev, "%s: bus write fail on handshake (ret=%d)\n", | ||
| 113 | __func__, rc); | ||
| 114 | |||
| 115 | return rc; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int cyttsp4_hw_soft_reset(struct cyttsp4 *cd) | ||
| 119 | { | ||
| 120 | u8 cmd = CY_HST_RESET; | ||
| 121 | int rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd); | ||
| 122 | if (rc < 0) { | ||
| 123 | dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n", | ||
| 124 | __func__); | ||
| 125 | return rc; | ||
| 126 | } | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int cyttsp4_hw_hard_reset(struct cyttsp4 *cd) | ||
| 131 | { | ||
| 132 | if (cd->cpdata->xres) { | ||
| 133 | cd->cpdata->xres(cd->cpdata, cd->dev); | ||
| 134 | dev_dbg(cd->dev, "%s: execute HARD reset\n", __func__); | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__); | ||
| 138 | return -ENOSYS; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int cyttsp4_hw_reset(struct cyttsp4 *cd) | ||
| 142 | { | ||
| 143 | int rc = cyttsp4_hw_hard_reset(cd); | ||
| 144 | if (rc == -ENOSYS) | ||
| 145 | rc = cyttsp4_hw_soft_reset(cd); | ||
| 146 | return rc; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* | ||
| 150 | * Gets number of bits for a touch filed as parameter, | ||
| 151 | * sets maximum value for field which is used as bit mask | ||
| 152 | * and returns number of bytes required for that field | ||
| 153 | */ | ||
| 154 | static int cyttsp4_bits_2_bytes(unsigned int nbits, size_t *max) | ||
| 155 | { | ||
| 156 | *max = 1 << nbits; | ||
| 157 | return (nbits + 7) / 8; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int cyttsp4_si_data_offsets(struct cyttsp4 *cd) | ||
| 161 | { | ||
| 162 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 163 | int rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(si->si_data), | ||
| 164 | &si->si_data); | ||
| 165 | if (rc < 0) { | ||
| 166 | dev_err(cd->dev, "%s: fail read sysinfo data offsets r=%d\n", | ||
| 167 | __func__, rc); | ||
| 168 | return rc; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* Print sysinfo data offsets */ | ||
| 172 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)&si->si_data, | ||
| 173 | sizeof(si->si_data), "sysinfo_data_offsets"); | ||
| 174 | |||
| 175 | /* convert sysinfo data offset bytes into integers */ | ||
| 176 | |||
| 177 | si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh, | ||
| 178 | si->si_data.map_szl); | ||
| 179 | si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh, | ||
| 180 | si->si_data.map_szl); | ||
| 181 | si->si_ofs.cydata_ofs = merge_bytes(si->si_data.cydata_ofsh, | ||
| 182 | si->si_data.cydata_ofsl); | ||
| 183 | si->si_ofs.test_ofs = merge_bytes(si->si_data.test_ofsh, | ||
| 184 | si->si_data.test_ofsl); | ||
| 185 | si->si_ofs.pcfg_ofs = merge_bytes(si->si_data.pcfg_ofsh, | ||
| 186 | si->si_data.pcfg_ofsl); | ||
| 187 | si->si_ofs.opcfg_ofs = merge_bytes(si->si_data.opcfg_ofsh, | ||
| 188 | si->si_data.opcfg_ofsl); | ||
| 189 | si->si_ofs.ddata_ofs = merge_bytes(si->si_data.ddata_ofsh, | ||
| 190 | si->si_data.ddata_ofsl); | ||
| 191 | si->si_ofs.mdata_ofs = merge_bytes(si->si_data.mdata_ofsh, | ||
| 192 | si->si_data.mdata_ofsl); | ||
| 193 | return rc; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int cyttsp4_si_get_cydata(struct cyttsp4 *cd) | ||
| 197 | { | ||
| 198 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 199 | int read_offset; | ||
| 200 | int mfgid_sz, calc_mfgid_sz; | ||
| 201 | void *p; | ||
| 202 | int rc; | ||
| 203 | |||
| 204 | si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs; | ||
| 205 | dev_dbg(cd->dev, "%s: cydata size: %Zd\n", __func__, | ||
| 206 | si->si_ofs.cydata_size); | ||
| 207 | |||
| 208 | p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL); | ||
| 209 | if (p == NULL) { | ||
| 210 | dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__); | ||
| 211 | return -ENOMEM; | ||
| 212 | } | ||
| 213 | si->si_ptrs.cydata = p; | ||
| 214 | |||
| 215 | read_offset = si->si_ofs.cydata_ofs; | ||
| 216 | |||
| 217 | /* Read the CYDA registers up to MFGID field */ | ||
| 218 | rc = cyttsp4_adap_read(cd, read_offset, | ||
| 219 | offsetof(struct cyttsp4_cydata, mfgid_sz) | ||
| 220 | + sizeof(si->si_ptrs.cydata->mfgid_sz), | ||
| 221 | si->si_ptrs.cydata); | ||
| 222 | if (rc < 0) { | ||
| 223 | dev_err(cd->dev, "%s: fail read cydata r=%d\n", | ||
| 224 | __func__, rc); | ||
| 225 | return rc; | ||
| 226 | } | ||
| 227 | |||
| 228 | /* Check MFGID size */ | ||
| 229 | mfgid_sz = si->si_ptrs.cydata->mfgid_sz; | ||
| 230 | calc_mfgid_sz = si->si_ofs.cydata_size - sizeof(struct cyttsp4_cydata); | ||
| 231 | if (mfgid_sz != calc_mfgid_sz) { | ||
| 232 | dev_err(cd->dev, "%s: mismatch in MFGID size, reported:%d calculated:%d\n", | ||
| 233 | __func__, mfgid_sz, calc_mfgid_sz); | ||
| 234 | return -EINVAL; | ||
| 235 | } | ||
| 236 | |||
| 237 | read_offset += offsetof(struct cyttsp4_cydata, mfgid_sz) | ||
| 238 | + sizeof(si->si_ptrs.cydata->mfgid_sz); | ||
| 239 | |||
| 240 | /* Read the CYDA registers for MFGID field */ | ||
| 241 | rc = cyttsp4_adap_read(cd, read_offset, si->si_ptrs.cydata->mfgid_sz, | ||
| 242 | si->si_ptrs.cydata->mfg_id); | ||
| 243 | if (rc < 0) { | ||
| 244 | dev_err(cd->dev, "%s: fail read cydata r=%d\n", | ||
| 245 | __func__, rc); | ||
| 246 | return rc; | ||
| 247 | } | ||
| 248 | |||
| 249 | read_offset += si->si_ptrs.cydata->mfgid_sz; | ||
| 250 | |||
| 251 | /* Read the rest of the CYDA registers */ | ||
| 252 | rc = cyttsp4_adap_read(cd, read_offset, | ||
| 253 | sizeof(struct cyttsp4_cydata) | ||
| 254 | - offsetof(struct cyttsp4_cydata, cyito_idh), | ||
| 255 | &si->si_ptrs.cydata->cyito_idh); | ||
| 256 | if (rc < 0) { | ||
| 257 | dev_err(cd->dev, "%s: fail read cydata r=%d\n", | ||
| 258 | __func__, rc); | ||
| 259 | return rc; | ||
| 260 | } | ||
| 261 | |||
| 262 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.cydata, | ||
| 263 | si->si_ofs.cydata_size, "sysinfo_cydata"); | ||
| 264 | return rc; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int cyttsp4_si_get_test_data(struct cyttsp4 *cd) | ||
| 268 | { | ||
| 269 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 270 | void *p; | ||
| 271 | int rc; | ||
| 272 | |||
| 273 | si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs; | ||
| 274 | |||
| 275 | p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL); | ||
| 276 | if (p == NULL) { | ||
| 277 | dev_err(cd->dev, "%s: fail alloc test memory\n", __func__); | ||
| 278 | return -ENOMEM; | ||
| 279 | } | ||
| 280 | si->si_ptrs.test = p; | ||
| 281 | |||
| 282 | rc = cyttsp4_adap_read(cd, si->si_ofs.test_ofs, si->si_ofs.test_size, | ||
| 283 | si->si_ptrs.test); | ||
| 284 | if (rc < 0) { | ||
| 285 | dev_err(cd->dev, "%s: fail read test data r=%d\n", | ||
| 286 | __func__, rc); | ||
| 287 | return rc; | ||
| 288 | } | ||
| 289 | |||
| 290 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
| 291 | (u8 *)si->si_ptrs.test, si->si_ofs.test_size, | ||
| 292 | "sysinfo_test_data"); | ||
| 293 | if (si->si_ptrs.test->post_codel & | ||
| 294 | CY_POST_CODEL_WDG_RST) | ||
| 295 | dev_info(cd->dev, "%s: %s codel=%02X\n", | ||
| 296 | __func__, "Reset was a WATCHDOG RESET", | ||
| 297 | si->si_ptrs.test->post_codel); | ||
| 298 | |||
| 299 | if (!(si->si_ptrs.test->post_codel & | ||
| 300 | CY_POST_CODEL_CFG_DATA_CRC_FAIL)) | ||
| 301 | dev_info(cd->dev, "%s: %s codel=%02X\n", __func__, | ||
| 302 | "Config Data CRC FAIL", | ||
| 303 | si->si_ptrs.test->post_codel); | ||
| 304 | |||
| 305 | if (!(si->si_ptrs.test->post_codel & | ||
| 306 | CY_POST_CODEL_PANEL_TEST_FAIL)) | ||
| 307 | dev_info(cd->dev, "%s: %s codel=%02X\n", | ||
| 308 | __func__, "PANEL TEST FAIL", | ||
| 309 | si->si_ptrs.test->post_codel); | ||
| 310 | |||
| 311 | dev_info(cd->dev, "%s: SCANNING is %s codel=%02X\n", | ||
| 312 | __func__, si->si_ptrs.test->post_codel & 0x08 ? | ||
| 313 | "ENABLED" : "DISABLED", | ||
| 314 | si->si_ptrs.test->post_codel); | ||
| 315 | return rc; | ||
| 316 | } | ||
| 317 | |||
| 318 | static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd) | ||
| 319 | { | ||
| 320 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 321 | void *p; | ||
| 322 | int rc; | ||
| 323 | |||
| 324 | si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs; | ||
| 325 | |||
| 326 | p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL); | ||
| 327 | if (p == NULL) { | ||
| 328 | rc = -ENOMEM; | ||
| 329 | dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n", | ||
| 330 | __func__, rc); | ||
| 331 | return rc; | ||
| 332 | } | ||
| 333 | si->si_ptrs.pcfg = p; | ||
| 334 | |||
| 335 | rc = cyttsp4_adap_read(cd, si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size, | ||
| 336 | si->si_ptrs.pcfg); | ||
| 337 | if (rc < 0) { | ||
| 338 | dev_err(cd->dev, "%s: fail read pcfg data r=%d\n", | ||
| 339 | __func__, rc); | ||
| 340 | return rc; | ||
| 341 | } | ||
| 342 | |||
| 343 | si->si_ofs.max_x = merge_bytes((si->si_ptrs.pcfg->res_xh | ||
| 344 | & CY_PCFG_RESOLUTION_X_MASK), si->si_ptrs.pcfg->res_xl); | ||
| 345 | si->si_ofs.x_origin = !!(si->si_ptrs.pcfg->res_xh | ||
| 346 | & CY_PCFG_ORIGIN_X_MASK); | ||
| 347 | si->si_ofs.max_y = merge_bytes((si->si_ptrs.pcfg->res_yh | ||
| 348 | & CY_PCFG_RESOLUTION_Y_MASK), si->si_ptrs.pcfg->res_yl); | ||
| 349 | si->si_ofs.y_origin = !!(si->si_ptrs.pcfg->res_yh | ||
| 350 | & CY_PCFG_ORIGIN_Y_MASK); | ||
| 351 | si->si_ofs.max_p = merge_bytes(si->si_ptrs.pcfg->max_zh, | ||
| 352 | si->si_ptrs.pcfg->max_zl); | ||
| 353 | |||
| 354 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
| 355 | (u8 *)si->si_ptrs.pcfg, | ||
| 356 | si->si_ofs.pcfg_size, "sysinfo_pcfg_data"); | ||
| 357 | return rc; | ||
| 358 | } | ||
| 359 | |||
| 360 | static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd) | ||
| 361 | { | ||
| 362 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 363 | struct cyttsp4_tch_abs_params *tch; | ||
| 364 | struct cyttsp4_tch_rec_params *tch_old, *tch_new; | ||
| 365 | enum cyttsp4_tch_abs abs; | ||
| 366 | int i; | ||
| 367 | void *p; | ||
| 368 | int rc; | ||
| 369 | |||
| 370 | si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs; | ||
| 371 | |||
| 372 | p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL); | ||
| 373 | if (p == NULL) { | ||
| 374 | dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__); | ||
| 375 | rc = -ENOMEM; | ||
| 376 | goto cyttsp4_si_get_opcfg_data_exit; | ||
| 377 | } | ||
| 378 | si->si_ptrs.opcfg = p; | ||
| 379 | |||
| 380 | rc = cyttsp4_adap_read(cd, si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size, | ||
| 381 | si->si_ptrs.opcfg); | ||
| 382 | if (rc < 0) { | ||
| 383 | dev_err(cd->dev, "%s: fail read opcfg data r=%d\n", | ||
| 384 | __func__, rc); | ||
| 385 | goto cyttsp4_si_get_opcfg_data_exit; | ||
| 386 | } | ||
| 387 | si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs; | ||
| 388 | si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs; | ||
| 389 | si->si_ofs.rep_sz = (si->si_ptrs.opcfg->rep_szh * 256) + | ||
| 390 | si->si_ptrs.opcfg->rep_szl; | ||
| 391 | si->si_ofs.num_btns = si->si_ptrs.opcfg->num_btns; | ||
| 392 | si->si_ofs.num_btn_regs = (si->si_ofs.num_btns + | ||
| 393 | CY_NUM_BTN_PER_REG - 1) / CY_NUM_BTN_PER_REG; | ||
| 394 | si->si_ofs.tt_stat_ofs = si->si_ptrs.opcfg->tt_stat_ofs; | ||
| 395 | si->si_ofs.obj_cfg0 = si->si_ptrs.opcfg->obj_cfg0; | ||
| 396 | si->si_ofs.max_tchs = si->si_ptrs.opcfg->max_tchs & | ||
| 397 | CY_BYTE_OFS_MASK; | ||
| 398 | si->si_ofs.tch_rec_size = si->si_ptrs.opcfg->tch_rec_size & | ||
| 399 | CY_BYTE_OFS_MASK; | ||
| 400 | |||
| 401 | /* Get the old touch fields */ | ||
| 402 | for (abs = CY_TCH_X; abs < CY_NUM_TCH_FIELDS; abs++) { | ||
| 403 | tch = &si->si_ofs.tch_abs[abs]; | ||
| 404 | tch_old = &si->si_ptrs.opcfg->tch_rec_old[abs]; | ||
| 405 | |||
| 406 | tch->ofs = tch_old->loc & CY_BYTE_OFS_MASK; | ||
| 407 | tch->size = cyttsp4_bits_2_bytes(tch_old->size, | ||
| 408 | &tch->max); | ||
| 409 | tch->bofs = (tch_old->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT; | ||
| 410 | } | ||
| 411 | |||
| 412 | /* button fields */ | ||
| 413 | si->si_ofs.btn_rec_size = si->si_ptrs.opcfg->btn_rec_size; | ||
| 414 | si->si_ofs.btn_diff_ofs = si->si_ptrs.opcfg->btn_diff_ofs; | ||
| 415 | si->si_ofs.btn_diff_size = si->si_ptrs.opcfg->btn_diff_size; | ||
| 416 | |||
| 417 | if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) { | ||
| 418 | /* Get the extended touch fields */ | ||
| 419 | for (i = 0; i < CY_NUM_EXT_TCH_FIELDS; abs++, i++) { | ||
| 420 | tch = &si->si_ofs.tch_abs[abs]; | ||
| 421 | tch_new = &si->si_ptrs.opcfg->tch_rec_new[i]; | ||
| 422 | |||
| 423 | tch->ofs = tch_new->loc & CY_BYTE_OFS_MASK; | ||
| 424 | tch->size = cyttsp4_bits_2_bytes(tch_new->size, | ||
| 425 | &tch->max); | ||
| 426 | tch->bofs = (tch_new->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT; | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | for (abs = 0; abs < CY_TCH_NUM_ABS; abs++) { | ||
| 431 | dev_dbg(cd->dev, "%s: tch_rec_%s\n", __func__, | ||
| 432 | cyttsp4_tch_abs_string[abs]); | ||
| 433 | dev_dbg(cd->dev, "%s: ofs =%2Zd\n", __func__, | ||
| 434 | si->si_ofs.tch_abs[abs].ofs); | ||
| 435 | dev_dbg(cd->dev, "%s: siz =%2Zd\n", __func__, | ||
| 436 | si->si_ofs.tch_abs[abs].size); | ||
| 437 | dev_dbg(cd->dev, "%s: max =%2Zd\n", __func__, | ||
| 438 | si->si_ofs.tch_abs[abs].max); | ||
| 439 | dev_dbg(cd->dev, "%s: bofs=%2Zd\n", __func__, | ||
| 440 | si->si_ofs.tch_abs[abs].bofs); | ||
| 441 | } | ||
| 442 | |||
| 443 | si->si_ofs.mode_size = si->si_ofs.tt_stat_ofs + 1; | ||
| 444 | si->si_ofs.data_size = si->si_ofs.max_tchs * | ||
| 445 | si->si_ptrs.opcfg->tch_rec_size; | ||
| 446 | |||
| 447 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg, | ||
| 448 | si->si_ofs.opcfg_size, "sysinfo_opcfg_data"); | ||
| 449 | |||
| 450 | cyttsp4_si_get_opcfg_data_exit: | ||
| 451 | return rc; | ||
| 452 | } | ||
| 453 | |||
| 454 | static int cyttsp4_si_get_ddata(struct cyttsp4 *cd) | ||
| 455 | { | ||
| 456 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 457 | void *p; | ||
| 458 | int rc; | ||
| 459 | |||
| 460 | si->si_ofs.ddata_size = si->si_ofs.mdata_ofs - si->si_ofs.ddata_ofs; | ||
| 461 | |||
| 462 | p = krealloc(si->si_ptrs.ddata, si->si_ofs.ddata_size, GFP_KERNEL); | ||
| 463 | if (p == NULL) { | ||
| 464 | dev_err(cd->dev, "%s: fail alloc ddata memory\n", __func__); | ||
| 465 | return -ENOMEM; | ||
| 466 | } | ||
| 467 | si->si_ptrs.ddata = p; | ||
| 468 | |||
| 469 | rc = cyttsp4_adap_read(cd, si->si_ofs.ddata_ofs, si->si_ofs.ddata_size, | ||
| 470 | si->si_ptrs.ddata); | ||
| 471 | if (rc < 0) | ||
| 472 | dev_err(cd->dev, "%s: fail read ddata data r=%d\n", | ||
| 473 | __func__, rc); | ||
| 474 | else | ||
| 475 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
| 476 | (u8 *)si->si_ptrs.ddata, | ||
| 477 | si->si_ofs.ddata_size, "sysinfo_ddata"); | ||
| 478 | return rc; | ||
| 479 | } | ||
| 480 | |||
| 481 | static int cyttsp4_si_get_mdata(struct cyttsp4 *cd) | ||
| 482 | { | ||
| 483 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 484 | void *p; | ||
| 485 | int rc; | ||
| 486 | |||
| 487 | si->si_ofs.mdata_size = si->si_ofs.map_sz - si->si_ofs.mdata_ofs; | ||
| 488 | |||
| 489 | p = krealloc(si->si_ptrs.mdata, si->si_ofs.mdata_size, GFP_KERNEL); | ||
| 490 | if (p == NULL) { | ||
| 491 | dev_err(cd->dev, "%s: fail alloc mdata memory\n", __func__); | ||
| 492 | return -ENOMEM; | ||
| 493 | } | ||
| 494 | si->si_ptrs.mdata = p; | ||
| 495 | |||
| 496 | rc = cyttsp4_adap_read(cd, si->si_ofs.mdata_ofs, si->si_ofs.mdata_size, | ||
| 497 | si->si_ptrs.mdata); | ||
| 498 | if (rc < 0) | ||
| 499 | dev_err(cd->dev, "%s: fail read mdata data r=%d\n", | ||
| 500 | __func__, rc); | ||
| 501 | else | ||
| 502 | cyttsp4_pr_buf(cd->dev, cd->pr_buf, | ||
| 503 | (u8 *)si->si_ptrs.mdata, | ||
| 504 | si->si_ofs.mdata_size, "sysinfo_mdata"); | ||
| 505 | return rc; | ||
| 506 | } | ||
| 507 | |||
| 508 | static int cyttsp4_si_get_btn_data(struct cyttsp4 *cd) | ||
| 509 | { | ||
| 510 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 511 | int btn; | ||
| 512 | int num_defined_keys; | ||
| 513 | u16 *key_table; | ||
| 514 | void *p; | ||
| 515 | int rc = 0; | ||
| 516 | |||
| 517 | if (si->si_ofs.num_btns) { | ||
| 518 | si->si_ofs.btn_keys_size = si->si_ofs.num_btns * | ||
| 519 | sizeof(struct cyttsp4_btn); | ||
| 520 | |||
| 521 | p = krealloc(si->btn, si->si_ofs.btn_keys_size, | ||
| 522 | GFP_KERNEL|__GFP_ZERO); | ||
| 523 | if (p == NULL) { | ||
| 524 | dev_err(cd->dev, "%s: %s\n", __func__, | ||
| 525 | "fail alloc btn_keys memory"); | ||
| 526 | return -ENOMEM; | ||
| 527 | } | ||
| 528 | si->btn = p; | ||
| 529 | |||
| 530 | if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS] == NULL) | ||
| 531 | num_defined_keys = 0; | ||
| 532 | else if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS]->data == NULL) | ||
| 533 | num_defined_keys = 0; | ||
| 534 | else | ||
| 535 | num_defined_keys = cd->cpdata->sett | ||
| 536 | [CY_IC_GRPNUM_BTN_KEYS]->size; | ||
| 537 | |||
| 538 | for (btn = 0; btn < si->si_ofs.num_btns && | ||
| 539 | btn < num_defined_keys; btn++) { | ||
| 540 | key_table = (u16 *)cd->cpdata->sett | ||
| 541 | [CY_IC_GRPNUM_BTN_KEYS]->data; | ||
| 542 | si->btn[btn].key_code = key_table[btn]; | ||
| 543 | si->btn[btn].state = CY_BTN_RELEASED; | ||
| 544 | si->btn[btn].enabled = true; | ||
| 545 | } | ||
| 546 | for (; btn < si->si_ofs.num_btns; btn++) { | ||
| 547 | si->btn[btn].key_code = KEY_RESERVED; | ||
| 548 | si->btn[btn].state = CY_BTN_RELEASED; | ||
| 549 | si->btn[btn].enabled = true; | ||
| 550 | } | ||
| 551 | |||
| 552 | return rc; | ||
| 553 | } | ||
| 554 | |||
| 555 | si->si_ofs.btn_keys_size = 0; | ||
| 556 | kfree(si->btn); | ||
| 557 | si->btn = NULL; | ||
| 558 | return rc; | ||
| 559 | } | ||
| 560 | |||
| 561 | static int cyttsp4_si_get_op_data_ptrs(struct cyttsp4 *cd) | ||
| 562 | { | ||
| 563 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 564 | void *p; | ||
| 565 | |||
| 566 | p = krealloc(si->xy_mode, si->si_ofs.mode_size, GFP_KERNEL|__GFP_ZERO); | ||
| 567 | if (p == NULL) | ||
| 568 | return -ENOMEM; | ||
| 569 | si->xy_mode = p; | ||
| 570 | |||
| 571 | p = krealloc(si->xy_data, si->si_ofs.data_size, GFP_KERNEL|__GFP_ZERO); | ||
| 572 | if (p == NULL) | ||
| 573 | return -ENOMEM; | ||
| 574 | si->xy_data = p; | ||
| 575 | |||
| 576 | p = krealloc(si->btn_rec_data, | ||
| 577 | si->si_ofs.btn_rec_size * si->si_ofs.num_btns, | ||
| 578 | GFP_KERNEL|__GFP_ZERO); | ||
| 579 | if (p == NULL) | ||
| 580 | return -ENOMEM; | ||
| 581 | si->btn_rec_data = p; | ||
| 582 | |||
| 583 | return 0; | ||
| 584 | } | ||
| 585 | |||
| 586 | static void cyttsp4_si_put_log_data(struct cyttsp4 *cd) | ||
| 587 | { | ||
| 588 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 589 | dev_dbg(cd->dev, "%s: cydata_ofs =%4Zd siz=%4Zd\n", __func__, | ||
| 590 | si->si_ofs.cydata_ofs, si->si_ofs.cydata_size); | ||
| 591 | dev_dbg(cd->dev, "%s: test_ofs =%4Zd siz=%4Zd\n", __func__, | ||
| 592 | si->si_ofs.test_ofs, si->si_ofs.test_size); | ||
| 593 | dev_dbg(cd->dev, "%s: pcfg_ofs =%4Zd siz=%4Zd\n", __func__, | ||
| 594 | si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size); | ||
| 595 | dev_dbg(cd->dev, "%s: opcfg_ofs =%4Zd siz=%4Zd\n", __func__, | ||
| 596 | si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size); | ||
| 597 | dev_dbg(cd->dev, "%s: ddata_ofs =%4Zd siz=%4Zd\n", __func__, | ||
| 598 | si->si_ofs.ddata_ofs, si->si_ofs.ddata_size); | ||
| 599 | dev_dbg(cd->dev, "%s: mdata_ofs =%4Zd siz=%4Zd\n", __func__, | ||
| 600 | si->si_ofs.mdata_ofs, si->si_ofs.mdata_size); | ||
| 601 | |||
| 602 | dev_dbg(cd->dev, "%s: cmd_ofs =%4Zd\n", __func__, | ||
| 603 | si->si_ofs.cmd_ofs); | ||
| 604 | dev_dbg(cd->dev, "%s: rep_ofs =%4Zd\n", __func__, | ||
| 605 | si->si_ofs.rep_ofs); | ||
| 606 | dev_dbg(cd->dev, "%s: rep_sz =%4Zd\n", __func__, | ||
| 607 | si->si_ofs.rep_sz); | ||
| 608 | dev_dbg(cd->dev, "%s: num_btns =%4Zd\n", __func__, | ||
| 609 | si->si_ofs.num_btns); | ||
| 610 | dev_dbg(cd->dev, "%s: num_btn_regs =%4Zd\n", __func__, | ||
| 611 | si->si_ofs.num_btn_regs); | ||
| 612 | dev_dbg(cd->dev, "%s: tt_stat_ofs =%4Zd\n", __func__, | ||
| 613 | si->si_ofs.tt_stat_ofs); | ||
| 614 | dev_dbg(cd->dev, "%s: tch_rec_size =%4Zd\n", __func__, | ||
| 615 | si->si_ofs.tch_rec_size); | ||
| 616 | dev_dbg(cd->dev, "%s: max_tchs =%4Zd\n", __func__, | ||
| 617 | si->si_ofs.max_tchs); | ||
| 618 | dev_dbg(cd->dev, "%s: mode_size =%4Zd\n", __func__, | ||
| 619 | si->si_ofs.mode_size); | ||
| 620 | dev_dbg(cd->dev, "%s: data_size =%4Zd\n", __func__, | ||
| 621 | si->si_ofs.data_size); | ||
| 622 | dev_dbg(cd->dev, "%s: map_sz =%4Zd\n", __func__, | ||
| 623 | si->si_ofs.map_sz); | ||
| 624 | |||
| 625 | dev_dbg(cd->dev, "%s: btn_rec_size =%2Zd\n", __func__, | ||
| 626 | si->si_ofs.btn_rec_size); | ||
| 627 | dev_dbg(cd->dev, "%s: btn_diff_ofs =%2Zd\n", __func__, | ||
| 628 | si->si_ofs.btn_diff_ofs); | ||
| 629 | dev_dbg(cd->dev, "%s: btn_diff_size =%2Zd\n", __func__, | ||
| 630 | si->si_ofs.btn_diff_size); | ||
| 631 | |||
| 632 | dev_dbg(cd->dev, "%s: max_x = 0x%04ZX (%Zd)\n", __func__, | ||
| 633 | si->si_ofs.max_x, si->si_ofs.max_x); | ||
| 634 | dev_dbg(cd->dev, "%s: x_origin = %Zd (%s)\n", __func__, | ||
| 635 | si->si_ofs.x_origin, | ||
| 636 | si->si_ofs.x_origin == CY_NORMAL_ORIGIN ? | ||
| 637 | "left corner" : "right corner"); | ||
| 638 | dev_dbg(cd->dev, "%s: max_y = 0x%04ZX (%Zd)\n", __func__, | ||
| 639 | si->si_ofs.max_y, si->si_ofs.max_y); | ||
| 640 | dev_dbg(cd->dev, "%s: y_origin = %Zd (%s)\n", __func__, | ||
| 641 | si->si_ofs.y_origin, | ||
| 642 | si->si_ofs.y_origin == CY_NORMAL_ORIGIN ? | ||
| 643 | "upper corner" : "lower corner"); | ||
| 644 | dev_dbg(cd->dev, "%s: max_p = 0x%04ZX (%Zd)\n", __func__, | ||
| 645 | si->si_ofs.max_p, si->si_ofs.max_p); | ||
| 646 | |||
| 647 | dev_dbg(cd->dev, "%s: xy_mode=%p xy_data=%p\n", __func__, | ||
| 648 | si->xy_mode, si->xy_data); | ||
| 649 | } | ||
| 650 | |||
| 651 | static int cyttsp4_get_sysinfo_regs(struct cyttsp4 *cd) | ||
| 652 | { | ||
| 653 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 654 | int rc; | ||
| 655 | |||
| 656 | rc = cyttsp4_si_data_offsets(cd); | ||
| 657 | if (rc < 0) | ||
| 658 | return rc; | ||
| 659 | |||
| 660 | rc = cyttsp4_si_get_cydata(cd); | ||
| 661 | if (rc < 0) | ||
| 662 | return rc; | ||
| 663 | |||
| 664 | rc = cyttsp4_si_get_test_data(cd); | ||
| 665 | if (rc < 0) | ||
| 666 | return rc; | ||
| 667 | |||
| 668 | rc = cyttsp4_si_get_pcfg_data(cd); | ||
| 669 | if (rc < 0) | ||
| 670 | return rc; | ||
| 671 | |||
| 672 | rc = cyttsp4_si_get_opcfg_data(cd); | ||
| 673 | if (rc < 0) | ||
| 674 | return rc; | ||
| 675 | |||
| 676 | rc = cyttsp4_si_get_ddata(cd); | ||
| 677 | if (rc < 0) | ||
| 678 | return rc; | ||
| 679 | |||
| 680 | rc = cyttsp4_si_get_mdata(cd); | ||
| 681 | if (rc < 0) | ||
| 682 | return rc; | ||
| 683 | |||
| 684 | rc = cyttsp4_si_get_btn_data(cd); | ||
| 685 | if (rc < 0) | ||
| 686 | return rc; | ||
| 687 | |||
| 688 | rc = cyttsp4_si_get_op_data_ptrs(cd); | ||
| 689 | if (rc < 0) { | ||
| 690 | dev_err(cd->dev, "%s: failed to get_op_data\n", | ||
| 691 | __func__); | ||
| 692 | return rc; | ||
| 693 | } | ||
| 694 | |||
| 695 | cyttsp4_si_put_log_data(cd); | ||
| 696 | |||
| 697 | /* provide flow control handshake */ | ||
| 698 | rc = cyttsp4_handshake(cd, si->si_data.hst_mode); | ||
| 699 | if (rc < 0) | ||
| 700 | dev_err(cd->dev, "%s: handshake fail on sysinfo reg\n", | ||
| 701 | __func__); | ||
| 702 | |||
| 703 | si->ready = true; | ||
| 704 | return rc; | ||
| 705 | } | ||
| 706 | |||
| 707 | static void cyttsp4_queue_startup_(struct cyttsp4 *cd) | ||
| 708 | { | ||
| 709 | if (cd->startup_state == STARTUP_NONE) { | ||
| 710 | cd->startup_state = STARTUP_QUEUED; | ||
| 711 | schedule_work(&cd->startup_work); | ||
| 712 | dev_dbg(cd->dev, "%s: cyttsp4_startup queued\n", __func__); | ||
| 713 | } else { | ||
| 714 | dev_dbg(cd->dev, "%s: startup_state = %d\n", __func__, | ||
| 715 | cd->startup_state); | ||
| 716 | } | ||
| 717 | } | ||
| 718 | |||
| 719 | static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md, | ||
| 720 | int max_slots) | ||
| 721 | { | ||
| 722 | int t; | ||
| 723 | |||
| 724 | if (md->num_prv_tch == 0) | ||
| 725 | return; | ||
| 726 | |||
| 727 | for (t = 0; t < max_slots; t++) { | ||
| 728 | input_mt_slot(md->input, t); | ||
| 729 | input_mt_report_slot_state(md->input, | ||
| 730 | MT_TOOL_FINGER, false); | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| 734 | static void cyttsp4_lift_all(struct cyttsp4_mt_data *md) | ||
| 735 | { | ||
| 736 | if (!md->si) | ||
| 737 | return; | ||
| 738 | |||
| 739 | if (md->num_prv_tch != 0) { | ||
| 740 | cyttsp4_report_slot_liftoff(md, | ||
| 741 | md->si->si_ofs.tch_abs[CY_TCH_T].max); | ||
| 742 | input_sync(md->input); | ||
| 743 | md->num_prv_tch = 0; | ||
| 744 | } | ||
| 745 | } | ||
| 746 | |||
| 747 | static void cyttsp4_get_touch_axis(struct cyttsp4_mt_data *md, | ||
| 748 | int *axis, int size, int max, u8 *xy_data, int bofs) | ||
| 749 | { | ||
| 750 | int nbyte; | ||
| 751 | int next; | ||
| 752 | |||
| 753 | for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) { | ||
| 754 | dev_vdbg(&md->input->dev, | ||
| 755 | "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p" | ||
| 756 | " xy_data[%d]=%02X(%d) bofs=%d\n", | ||
| 757 | __func__, *axis, *axis, size, max, xy_data, next, | ||
| 758 | xy_data[next], xy_data[next], bofs); | ||
| 759 | *axis = (*axis * 256) + (xy_data[next] >> bofs); | ||
| 760 | next++; | ||
| 761 | } | ||
| 762 | |||
| 763 | *axis &= max - 1; | ||
| 764 | |||
| 765 | dev_vdbg(&md->input->dev, | ||
| 766 | "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p" | ||
| 767 | " xy_data[%d]=%02X(%d)\n", | ||
| 768 | __func__, *axis, *axis, size, max, xy_data, next, | ||
| 769 | xy_data[next], xy_data[next]); | ||
| 770 | } | ||
| 771 | |||
| 772 | static void cyttsp4_get_touch(struct cyttsp4_mt_data *md, | ||
| 773 | struct cyttsp4_touch *touch, u8 *xy_data) | ||
| 774 | { | ||
| 775 | struct device *dev = &md->input->dev; | ||
| 776 | struct cyttsp4_sysinfo *si = md->si; | ||
| 777 | enum cyttsp4_tch_abs abs; | ||
| 778 | int tmp; | ||
| 779 | bool flipped; | ||
| 780 | |||
| 781 | for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) { | ||
| 782 | cyttsp4_get_touch_axis(md, &touch->abs[abs], | ||
| 783 | si->si_ofs.tch_abs[abs].size, | ||
| 784 | si->si_ofs.tch_abs[abs].max, | ||
| 785 | xy_data + si->si_ofs.tch_abs[abs].ofs, | ||
| 786 | si->si_ofs.tch_abs[abs].bofs); | ||
| 787 | dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__, | ||
| 788 | cyttsp4_tch_abs_string[abs], | ||
| 789 | touch->abs[abs], touch->abs[abs]); | ||
| 790 | } | ||
| 791 | |||
| 792 | if (md->pdata->flags & CY_FLAG_FLIP) { | ||
| 793 | tmp = touch->abs[CY_TCH_X]; | ||
| 794 | touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y]; | ||
| 795 | touch->abs[CY_TCH_Y] = tmp; | ||
| 796 | flipped = true; | ||
| 797 | } else | ||
| 798 | flipped = false; | ||
| 799 | |||
| 800 | if (md->pdata->flags & CY_FLAG_INV_X) { | ||
| 801 | if (flipped) | ||
| 802 | touch->abs[CY_TCH_X] = md->si->si_ofs.max_y - | ||
| 803 | touch->abs[CY_TCH_X]; | ||
| 804 | else | ||
| 805 | touch->abs[CY_TCH_X] = md->si->si_ofs.max_x - | ||
| 806 | touch->abs[CY_TCH_X]; | ||
| 807 | } | ||
| 808 | if (md->pdata->flags & CY_FLAG_INV_Y) { | ||
| 809 | if (flipped) | ||
| 810 | touch->abs[CY_TCH_Y] = md->si->si_ofs.max_x - | ||
| 811 | touch->abs[CY_TCH_Y]; | ||
| 812 | else | ||
| 813 | touch->abs[CY_TCH_Y] = md->si->si_ofs.max_y - | ||
| 814 | touch->abs[CY_TCH_Y]; | ||
| 815 | } | ||
| 816 | |||
| 817 | dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n", | ||
| 818 | __func__, flipped ? "true" : "false", | ||
| 819 | md->pdata->flags & CY_FLAG_INV_X ? "true" : "false", | ||
| 820 | md->pdata->flags & CY_FLAG_INV_Y ? "true" : "false", | ||
| 821 | touch->abs[CY_TCH_X], touch->abs[CY_TCH_X], | ||
| 822 | touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]); | ||
| 823 | } | ||
| 824 | |||
| 825 | static void cyttsp4_final_sync(struct input_dev *input, int max_slots, int *ids) | ||
| 826 | { | ||
| 827 | int t; | ||
| 828 | |||
| 829 | for (t = 0; t < max_slots; t++) { | ||
| 830 | if (ids[t]) | ||
| 831 | continue; | ||
| 832 | input_mt_slot(input, t); | ||
| 833 | input_mt_report_slot_state(input, MT_TOOL_FINGER, false); | ||
| 834 | } | ||
| 835 | |||
| 836 | input_sync(input); | ||
| 837 | } | ||
| 838 | |||
| 839 | static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch) | ||
| 840 | { | ||
| 841 | struct device *dev = &md->input->dev; | ||
| 842 | struct cyttsp4_sysinfo *si = md->si; | ||
| 843 | struct cyttsp4_touch tch; | ||
| 844 | int sig; | ||
| 845 | int i, j, t = 0; | ||
| 846 | int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)]; | ||
| 847 | |||
| 848 | memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int)); | ||
| 849 | for (i = 0; i < num_cur_tch; i++) { | ||
| 850 | cyttsp4_get_touch(md, &tch, si->xy_data + | ||
| 851 | (i * si->si_ofs.tch_rec_size)); | ||
| 852 | if ((tch.abs[CY_TCH_T] < md->pdata->frmwrk->abs | ||
| 853 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]) || | ||
| 854 | (tch.abs[CY_TCH_T] > md->pdata->frmwrk->abs | ||
| 855 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MAX_OST])) { | ||
| 856 | dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n", | ||
| 857 | __func__, i, tch.abs[CY_TCH_T], | ||
| 858 | md->pdata->frmwrk->abs[(CY_ABS_ID_OST * | ||
| 859 | CY_NUM_ABS_SET) + CY_MAX_OST]); | ||
| 860 | continue; | ||
| 861 | } | ||
| 862 | |||
| 863 | /* use 0 based track id's */ | ||
| 864 | sig = md->pdata->frmwrk->abs | ||
| 865 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + 0]; | ||
| 866 | if (sig != CY_IGNORE_VALUE) { | ||
| 867 | t = tch.abs[CY_TCH_T] - md->pdata->frmwrk->abs | ||
| 868 | [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]; | ||
| 869 | if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF) { | ||
| 870 | dev_dbg(dev, "%s: t=%d e=%d lift-off\n", | ||
| 871 | __func__, t, tch.abs[CY_TCH_E]); | ||
| 872 | goto cyttsp4_get_mt_touches_pr_tch; | ||
| 873 | } | ||
| 874 | input_mt_slot(md->input, t); | ||
| 875 | input_mt_report_slot_state(md->input, MT_TOOL_FINGER, | ||
| 876 | true); | ||
| 877 | ids[t] = true; | ||
| 878 | } | ||
| 879 | |||
| 880 | /* all devices: position and pressure fields */ | ||
| 881 | for (j = 0; j <= CY_ABS_W_OST; j++) { | ||
| 882 | sig = md->pdata->frmwrk->abs[((CY_ABS_X_OST + j) * | ||
| 883 | CY_NUM_ABS_SET) + 0]; | ||
| 884 | if (sig != CY_IGNORE_VALUE) | ||
| 885 | input_report_abs(md->input, sig, | ||
| 886 | tch.abs[CY_TCH_X + j]); | ||
| 887 | } | ||
| 888 | if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) { | ||
| 889 | /* | ||
| 890 | * TMA400 size and orientation fields: | ||
| 891 | * if pressure is non-zero and major touch | ||
| 892 | * signal is zero, then set major and minor touch | ||
| 893 | * signals to minimum non-zero value | ||
| 894 | */ | ||
| 895 | if (tch.abs[CY_TCH_P] > 0 && tch.abs[CY_TCH_MAJ] == 0) | ||
| 896 | tch.abs[CY_TCH_MAJ] = tch.abs[CY_TCH_MIN] = 1; | ||
| 897 | |||
| 898 | /* Get the extended touch fields */ | ||
| 899 | for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) { | ||
| 900 | sig = md->pdata->frmwrk->abs | ||
| 901 | [((CY_ABS_MAJ_OST + j) * | ||
| 902 | CY_NUM_ABS_SET) + 0]; | ||
| 903 | if (sig != CY_IGNORE_VALUE) | ||
| 904 | input_report_abs(md->input, sig, | ||
| 905 | tch.abs[CY_TCH_MAJ + j]); | ||
| 906 | } | ||
| 907 | } | ||
| 908 | |||
| 909 | cyttsp4_get_mt_touches_pr_tch: | ||
| 910 | if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) | ||
| 911 | dev_dbg(dev, | ||
| 912 | "%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d\n", | ||
| 913 | __func__, t, | ||
| 914 | tch.abs[CY_TCH_X], | ||
| 915 | tch.abs[CY_TCH_Y], | ||
| 916 | tch.abs[CY_TCH_P], | ||
| 917 | tch.abs[CY_TCH_MAJ], | ||
| 918 | tch.abs[CY_TCH_MIN], | ||
| 919 | tch.abs[CY_TCH_OR], | ||
| 920 | tch.abs[CY_TCH_E]); | ||
| 921 | else | ||
| 922 | dev_dbg(dev, | ||
| 923 | "%s: t=%d x=%d y=%d z=%d e=%d\n", __func__, | ||
| 924 | t, | ||
| 925 | tch.abs[CY_TCH_X], | ||
| 926 | tch.abs[CY_TCH_Y], | ||
| 927 | tch.abs[CY_TCH_P], | ||
| 928 | tch.abs[CY_TCH_E]); | ||
| 929 | } | ||
| 930 | |||
| 931 | cyttsp4_final_sync(md->input, si->si_ofs.tch_abs[CY_TCH_T].max, ids); | ||
| 932 | |||
| 933 | md->num_prv_tch = num_cur_tch; | ||
| 934 | |||
| 935 | return; | ||
| 936 | } | ||
| 937 | |||
| 938 | /* read xy_data for all current touches */ | ||
| 939 | static int cyttsp4_xy_worker(struct cyttsp4 *cd) | ||
| 940 | { | ||
| 941 | struct cyttsp4_mt_data *md = &cd->md; | ||
| 942 | struct device *dev = &md->input->dev; | ||
| 943 | struct cyttsp4_sysinfo *si = md->si; | ||
| 944 | u8 num_cur_tch; | ||
| 945 | u8 hst_mode; | ||
| 946 | u8 rep_len; | ||
| 947 | u8 rep_stat; | ||
| 948 | u8 tt_stat; | ||
| 949 | int rc = 0; | ||
| 950 | |||
| 951 | /* | ||
| 952 | * Get event data from cyttsp4 device. | ||
| 953 | * The event data includes all data | ||
| 954 | * for all active touches. | ||
| 955 | * Event data also includes button data | ||
| 956 | */ | ||
| 957 | /* | ||
| 958 | * Use 2 reads: | ||
| 959 | * 1st read to get mode + button bytes + touch count (core) | ||
| 960 | * 2nd read (optional) to get touch 1 - touch n data | ||
| 961 | */ | ||
| 962 | hst_mode = si->xy_mode[CY_REG_BASE]; | ||
| 963 | rep_len = si->xy_mode[si->si_ofs.rep_ofs]; | ||
| 964 | rep_stat = si->xy_mode[si->si_ofs.rep_ofs + 1]; | ||
| 965 | tt_stat = si->xy_mode[si->si_ofs.tt_stat_ofs]; | ||
| 966 | dev_vdbg(dev, "%s: %s%02X %s%d %s%02X %s%02X\n", __func__, | ||
| 967 | "hst_mode=", hst_mode, "rep_len=", rep_len, | ||
| 968 | "rep_stat=", rep_stat, "tt_stat=", tt_stat); | ||
| 969 | |||
| 970 | num_cur_tch = GET_NUM_TOUCHES(tt_stat); | ||
| 971 | dev_vdbg(dev, "%s: num_cur_tch=%d\n", __func__, num_cur_tch); | ||
| 972 | |||
| 973 | if (rep_len == 0 && num_cur_tch > 0) { | ||
| 974 | dev_err(dev, "%s: report length error rep_len=%d num_tch=%d\n", | ||
| 975 | __func__, rep_len, num_cur_tch); | ||
| 976 | goto cyttsp4_xy_worker_exit; | ||
| 977 | } | ||
| 978 | |||
| 979 | /* read touches */ | ||
| 980 | if (num_cur_tch > 0) { | ||
| 981 | rc = cyttsp4_adap_read(cd, si->si_ofs.tt_stat_ofs + 1, | ||
| 982 | num_cur_tch * si->si_ofs.tch_rec_size, | ||
| 983 | si->xy_data); | ||
| 984 | if (rc < 0) { | ||
| 985 | dev_err(dev, "%s: read fail on touch regs r=%d\n", | ||
| 986 | __func__, rc); | ||
| 987 | goto cyttsp4_xy_worker_exit; | ||
| 988 | } | ||
| 989 | } | ||
| 990 | |||
| 991 | /* print xy data */ | ||
| 992 | cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_data, num_cur_tch * | ||
| 993 | si->si_ofs.tch_rec_size, "xy_data"); | ||
| 994 | |||
| 995 | /* check any error conditions */ | ||
| 996 | if (IS_BAD_PKT(rep_stat)) { | ||
| 997 | dev_dbg(dev, "%s: Invalid buffer detected\n", __func__); | ||
| 998 | rc = 0; | ||
| 999 | goto cyttsp4_xy_worker_exit; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | if (IS_LARGE_AREA(tt_stat)) | ||
| 1003 | dev_dbg(dev, "%s: Large area detected\n", __func__); | ||
| 1004 | |||
| 1005 | if (num_cur_tch > si->si_ofs.max_tchs) { | ||
| 1006 | dev_err(dev, "%s: too many tch; set to max tch (n=%d c=%Zd)\n", | ||
| 1007 | __func__, num_cur_tch, si->si_ofs.max_tchs); | ||
| 1008 | num_cur_tch = si->si_ofs.max_tchs; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | /* extract xy_data for all currently reported touches */ | ||
| 1012 | dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__, | ||
| 1013 | num_cur_tch); | ||
| 1014 | if (num_cur_tch) | ||
| 1015 | cyttsp4_get_mt_touches(md, num_cur_tch); | ||
| 1016 | else | ||
| 1017 | cyttsp4_lift_all(md); | ||
| 1018 | |||
| 1019 | rc = 0; | ||
| 1020 | |||
| 1021 | cyttsp4_xy_worker_exit: | ||
| 1022 | return rc; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static int cyttsp4_mt_attention(struct cyttsp4 *cd) | ||
| 1026 | { | ||
| 1027 | struct device *dev = cd->dev; | ||
| 1028 | struct cyttsp4_mt_data *md = &cd->md; | ||
| 1029 | int rc = 0; | ||
| 1030 | |||
| 1031 | if (!md->si) | ||
| 1032 | return 0; | ||
| 1033 | |||
| 1034 | mutex_lock(&md->report_lock); | ||
| 1035 | if (!md->is_suspended) { | ||
| 1036 | /* core handles handshake */ | ||
| 1037 | rc = cyttsp4_xy_worker(cd); | ||
| 1038 | } else { | ||
| 1039 | dev_vdbg(dev, "%s: Ignoring report while suspended\n", | ||
| 1040 | __func__); | ||
| 1041 | } | ||
| 1042 | mutex_unlock(&md->report_lock); | ||
| 1043 | if (rc < 0) | ||
| 1044 | dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc); | ||
| 1045 | |||
| 1046 | return rc; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | static irqreturn_t cyttsp4_irq(int irq, void *handle) | ||
| 1050 | { | ||
| 1051 | struct cyttsp4 *cd = handle; | ||
| 1052 | struct device *dev = cd->dev; | ||
| 1053 | enum cyttsp4_mode cur_mode; | ||
| 1054 | u8 cmd_ofs = cd->sysinfo.si_ofs.cmd_ofs; | ||
| 1055 | u8 mode[3]; | ||
| 1056 | int rc; | ||
| 1057 | |||
| 1058 | /* | ||
| 1059 | * Check whether this IRQ should be ignored (external) | ||
| 1060 | * This should be the very first thing to check since | ||
| 1061 | * ignore_irq may be set for a very short period of time | ||
| 1062 | */ | ||
| 1063 | if (atomic_read(&cd->ignore_irq)) { | ||
| 1064 | dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__); | ||
| 1065 | return IRQ_HANDLED; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | dev_dbg(dev, "%s int:0x%x\n", __func__, cd->int_status); | ||
| 1069 | |||
| 1070 | mutex_lock(&cd->system_lock); | ||
| 1071 | |||
| 1072 | /* Just to debug */ | ||
| 1073 | if (cd->sleep_state == SS_SLEEP_ON || cd->sleep_state == SS_SLEEPING) | ||
| 1074 | dev_vdbg(dev, "%s: Received IRQ while in sleep\n", __func__); | ||
| 1075 | |||
| 1076 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), mode); | ||
| 1077 | if (rc) { | ||
| 1078 | dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc); | ||
| 1079 | goto cyttsp4_irq_exit; | ||
| 1080 | } | ||
| 1081 | dev_vdbg(dev, "%s mode[0-2]:0x%X 0x%X 0x%X\n", __func__, | ||
| 1082 | mode[0], mode[1], mode[2]); | ||
| 1083 | |||
| 1084 | if (IS_BOOTLOADER(mode[0], mode[1])) { | ||
| 1085 | cur_mode = CY_MODE_BOOTLOADER; | ||
| 1086 | dev_vdbg(dev, "%s: bl running\n", __func__); | ||
| 1087 | if (cd->mode == CY_MODE_BOOTLOADER) { | ||
| 1088 | /* Signal bootloader heartbeat heard */ | ||
| 1089 | wake_up(&cd->wait_q); | ||
| 1090 | goto cyttsp4_irq_exit; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* switch to bootloader */ | ||
| 1094 | dev_dbg(dev, "%s: restart switch to bl m=%d -> m=%d\n", | ||
| 1095 | __func__, cd->mode, cur_mode); | ||
| 1096 | |||
| 1097 | /* catch operation->bl glitch */ | ||
| 1098 | if (cd->mode != CY_MODE_UNKNOWN) { | ||
| 1099 | /* Incase startup_state do not let startup_() */ | ||
| 1100 | cd->mode = CY_MODE_UNKNOWN; | ||
| 1101 | cyttsp4_queue_startup_(cd); | ||
| 1102 | goto cyttsp4_irq_exit; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | /* | ||
| 1106 | * do not wake thread on this switch since | ||
| 1107 | * it is possible to get an early heartbeat | ||
| 1108 | * prior to performing the reset | ||
| 1109 | */ | ||
| 1110 | cd->mode = cur_mode; | ||
| 1111 | |||
| 1112 | goto cyttsp4_irq_exit; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | switch (mode[0] & CY_HST_MODE) { | ||
| 1116 | case CY_HST_OPERATE: | ||
| 1117 | cur_mode = CY_MODE_OPERATIONAL; | ||
| 1118 | dev_vdbg(dev, "%s: operational\n", __func__); | ||
| 1119 | break; | ||
| 1120 | case CY_HST_CAT: | ||
| 1121 | cur_mode = CY_MODE_CAT; | ||
| 1122 | dev_vdbg(dev, "%s: CaT\n", __func__); | ||
| 1123 | break; | ||
| 1124 | case CY_HST_SYSINFO: | ||
| 1125 | cur_mode = CY_MODE_SYSINFO; | ||
| 1126 | dev_vdbg(dev, "%s: sysinfo\n", __func__); | ||
| 1127 | break; | ||
| 1128 | default: | ||
| 1129 | cur_mode = CY_MODE_UNKNOWN; | ||
| 1130 | dev_err(dev, "%s: unknown HST mode 0x%02X\n", __func__, | ||
| 1131 | mode[0]); | ||
| 1132 | break; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | /* Check whether this IRQ should be ignored (internal) */ | ||
| 1136 | if (cd->int_status & CY_INT_IGNORE) { | ||
| 1137 | dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__); | ||
| 1138 | goto cyttsp4_irq_exit; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | /* Check for wake up interrupt */ | ||
| 1142 | if (cd->int_status & CY_INT_AWAKE) { | ||
| 1143 | cd->int_status &= ~CY_INT_AWAKE; | ||
| 1144 | wake_up(&cd->wait_q); | ||
| 1145 | dev_vdbg(dev, "%s: Received wake up interrupt\n", __func__); | ||
| 1146 | goto cyttsp4_irq_handshake; | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | /* Expecting mode change interrupt */ | ||
| 1150 | if ((cd->int_status & CY_INT_MODE_CHANGE) | ||
| 1151 | && (mode[0] & CY_HST_MODE_CHANGE) == 0) { | ||
| 1152 | cd->int_status &= ~CY_INT_MODE_CHANGE; | ||
| 1153 | dev_dbg(dev, "%s: finish mode switch m=%d -> m=%d\n", | ||
| 1154 | __func__, cd->mode, cur_mode); | ||
| 1155 | cd->mode = cur_mode; | ||
| 1156 | wake_up(&cd->wait_q); | ||
| 1157 | goto cyttsp4_irq_handshake; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | /* compare current core mode to current device mode */ | ||
| 1161 | dev_vdbg(dev, "%s: cd->mode=%d cur_mode=%d\n", | ||
| 1162 | __func__, cd->mode, cur_mode); | ||
| 1163 | if ((mode[0] & CY_HST_MODE_CHANGE) == 0 && cd->mode != cur_mode) { | ||
| 1164 | /* Unexpected mode change occurred */ | ||
| 1165 | dev_err(dev, "%s %d->%d 0x%x\n", __func__, cd->mode, | ||
| 1166 | cur_mode, cd->int_status); | ||
| 1167 | dev_dbg(dev, "%s: Unexpected mode change, startup\n", | ||
| 1168 | __func__); | ||
| 1169 | cyttsp4_queue_startup_(cd); | ||
| 1170 | goto cyttsp4_irq_exit; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | /* Expecting command complete interrupt */ | ||
| 1174 | dev_vdbg(dev, "%s: command byte:0x%x\n", __func__, mode[cmd_ofs]); | ||
| 1175 | if ((cd->int_status & CY_INT_EXEC_CMD) | ||
| 1176 | && mode[cmd_ofs] & CY_CMD_COMPLETE) { | ||
| 1177 | cd->int_status &= ~CY_INT_EXEC_CMD; | ||
| 1178 | dev_vdbg(dev, "%s: Received command complete interrupt\n", | ||
| 1179 | __func__); | ||
| 1180 | wake_up(&cd->wait_q); | ||
| 1181 | /* | ||
| 1182 | * It is possible to receive a single interrupt for | ||
| 1183 | * command complete and touch/button status report. | ||
| 1184 | * Continue processing for a possible status report. | ||
| 1185 | */ | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | /* This should be status report, read status regs */ | ||
| 1189 | if (cd->mode == CY_MODE_OPERATIONAL) { | ||
| 1190 | dev_vdbg(dev, "%s: Read status registers\n", __func__); | ||
| 1191 | rc = cyttsp4_load_status_regs(cd); | ||
| 1192 | if (rc < 0) | ||
| 1193 | dev_err(dev, "%s: fail read mode regs r=%d\n", | ||
| 1194 | __func__, rc); | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | cyttsp4_mt_attention(cd); | ||
| 1198 | |||
| 1199 | cyttsp4_irq_handshake: | ||
| 1200 | /* handshake the event */ | ||
| 1201 | dev_vdbg(dev, "%s: Handshake mode=0x%02X r=%d\n", | ||
| 1202 | __func__, mode[0], rc); | ||
| 1203 | rc = cyttsp4_handshake(cd, mode[0]); | ||
| 1204 | if (rc < 0) | ||
| 1205 | dev_err(dev, "%s: Fail handshake mode=0x%02X r=%d\n", | ||
| 1206 | __func__, mode[0], rc); | ||
| 1207 | |||
| 1208 | /* | ||
| 1209 | * a non-zero udelay period is required for using | ||
| 1210 | * IRQF_TRIGGER_LOW in order to delay until the | ||
| 1211 | * device completes isr deassert | ||
| 1212 | */ | ||
| 1213 | udelay(cd->cpdata->level_irq_udelay); | ||
| 1214 | |||
| 1215 | cyttsp4_irq_exit: | ||
| 1216 | mutex_unlock(&cd->system_lock); | ||
| 1217 | return IRQ_HANDLED; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | static void cyttsp4_start_wd_timer(struct cyttsp4 *cd) | ||
| 1221 | { | ||
| 1222 | if (!CY_WATCHDOG_TIMEOUT) | ||
| 1223 | return; | ||
| 1224 | |||
| 1225 | mod_timer(&cd->watchdog_timer, jiffies + | ||
| 1226 | msecs_to_jiffies(CY_WATCHDOG_TIMEOUT)); | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd) | ||
| 1230 | { | ||
| 1231 | if (!CY_WATCHDOG_TIMEOUT) | ||
| 1232 | return; | ||
| 1233 | |||
| 1234 | /* | ||
| 1235 | * Ensure we wait until the watchdog timer | ||
| 1236 | * running on a different CPU finishes | ||
| 1237 | */ | ||
| 1238 | del_timer_sync(&cd->watchdog_timer); | ||
| 1239 | cancel_work_sync(&cd->watchdog_work); | ||
| 1240 | del_timer_sync(&cd->watchdog_timer); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | static void cyttsp4_watchdog_timer(unsigned long handle) | ||
| 1244 | { | ||
| 1245 | struct cyttsp4 *cd = (struct cyttsp4 *)handle; | ||
| 1246 | |||
| 1247 | dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__); | ||
| 1248 | |||
| 1249 | if (!cd) | ||
| 1250 | return; | ||
| 1251 | |||
| 1252 | if (!work_pending(&cd->watchdog_work)) | ||
| 1253 | schedule_work(&cd->watchdog_work); | ||
| 1254 | |||
| 1255 | return; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | static int cyttsp4_request_exclusive(struct cyttsp4 *cd, void *ownptr, | ||
| 1259 | int timeout_ms) | ||
| 1260 | { | ||
| 1261 | int t = msecs_to_jiffies(timeout_ms); | ||
| 1262 | bool with_timeout = (timeout_ms != 0); | ||
| 1263 | |||
| 1264 | mutex_lock(&cd->system_lock); | ||
| 1265 | if (!cd->exclusive_dev && cd->exclusive_waits == 0) { | ||
| 1266 | cd->exclusive_dev = ownptr; | ||
| 1267 | goto exit; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | cd->exclusive_waits++; | ||
| 1271 | wait: | ||
| 1272 | mutex_unlock(&cd->system_lock); | ||
| 1273 | if (with_timeout) { | ||
| 1274 | t = wait_event_timeout(cd->wait_q, !cd->exclusive_dev, t); | ||
| 1275 | if (IS_TMO(t)) { | ||
| 1276 | dev_err(cd->dev, "%s: tmo waiting exclusive access\n", | ||
| 1277 | __func__); | ||
| 1278 | mutex_lock(&cd->system_lock); | ||
| 1279 | cd->exclusive_waits--; | ||
| 1280 | mutex_unlock(&cd->system_lock); | ||
| 1281 | return -ETIME; | ||
| 1282 | } | ||
| 1283 | } else { | ||
| 1284 | wait_event(cd->wait_q, !cd->exclusive_dev); | ||
| 1285 | } | ||
| 1286 | mutex_lock(&cd->system_lock); | ||
| 1287 | if (cd->exclusive_dev) | ||
| 1288 | goto wait; | ||
| 1289 | cd->exclusive_dev = ownptr; | ||
| 1290 | cd->exclusive_waits--; | ||
| 1291 | exit: | ||
| 1292 | mutex_unlock(&cd->system_lock); | ||
| 1293 | |||
| 1294 | return 0; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | /* | ||
| 1298 | * returns error if was not owned | ||
| 1299 | */ | ||
| 1300 | static int cyttsp4_release_exclusive(struct cyttsp4 *cd, void *ownptr) | ||
| 1301 | { | ||
| 1302 | mutex_lock(&cd->system_lock); | ||
| 1303 | if (cd->exclusive_dev != ownptr) { | ||
| 1304 | mutex_unlock(&cd->system_lock); | ||
| 1305 | return -EINVAL; | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | dev_vdbg(cd->dev, "%s: exclusive_dev %p freed\n", | ||
| 1309 | __func__, cd->exclusive_dev); | ||
| 1310 | cd->exclusive_dev = NULL; | ||
| 1311 | wake_up(&cd->wait_q); | ||
| 1312 | mutex_unlock(&cd->system_lock); | ||
| 1313 | return 0; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | static int cyttsp4_wait_bl_heartbeat(struct cyttsp4 *cd) | ||
| 1317 | { | ||
| 1318 | long t; | ||
| 1319 | int rc = 0; | ||
| 1320 | |||
| 1321 | /* wait heartbeat */ | ||
| 1322 | dev_vdbg(cd->dev, "%s: wait heartbeat...\n", __func__); | ||
| 1323 | t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_BOOTLOADER, | ||
| 1324 | msecs_to_jiffies(CY_CORE_RESET_AND_WAIT_TIMEOUT)); | ||
| 1325 | if (IS_TMO(t)) { | ||
| 1326 | dev_err(cd->dev, "%s: tmo waiting bl heartbeat cd->mode=%d\n", | ||
| 1327 | __func__, cd->mode); | ||
| 1328 | rc = -ETIME; | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | return rc; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | static int cyttsp4_wait_sysinfo_mode(struct cyttsp4 *cd) | ||
| 1335 | { | ||
| 1336 | long t; | ||
| 1337 | |||
| 1338 | dev_vdbg(cd->dev, "%s: wait sysinfo...\n", __func__); | ||
| 1339 | |||
| 1340 | t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_SYSINFO, | ||
| 1341 | msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT)); | ||
| 1342 | if (IS_TMO(t)) { | ||
| 1343 | dev_err(cd->dev, "%s: tmo waiting exit bl cd->mode=%d\n", | ||
| 1344 | __func__, cd->mode); | ||
| 1345 | mutex_lock(&cd->system_lock); | ||
| 1346 | cd->int_status &= ~CY_INT_MODE_CHANGE; | ||
| 1347 | mutex_unlock(&cd->system_lock); | ||
| 1348 | return -ETIME; | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | return 0; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | static int cyttsp4_reset_and_wait(struct cyttsp4 *cd) | ||
| 1355 | { | ||
| 1356 | int rc; | ||
| 1357 | |||
| 1358 | /* reset hardware */ | ||
| 1359 | mutex_lock(&cd->system_lock); | ||
| 1360 | dev_dbg(cd->dev, "%s: reset hw...\n", __func__); | ||
| 1361 | rc = cyttsp4_hw_reset(cd); | ||
| 1362 | cd->mode = CY_MODE_UNKNOWN; | ||
| 1363 | mutex_unlock(&cd->system_lock); | ||
| 1364 | if (rc < 0) { | ||
| 1365 | dev_err(cd->dev, "%s:Fail hw reset r=%d\n", __func__, rc); | ||
| 1366 | return rc; | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | return cyttsp4_wait_bl_heartbeat(cd); | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | /* | ||
| 1373 | * returns err if refused or timeout; block until mode change complete | ||
| 1374 | * bit is set (mode change interrupt) | ||
| 1375 | */ | ||
| 1376 | static int cyttsp4_set_mode(struct cyttsp4 *cd, int new_mode) | ||
| 1377 | { | ||
| 1378 | u8 new_dev_mode; | ||
| 1379 | u8 mode; | ||
| 1380 | long t; | ||
| 1381 | int rc; | ||
| 1382 | |||
| 1383 | switch (new_mode) { | ||
| 1384 | case CY_MODE_OPERATIONAL: | ||
| 1385 | new_dev_mode = CY_HST_OPERATE; | ||
| 1386 | break; | ||
| 1387 | case CY_MODE_SYSINFO: | ||
| 1388 | new_dev_mode = CY_HST_SYSINFO; | ||
| 1389 | break; | ||
| 1390 | case CY_MODE_CAT: | ||
| 1391 | new_dev_mode = CY_HST_CAT; | ||
| 1392 | break; | ||
| 1393 | default: | ||
| 1394 | dev_err(cd->dev, "%s: invalid mode: %02X(%d)\n", | ||
| 1395 | __func__, new_mode, new_mode); | ||
| 1396 | return -EINVAL; | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | /* change mode */ | ||
| 1400 | dev_dbg(cd->dev, "%s: %s=%p new_dev_mode=%02X new_mode=%d\n", | ||
| 1401 | __func__, "have exclusive", cd->exclusive_dev, | ||
| 1402 | new_dev_mode, new_mode); | ||
| 1403 | |||
| 1404 | mutex_lock(&cd->system_lock); | ||
| 1405 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
| 1406 | if (rc < 0) { | ||
| 1407 | mutex_unlock(&cd->system_lock); | ||
| 1408 | dev_err(cd->dev, "%s: Fail read mode r=%d\n", | ||
| 1409 | __func__, rc); | ||
| 1410 | goto exit; | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | /* Clear device mode bits and set to new mode */ | ||
| 1414 | mode &= ~CY_HST_MODE; | ||
| 1415 | mode |= new_dev_mode | CY_HST_MODE_CHANGE; | ||
| 1416 | |||
| 1417 | cd->int_status |= CY_INT_MODE_CHANGE; | ||
| 1418 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
| 1419 | mutex_unlock(&cd->system_lock); | ||
| 1420 | if (rc < 0) { | ||
| 1421 | dev_err(cd->dev, "%s: Fail write mode change r=%d\n", | ||
| 1422 | __func__, rc); | ||
| 1423 | goto exit; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | /* wait for mode change done interrupt */ | ||
| 1427 | t = wait_event_timeout(cd->wait_q, | ||
| 1428 | (cd->int_status & CY_INT_MODE_CHANGE) == 0, | ||
| 1429 | msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT)); | ||
| 1430 | dev_dbg(cd->dev, "%s: back from wait t=%ld cd->mode=%d\n", | ||
| 1431 | __func__, t, cd->mode); | ||
| 1432 | |||
| 1433 | if (IS_TMO(t)) { | ||
| 1434 | dev_err(cd->dev, "%s: %s\n", __func__, | ||
| 1435 | "tmo waiting mode change"); | ||
| 1436 | mutex_lock(&cd->system_lock); | ||
| 1437 | cd->int_status &= ~CY_INT_MODE_CHANGE; | ||
| 1438 | mutex_unlock(&cd->system_lock); | ||
| 1439 | rc = -EINVAL; | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | exit: | ||
| 1443 | return rc; | ||
| 1444 | } | ||
| 1445 | |||
| 1446 | static void cyttsp4_watchdog_work(struct work_struct *work) | ||
| 1447 | { | ||
| 1448 | struct cyttsp4 *cd = | ||
| 1449 | container_of(work, struct cyttsp4, watchdog_work); | ||
| 1450 | u8 *mode; | ||
| 1451 | int retval; | ||
| 1452 | |||
| 1453 | if (cd == NULL) { | ||
| 1454 | dev_err(cd->dev, "%s: NULL context pointer\n", __func__); | ||
| 1455 | return; | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | mutex_lock(&cd->system_lock); | ||
| 1459 | retval = cyttsp4_load_status_regs(cd); | ||
| 1460 | if (retval < 0) { | ||
| 1461 | dev_err(cd->dev, | ||
| 1462 | "%s: failed to access device in watchdog timer r=%d\n", | ||
| 1463 | __func__, retval); | ||
| 1464 | cyttsp4_queue_startup_(cd); | ||
| 1465 | goto cyttsp4_timer_watchdog_exit_error; | ||
| 1466 | } | ||
| 1467 | mode = &cd->sysinfo.xy_mode[CY_REG_BASE]; | ||
| 1468 | if (IS_BOOTLOADER(mode[0], mode[1])) { | ||
| 1469 | dev_err(cd->dev, | ||
| 1470 | "%s: device found in bootloader mode when operational mode\n", | ||
| 1471 | __func__); | ||
| 1472 | cyttsp4_queue_startup_(cd); | ||
| 1473 | goto cyttsp4_timer_watchdog_exit_error; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | cyttsp4_start_wd_timer(cd); | ||
| 1477 | cyttsp4_timer_watchdog_exit_error: | ||
| 1478 | mutex_unlock(&cd->system_lock); | ||
| 1479 | return; | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | static int cyttsp4_core_sleep_(struct cyttsp4 *cd) | ||
| 1483 | { | ||
| 1484 | enum cyttsp4_sleep_state ss = SS_SLEEP_ON; | ||
| 1485 | enum cyttsp4_int_state int_status = CY_INT_IGNORE; | ||
| 1486 | int rc = 0; | ||
| 1487 | u8 mode[2]; | ||
| 1488 | |||
| 1489 | /* Already in sleep mode? */ | ||
| 1490 | mutex_lock(&cd->system_lock); | ||
| 1491 | if (cd->sleep_state == SS_SLEEP_ON) { | ||
| 1492 | mutex_unlock(&cd->system_lock); | ||
| 1493 | return 0; | ||
| 1494 | } | ||
| 1495 | cd->sleep_state = SS_SLEEPING; | ||
| 1496 | mutex_unlock(&cd->system_lock); | ||
| 1497 | |||
| 1498 | cyttsp4_stop_wd_timer(cd); | ||
| 1499 | |||
| 1500 | /* Wait until currently running IRQ handler exits and disable IRQ */ | ||
| 1501 | disable_irq(cd->irq); | ||
| 1502 | |||
| 1503 | dev_vdbg(cd->dev, "%s: write DEEP SLEEP...\n", __func__); | ||
| 1504 | mutex_lock(&cd->system_lock); | ||
| 1505 | rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
| 1506 | if (rc) { | ||
| 1507 | mutex_unlock(&cd->system_lock); | ||
| 1508 | dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc); | ||
| 1509 | goto error; | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | if (IS_BOOTLOADER(mode[0], mode[1])) { | ||
| 1513 | mutex_unlock(&cd->system_lock); | ||
| 1514 | dev_err(cd->dev, "%s: Device in BOOTLADER mode.\n", __func__); | ||
| 1515 | rc = -EINVAL; | ||
| 1516 | goto error; | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | mode[0] |= CY_HST_SLEEP; | ||
| 1520 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode[0]), &mode[0]); | ||
| 1521 | mutex_unlock(&cd->system_lock); | ||
| 1522 | if (rc) { | ||
| 1523 | dev_err(cd->dev, "%s: Fail write adapter r=%d\n", __func__, rc); | ||
| 1524 | goto error; | ||
| 1525 | } | ||
| 1526 | dev_vdbg(cd->dev, "%s: write DEEP SLEEP succeeded\n", __func__); | ||
| 1527 | |||
| 1528 | if (cd->cpdata->power) { | ||
| 1529 | dev_dbg(cd->dev, "%s: Power down HW\n", __func__); | ||
| 1530 | rc = cd->cpdata->power(cd->cpdata, 0, cd->dev, &cd->ignore_irq); | ||
| 1531 | } else { | ||
| 1532 | dev_dbg(cd->dev, "%s: No power function\n", __func__); | ||
| 1533 | rc = 0; | ||
| 1534 | } | ||
| 1535 | if (rc < 0) { | ||
| 1536 | dev_err(cd->dev, "%s: HW Power down fails r=%d\n", | ||
| 1537 | __func__, rc); | ||
| 1538 | goto error; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | /* Give time to FW to sleep */ | ||
| 1542 | msleep(50); | ||
| 1543 | |||
| 1544 | goto exit; | ||
| 1545 | |||
| 1546 | error: | ||
| 1547 | ss = SS_SLEEP_OFF; | ||
| 1548 | int_status = CY_INT_NONE; | ||
| 1549 | cyttsp4_start_wd_timer(cd); | ||
| 1550 | |||
| 1551 | exit: | ||
| 1552 | mutex_lock(&cd->system_lock); | ||
| 1553 | cd->sleep_state = ss; | ||
| 1554 | cd->int_status |= int_status; | ||
| 1555 | mutex_unlock(&cd->system_lock); | ||
| 1556 | enable_irq(cd->irq); | ||
| 1557 | return rc; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | static int cyttsp4_core_sleep(struct cyttsp4 *cd) | ||
| 1561 | { | ||
| 1562 | int rc; | ||
| 1563 | |||
| 1564 | rc = cyttsp4_request_exclusive(cd, cd->dev, | ||
| 1565 | CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT); | ||
| 1566 | if (rc < 0) { | ||
| 1567 | dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n", | ||
| 1568 | __func__, cd->exclusive_dev, cd->dev); | ||
| 1569 | return 0; | ||
| 1570 | } | ||
| 1571 | |||
| 1572 | rc = cyttsp4_core_sleep_(cd); | ||
| 1573 | |||
| 1574 | if (cyttsp4_release_exclusive(cd, cd->dev) < 0) | ||
| 1575 | dev_err(cd->dev, "%s: fail to release exclusive\n", __func__); | ||
| 1576 | else | ||
| 1577 | dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__); | ||
| 1578 | |||
| 1579 | return rc; | ||
| 1580 | } | ||
| 1581 | |||
| 1582 | static int cyttsp4_core_wake_(struct cyttsp4 *cd) | ||
| 1583 | { | ||
| 1584 | struct device *dev = cd->dev; | ||
| 1585 | int rc; | ||
| 1586 | u8 mode; | ||
| 1587 | int t; | ||
| 1588 | |||
| 1589 | /* Already woken? */ | ||
| 1590 | mutex_lock(&cd->system_lock); | ||
| 1591 | if (cd->sleep_state == SS_SLEEP_OFF) { | ||
| 1592 | mutex_unlock(&cd->system_lock); | ||
| 1593 | return 0; | ||
| 1594 | } | ||
| 1595 | cd->int_status &= ~CY_INT_IGNORE; | ||
| 1596 | cd->int_status |= CY_INT_AWAKE; | ||
| 1597 | cd->sleep_state = SS_WAKING; | ||
| 1598 | |||
| 1599 | if (cd->cpdata->power) { | ||
| 1600 | dev_dbg(dev, "%s: Power up HW\n", __func__); | ||
| 1601 | rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq); | ||
| 1602 | } else { | ||
| 1603 | dev_dbg(dev, "%s: No power function\n", __func__); | ||
| 1604 | rc = -ENOSYS; | ||
| 1605 | } | ||
| 1606 | if (rc < 0) { | ||
| 1607 | dev_err(dev, "%s: HW Power up fails r=%d\n", | ||
| 1608 | __func__, rc); | ||
| 1609 | |||
| 1610 | /* Initiate a read transaction to wake up */ | ||
| 1611 | cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode); | ||
| 1612 | } else | ||
| 1613 | dev_vdbg(cd->dev, "%s: HW power up succeeds\n", | ||
| 1614 | __func__); | ||
| 1615 | mutex_unlock(&cd->system_lock); | ||
| 1616 | |||
| 1617 | t = wait_event_timeout(cd->wait_q, | ||
| 1618 | (cd->int_status & CY_INT_AWAKE) == 0, | ||
| 1619 | msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT)); | ||
| 1620 | if (IS_TMO(t)) { | ||
| 1621 | dev_err(dev, "%s: TMO waiting for wakeup\n", __func__); | ||
| 1622 | mutex_lock(&cd->system_lock); | ||
| 1623 | cd->int_status &= ~CY_INT_AWAKE; | ||
| 1624 | /* Try starting up */ | ||
| 1625 | cyttsp4_queue_startup_(cd); | ||
| 1626 | mutex_unlock(&cd->system_lock); | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | mutex_lock(&cd->system_lock); | ||
| 1630 | cd->sleep_state = SS_SLEEP_OFF; | ||
| 1631 | mutex_unlock(&cd->system_lock); | ||
| 1632 | |||
| 1633 | cyttsp4_start_wd_timer(cd); | ||
| 1634 | |||
| 1635 | return 0; | ||
| 1636 | } | ||
| 1637 | |||
| 1638 | static int cyttsp4_core_wake(struct cyttsp4 *cd) | ||
| 1639 | { | ||
| 1640 | int rc; | ||
| 1641 | |||
| 1642 | rc = cyttsp4_request_exclusive(cd, cd->dev, | ||
| 1643 | CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT); | ||
| 1644 | if (rc < 0) { | ||
| 1645 | dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n", | ||
| 1646 | __func__, cd->exclusive_dev, cd->dev); | ||
| 1647 | return 0; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | rc = cyttsp4_core_wake_(cd); | ||
| 1651 | |||
| 1652 | if (cyttsp4_release_exclusive(cd, cd->dev) < 0) | ||
| 1653 | dev_err(cd->dev, "%s: fail to release exclusive\n", __func__); | ||
| 1654 | else | ||
| 1655 | dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__); | ||
| 1656 | |||
| 1657 | return rc; | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | static int cyttsp4_startup_(struct cyttsp4 *cd) | ||
| 1661 | { | ||
| 1662 | int retry = CY_CORE_STARTUP_RETRY_COUNT; | ||
| 1663 | int rc; | ||
| 1664 | |||
| 1665 | cyttsp4_stop_wd_timer(cd); | ||
| 1666 | |||
| 1667 | reset: | ||
| 1668 | if (retry != CY_CORE_STARTUP_RETRY_COUNT) | ||
| 1669 | dev_dbg(cd->dev, "%s: Retry %d\n", __func__, | ||
| 1670 | CY_CORE_STARTUP_RETRY_COUNT - retry); | ||
| 1671 | |||
| 1672 | /* reset hardware and wait for heartbeat */ | ||
| 1673 | rc = cyttsp4_reset_and_wait(cd); | ||
| 1674 | if (rc < 0) { | ||
| 1675 | dev_err(cd->dev, "%s: Error on h/w reset r=%d\n", __func__, rc); | ||
| 1676 | if (retry--) | ||
| 1677 | goto reset; | ||
| 1678 | goto exit; | ||
| 1679 | } | ||
| 1680 | |||
| 1681 | /* exit bl into sysinfo mode */ | ||
| 1682 | dev_vdbg(cd->dev, "%s: write exit ldr...\n", __func__); | ||
| 1683 | mutex_lock(&cd->system_lock); | ||
| 1684 | cd->int_status &= ~CY_INT_IGNORE; | ||
| 1685 | cd->int_status |= CY_INT_MODE_CHANGE; | ||
| 1686 | |||
| 1687 | rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(ldr_exit), | ||
| 1688 | (u8 *)ldr_exit); | ||
| 1689 | mutex_unlock(&cd->system_lock); | ||
| 1690 | if (rc < 0) { | ||
| 1691 | dev_err(cd->dev, "%s: Fail write r=%d\n", __func__, rc); | ||
| 1692 | if (retry--) | ||
| 1693 | goto reset; | ||
| 1694 | goto exit; | ||
| 1695 | } | ||
| 1696 | |||
| 1697 | rc = cyttsp4_wait_sysinfo_mode(cd); | ||
| 1698 | if (rc < 0) { | ||
| 1699 | u8 buf[sizeof(ldr_err_app)]; | ||
| 1700 | int rc1; | ||
| 1701 | |||
| 1702 | /* Check for invalid/corrupted touch application */ | ||
| 1703 | rc1 = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(ldr_err_app), | ||
| 1704 | buf); | ||
| 1705 | if (rc1) { | ||
| 1706 | dev_err(cd->dev, "%s: Fail read r=%d\n", __func__, rc1); | ||
| 1707 | } else if (!memcmp(buf, ldr_err_app, sizeof(ldr_err_app))) { | ||
| 1708 | dev_err(cd->dev, "%s: Error launching touch application\n", | ||
| 1709 | __func__); | ||
| 1710 | mutex_lock(&cd->system_lock); | ||
| 1711 | cd->invalid_touch_app = true; | ||
| 1712 | mutex_unlock(&cd->system_lock); | ||
| 1713 | goto exit_no_wd; | ||
| 1714 | } | ||
| 1715 | |||
| 1716 | if (retry--) | ||
| 1717 | goto reset; | ||
| 1718 | goto exit; | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | mutex_lock(&cd->system_lock); | ||
| 1722 | cd->invalid_touch_app = false; | ||
| 1723 | mutex_unlock(&cd->system_lock); | ||
| 1724 | |||
| 1725 | /* read sysinfo data */ | ||
| 1726 | dev_vdbg(cd->dev, "%s: get sysinfo regs..\n", __func__); | ||
| 1727 | rc = cyttsp4_get_sysinfo_regs(cd); | ||
| 1728 | if (rc < 0) { | ||
| 1729 | dev_err(cd->dev, "%s: failed to get sysinfo regs rc=%d\n", | ||
| 1730 | __func__, rc); | ||
| 1731 | if (retry--) | ||
| 1732 | goto reset; | ||
| 1733 | goto exit; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | rc = cyttsp4_set_mode(cd, CY_MODE_OPERATIONAL); | ||
| 1737 | if (rc < 0) { | ||
| 1738 | dev_err(cd->dev, "%s: failed to set mode to operational rc=%d\n", | ||
| 1739 | __func__, rc); | ||
| 1740 | if (retry--) | ||
| 1741 | goto reset; | ||
| 1742 | goto exit; | ||
| 1743 | } | ||
| 1744 | |||
| 1745 | cyttsp4_lift_all(&cd->md); | ||
| 1746 | |||
| 1747 | /* restore to sleep if was suspended */ | ||
| 1748 | mutex_lock(&cd->system_lock); | ||
| 1749 | if (cd->sleep_state == SS_SLEEP_ON) { | ||
| 1750 | cd->sleep_state = SS_SLEEP_OFF; | ||
| 1751 | mutex_unlock(&cd->system_lock); | ||
| 1752 | cyttsp4_core_sleep_(cd); | ||
| 1753 | goto exit_no_wd; | ||
| 1754 | } | ||
| 1755 | mutex_unlock(&cd->system_lock); | ||
| 1756 | |||
| 1757 | exit: | ||
| 1758 | cyttsp4_start_wd_timer(cd); | ||
| 1759 | exit_no_wd: | ||
| 1760 | return rc; | ||
| 1761 | } | ||
| 1762 | |||
| 1763 | static int cyttsp4_startup(struct cyttsp4 *cd) | ||
| 1764 | { | ||
| 1765 | int rc; | ||
| 1766 | |||
| 1767 | mutex_lock(&cd->system_lock); | ||
| 1768 | cd->startup_state = STARTUP_RUNNING; | ||
| 1769 | mutex_unlock(&cd->system_lock); | ||
| 1770 | |||
| 1771 | rc = cyttsp4_request_exclusive(cd, cd->dev, | ||
| 1772 | CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT); | ||
| 1773 | if (rc < 0) { | ||
| 1774 | dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n", | ||
| 1775 | __func__, cd->exclusive_dev, cd->dev); | ||
| 1776 | goto exit; | ||
| 1777 | } | ||
| 1778 | |||
| 1779 | rc = cyttsp4_startup_(cd); | ||
| 1780 | |||
| 1781 | if (cyttsp4_release_exclusive(cd, cd->dev) < 0) | ||
| 1782 | /* Don't return fail code, mode is already changed. */ | ||
| 1783 | dev_err(cd->dev, "%s: fail to release exclusive\n", __func__); | ||
| 1784 | else | ||
| 1785 | dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__); | ||
| 1786 | |||
| 1787 | exit: | ||
| 1788 | mutex_lock(&cd->system_lock); | ||
| 1789 | cd->startup_state = STARTUP_NONE; | ||
| 1790 | mutex_unlock(&cd->system_lock); | ||
| 1791 | |||
| 1792 | /* Wake the waiters for end of startup */ | ||
| 1793 | wake_up(&cd->wait_q); | ||
| 1794 | |||
| 1795 | return rc; | ||
| 1796 | } | ||
| 1797 | |||
| 1798 | static void cyttsp4_startup_work_function(struct work_struct *work) | ||
| 1799 | { | ||
| 1800 | struct cyttsp4 *cd = container_of(work, struct cyttsp4, startup_work); | ||
| 1801 | int rc; | ||
| 1802 | |||
| 1803 | rc = cyttsp4_startup(cd); | ||
| 1804 | if (rc < 0) | ||
| 1805 | dev_err(cd->dev, "%s: Fail queued startup r=%d\n", | ||
| 1806 | __func__, rc); | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd) | ||
| 1810 | { | ||
| 1811 | struct cyttsp4_sysinfo *si = &cd->sysinfo; | ||
| 1812 | |||
| 1813 | if (!si) | ||
| 1814 | return; | ||
| 1815 | |||
| 1816 | kfree(si->si_ptrs.cydata); | ||
| 1817 | kfree(si->si_ptrs.test); | ||
| 1818 | kfree(si->si_ptrs.pcfg); | ||
| 1819 | kfree(si->si_ptrs.opcfg); | ||
| 1820 | kfree(si->si_ptrs.ddata); | ||
| 1821 | kfree(si->si_ptrs.mdata); | ||
| 1822 | kfree(si->btn); | ||
| 1823 | kfree(si->xy_mode); | ||
| 1824 | kfree(si->xy_data); | ||
| 1825 | kfree(si->btn_rec_data); | ||
| 1826 | } | ||
| 1827 | |||
| 1828 | #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) | ||
| 1829 | static int cyttsp4_core_suspend(struct device *dev) | ||
| 1830 | { | ||
| 1831 | struct cyttsp4 *cd = dev_get_drvdata(dev); | ||
| 1832 | struct cyttsp4_mt_data *md = &cd->md; | ||
| 1833 | int rc; | ||
| 1834 | |||
| 1835 | md->is_suspended = true; | ||
| 1836 | |||
| 1837 | rc = cyttsp4_core_sleep(cd); | ||
| 1838 | if (rc < 0) { | ||
| 1839 | dev_err(dev, "%s: Error on sleep\n", __func__); | ||
| 1840 | return -EAGAIN; | ||
| 1841 | } | ||
| 1842 | return 0; | ||
| 1843 | } | ||
| 1844 | |||
| 1845 | static int cyttsp4_core_resume(struct device *dev) | ||
| 1846 | { | ||
| 1847 | struct cyttsp4 *cd = dev_get_drvdata(dev); | ||
| 1848 | struct cyttsp4_mt_data *md = &cd->md; | ||
| 1849 | int rc; | ||
| 1850 | |||
| 1851 | md->is_suspended = false; | ||
| 1852 | |||
| 1853 | rc = cyttsp4_core_wake(cd); | ||
| 1854 | if (rc < 0) { | ||
| 1855 | dev_err(dev, "%s: Error on wake\n", __func__); | ||
| 1856 | return -EAGAIN; | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | return 0; | ||
| 1860 | } | ||
| 1861 | #endif | ||
| 1862 | |||
| 1863 | const struct dev_pm_ops cyttsp4_pm_ops = { | ||
| 1864 | SET_SYSTEM_SLEEP_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume) | ||
| 1865 | SET_RUNTIME_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume, NULL) | ||
| 1866 | }; | ||
| 1867 | EXPORT_SYMBOL_GPL(cyttsp4_pm_ops); | ||
| 1868 | |||
| 1869 | static int cyttsp4_mt_open(struct input_dev *input) | ||
| 1870 | { | ||
| 1871 | pm_runtime_get(input->dev.parent); | ||
| 1872 | return 0; | ||
| 1873 | } | ||
| 1874 | |||
| 1875 | static void cyttsp4_mt_close(struct input_dev *input) | ||
| 1876 | { | ||
| 1877 | struct cyttsp4_mt_data *md = input_get_drvdata(input); | ||
| 1878 | mutex_lock(&md->report_lock); | ||
| 1879 | if (!md->is_suspended) | ||
| 1880 | pm_runtime_put(input->dev.parent); | ||
| 1881 | mutex_unlock(&md->report_lock); | ||
| 1882 | } | ||
| 1883 | |||
| 1884 | |||
| 1885 | static int cyttsp4_setup_input_device(struct cyttsp4 *cd) | ||
| 1886 | { | ||
| 1887 | struct device *dev = cd->dev; | ||
| 1888 | struct cyttsp4_mt_data *md = &cd->md; | ||
| 1889 | int signal = CY_IGNORE_VALUE; | ||
| 1890 | int max_x, max_y, max_p, min, max; | ||
| 1891 | int max_x_tmp, max_y_tmp; | ||
| 1892 | int i; | ||
| 1893 | int rc; | ||
| 1894 | |||
| 1895 | dev_vdbg(dev, "%s: Initialize event signals\n", __func__); | ||
| 1896 | __set_bit(EV_ABS, md->input->evbit); | ||
| 1897 | __set_bit(EV_REL, md->input->evbit); | ||
| 1898 | __set_bit(EV_KEY, md->input->evbit); | ||
| 1899 | |||
| 1900 | max_x_tmp = md->si->si_ofs.max_x; | ||
| 1901 | max_y_tmp = md->si->si_ofs.max_y; | ||
| 1902 | |||
| 1903 | /* get maximum values from the sysinfo data */ | ||
| 1904 | if (md->pdata->flags & CY_FLAG_FLIP) { | ||
| 1905 | max_x = max_y_tmp - 1; | ||
| 1906 | max_y = max_x_tmp - 1; | ||
| 1907 | } else { | ||
| 1908 | max_x = max_x_tmp - 1; | ||
| 1909 | max_y = max_y_tmp - 1; | ||
| 1910 | } | ||
| 1911 | max_p = md->si->si_ofs.max_p; | ||
| 1912 | |||
| 1913 | /* set event signal capabilities */ | ||
| 1914 | for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) { | ||
| 1915 | signal = md->pdata->frmwrk->abs | ||
| 1916 | [(i * CY_NUM_ABS_SET) + CY_SIGNAL_OST]; | ||
| 1917 | if (signal != CY_IGNORE_VALUE) { | ||
| 1918 | __set_bit(signal, md->input->absbit); | ||
| 1919 | min = md->pdata->frmwrk->abs | ||
| 1920 | [(i * CY_NUM_ABS_SET) + CY_MIN_OST]; | ||
| 1921 | max = md->pdata->frmwrk->abs | ||
| 1922 | [(i * CY_NUM_ABS_SET) + CY_MAX_OST]; | ||
| 1923 | if (i == CY_ABS_ID_OST) { | ||
| 1924 | /* shift track ids down to start at 0 */ | ||
| 1925 | max = max - min; | ||
| 1926 | min = min - min; | ||
| 1927 | } else if (i == CY_ABS_X_OST) | ||
| 1928 | max = max_x; | ||
| 1929 | else if (i == CY_ABS_Y_OST) | ||
| 1930 | max = max_y; | ||
| 1931 | else if (i == CY_ABS_P_OST) | ||
| 1932 | max = max_p; | ||
| 1933 | input_set_abs_params(md->input, signal, min, max, | ||
| 1934 | md->pdata->frmwrk->abs | ||
| 1935 | [(i * CY_NUM_ABS_SET) + CY_FUZZ_OST], | ||
| 1936 | md->pdata->frmwrk->abs | ||
| 1937 | [(i * CY_NUM_ABS_SET) + CY_FLAT_OST]); | ||
| 1938 | dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n", | ||
| 1939 | __func__, signal, min, max); | ||
| 1940 | if ((i == CY_ABS_ID_OST) && | ||
| 1941 | (md->si->si_ofs.tch_rec_size < | ||
| 1942 | CY_TMA4XX_TCH_REC_SIZE)) | ||
| 1943 | break; | ||
| 1944 | } | ||
| 1945 | } | ||
| 1946 | |||
| 1947 | input_mt_init_slots(md->input, md->si->si_ofs.tch_abs[CY_TCH_T].max, | ||
| 1948 | INPUT_MT_DIRECT); | ||
| 1949 | rc = input_register_device(md->input); | ||
| 1950 | if (rc < 0) | ||
| 1951 | dev_err(dev, "%s: Error, failed register input device r=%d\n", | ||
| 1952 | __func__, rc); | ||
| 1953 | return rc; | ||
| 1954 | } | ||
| 1955 | |||
| 1956 | static int cyttsp4_mt_probe(struct cyttsp4 *cd) | ||
| 1957 | { | ||
| 1958 | struct device *dev = cd->dev; | ||
| 1959 | struct cyttsp4_mt_data *md = &cd->md; | ||
| 1960 | struct cyttsp4_mt_platform_data *pdata = cd->pdata->mt_pdata; | ||
| 1961 | int rc = 0; | ||
| 1962 | |||
| 1963 | mutex_init(&md->report_lock); | ||
| 1964 | md->pdata = pdata; | ||
| 1965 | /* Create the input device and register it. */ | ||
| 1966 | dev_vdbg(dev, "%s: Create the input device and register it\n", | ||
| 1967 | __func__); | ||
| 1968 | md->input = input_allocate_device(); | ||
| 1969 | if (md->input == NULL) { | ||
| 1970 | dev_err(dev, "%s: Error, failed to allocate input device\n", | ||
| 1971 | __func__); | ||
| 1972 | rc = -ENOSYS; | ||
| 1973 | goto error_alloc_failed; | ||
| 1974 | } | ||
| 1975 | |||
| 1976 | md->input->name = pdata->inp_dev_name; | ||
| 1977 | scnprintf(md->phys, sizeof(md->phys)-1, "%s", dev_name(dev)); | ||
| 1978 | md->input->phys = md->phys; | ||
| 1979 | md->input->id.bustype = cd->bus_ops->bustype; | ||
| 1980 | md->input->dev.parent = dev; | ||
| 1981 | md->input->open = cyttsp4_mt_open; | ||
| 1982 | md->input->close = cyttsp4_mt_close; | ||
| 1983 | input_set_drvdata(md->input, md); | ||
| 1984 | |||
| 1985 | /* get sysinfo */ | ||
| 1986 | md->si = &cd->sysinfo; | ||
| 1987 | if (!md->si) { | ||
| 1988 | dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n", | ||
| 1989 | __func__, md->si); | ||
| 1990 | goto error_get_sysinfo; | ||
| 1991 | } | ||
| 1992 | |||
| 1993 | rc = cyttsp4_setup_input_device(cd); | ||
| 1994 | if (rc) | ||
| 1995 | goto error_init_input; | ||
| 1996 | |||
| 1997 | return 0; | ||
| 1998 | |||
| 1999 | error_init_input: | ||
| 2000 | input_free_device(md->input); | ||
| 2001 | error_get_sysinfo: | ||
| 2002 | input_set_drvdata(md->input, NULL); | ||
| 2003 | error_alloc_failed: | ||
| 2004 | dev_err(dev, "%s failed.\n", __func__); | ||
| 2005 | return rc; | ||
| 2006 | } | ||
| 2007 | |||
| 2008 | struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops, | ||
| 2009 | struct device *dev, u16 irq, size_t xfer_buf_size) | ||
| 2010 | { | ||
| 2011 | struct cyttsp4 *cd; | ||
| 2012 | struct cyttsp4_platform_data *pdata = dev_get_platdata(dev); | ||
| 2013 | unsigned long irq_flags; | ||
| 2014 | int rc = 0; | ||
| 2015 | |||
| 2016 | if (!pdata || !pdata->core_pdata || !pdata->mt_pdata) { | ||
| 2017 | dev_err(dev, "%s: Missing platform data\n", __func__); | ||
| 2018 | rc = -ENODEV; | ||
| 2019 | goto error_no_pdata; | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | cd = kzalloc(sizeof(*cd), GFP_KERNEL); | ||
| 2023 | if (!cd) { | ||
| 2024 | dev_err(dev, "%s: Error, kzalloc\n", __func__); | ||
| 2025 | rc = -ENOMEM; | ||
| 2026 | goto error_alloc_data; | ||
| 2027 | } | ||
| 2028 | |||
| 2029 | cd->xfer_buf = kzalloc(xfer_buf_size, GFP_KERNEL); | ||
| 2030 | if (!cd->xfer_buf) { | ||
| 2031 | dev_err(dev, "%s: Error, kzalloc\n", __func__); | ||
| 2032 | rc = -ENOMEM; | ||
| 2033 | goto error_alloc_data; | ||
| 2034 | } | ||
| 2035 | |||
| 2036 | /* Initialize device info */ | ||
| 2037 | cd->dev = dev; | ||
| 2038 | cd->pdata = pdata; | ||
| 2039 | cd->cpdata = pdata->core_pdata; | ||
| 2040 | cd->bus_ops = ops; | ||
| 2041 | |||
| 2042 | /* Initialize mutexes and spinlocks */ | ||
| 2043 | mutex_init(&cd->system_lock); | ||
| 2044 | mutex_init(&cd->adap_lock); | ||
| 2045 | |||
| 2046 | /* Initialize wait queue */ | ||
| 2047 | init_waitqueue_head(&cd->wait_q); | ||
| 2048 | |||
| 2049 | /* Initialize works */ | ||
| 2050 | INIT_WORK(&cd->startup_work, cyttsp4_startup_work_function); | ||
| 2051 | INIT_WORK(&cd->watchdog_work, cyttsp4_watchdog_work); | ||
| 2052 | |||
| 2053 | /* Initialize IRQ */ | ||
| 2054 | cd->irq = gpio_to_irq(cd->cpdata->irq_gpio); | ||
| 2055 | if (cd->irq < 0) { | ||
| 2056 | rc = -EINVAL; | ||
| 2057 | goto error_gpio_irq; | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | dev_set_drvdata(dev, cd); | ||
| 2061 | |||
| 2062 | /* Call platform init function */ | ||
| 2063 | if (cd->cpdata->init) { | ||
| 2064 | dev_dbg(cd->dev, "%s: Init HW\n", __func__); | ||
| 2065 | rc = cd->cpdata->init(cd->cpdata, 1, cd->dev); | ||
| 2066 | } else { | ||
| 2067 | dev_dbg(cd->dev, "%s: No HW INIT function\n", __func__); | ||
| 2068 | rc = 0; | ||
| 2069 | } | ||
| 2070 | if (rc < 0) | ||
| 2071 | dev_err(cd->dev, "%s: HW Init fail r=%d\n", __func__, rc); | ||
| 2072 | |||
| 2073 | dev_dbg(dev, "%s: initialize threaded irq=%d\n", __func__, cd->irq); | ||
| 2074 | if (cd->cpdata->level_irq_udelay > 0) | ||
| 2075 | /* use level triggered interrupts */ | ||
| 2076 | irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT; | ||
| 2077 | else | ||
| 2078 | /* use edge triggered interrupts */ | ||
| 2079 | irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | ||
| 2080 | |||
| 2081 | rc = request_threaded_irq(cd->irq, NULL, cyttsp4_irq, irq_flags, | ||
| 2082 | dev_name(dev), cd); | ||
| 2083 | if (rc < 0) { | ||
| 2084 | dev_err(dev, "%s: Error, could not request irq\n", __func__); | ||
| 2085 | goto error_request_irq; | ||
| 2086 | } | ||
| 2087 | |||
| 2088 | /* Setup watchdog timer */ | ||
| 2089 | setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer, | ||
| 2090 | (unsigned long)cd); | ||
| 2091 | |||
| 2092 | /* | ||
| 2093 | * call startup directly to ensure that the device | ||
| 2094 | * is tested before leaving the probe | ||
| 2095 | */ | ||
| 2096 | rc = cyttsp4_startup(cd); | ||
| 2097 | |||
| 2098 | /* Do not fail probe if startup fails but the device is detected */ | ||
| 2099 | if (rc < 0 && cd->mode == CY_MODE_UNKNOWN) { | ||
| 2100 | dev_err(cd->dev, "%s: Fail initial startup r=%d\n", | ||
| 2101 | __func__, rc); | ||
| 2102 | goto error_startup; | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | rc = cyttsp4_mt_probe(cd); | ||
| 2106 | if (rc < 0) { | ||
| 2107 | dev_err(dev, "%s: Error, fail mt probe\n", __func__); | ||
| 2108 | goto error_startup; | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | pm_runtime_enable(dev); | ||
| 2112 | |||
| 2113 | return cd; | ||
| 2114 | |||
| 2115 | error_startup: | ||
| 2116 | cancel_work_sync(&cd->startup_work); | ||
| 2117 | cyttsp4_stop_wd_timer(cd); | ||
| 2118 | pm_runtime_disable(dev); | ||
| 2119 | cyttsp4_free_si_ptrs(cd); | ||
| 2120 | free_irq(cd->irq, cd); | ||
| 2121 | error_request_irq: | ||
| 2122 | if (cd->cpdata->init) | ||
| 2123 | cd->cpdata->init(cd->cpdata, 0, dev); | ||
| 2124 | dev_set_drvdata(dev, NULL); | ||
| 2125 | error_gpio_irq: | ||
| 2126 | kfree(cd); | ||
| 2127 | error_alloc_data: | ||
| 2128 | error_no_pdata: | ||
| 2129 | dev_err(dev, "%s failed.\n", __func__); | ||
| 2130 | return ERR_PTR(rc); | ||
| 2131 | } | ||
| 2132 | EXPORT_SYMBOL_GPL(cyttsp4_probe); | ||
| 2133 | |||
| 2134 | static void cyttsp4_mt_release(struct cyttsp4_mt_data *md) | ||
| 2135 | { | ||
| 2136 | input_unregister_device(md->input); | ||
| 2137 | input_set_drvdata(md->input, NULL); | ||
| 2138 | } | ||
| 2139 | |||
| 2140 | int cyttsp4_remove(struct cyttsp4 *cd) | ||
| 2141 | { | ||
| 2142 | struct device *dev = cd->dev; | ||
| 2143 | |||
| 2144 | cyttsp4_mt_release(&cd->md); | ||
| 2145 | |||
| 2146 | /* | ||
| 2147 | * Suspend the device before freeing the startup_work and stopping | ||
| 2148 | * the watchdog since sleep function restarts watchdog on failure | ||
| 2149 | */ | ||
| 2150 | pm_runtime_suspend(dev); | ||
| 2151 | pm_runtime_disable(dev); | ||
| 2152 | |||
| 2153 | cancel_work_sync(&cd->startup_work); | ||
| 2154 | |||
| 2155 | cyttsp4_stop_wd_timer(cd); | ||
| 2156 | |||
| 2157 | free_irq(cd->irq, cd); | ||
| 2158 | if (cd->cpdata->init) | ||
| 2159 | cd->cpdata->init(cd->cpdata, 0, dev); | ||
| 2160 | dev_set_drvdata(dev, NULL); | ||
| 2161 | cyttsp4_free_si_ptrs(cd); | ||
| 2162 | kfree(cd); | ||
| 2163 | return 0; | ||
| 2164 | } | ||
| 2165 | EXPORT_SYMBOL_GPL(cyttsp4_remove); | ||
| 2166 | |||
| 2167 | MODULE_LICENSE("GPL"); | ||
| 2168 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen core driver"); | ||
| 2169 | MODULE_AUTHOR("Cypress"); | ||
diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h new file mode 100644 index 000000000000..86a254354136 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_core.h | |||
| @@ -0,0 +1,472 @@ | |||
| 1 | /* | ||
| 2 | * cyttsp4_core.h | ||
| 3 | * Cypress TrueTouch(TM) Standard Product V4 Core driver module. | ||
| 4 | * For use with Cypress Txx4xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * TMA4XX | ||
| 7 | * TMA1036 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2012 Cypress Semiconductor | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU General Public License | ||
| 13 | * version 2, and only version 2, as published by the | ||
| 14 | * Free Software Foundation. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #ifndef _LINUX_CYTTSP4_CORE_H | ||
| 26 | #define _LINUX_CYTTSP4_CORE_H | ||
| 27 | |||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/err.h> | ||
| 30 | #include <linux/input.h> | ||
| 31 | #include <linux/kernel.h> | ||
| 32 | #include <linux/limits.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | #include <linux/stringify.h> | ||
| 35 | #include <linux/types.h> | ||
| 36 | #include <linux/platform_data/cyttsp4.h> | ||
| 37 | |||
| 38 | #define CY_REG_BASE 0x00 | ||
| 39 | |||
| 40 | #define CY_POST_CODEL_WDG_RST 0x01 | ||
| 41 | #define CY_POST_CODEL_CFG_DATA_CRC_FAIL 0x02 | ||
| 42 | #define CY_POST_CODEL_PANEL_TEST_FAIL 0x04 | ||
| 43 | |||
| 44 | #define CY_NUM_BTN_PER_REG 4 | ||
| 45 | |||
| 46 | /* touch record system information offset masks and shifts */ | ||
| 47 | #define CY_BYTE_OFS_MASK 0x1F | ||
| 48 | #define CY_BOFS_MASK 0xE0 | ||
| 49 | #define CY_BOFS_SHIFT 5 | ||
| 50 | |||
| 51 | #define CY_TMA1036_TCH_REC_SIZE 6 | ||
| 52 | #define CY_TMA4XX_TCH_REC_SIZE 9 | ||
| 53 | #define CY_TMA1036_MAX_TCH 0x0E | ||
| 54 | #define CY_TMA4XX_MAX_TCH 0x1E | ||
| 55 | |||
| 56 | #define CY_NORMAL_ORIGIN 0 /* upper, left corner */ | ||
| 57 | #define CY_INVERT_ORIGIN 1 /* lower, right corner */ | ||
| 58 | |||
| 59 | /* helpers */ | ||
| 60 | #define GET_NUM_TOUCHES(x) ((x) & 0x1F) | ||
| 61 | #define IS_LARGE_AREA(x) ((x) & 0x20) | ||
| 62 | #define IS_BAD_PKT(x) ((x) & 0x20) | ||
| 63 | #define IS_BOOTLOADER(hst_mode, reset_detect) \ | ||
| 64 | ((hst_mode) & 0x01 || (reset_detect) != 0) | ||
| 65 | #define IS_TMO(t) ((t) == 0) | ||
| 66 | |||
| 67 | |||
| 68 | enum cyttsp_cmd_bits { | ||
| 69 | CY_CMD_COMPLETE = (1 << 6), | ||
| 70 | }; | ||
| 71 | |||
| 72 | /* Timeout in ms. */ | ||
| 73 | #define CY_WATCHDOG_TIMEOUT 1000 | ||
| 74 | |||
| 75 | #define CY_MAX_PRINT_SIZE 512 | ||
| 76 | #ifdef VERBOSE_DEBUG | ||
| 77 | #define CY_MAX_PRBUF_SIZE PIPE_BUF | ||
| 78 | #define CY_PR_TRUNCATED " truncated..." | ||
| 79 | #endif | ||
| 80 | |||
| 81 | enum cyttsp4_ic_grpnum { | ||
| 82 | CY_IC_GRPNUM_RESERVED, | ||
| 83 | CY_IC_GRPNUM_CMD_REGS, | ||
| 84 | CY_IC_GRPNUM_TCH_REP, | ||
| 85 | CY_IC_GRPNUM_DATA_REC, | ||
| 86 | CY_IC_GRPNUM_TEST_REC, | ||
| 87 | CY_IC_GRPNUM_PCFG_REC, | ||
| 88 | CY_IC_GRPNUM_TCH_PARM_VAL, | ||
| 89 | CY_IC_GRPNUM_TCH_PARM_SIZE, | ||
| 90 | CY_IC_GRPNUM_RESERVED1, | ||
| 91 | CY_IC_GRPNUM_RESERVED2, | ||
| 92 | CY_IC_GRPNUM_OPCFG_REC, | ||
| 93 | CY_IC_GRPNUM_DDATA_REC, | ||
| 94 | CY_IC_GRPNUM_MDATA_REC, | ||
| 95 | CY_IC_GRPNUM_TEST_REGS, | ||
| 96 | CY_IC_GRPNUM_BTN_KEYS, | ||
| 97 | CY_IC_GRPNUM_TTHE_REGS, | ||
| 98 | CY_IC_GRPNUM_NUM | ||
| 99 | }; | ||
| 100 | |||
| 101 | enum cyttsp4_int_state { | ||
| 102 | CY_INT_NONE, | ||
| 103 | CY_INT_IGNORE = (1 << 0), | ||
| 104 | CY_INT_MODE_CHANGE = (1 << 1), | ||
| 105 | CY_INT_EXEC_CMD = (1 << 2), | ||
| 106 | CY_INT_AWAKE = (1 << 3), | ||
| 107 | }; | ||
| 108 | |||
| 109 | enum cyttsp4_mode { | ||
| 110 | CY_MODE_UNKNOWN, | ||
| 111 | CY_MODE_BOOTLOADER = (1 << 1), | ||
| 112 | CY_MODE_OPERATIONAL = (1 << 2), | ||
| 113 | CY_MODE_SYSINFO = (1 << 3), | ||
| 114 | CY_MODE_CAT = (1 << 4), | ||
| 115 | CY_MODE_STARTUP = (1 << 5), | ||
| 116 | CY_MODE_LOADER = (1 << 6), | ||
| 117 | CY_MODE_CHANGE_MODE = (1 << 7), | ||
| 118 | CY_MODE_CHANGED = (1 << 8), | ||
| 119 | CY_MODE_CMD_COMPLETE = (1 << 9), | ||
| 120 | }; | ||
| 121 | |||
| 122 | enum cyttsp4_sleep_state { | ||
| 123 | SS_SLEEP_OFF, | ||
| 124 | SS_SLEEP_ON, | ||
| 125 | SS_SLEEPING, | ||
| 126 | SS_WAKING, | ||
| 127 | }; | ||
| 128 | |||
| 129 | enum cyttsp4_startup_state { | ||
| 130 | STARTUP_NONE, | ||
| 131 | STARTUP_QUEUED, | ||
| 132 | STARTUP_RUNNING, | ||
| 133 | }; | ||
| 134 | |||
| 135 | #define CY_NUM_REVCTRL 8 | ||
| 136 | struct cyttsp4_cydata { | ||
| 137 | u8 ttpidh; | ||
| 138 | u8 ttpidl; | ||
| 139 | u8 fw_ver_major; | ||
| 140 | u8 fw_ver_minor; | ||
| 141 | u8 revctrl[CY_NUM_REVCTRL]; | ||
| 142 | u8 blver_major; | ||
| 143 | u8 blver_minor; | ||
| 144 | u8 jtag_si_id3; | ||
| 145 | u8 jtag_si_id2; | ||
| 146 | u8 jtag_si_id1; | ||
| 147 | u8 jtag_si_id0; | ||
| 148 | u8 mfgid_sz; | ||
| 149 | u8 cyito_idh; | ||
| 150 | u8 cyito_idl; | ||
| 151 | u8 cyito_verh; | ||
| 152 | u8 cyito_verl; | ||
| 153 | u8 ttsp_ver_major; | ||
| 154 | u8 ttsp_ver_minor; | ||
| 155 | u8 device_info; | ||
| 156 | u8 mfg_id[]; | ||
| 157 | } __packed; | ||
| 158 | |||
| 159 | struct cyttsp4_test { | ||
| 160 | u8 post_codeh; | ||
| 161 | u8 post_codel; | ||
| 162 | } __packed; | ||
| 163 | |||
| 164 | struct cyttsp4_pcfg { | ||
| 165 | u8 electrodes_x; | ||
| 166 | u8 electrodes_y; | ||
| 167 | u8 len_xh; | ||
| 168 | u8 len_xl; | ||
| 169 | u8 len_yh; | ||
| 170 | u8 len_yl; | ||
| 171 | u8 res_xh; | ||
| 172 | u8 res_xl; | ||
| 173 | u8 res_yh; | ||
| 174 | u8 res_yl; | ||
| 175 | u8 max_zh; | ||
| 176 | u8 max_zl; | ||
| 177 | u8 panel_info0; | ||
| 178 | } __packed; | ||
| 179 | |||
| 180 | struct cyttsp4_tch_rec_params { | ||
| 181 | u8 loc; | ||
| 182 | u8 size; | ||
| 183 | } __packed; | ||
| 184 | |||
| 185 | #define CY_NUM_TCH_FIELDS 7 | ||
| 186 | #define CY_NUM_EXT_TCH_FIELDS 3 | ||
| 187 | struct cyttsp4_opcfg { | ||
| 188 | u8 cmd_ofs; | ||
| 189 | u8 rep_ofs; | ||
| 190 | u8 rep_szh; | ||
| 191 | u8 rep_szl; | ||
| 192 | u8 num_btns; | ||
| 193 | u8 tt_stat_ofs; | ||
| 194 | u8 obj_cfg0; | ||
| 195 | u8 max_tchs; | ||
| 196 | u8 tch_rec_size; | ||
| 197 | struct cyttsp4_tch_rec_params tch_rec_old[CY_NUM_TCH_FIELDS]; | ||
| 198 | u8 btn_rec_size; /* btn record size (in bytes) */ | ||
| 199 | u8 btn_diff_ofs; /* btn data loc, diff counts */ | ||
| 200 | u8 btn_diff_size; /* btn size of diff counts (in bits) */ | ||
| 201 | struct cyttsp4_tch_rec_params tch_rec_new[CY_NUM_EXT_TCH_FIELDS]; | ||
| 202 | } __packed; | ||
| 203 | |||
| 204 | struct cyttsp4_sysinfo_ptr { | ||
| 205 | struct cyttsp4_cydata *cydata; | ||
| 206 | struct cyttsp4_test *test; | ||
| 207 | struct cyttsp4_pcfg *pcfg; | ||
| 208 | struct cyttsp4_opcfg *opcfg; | ||
| 209 | struct cyttsp4_ddata *ddata; | ||
| 210 | struct cyttsp4_mdata *mdata; | ||
| 211 | } __packed; | ||
| 212 | |||
| 213 | struct cyttsp4_sysinfo_data { | ||
| 214 | u8 hst_mode; | ||
| 215 | u8 reserved; | ||
| 216 | u8 map_szh; | ||
| 217 | u8 map_szl; | ||
| 218 | u8 cydata_ofsh; | ||
| 219 | u8 cydata_ofsl; | ||
| 220 | u8 test_ofsh; | ||
| 221 | u8 test_ofsl; | ||
| 222 | u8 pcfg_ofsh; | ||
| 223 | u8 pcfg_ofsl; | ||
| 224 | u8 opcfg_ofsh; | ||
| 225 | u8 opcfg_ofsl; | ||
| 226 | u8 ddata_ofsh; | ||
| 227 | u8 ddata_ofsl; | ||
| 228 | u8 mdata_ofsh; | ||
| 229 | u8 mdata_ofsl; | ||
| 230 | } __packed; | ||
| 231 | |||
| 232 | enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */ | ||
| 233 | CY_TCH_X, /* X */ | ||
| 234 | CY_TCH_Y, /* Y */ | ||
| 235 | CY_TCH_P, /* P (Z) */ | ||
| 236 | CY_TCH_T, /* TOUCH ID */ | ||
| 237 | CY_TCH_E, /* EVENT ID */ | ||
| 238 | CY_TCH_O, /* OBJECT ID */ | ||
| 239 | CY_TCH_W, /* SIZE */ | ||
| 240 | CY_TCH_MAJ, /* TOUCH_MAJOR */ | ||
| 241 | CY_TCH_MIN, /* TOUCH_MINOR */ | ||
| 242 | CY_TCH_OR, /* ORIENTATION */ | ||
| 243 | CY_TCH_NUM_ABS | ||
| 244 | }; | ||
| 245 | |||
| 246 | static const char * const cyttsp4_tch_abs_string[] = { | ||
| 247 | [CY_TCH_X] = "X", | ||
| 248 | [CY_TCH_Y] = "Y", | ||
| 249 | [CY_TCH_P] = "P", | ||
| 250 | [CY_TCH_T] = "T", | ||
| 251 | [CY_TCH_E] = "E", | ||
| 252 | [CY_TCH_O] = "O", | ||
| 253 | [CY_TCH_W] = "W", | ||
| 254 | [CY_TCH_MAJ] = "MAJ", | ||
| 255 | [CY_TCH_MIN] = "MIN", | ||
| 256 | [CY_TCH_OR] = "OR", | ||
| 257 | [CY_TCH_NUM_ABS] = "INVALID" | ||
| 258 | }; | ||
| 259 | |||
| 260 | struct cyttsp4_touch { | ||
| 261 | int abs[CY_TCH_NUM_ABS]; | ||
| 262 | }; | ||
| 263 | |||
| 264 | struct cyttsp4_tch_abs_params { | ||
| 265 | size_t ofs; /* abs byte offset */ | ||
| 266 | size_t size; /* size in bits */ | ||
| 267 | size_t max; /* max value */ | ||
| 268 | size_t bofs; /* bit offset */ | ||
| 269 | }; | ||
| 270 | |||
| 271 | struct cyttsp4_sysinfo_ofs { | ||
| 272 | size_t chip_type; | ||
| 273 | size_t cmd_ofs; | ||
| 274 | size_t rep_ofs; | ||
| 275 | size_t rep_sz; | ||
| 276 | size_t num_btns; | ||
| 277 | size_t num_btn_regs; /* ceil(num_btns/4) */ | ||
| 278 | size_t tt_stat_ofs; | ||
| 279 | size_t tch_rec_size; | ||
| 280 | size_t obj_cfg0; | ||
| 281 | size_t max_tchs; | ||
| 282 | size_t mode_size; | ||
| 283 | size_t data_size; | ||
| 284 | size_t map_sz; | ||
| 285 | size_t max_x; | ||
| 286 | size_t x_origin; /* left or right corner */ | ||
| 287 | size_t max_y; | ||
| 288 | size_t y_origin; /* upper or lower corner */ | ||
| 289 | size_t max_p; | ||
| 290 | size_t cydata_ofs; | ||
| 291 | size_t test_ofs; | ||
| 292 | size_t pcfg_ofs; | ||
| 293 | size_t opcfg_ofs; | ||
| 294 | size_t ddata_ofs; | ||
| 295 | size_t mdata_ofs; | ||
| 296 | size_t cydata_size; | ||
| 297 | size_t test_size; | ||
| 298 | size_t pcfg_size; | ||
| 299 | size_t opcfg_size; | ||
| 300 | size_t ddata_size; | ||
| 301 | size_t mdata_size; | ||
| 302 | size_t btn_keys_size; | ||
| 303 | struct cyttsp4_tch_abs_params tch_abs[CY_TCH_NUM_ABS]; | ||
| 304 | size_t btn_rec_size; /* btn record size (in bytes) */ | ||
| 305 | size_t btn_diff_ofs;/* btn data loc ,diff counts, (Op-Mode byte ofs) */ | ||
| 306 | size_t btn_diff_size;/* btn size of diff counts (in bits) */ | ||
| 307 | }; | ||
| 308 | |||
| 309 | enum cyttsp4_btn_state { | ||
| 310 | CY_BTN_RELEASED, | ||
| 311 | CY_BTN_PRESSED, | ||
| 312 | CY_BTN_NUM_STATE | ||
| 313 | }; | ||
| 314 | |||
| 315 | struct cyttsp4_btn { | ||
| 316 | bool enabled; | ||
| 317 | int state; /* CY_BTN_PRESSED, CY_BTN_RELEASED */ | ||
| 318 | int key_code; | ||
| 319 | }; | ||
| 320 | |||
| 321 | struct cyttsp4_sysinfo { | ||
| 322 | bool ready; | ||
| 323 | struct cyttsp4_sysinfo_data si_data; | ||
| 324 | struct cyttsp4_sysinfo_ptr si_ptrs; | ||
| 325 | struct cyttsp4_sysinfo_ofs si_ofs; | ||
| 326 | struct cyttsp4_btn *btn; /* button states */ | ||
| 327 | u8 *btn_rec_data; /* button diff count data */ | ||
| 328 | u8 *xy_mode; /* operational mode and status regs */ | ||
| 329 | u8 *xy_data; /* operational touch regs */ | ||
| 330 | }; | ||
| 331 | |||
| 332 | struct cyttsp4_mt_data { | ||
| 333 | struct cyttsp4_mt_platform_data *pdata; | ||
| 334 | struct cyttsp4_sysinfo *si; | ||
| 335 | struct input_dev *input; | ||
| 336 | struct mutex report_lock; | ||
| 337 | bool is_suspended; | ||
| 338 | char phys[NAME_MAX]; | ||
| 339 | int num_prv_tch; | ||
| 340 | }; | ||
| 341 | |||
| 342 | struct cyttsp4 { | ||
| 343 | struct device *dev; | ||
| 344 | struct mutex system_lock; | ||
| 345 | struct mutex adap_lock; | ||
| 346 | enum cyttsp4_mode mode; | ||
| 347 | enum cyttsp4_sleep_state sleep_state; | ||
| 348 | enum cyttsp4_startup_state startup_state; | ||
| 349 | int int_status; | ||
| 350 | wait_queue_head_t wait_q; | ||
| 351 | int irq; | ||
| 352 | struct work_struct startup_work; | ||
| 353 | struct work_struct watchdog_work; | ||
| 354 | struct timer_list watchdog_timer; | ||
| 355 | struct cyttsp4_sysinfo sysinfo; | ||
| 356 | void *exclusive_dev; | ||
| 357 | int exclusive_waits; | ||
| 358 | atomic_t ignore_irq; | ||
| 359 | bool invalid_touch_app; | ||
| 360 | struct cyttsp4_mt_data md; | ||
| 361 | struct cyttsp4_platform_data *pdata; | ||
| 362 | struct cyttsp4_core_platform_data *cpdata; | ||
| 363 | const struct cyttsp4_bus_ops *bus_ops; | ||
| 364 | u8 *xfer_buf; | ||
| 365 | #ifdef VERBOSE_DEBUG | ||
| 366 | u8 pr_buf[CY_MAX_PRBUF_SIZE]; | ||
| 367 | #endif | ||
| 368 | }; | ||
| 369 | |||
| 370 | struct cyttsp4_bus_ops { | ||
| 371 | u16 bustype; | ||
| 372 | int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, | ||
| 373 | const void *values); | ||
| 374 | int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, | ||
| 375 | void *values); | ||
| 376 | }; | ||
| 377 | |||
| 378 | enum cyttsp4_hst_mode_bits { | ||
| 379 | CY_HST_TOGGLE = (1 << 7), | ||
| 380 | CY_HST_MODE_CHANGE = (1 << 3), | ||
| 381 | CY_HST_MODE = (7 << 4), | ||
| 382 | CY_HST_OPERATE = (0 << 4), | ||
| 383 | CY_HST_SYSINFO = (1 << 4), | ||
| 384 | CY_HST_CAT = (2 << 4), | ||
| 385 | CY_HST_LOWPOW = (1 << 2), | ||
| 386 | CY_HST_SLEEP = (1 << 1), | ||
| 387 | CY_HST_RESET = (1 << 0), | ||
| 388 | }; | ||
| 389 | |||
| 390 | /* abs settings */ | ||
| 391 | #define CY_IGNORE_VALUE 0xFFFF | ||
| 392 | |||
| 393 | /* abs signal capabilities offsets in the frameworks array */ | ||
| 394 | enum cyttsp4_sig_caps { | ||
| 395 | CY_SIGNAL_OST, | ||
| 396 | CY_MIN_OST, | ||
| 397 | CY_MAX_OST, | ||
| 398 | CY_FUZZ_OST, | ||
| 399 | CY_FLAT_OST, | ||
| 400 | CY_NUM_ABS_SET /* number of signal capability fields */ | ||
| 401 | }; | ||
| 402 | |||
| 403 | /* abs axis signal offsets in the framworks array */ | ||
| 404 | enum cyttsp4_sig_ost { | ||
| 405 | CY_ABS_X_OST, | ||
| 406 | CY_ABS_Y_OST, | ||
| 407 | CY_ABS_P_OST, | ||
| 408 | CY_ABS_W_OST, | ||
| 409 | CY_ABS_ID_OST, | ||
| 410 | CY_ABS_MAJ_OST, | ||
| 411 | CY_ABS_MIN_OST, | ||
| 412 | CY_ABS_OR_OST, | ||
| 413 | CY_NUM_ABS_OST /* number of abs signals */ | ||
| 414 | }; | ||
| 415 | |||
| 416 | enum cyttsp4_flags { | ||
| 417 | CY_FLAG_NONE = 0x00, | ||
| 418 | CY_FLAG_HOVER = 0x04, | ||
| 419 | CY_FLAG_FLIP = 0x08, | ||
| 420 | CY_FLAG_INV_X = 0x10, | ||
| 421 | CY_FLAG_INV_Y = 0x20, | ||
| 422 | CY_FLAG_VKEYS = 0x40, | ||
| 423 | }; | ||
| 424 | |||
| 425 | enum cyttsp4_object_id { | ||
| 426 | CY_OBJ_STANDARD_FINGER, | ||
| 427 | CY_OBJ_LARGE_OBJECT, | ||
| 428 | CY_OBJ_STYLUS, | ||
| 429 | CY_OBJ_HOVER, | ||
| 430 | }; | ||
| 431 | |||
| 432 | enum cyttsp4_event_id { | ||
| 433 | CY_EV_NO_EVENT, | ||
| 434 | CY_EV_TOUCHDOWN, | ||
| 435 | CY_EV_MOVE, /* significant displacement (> act dist) */ | ||
| 436 | CY_EV_LIFTOFF, /* record reports last position */ | ||
| 437 | }; | ||
| 438 | |||
| 439 | /* x-axis resolution of panel in pixels */ | ||
| 440 | #define CY_PCFG_RESOLUTION_X_MASK 0x7F | ||
| 441 | |||
| 442 | /* y-axis resolution of panel in pixels */ | ||
| 443 | #define CY_PCFG_RESOLUTION_Y_MASK 0x7F | ||
| 444 | |||
| 445 | /* x-axis, 0:origin is on left side of panel, 1: right */ | ||
| 446 | #define CY_PCFG_ORIGIN_X_MASK 0x80 | ||
| 447 | |||
| 448 | /* y-axis, 0:origin is on top side of panel, 1: bottom */ | ||
| 449 | #define CY_PCFG_ORIGIN_Y_MASK 0x80 | ||
| 450 | |||
| 451 | static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u8 addr, int size, | ||
| 452 | void *buf) | ||
| 453 | { | ||
| 454 | return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf); | ||
| 455 | } | ||
| 456 | |||
| 457 | static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size, | ||
| 458 | const void *buf) | ||
| 459 | { | ||
| 460 | return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf); | ||
| 461 | } | ||
| 462 | |||
| 463 | extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops, | ||
| 464 | struct device *dev, u16 irq, size_t xfer_buf_size); | ||
| 465 | extern int cyttsp4_remove(struct cyttsp4 *ts); | ||
| 466 | int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
| 467 | u8 length, const void *values); | ||
| 468 | int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
| 469 | u8 length, void *values); | ||
| 470 | extern const struct dev_pm_ops cyttsp4_pm_ops; | ||
| 471 | |||
| 472 | #endif /* _LINUX_CYTTSP4_CORE_H */ | ||
diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c new file mode 100644 index 000000000000..8e2012c79058 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_i2c.c | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | /* | ||
| 2 | * cyttsp_i2c.c | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. | ||
| 4 | * For use with Cypress Txx4xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * TMA4XX | ||
| 7 | * TMA1036 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 11 | * Copyright (C) 2013 Cypress Semiconductor | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or | ||
| 14 | * modify it under the terms of the GNU General Public License | ||
| 15 | * version 2, and only version 2, as published by the | ||
| 16 | * Free Software Foundation. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include "cyttsp4_core.h" | ||
| 28 | |||
| 29 | #include <linux/i2c.h> | ||
| 30 | #include <linux/input.h> | ||
| 31 | |||
| 32 | #define CYTTSP4_I2C_DATA_SIZE (3 * 256) | ||
| 33 | |||
| 34 | static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = { | ||
| 35 | .bustype = BUS_I2C, | ||
| 36 | .write = cyttsp_i2c_write_block_data, | ||
| 37 | .read = cyttsp_i2c_read_block_data, | ||
| 38 | }; | ||
| 39 | |||
| 40 | static int cyttsp4_i2c_probe(struct i2c_client *client, | ||
| 41 | const struct i2c_device_id *id) | ||
| 42 | { | ||
| 43 | struct cyttsp4 *ts; | ||
| 44 | |||
| 45 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
| 46 | dev_err(&client->dev, "I2C functionality not Supported\n"); | ||
| 47 | return -EIO; | ||
| 48 | } | ||
| 49 | |||
| 50 | ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq, | ||
| 51 | CYTTSP4_I2C_DATA_SIZE); | ||
| 52 | |||
| 53 | if (IS_ERR(ts)) | ||
| 54 | return PTR_ERR(ts); | ||
| 55 | |||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static int cyttsp4_i2c_remove(struct i2c_client *client) | ||
| 60 | { | ||
| 61 | struct cyttsp4 *ts = i2c_get_clientdata(client); | ||
| 62 | |||
| 63 | cyttsp4_remove(ts); | ||
| 64 | |||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | static const struct i2c_device_id cyttsp4_i2c_id[] = { | ||
| 69 | { CYTTSP4_I2C_NAME, 0 }, | ||
| 70 | { } | ||
| 71 | }; | ||
| 72 | MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id); | ||
| 73 | |||
| 74 | static struct i2c_driver cyttsp4_i2c_driver = { | ||
| 75 | .driver = { | ||
| 76 | .name = CYTTSP4_I2C_NAME, | ||
| 77 | .owner = THIS_MODULE, | ||
| 78 | .pm = &cyttsp4_pm_ops, | ||
| 79 | }, | ||
| 80 | .probe = cyttsp4_i2c_probe, | ||
| 81 | .remove = cyttsp4_i2c_remove, | ||
| 82 | .id_table = cyttsp4_i2c_id, | ||
| 83 | }; | ||
| 84 | |||
| 85 | module_i2c_driver(cyttsp4_i2c_driver); | ||
| 86 | |||
| 87 | MODULE_LICENSE("GPL"); | ||
| 88 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"); | ||
| 89 | MODULE_AUTHOR("Cypress"); | ||
| 90 | MODULE_ALIAS("i2c:cyttsp4"); | ||
diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c new file mode 100644 index 000000000000..f8f891bead34 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp4_spi.c | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | * Source for: | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver. | ||
| 4 | * For use with Cypress Txx4xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * TMA4XX | ||
| 7 | * TMA1036 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 11 | * Copyright (C) 2013 Cypress Semiconductor | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or | ||
| 14 | * modify it under the terms of the GNU General Public License | ||
| 15 | * version 2, and only version 2, as published by the | ||
| 16 | * Free Software Foundation. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include "cyttsp4_core.h" | ||
| 28 | |||
| 29 | #include <linux/delay.h> | ||
| 30 | #include <linux/input.h> | ||
| 31 | #include <linux/spi/spi.h> | ||
| 32 | |||
| 33 | #define CY_SPI_WR_OP 0x00 /* r/~w */ | ||
| 34 | #define CY_SPI_RD_OP 0x01 | ||
| 35 | #define CY_SPI_BITS_PER_WORD 8 | ||
| 36 | #define CY_SPI_A8_BIT 0x02 | ||
| 37 | #define CY_SPI_WR_HEADER_BYTES 2 | ||
| 38 | #define CY_SPI_RD_HEADER_BYTES 1 | ||
| 39 | #define CY_SPI_CMD_BYTES 2 | ||
| 40 | #define CY_SPI_SYNC_BYTE 0 | ||
| 41 | #define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */ | ||
| 42 | #define CY_SPI_DATA_SIZE (2 * 256) | ||
| 43 | |||
| 44 | #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) | ||
| 45 | |||
| 46 | static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, | ||
| 47 | u8 op, u8 reg, u8 *buf, int length) | ||
| 48 | { | ||
| 49 | struct spi_device *spi = to_spi_device(dev); | ||
| 50 | struct spi_message msg; | ||
| 51 | struct spi_transfer xfer[2]; | ||
| 52 | u8 *wr_buf = &xfer_buf[0]; | ||
| 53 | u8 rd_buf[CY_SPI_CMD_BYTES]; | ||
| 54 | int retval; | ||
| 55 | int i; | ||
| 56 | |||
| 57 | if (length > CY_SPI_DATA_SIZE) { | ||
| 58 | dev_err(dev, "%s: length %d is too big.\n", | ||
| 59 | __func__, length); | ||
| 60 | return -EINVAL; | ||
| 61 | } | ||
| 62 | |||
| 63 | memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE); | ||
| 64 | memset(rd_buf, 0, CY_SPI_CMD_BYTES); | ||
| 65 | |||
| 66 | if (reg > 255) | ||
| 67 | wr_buf[0] = op + CY_SPI_A8_BIT; | ||
| 68 | else | ||
| 69 | wr_buf[0] = op; | ||
| 70 | if (op == CY_SPI_WR_OP) | ||
| 71 | wr_buf[1] = reg % 256; | ||
| 72 | if (op == CY_SPI_WR_OP && length > 0) | ||
| 73 | memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); | ||
| 74 | |||
| 75 | memset(xfer, 0, sizeof(xfer)); | ||
| 76 | spi_message_init(&msg); | ||
| 77 | |||
| 78 | /* | ||
| 79 | We set both TX and RX buffers because Cypress TTSP | ||
| 80 | requires full duplex operation. | ||
| 81 | */ | ||
| 82 | xfer[0].tx_buf = wr_buf; | ||
| 83 | xfer[0].rx_buf = rd_buf; | ||
| 84 | switch (op) { | ||
| 85 | case CY_SPI_WR_OP: | ||
| 86 | xfer[0].len = length + CY_SPI_CMD_BYTES; | ||
| 87 | spi_message_add_tail(&xfer[0], &msg); | ||
| 88 | break; | ||
| 89 | |||
| 90 | case CY_SPI_RD_OP: | ||
| 91 | xfer[0].len = CY_SPI_RD_HEADER_BYTES; | ||
| 92 | spi_message_add_tail(&xfer[0], &msg); | ||
| 93 | |||
| 94 | xfer[1].rx_buf = buf; | ||
| 95 | xfer[1].len = length; | ||
| 96 | spi_message_add_tail(&xfer[1], &msg); | ||
| 97 | break; | ||
| 98 | |||
| 99 | default: | ||
| 100 | dev_err(dev, "%s: bad operation code=%d\n", __func__, op); | ||
| 101 | return -EINVAL; | ||
| 102 | } | ||
| 103 | |||
| 104 | retval = spi_sync(spi, &msg); | ||
| 105 | if (retval < 0) { | ||
| 106 | dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n", | ||
| 107 | __func__, retval, xfer[1].len, op); | ||
| 108 | |||
| 109 | /* | ||
| 110 | * do not return here since was a bad ACK sequence | ||
| 111 | * let the following ACK check handle any errors and | ||
| 112 | * allow silent retries | ||
| 113 | */ | ||
| 114 | } | ||
| 115 | |||
| 116 | if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) { | ||
| 117 | dev_dbg(dev, "%s: operation %d failed\n", __func__, op); | ||
| 118 | |||
| 119 | for (i = 0; i < CY_SPI_CMD_BYTES; i++) | ||
| 120 | dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n", | ||
| 121 | __func__, i, rd_buf[i]); | ||
| 122 | for (i = 0; i < length; i++) | ||
| 123 | dev_dbg(dev, "%s: test buf[%d]:0x%02x\n", | ||
| 124 | __func__, i, buf[i]); | ||
| 125 | |||
| 126 | return -EIO; | ||
| 127 | } | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf, | ||
| 133 | u8 addr, u8 length, void *data) | ||
| 134 | { | ||
| 135 | int rc; | ||
| 136 | |||
| 137 | rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0); | ||
| 138 | if (rc) | ||
| 139 | return rc; | ||
| 140 | else | ||
| 141 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data, | ||
| 142 | length); | ||
| 143 | } | ||
| 144 | |||
| 145 | static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf, | ||
| 146 | u8 addr, u8 length, const void *data) | ||
| 147 | { | ||
| 148 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data, | ||
| 149 | length); | ||
| 150 | } | ||
| 151 | |||
| 152 | static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = { | ||
| 153 | .bustype = BUS_SPI, | ||
| 154 | .write = cyttsp_spi_write_block_data, | ||
| 155 | .read = cyttsp_spi_read_block_data, | ||
| 156 | }; | ||
| 157 | |||
| 158 | static int cyttsp4_spi_probe(struct spi_device *spi) | ||
| 159 | { | ||
| 160 | struct cyttsp4 *ts; | ||
| 161 | int error; | ||
| 162 | |||
| 163 | /* Set up SPI*/ | ||
| 164 | spi->bits_per_word = CY_SPI_BITS_PER_WORD; | ||
| 165 | spi->mode = SPI_MODE_0; | ||
| 166 | error = spi_setup(spi); | ||
| 167 | if (error < 0) { | ||
| 168 | dev_err(&spi->dev, "%s: SPI setup error %d\n", | ||
| 169 | __func__, error); | ||
| 170 | return error; | ||
| 171 | } | ||
| 172 | |||
| 173 | ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq, | ||
| 174 | CY_SPI_DATA_BUF_SIZE); | ||
| 175 | |||
| 176 | if (IS_ERR(ts)) | ||
| 177 | return PTR_ERR(ts); | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static int cyttsp4_spi_remove(struct spi_device *spi) | ||
| 183 | { | ||
| 184 | struct cyttsp4 *ts = spi_get_drvdata(spi); | ||
| 185 | cyttsp4_remove(ts); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static struct spi_driver cyttsp4_spi_driver = { | ||
| 191 | .driver = { | ||
| 192 | .name = CYTTSP4_SPI_NAME, | ||
| 193 | .owner = THIS_MODULE, | ||
| 194 | .pm = &cyttsp4_pm_ops, | ||
| 195 | }, | ||
| 196 | .probe = cyttsp4_spi_probe, | ||
| 197 | .remove = cyttsp4_spi_remove, | ||
| 198 | }; | ||
| 199 | |||
| 200 | module_spi_driver(cyttsp4_spi_driver); | ||
| 201 | |||
| 202 | MODULE_LICENSE("GPL"); | ||
| 203 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver"); | ||
| 204 | MODULE_AUTHOR("Cypress"); | ||
| 205 | MODULE_ALIAS("spi:cyttsp4"); | ||
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index ae89d2609ab0..d53e0b72a407 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c | |||
| @@ -84,7 +84,8 @@ static int ttsp_read_block_data(struct cyttsp *ts, u8 command, | |||
| 84 | int tries; | 84 | int tries; |
| 85 | 85 | ||
| 86 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { | 86 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { |
| 87 | error = ts->bus_ops->read(ts, command, length, buf); | 87 | error = ts->bus_ops->read(ts->dev, ts->xfer_buf, command, |
| 88 | length, buf); | ||
| 88 | if (!error) | 89 | if (!error) |
| 89 | return 0; | 90 | return 0; |
| 90 | 91 | ||
| @@ -101,7 +102,8 @@ static int ttsp_write_block_data(struct cyttsp *ts, u8 command, | |||
| 101 | int tries; | 102 | int tries; |
| 102 | 103 | ||
| 103 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { | 104 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { |
| 104 | error = ts->bus_ops->write(ts, command, length, buf); | 105 | error = ts->bus_ops->write(ts->dev, ts->xfer_buf, command, |
| 106 | length, buf); | ||
| 105 | if (!error) | 107 | if (!error) |
| 106 | return 0; | 108 | return 0; |
| 107 | 109 | ||
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h index f1ebde369f86..0cf564a79fb5 100644 --- a/drivers/input/touchscreen/cyttsp_core.h +++ b/drivers/input/touchscreen/cyttsp_core.h | |||
| @@ -112,9 +112,10 @@ struct cyttsp; | |||
| 112 | 112 | ||
| 113 | struct cyttsp_bus_ops { | 113 | struct cyttsp_bus_ops { |
| 114 | u16 bustype; | 114 | u16 bustype; |
| 115 | int (*write)(struct cyttsp *ts, | 115 | int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, |
| 116 | u8 addr, u8 length, const void *values); | 116 | const void *values); |
| 117 | int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values); | 117 | int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length, |
| 118 | void *values); | ||
| 118 | }; | 119 | }; |
| 119 | 120 | ||
| 120 | enum cyttsp_state { | 121 | enum cyttsp_state { |
| @@ -144,6 +145,10 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, | |||
| 144 | struct device *dev, int irq, size_t xfer_buf_size); | 145 | struct device *dev, int irq, size_t xfer_buf_size); |
| 145 | void cyttsp_remove(struct cyttsp *ts); | 146 | void cyttsp_remove(struct cyttsp *ts); |
| 146 | 147 | ||
| 148 | int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
| 149 | u8 length, const void *values); | ||
| 150 | int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr, | ||
| 151 | u8 length, void *values); | ||
| 147 | extern const struct dev_pm_ops cyttsp_pm_ops; | 152 | extern const struct dev_pm_ops cyttsp_pm_ops; |
| 148 | 153 | ||
| 149 | #endif /* __CYTTSP_CORE_H__ */ | 154 | #endif /* __CYTTSP_CORE_H__ */ |
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 4dbdf44b8fc5..63104a86a9bd 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Source for: | 2 | * cyttsp_i2c.c |
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. | 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. |
| 4 | * For use with Cypress Txx3xx parts. | 4 | * For use with Cypress Txx3xx parts. |
| 5 | * Supported parts include: | 5 | * Supported parts include: |
| @@ -19,11 +19,7 @@ | |||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
| 21 | * | 21 | * |
| 22 | * You should have received a copy of the GNU General Public License along | 22 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> |
| 23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 24 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 25 | * | ||
| 26 | * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> | ||
| 27 | * | 23 | * |
| 28 | */ | 24 | */ |
| 29 | 25 | ||
| @@ -34,47 +30,6 @@ | |||
| 34 | 30 | ||
| 35 | #define CY_I2C_DATA_SIZE 128 | 31 | #define CY_I2C_DATA_SIZE 128 |
| 36 | 32 | ||
| 37 | static int cyttsp_i2c_read_block_data(struct cyttsp *ts, | ||
| 38 | u8 addr, u8 length, void *values) | ||
| 39 | { | ||
| 40 | struct i2c_client *client = to_i2c_client(ts->dev); | ||
| 41 | struct i2c_msg msgs[] = { | ||
| 42 | { | ||
| 43 | .addr = client->addr, | ||
| 44 | .flags = 0, | ||
| 45 | .len = 1, | ||
| 46 | .buf = &addr, | ||
| 47 | }, | ||
| 48 | { | ||
| 49 | .addr = client->addr, | ||
| 50 | .flags = I2C_M_RD, | ||
| 51 | .len = length, | ||
| 52 | .buf = values, | ||
| 53 | }, | ||
| 54 | }; | ||
| 55 | int retval; | ||
| 56 | |||
| 57 | retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
| 58 | if (retval < 0) | ||
| 59 | return retval; | ||
| 60 | |||
| 61 | return retval != ARRAY_SIZE(msgs) ? -EIO : 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | static int cyttsp_i2c_write_block_data(struct cyttsp *ts, | ||
| 65 | u8 addr, u8 length, const void *values) | ||
| 66 | { | ||
| 67 | struct i2c_client *client = to_i2c_client(ts->dev); | ||
| 68 | int retval; | ||
| 69 | |||
| 70 | ts->xfer_buf[0] = addr; | ||
| 71 | memcpy(&ts->xfer_buf[1], values, length); | ||
| 72 | |||
| 73 | retval = i2c_master_send(client, ts->xfer_buf, length + 1); | ||
| 74 | |||
| 75 | return retval < 0 ? retval : 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { | 33 | static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { |
| 79 | .bustype = BUS_I2C, | 34 | .bustype = BUS_I2C, |
| 80 | .write = cyttsp_i2c_write_block_data, | 35 | .write = cyttsp_i2c_write_block_data, |
| @@ -98,7 +53,6 @@ static int cyttsp_i2c_probe(struct i2c_client *client, | |||
| 98 | return PTR_ERR(ts); | 53 | return PTR_ERR(ts); |
| 99 | 54 | ||
| 100 | i2c_set_clientdata(client, ts); | 55 | i2c_set_clientdata(client, ts); |
| 101 | |||
| 102 | return 0; | 56 | return 0; |
| 103 | } | 57 | } |
| 104 | 58 | ||
diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c new file mode 100644 index 000000000000..07c553fbcef2 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp_i2c_common.c | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* | ||
| 2 | * cyttsp_i2c_common.c | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. | ||
| 4 | * For use with Cypress Txx3xx and Txx4xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * CY8CTST341 | ||
| 7 | * CY8CTMA340 | ||
| 8 | * TMA4XX | ||
| 9 | * TMA1036 | ||
| 10 | * | ||
| 11 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 12 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or | ||
| 15 | * modify it under the terms of the GNU General Public License | ||
| 16 | * version 2, and only version 2, as published by the | ||
| 17 | * Free Software Foundation. | ||
| 18 | * | ||
| 19 | * This program is distributed in the hope that it will be useful, | ||
| 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 22 | * GNU General Public License for more details. | ||
| 23 | * | ||
| 24 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/export.h> | ||
| 30 | #include <linux/i2c.h> | ||
| 31 | #include <linux/module.h> | ||
| 32 | #include <linux/types.h> | ||
| 33 | |||
| 34 | int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, | ||
| 35 | u8 addr, u8 length, void *values) | ||
| 36 | { | ||
| 37 | struct i2c_client *client = to_i2c_client(dev); | ||
| 38 | struct i2c_msg msgs[] = { | ||
| 39 | { | ||
| 40 | .addr = client->addr, | ||
| 41 | .flags = 0, | ||
| 42 | .len = 1, | ||
| 43 | .buf = &addr, | ||
| 44 | }, | ||
| 45 | { | ||
| 46 | .addr = client->addr, | ||
| 47 | .flags = I2C_M_RD, | ||
| 48 | .len = length, | ||
| 49 | .buf = values, | ||
| 50 | }, | ||
| 51 | }; | ||
| 52 | int retval; | ||
| 53 | |||
| 54 | retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
| 55 | if (retval < 0) | ||
| 56 | return retval; | ||
| 57 | |||
| 58 | return retval != ARRAY_SIZE(msgs) ? -EIO : 0; | ||
| 59 | } | ||
| 60 | EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data); | ||
| 61 | |||
| 62 | int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, | ||
| 63 | u8 addr, u8 length, const void *values) | ||
| 64 | { | ||
| 65 | struct i2c_client *client = to_i2c_client(dev); | ||
| 66 | int retval; | ||
| 67 | |||
| 68 | xfer_buf[0] = addr; | ||
| 69 | memcpy(&xfer_buf[1], values, length); | ||
| 70 | |||
| 71 | retval = i2c_master_send(client, xfer_buf, length + 1); | ||
| 72 | |||
| 73 | return retval < 0 ? retval : 0; | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data); | ||
| 76 | |||
| 77 | |||
| 78 | MODULE_LICENSE("GPL"); | ||
| 79 | MODULE_AUTHOR("Cypress"); | ||
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c index 861b7f77605b..1df625337b84 100644 --- a/drivers/input/touchscreen/cyttsp_spi.c +++ b/drivers/input/touchscreen/cyttsp_spi.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | * | 8 | * |
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. |
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> |
| 11 | * Copyright (C) 2013 Cypress Semiconductor | ||
| 11 | * | 12 | * |
| 12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
| @@ -19,11 +20,7 @@ | |||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
| 21 | * | 22 | * |
| 22 | * You should have received a copy of the GNU General Public License along | 23 | * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> |
| 23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 24 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 25 | * | ||
| 26 | * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> | ||
| 27 | * | 24 | * |
| 28 | */ | 25 | */ |
| 29 | 26 | ||
| @@ -43,19 +40,19 @@ | |||
| 43 | #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) | 40 | #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) |
| 44 | #define CY_SPI_BITS_PER_WORD 8 | 41 | #define CY_SPI_BITS_PER_WORD 8 |
| 45 | 42 | ||
| 46 | static int cyttsp_spi_xfer(struct cyttsp *ts, | 43 | static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, |
| 47 | u8 op, u8 reg, u8 *buf, int length) | 44 | u8 op, u8 reg, u8 *buf, int length) |
| 48 | { | 45 | { |
| 49 | struct spi_device *spi = to_spi_device(ts->dev); | 46 | struct spi_device *spi = to_spi_device(dev); |
| 50 | struct spi_message msg; | 47 | struct spi_message msg; |
| 51 | struct spi_transfer xfer[2]; | 48 | struct spi_transfer xfer[2]; |
| 52 | u8 *wr_buf = &ts->xfer_buf[0]; | 49 | u8 *wr_buf = &xfer_buf[0]; |
| 53 | u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE]; | 50 | u8 *rd_buf = &xfer_buf[CY_SPI_DATA_BUF_SIZE]; |
| 54 | int retval; | 51 | int retval; |
| 55 | int i; | 52 | int i; |
| 56 | 53 | ||
| 57 | if (length > CY_SPI_DATA_SIZE) { | 54 | if (length > CY_SPI_DATA_SIZE) { |
| 58 | dev_err(ts->dev, "%s: length %d is too big.\n", | 55 | dev_err(dev, "%s: length %d is too big.\n", |
| 59 | __func__, length); | 56 | __func__, length); |
| 60 | return -EINVAL; | 57 | return -EINVAL; |
| 61 | } | 58 | } |
| @@ -95,13 +92,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts, | |||
| 95 | break; | 92 | break; |
| 96 | 93 | ||
| 97 | default: | 94 | default: |
| 98 | dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op); | 95 | dev_err(dev, "%s: bad operation code=%d\n", __func__, op); |
| 99 | return -EINVAL; | 96 | return -EINVAL; |
| 100 | } | 97 | } |
| 101 | 98 | ||
| 102 | retval = spi_sync(spi, &msg); | 99 | retval = spi_sync(spi, &msg); |
| 103 | if (retval < 0) { | 100 | if (retval < 0) { |
| 104 | dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n", | 101 | dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n", |
| 105 | __func__, retval, xfer[1].len, op); | 102 | __func__, retval, xfer[1].len, op); |
| 106 | 103 | ||
| 107 | /* | 104 | /* |
| @@ -113,14 +110,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts, | |||
| 113 | 110 | ||
| 114 | if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 || | 111 | if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 || |
| 115 | rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) { | 112 | rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) { |
| 116 | 113 | dev_dbg(dev, "%s: operation %d failed\n", __func__, op); | |
| 117 | dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op); | ||
| 118 | 114 | ||
| 119 | for (i = 0; i < CY_SPI_CMD_BYTES; i++) | 115 | for (i = 0; i < CY_SPI_CMD_BYTES; i++) |
| 120 | dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n", | 116 | dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n", |
| 121 | __func__, i, rd_buf[i]); | 117 | __func__, i, rd_buf[i]); |
| 122 | for (i = 0; i < length; i++) | 118 | for (i = 0; i < length; i++) |
| 123 | dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n", | 119 | dev_dbg(dev, "%s: test buf[%d]:0x%02x\n", |
| 124 | __func__, i, buf[i]); | 120 | __func__, i, buf[i]); |
| 125 | 121 | ||
| 126 | return -EIO; | 122 | return -EIO; |
| @@ -129,16 +125,18 @@ static int cyttsp_spi_xfer(struct cyttsp *ts, | |||
| 129 | return 0; | 125 | return 0; |
| 130 | } | 126 | } |
| 131 | 127 | ||
| 132 | static int cyttsp_spi_read_block_data(struct cyttsp *ts, | 128 | static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf, |
| 133 | u8 addr, u8 length, void *data) | 129 | u8 addr, u8 length, void *data) |
| 134 | { | 130 | { |
| 135 | return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length); | 131 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data, |
| 132 | length); | ||
| 136 | } | 133 | } |
| 137 | 134 | ||
| 138 | static int cyttsp_spi_write_block_data(struct cyttsp *ts, | 135 | static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf, |
| 139 | u8 addr, u8 length, const void *data) | 136 | u8 addr, u8 length, const void *data) |
| 140 | { | 137 | { |
| 141 | return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length); | 138 | return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data, |
| 139 | length); | ||
| 142 | } | 140 | } |
| 143 | 141 | ||
| 144 | static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = { | 142 | static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = { |
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index 8f561e22bdd4..ab64d58c3ac0 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c | |||
| @@ -329,8 +329,6 @@ static int da9052_ts_remove(struct platform_device *pdev) | |||
| 329 | input_unregister_device(tsi->dev); | 329 | input_unregister_device(tsi->dev); |
| 330 | kfree(tsi); | 330 | kfree(tsi); |
| 331 | 331 | ||
| 332 | platform_set_drvdata(pdev, NULL); | ||
| 333 | |||
| 334 | return 0; | 332 | return 0; |
| 335 | } | 333 | } |
| 336 | 334 | ||
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 39f3df8670c3..ef5fcb0945e9 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c | |||
| @@ -166,24 +166,22 @@ static int egalax_firmware_version(struct i2c_client *client) | |||
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | static int egalax_ts_probe(struct i2c_client *client, | 168 | static int egalax_ts_probe(struct i2c_client *client, |
| 169 | const struct i2c_device_id *id) | 169 | const struct i2c_device_id *id) |
| 170 | { | 170 | { |
| 171 | struct egalax_ts *ts; | 171 | struct egalax_ts *ts; |
| 172 | struct input_dev *input_dev; | 172 | struct input_dev *input_dev; |
| 173 | int ret; | ||
| 174 | int error; | 173 | int error; |
| 175 | 174 | ||
| 176 | ts = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL); | 175 | ts = devm_kzalloc(&client->dev, sizeof(struct egalax_ts), GFP_KERNEL); |
| 177 | if (!ts) { | 176 | if (!ts) { |
| 178 | dev_err(&client->dev, "Failed to allocate memory\n"); | 177 | dev_err(&client->dev, "Failed to allocate memory\n"); |
| 179 | return -ENOMEM; | 178 | return -ENOMEM; |
| 180 | } | 179 | } |
| 181 | 180 | ||
| 182 | input_dev = input_allocate_device(); | 181 | input_dev = devm_input_allocate_device(&client->dev); |
| 183 | if (!input_dev) { | 182 | if (!input_dev) { |
| 184 | dev_err(&client->dev, "Failed to allocate memory\n"); | 183 | dev_err(&client->dev, "Failed to allocate memory\n"); |
| 185 | error = -ENOMEM; | 184 | return -ENOMEM; |
| 186 | goto err_free_ts; | ||
| 187 | } | 185 | } |
| 188 | 186 | ||
| 189 | ts->client = client; | 187 | ts->client = client; |
| @@ -193,19 +191,17 @@ static int egalax_ts_probe(struct i2c_client *client, | |||
| 193 | error = egalax_wake_up_device(client); | 191 | error = egalax_wake_up_device(client); |
| 194 | if (error) { | 192 | if (error) { |
| 195 | dev_err(&client->dev, "Failed to wake up the controller\n"); | 193 | dev_err(&client->dev, "Failed to wake up the controller\n"); |
| 196 | goto err_free_dev; | 194 | return error; |
| 197 | } | 195 | } |
| 198 | 196 | ||
| 199 | ret = egalax_firmware_version(client); | 197 | error = egalax_firmware_version(client); |
| 200 | if (ret < 0) { | 198 | if (error < 0) { |
| 201 | dev_err(&client->dev, "Failed to read firmware version\n"); | 199 | dev_err(&client->dev, "Failed to read firmware version\n"); |
| 202 | error = -EIO; | 200 | return error; |
| 203 | goto err_free_dev; | ||
| 204 | } | 201 | } |
| 205 | 202 | ||
| 206 | input_dev->name = "EETI eGalax Touch Screen"; | 203 | input_dev->name = "EETI eGalax Touch Screen"; |
| 207 | input_dev->id.bustype = BUS_I2C; | 204 | input_dev->id.bustype = BUS_I2C; |
| 208 | input_dev->dev.parent = &client->dev; | ||
| 209 | 205 | ||
| 210 | __set_bit(EV_ABS, input_dev->evbit); | 206 | __set_bit(EV_ABS, input_dev->evbit); |
| 211 | __set_bit(EV_KEY, input_dev->evbit); | 207 | __set_bit(EV_KEY, input_dev->evbit); |
| @@ -221,41 +217,21 @@ static int egalax_ts_probe(struct i2c_client *client, | |||
| 221 | 217 | ||
| 222 | input_set_drvdata(input_dev, ts); | 218 | input_set_drvdata(input_dev, ts); |
| 223 | 219 | ||
| 224 | error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt, | 220 | error = devm_request_threaded_irq(&client->dev, client->irq, NULL, |
| 225 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 221 | egalax_ts_interrupt, |
| 226 | "egalax_ts", ts); | 222 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
| 223 | "egalax_ts", ts); | ||
| 227 | if (error < 0) { | 224 | if (error < 0) { |
| 228 | dev_err(&client->dev, "Failed to register interrupt\n"); | 225 | dev_err(&client->dev, "Failed to register interrupt\n"); |
| 229 | goto err_free_dev; | 226 | return error; |
| 230 | } | 227 | } |
| 231 | 228 | ||
| 232 | error = input_register_device(ts->input_dev); | 229 | error = input_register_device(ts->input_dev); |
| 233 | if (error) | 230 | if (error) |
| 234 | goto err_free_irq; | 231 | return error; |
| 235 | 232 | ||
| 236 | i2c_set_clientdata(client, ts); | 233 | i2c_set_clientdata(client, ts); |
| 237 | return 0; | 234 | return 0; |
| 238 | |||
| 239 | err_free_irq: | ||
| 240 | free_irq(client->irq, ts); | ||
| 241 | err_free_dev: | ||
| 242 | input_free_device(input_dev); | ||
| 243 | err_free_ts: | ||
| 244 | kfree(ts); | ||
| 245 | |||
| 246 | return error; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int egalax_ts_remove(struct i2c_client *client) | ||
| 250 | { | ||
| 251 | struct egalax_ts *ts = i2c_get_clientdata(client); | ||
| 252 | |||
| 253 | free_irq(client->irq, ts); | ||
| 254 | |||
| 255 | input_unregister_device(ts->input_dev); | ||
| 256 | kfree(ts); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | 235 | } |
| 260 | 236 | ||
| 261 | static const struct i2c_device_id egalax_ts_id[] = { | 237 | static const struct i2c_device_id egalax_ts_id[] = { |
| @@ -301,7 +277,6 @@ static struct i2c_driver egalax_ts_driver = { | |||
| 301 | }, | 277 | }, |
| 302 | .id_table = egalax_ts_id, | 278 | .id_table = egalax_ts_id, |
| 303 | .probe = egalax_ts_probe, | 279 | .probe = egalax_ts_probe, |
| 304 | .remove = egalax_ts_remove, | ||
| 305 | }; | 280 | }; |
| 306 | 281 | ||
| 307 | module_i2c_driver(egalax_ts_driver); | 282 | module_i2c_driver(egalax_ts_driver); |
diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index 465db5dba8b4..e30d837dae2f 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c | |||
| @@ -651,8 +651,6 @@ static int mrstouch_remove(struct platform_device *pdev) | |||
| 651 | input_unregister_device(tsdev->input); | 651 | input_unregister_device(tsdev->input); |
| 652 | kfree(tsdev); | 652 | kfree(tsdev); |
| 653 | 653 | ||
| 654 | platform_set_drvdata(pdev, NULL); | ||
| 655 | |||
| 656 | return 0; | 654 | return 0; |
| 657 | } | 655 | } |
| 658 | 656 | ||
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 282d7c7ad2fc..e463a79ffecc 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c | |||
| @@ -145,7 +145,6 @@ static int jornada720_ts_probe(struct platform_device *pdev) | |||
| 145 | fail2: | 145 | fail2: |
| 146 | free_irq(IRQ_GPIO9, pdev); | 146 | free_irq(IRQ_GPIO9, pdev); |
| 147 | fail1: | 147 | fail1: |
| 148 | platform_set_drvdata(pdev, NULL); | ||
| 149 | input_free_device(input_dev); | 148 | input_free_device(input_dev); |
| 150 | kfree(jornada_ts); | 149 | kfree(jornada_ts); |
| 151 | return error; | 150 | return error; |
| @@ -156,7 +155,6 @@ static int jornada720_ts_remove(struct platform_device *pdev) | |||
| 156 | struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); | 155 | struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); |
| 157 | 156 | ||
| 158 | free_irq(IRQ_GPIO9, pdev); | 157 | free_irq(IRQ_GPIO9, pdev); |
| 159 | platform_set_drvdata(pdev, NULL); | ||
| 160 | input_unregister_device(jornada_ts->dev); | 158 | input_unregister_device(jornada_ts->dev); |
| 161 | kfree(jornada_ts); | 159 | kfree(jornada_ts); |
| 162 | 160 | ||
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index 89308fe38752..d6f099c47f84 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c | |||
| @@ -233,8 +233,6 @@ static int mc13783_ts_remove(struct platform_device *pdev) | |||
| 233 | { | 233 | { |
| 234 | struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); | 234 | struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); |
| 235 | 235 | ||
| 236 | platform_set_drvdata(pdev, NULL); | ||
| 237 | |||
| 238 | destroy_workqueue(priv->workq); | 236 | destroy_workqueue(priv->workq); |
| 239 | input_unregister_device(priv->idev); | 237 | input_unregister_device(priv->idev); |
| 240 | kfree(priv); | 238 | kfree(priv); |
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 51e7b87827a4..50fb1293874e 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
| @@ -336,7 +336,6 @@ static int titsc_remove(struct platform_device *pdev) | |||
| 336 | 336 | ||
| 337 | input_unregister_device(ts_dev->input); | 337 | input_unregister_device(ts_dev->input); |
| 338 | 338 | ||
| 339 | platform_set_drvdata(pdev, NULL); | ||
| 340 | kfree(ts_dev); | 339 | kfree(ts_dev); |
| 341 | return 0; | 340 | return 0; |
| 342 | } | 341 | } |
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c index acfb87607b87..c47827a26e3c 100644 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ b/drivers/input/touchscreen/tnetv107x-ts.c | |||
| @@ -351,7 +351,6 @@ error_clk: | |||
| 351 | error_map: | 351 | error_map: |
| 352 | release_mem_region(ts->res->start, resource_size(ts->res)); | 352 | release_mem_region(ts->res->start, resource_size(ts->res)); |
| 353 | error_res: | 353 | error_res: |
| 354 | platform_set_drvdata(pdev, NULL); | ||
| 355 | kfree(ts); | 354 | kfree(ts); |
| 356 | 355 | ||
| 357 | return error; | 356 | return error; |
| @@ -366,7 +365,6 @@ static int tsc_remove(struct platform_device *pdev) | |||
| 366 | clk_put(ts->clk); | 365 | clk_put(ts->clk); |
| 367 | iounmap(ts->regs); | 366 | iounmap(ts->regs); |
| 368 | release_mem_region(ts->res->start, resource_size(ts->res)); | 367 | release_mem_region(ts->res->start, resource_size(ts->res)); |
| 369 | platform_set_drvdata(pdev, NULL); | ||
| 370 | kfree(ts); | 368 | kfree(ts); |
| 371 | 369 | ||
| 372 | return 0; | 370 | return 0; |
diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index d2ef8f05c66e..003d0c3b5d08 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c | |||
| @@ -318,8 +318,6 @@ static int w90x900ts_remove(struct platform_device *pdev) | |||
| 318 | input_unregister_device(w90p910_ts->input); | 318 | input_unregister_device(w90p910_ts->input); |
| 319 | kfree(w90p910_ts); | 319 | kfree(w90p910_ts); |
| 320 | 320 | ||
| 321 | platform_set_drvdata(pdev, NULL); | ||
| 322 | |||
| 323 | return 0; | 321 | return 0; |
| 324 | } | 322 | } |
| 325 | 323 | ||
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index bf0d07620bac..7ccaa1b12b05 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Wacom Penabled Driver for I2C | 2 | * Wacom Penabled Driver for I2C |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2011 Tatsunosuke Tobita, Wacom. | 4 | * Copyright (c) 2011 - 2013 Tatsunosuke Tobita, Wacom. |
| 5 | * <tobita.tatsunosuke@wacom.co.jp> | 5 | * <tobita.tatsunosuke@wacom.co.jp> |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it | 7 | * This program is free software; you can redistribute it |
| @@ -27,7 +27,6 @@ | |||
| 27 | #define WACOM_CMD_THROW0 0x05 | 27 | #define WACOM_CMD_THROW0 0x05 |
| 28 | #define WACOM_CMD_THROW1 0x00 | 28 | #define WACOM_CMD_THROW1 0x00 |
| 29 | #define WACOM_QUERY_SIZE 19 | 29 | #define WACOM_QUERY_SIZE 19 |
| 30 | #define WACOM_RETRY_CNT 100 | ||
| 31 | 30 | ||
| 32 | struct wacom_features { | 31 | struct wacom_features { |
| 33 | int x_max; | 32 | int x_max; |
| @@ -40,6 +39,8 @@ struct wacom_i2c { | |||
| 40 | struct i2c_client *client; | 39 | struct i2c_client *client; |
| 41 | struct input_dev *input; | 40 | struct input_dev *input; |
| 42 | u8 data[WACOM_QUERY_SIZE]; | 41 | u8 data[WACOM_QUERY_SIZE]; |
| 42 | bool prox; | ||
| 43 | int tool; | ||
| 43 | }; | 44 | }; |
| 44 | 45 | ||
| 45 | static int wacom_query_device(struct i2c_client *client, | 46 | static int wacom_query_device(struct i2c_client *client, |
| @@ -112,9 +113,14 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id) | |||
| 112 | y = le16_to_cpup((__le16 *)&data[6]); | 113 | y = le16_to_cpup((__le16 *)&data[6]); |
| 113 | pressure = le16_to_cpup((__le16 *)&data[8]); | 114 | pressure = le16_to_cpup((__le16 *)&data[8]); |
| 114 | 115 | ||
| 116 | if (!wac_i2c->prox) | ||
| 117 | wac_i2c->tool = (data[3] & 0x0c) ? | ||
| 118 | BTN_TOOL_RUBBER : BTN_TOOL_PEN; | ||
| 119 | |||
| 120 | wac_i2c->prox = data[3] & 0x20; | ||
| 121 | |||
| 115 | input_report_key(input, BTN_TOUCH, tsw || ers); | 122 | input_report_key(input, BTN_TOUCH, tsw || ers); |
| 116 | input_report_key(input, BTN_TOOL_PEN, tsw); | 123 | input_report_key(input, wac_i2c->tool, wac_i2c->prox); |
| 117 | input_report_key(input, BTN_TOOL_RUBBER, ers); | ||
| 118 | input_report_key(input, BTN_STYLUS, f1); | 124 | input_report_key(input, BTN_STYLUS, f1); |
| 119 | input_report_key(input, BTN_STYLUS2, f2); | 125 | input_report_key(input, BTN_STYLUS2, f2); |
| 120 | input_report_abs(input, ABS_X, x); | 126 | input_report_abs(input, ABS_X, x); |
