diff options
40 files changed, 2974 insertions, 216 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 4e41d5255d72..b31d1c954661 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -2089,6 +2089,13 @@ W: http://www.cyclades.com/ | |||
| 2089 | S: Orphan | 2089 | S: Orphan |
| 2090 | F: drivers/net/wan/pc300* | 2090 | F: drivers/net/wan/pc300* |
| 2091 | 2091 | ||
| 2092 | CYTTSP TOUCHSCREEN DRIVER | ||
| 2093 | M: Javier Martinez Canillas <javier@dowhile0.org> | ||
| 2094 | L: linux-input@vger.kernel.org | ||
| 2095 | S: Maintained | ||
| 2096 | F: drivers/input/touchscreen/cyttsp* | ||
| 2097 | F: include/linux/input/cyttsp.h | ||
| 2098 | |||
| 2092 | DAMA SLAVE for AX.25 | 2099 | DAMA SLAVE for AX.25 |
| 2093 | M: Joerg Reuter <jreuter@yaina.de> | 2100 | M: Joerg Reuter <jreuter@yaina.de> |
| 2094 | W: http://yaina.de/jreuter/ | 2101 | W: http://yaina.de/jreuter/ |
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h index 20bb0545f992..a13025612939 100644 --- a/arch/arm/mach-tegra/include/mach/kbc.h +++ b/arch/arm/mach-tegra/include/mach/kbc.h | |||
| @@ -24,20 +24,21 @@ | |||
| 24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
| 25 | #include <linux/input/matrix_keypad.h> | 25 | #include <linux/input/matrix_keypad.h> |
| 26 | 26 | ||
| 27 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
| 28 | #define KBC_MAX_GPIO 24 | 27 | #define KBC_MAX_GPIO 24 |
| 29 | #define KBC_MAX_KPENT 8 | 28 | #define KBC_MAX_KPENT 8 |
| 30 | #else | ||
| 31 | #define KBC_MAX_GPIO 20 | ||
| 32 | #define KBC_MAX_KPENT 7 | ||
| 33 | #endif | ||
| 34 | 29 | ||
| 35 | #define KBC_MAX_ROW 16 | 30 | #define KBC_MAX_ROW 16 |
| 36 | #define KBC_MAX_COL 8 | 31 | #define KBC_MAX_COL 8 |
| 37 | #define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL) | 32 | #define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL) |
| 38 | 33 | ||
| 34 | enum tegra_pin_type { | ||
| 35 | PIN_CFG_IGNORE, | ||
| 36 | PIN_CFG_COL, | ||
| 37 | PIN_CFG_ROW, | ||
| 38 | }; | ||
| 39 | |||
| 39 | struct tegra_kbc_pin_cfg { | 40 | struct tegra_kbc_pin_cfg { |
| 40 | bool is_row; | 41 | enum tegra_pin_type type; |
| 41 | unsigned char num; | 42 | unsigned char num; |
| 42 | }; | 43 | }; |
| 43 | 44 | ||
diff --git a/arch/arm/plat-spear/include/plat/keyboard.h b/arch/arm/plat-spear/include/plat/keyboard.h index 68b5394fc583..c16cc31ecbed 100644 --- a/arch/arm/plat-spear/include/plat/keyboard.h +++ b/arch/arm/plat-spear/include/plat/keyboard.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include <linux/input/matrix_keypad.h> | 15 | #include <linux/input/matrix_keypad.h> |
| 16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
| 17 | 17 | ||
| 18 | #define DECLARE_KEYMAP(_name) \ | 18 | #define DECLARE_9x9_KEYMAP(_name) \ |
| 19 | int _name[] = { \ | 19 | int _name[] = { \ |
| 20 | KEY(0, 0, KEY_ESC), \ | 20 | KEY(0, 0, KEY_ESC), \ |
| 21 | KEY(0, 1, KEY_1), \ | 21 | KEY(0, 1, KEY_1), \ |
| @@ -62,24 +62,6 @@ int _name[] = { \ | |||
| 62 | KEY(4, 6, KEY_Z), \ | 62 | KEY(4, 6, KEY_Z), \ |
| 63 | KEY(4, 7, KEY_X), \ | 63 | KEY(4, 7, KEY_X), \ |
| 64 | KEY(4, 8, KEY_C), \ | 64 | KEY(4, 8, KEY_C), \ |
| 65 | KEY(4, 0, KEY_L), \ | ||
| 66 | KEY(4, 1, KEY_SEMICOLON), \ | ||
| 67 | KEY(4, 2, KEY_APOSTROPHE), \ | ||
| 68 | KEY(4, 3, KEY_GRAVE), \ | ||
| 69 | KEY(4, 4, KEY_LEFTSHIFT), \ | ||
| 70 | KEY(4, 5, KEY_BACKSLASH), \ | ||
| 71 | KEY(4, 6, KEY_Z), \ | ||
| 72 | KEY(4, 7, KEY_X), \ | ||
| 73 | KEY(4, 8, KEY_C), \ | ||
| 74 | KEY(4, 0, KEY_L), \ | ||
| 75 | KEY(4, 1, KEY_SEMICOLON), \ | ||
| 76 | KEY(4, 2, KEY_APOSTROPHE), \ | ||
| 77 | KEY(4, 3, KEY_GRAVE), \ | ||
| 78 | KEY(4, 4, KEY_LEFTSHIFT), \ | ||
| 79 | KEY(4, 5, KEY_BACKSLASH), \ | ||
| 80 | KEY(4, 6, KEY_Z), \ | ||
| 81 | KEY(4, 7, KEY_X), \ | ||
| 82 | KEY(4, 8, KEY_C), \ | ||
| 83 | KEY(5, 0, KEY_V), \ | 65 | KEY(5, 0, KEY_V), \ |
| 84 | KEY(5, 1, KEY_B), \ | 66 | KEY(5, 1, KEY_B), \ |
| 85 | KEY(5, 2, KEY_N), \ | 67 | KEY(5, 2, KEY_N), \ |
| @@ -118,10 +100,55 @@ int _name[] = { \ | |||
| 118 | KEY(8, 8, KEY_KP0), \ | 100 | KEY(8, 8, KEY_KP0), \ |
| 119 | } | 101 | } |
| 120 | 102 | ||
| 103 | #define DECLARE_6x6_KEYMAP(_name) \ | ||
| 104 | int _name[] = { \ | ||
| 105 | KEY(0, 0, KEY_RESERVED), \ | ||
| 106 | KEY(0, 1, KEY_1), \ | ||
| 107 | KEY(0, 2, KEY_2), \ | ||
| 108 | KEY(0, 3, KEY_3), \ | ||
| 109 | KEY(0, 4, KEY_4), \ | ||
| 110 | KEY(0, 5, KEY_5), \ | ||
| 111 | KEY(1, 0, KEY_Q), \ | ||
| 112 | KEY(1, 1, KEY_W), \ | ||
| 113 | KEY(1, 2, KEY_E), \ | ||
| 114 | KEY(1, 3, KEY_R), \ | ||
| 115 | KEY(1, 4, KEY_T), \ | ||
| 116 | KEY(1, 5, KEY_Y), \ | ||
| 117 | KEY(2, 0, KEY_D), \ | ||
| 118 | KEY(2, 1, KEY_F), \ | ||
| 119 | KEY(2, 2, KEY_G), \ | ||
| 120 | KEY(2, 3, KEY_H), \ | ||
| 121 | KEY(2, 4, KEY_J), \ | ||
| 122 | KEY(2, 5, KEY_K), \ | ||
| 123 | KEY(3, 0, KEY_B), \ | ||
| 124 | KEY(3, 1, KEY_N), \ | ||
| 125 | KEY(3, 2, KEY_M), \ | ||
| 126 | KEY(3, 3, KEY_COMMA), \ | ||
| 127 | KEY(3, 4, KEY_DOT), \ | ||
| 128 | KEY(3, 5, KEY_SLASH), \ | ||
| 129 | KEY(4, 0, KEY_F6), \ | ||
| 130 | KEY(4, 1, KEY_F7), \ | ||
| 131 | KEY(4, 2, KEY_F8), \ | ||
| 132 | KEY(4, 3, KEY_F9), \ | ||
| 133 | KEY(4, 4, KEY_F10), \ | ||
| 134 | KEY(4, 5, KEY_NUMLOCK), \ | ||
| 135 | KEY(5, 0, KEY_KP2), \ | ||
| 136 | KEY(5, 1, KEY_KP3), \ | ||
| 137 | KEY(5, 2, KEY_KP0), \ | ||
| 138 | KEY(5, 3, KEY_KPDOT), \ | ||
| 139 | KEY(5, 4, KEY_RO), \ | ||
| 140 | KEY(5, 5, KEY_ZENKAKUHANKAKU), \ | ||
| 141 | } | ||
| 142 | |||
| 143 | #define KEYPAD_9x9 0 | ||
| 144 | #define KEYPAD_6x6 1 | ||
| 145 | #define KEYPAD_2x2 2 | ||
| 146 | |||
| 121 | /** | 147 | /** |
| 122 | * struct kbd_platform_data - spear keyboard platform data | 148 | * struct kbd_platform_data - spear keyboard platform data |
| 123 | * keymap: pointer to keymap data (table and size) | 149 | * keymap: pointer to keymap data (table and size) |
| 124 | * rep: enables key autorepeat | 150 | * rep: enables key autorepeat |
| 151 | * mode: choose keyboard support(9x9, 6x6, 2x2) | ||
| 125 | * | 152 | * |
| 126 | * This structure is supposed to be used by platform code to supply | 153 | * This structure is supposed to be used by platform code to supply |
| 127 | * keymaps to drivers that implement keyboards. | 154 | * keymaps to drivers that implement keyboards. |
| @@ -129,6 +156,7 @@ int _name[] = { \ | |||
| 129 | struct kbd_platform_data { | 156 | struct kbd_platform_data { |
| 130 | const struct matrix_keymap_data *keymap; | 157 | const struct matrix_keymap_data *keymap; |
| 131 | bool rep; | 158 | bool rep; |
| 159 | unsigned int mode; | ||
| 132 | }; | 160 | }; |
| 133 | 161 | ||
| 134 | /* This function is used to set platform data field of pdev->dev */ | 162 | /* This function is used to set platform data field of pdev->dev */ |
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index ad10fecec2fe..be936480b964 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/rtc.h> | 24 | #include <linux/rtc.h> |
| 25 | #include <linux/vt_kern.h> | 25 | #include <linux/vt_kern.h> |
| 26 | #include <linux/bcd.h> | 26 | #include <linux/bcd.h> |
| 27 | #include <linux/platform_device.h> | ||
| 27 | 28 | ||
| 28 | #include <asm/io.h> | 29 | #include <asm/io.h> |
| 29 | #include <asm/rtc.h> | 30 | #include <asm/rtc.h> |
| @@ -329,3 +330,15 @@ static int q40_set_rtc_pll(struct rtc_pll_info *pll) | |||
| 329 | } else | 330 | } else |
| 330 | return -EINVAL; | 331 | return -EINVAL; |
| 331 | } | 332 | } |
| 333 | |||
| 334 | static __init int q40_add_kbd_device(void) | ||
| 335 | { | ||
| 336 | struct platform_device *pdev; | ||
| 337 | |||
| 338 | pdev = platform_device_register_simple("q40kbd", -1, NULL, 0); | ||
| 339 | if (IS_ERR(pdev)) | ||
| 340 | return PTR_ERR(pdev); | ||
| 341 | |||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | arch_initcall(q40_add_kbd_device); | ||
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index af08ce7207d9..4c861e239993 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
| @@ -1912,6 +1912,16 @@ static const struct hid_device_id hid_ignore_list[] = { | |||
| 1912 | { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, | 1912 | { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, |
| 1913 | { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, | 1913 | { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, |
| 1914 | { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, | 1914 | { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, |
| 1915 | #if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE) | ||
| 1916 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) }, | ||
| 1917 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) }, | ||
| 1918 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) }, | ||
| 1919 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) }, | ||
| 1920 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) }, | ||
| 1921 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) }, | ||
| 1922 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) }, | ||
| 1923 | { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) }, | ||
| 1924 | #endif | ||
| 1915 | { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, | 1925 | { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, |
| 1916 | { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, | 1926 | { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, |
| 1917 | { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, | 1927 | { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b8574cddd953..8e96f19b62ea 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
| @@ -652,6 +652,17 @@ | |||
| 652 | #define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800 | 652 | #define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800 |
| 653 | #define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300 | 653 | #define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300 |
| 654 | 654 | ||
| 655 | #define USB_VENDOR_ID_SYNAPTICS 0x06cb | ||
| 656 | #define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 | ||
| 657 | #define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 | ||
| 658 | #define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 | ||
| 659 | #define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 | ||
| 660 | #define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 | ||
| 661 | #define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 | ||
| 662 | #define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 | ||
| 663 | #define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 | ||
| 664 | #define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 | ||
| 665 | |||
| 655 | #define USB_VENDOR_ID_THRUSTMASTER 0x044f | 666 | #define USB_VENDOR_ID_THRUSTMASTER 0x044f |
| 656 | 667 | ||
| 657 | #define USB_VENDOR_ID_TOPSEED 0x0766 | 668 | #define USB_VENDOR_ID_TOPSEED 0x0766 |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index afc166fcc3d9..3626b1ce4609 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -46,6 +46,7 @@ struct evdev_client { | |||
| 46 | struct fasync_struct *fasync; | 46 | struct fasync_struct *fasync; |
| 47 | struct evdev *evdev; | 47 | struct evdev *evdev; |
| 48 | struct list_head node; | 48 | struct list_head node; |
| 49 | int clkid; | ||
| 49 | unsigned int bufsize; | 50 | unsigned int bufsize; |
| 50 | struct input_event buffer[]; | 51 | struct input_event buffer[]; |
| 51 | }; | 52 | }; |
| @@ -54,8 +55,12 @@ static struct evdev *evdev_table[EVDEV_MINORS]; | |||
| 54 | static DEFINE_MUTEX(evdev_table_mutex); | 55 | static DEFINE_MUTEX(evdev_table_mutex); |
| 55 | 56 | ||
| 56 | static void evdev_pass_event(struct evdev_client *client, | 57 | static void evdev_pass_event(struct evdev_client *client, |
| 57 | struct input_event *event) | 58 | struct input_event *event, |
| 59 | ktime_t mono, ktime_t real) | ||
| 58 | { | 60 | { |
| 61 | event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | ||
| 62 | mono : real); | ||
| 63 | |||
| 59 | /* Interrupts are disabled, just acquire the lock. */ | 64 | /* Interrupts are disabled, just acquire the lock. */ |
| 60 | spin_lock(&client->buffer_lock); | 65 | spin_lock(&client->buffer_lock); |
| 61 | 66 | ||
| @@ -94,8 +99,11 @@ static void evdev_event(struct input_handle *handle, | |||
| 94 | struct evdev *evdev = handle->private; | 99 | struct evdev *evdev = handle->private; |
| 95 | struct evdev_client *client; | 100 | struct evdev_client *client; |
| 96 | struct input_event event; | 101 | struct input_event event; |
| 102 | ktime_t time_mono, time_real; | ||
| 103 | |||
| 104 | time_mono = ktime_get(); | ||
| 105 | time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); | ||
| 97 | 106 | ||
| 98 | do_gettimeofday(&event.time); | ||
| 99 | event.type = type; | 107 | event.type = type; |
| 100 | event.code = code; | 108 | event.code = code; |
| 101 | event.value = value; | 109 | event.value = value; |
| @@ -103,11 +111,12 @@ static void evdev_event(struct input_handle *handle, | |||
| 103 | rcu_read_lock(); | 111 | rcu_read_lock(); |
| 104 | 112 | ||
| 105 | client = rcu_dereference(evdev->grab); | 113 | client = rcu_dereference(evdev->grab); |
| 114 | |||
| 106 | if (client) | 115 | if (client) |
| 107 | evdev_pass_event(client, &event); | 116 | evdev_pass_event(client, &event, time_mono, time_real); |
| 108 | else | 117 | else |
| 109 | list_for_each_entry_rcu(client, &evdev->client_list, node) | 118 | list_for_each_entry_rcu(client, &evdev->client_list, node) |
| 110 | evdev_pass_event(client, &event); | 119 | evdev_pass_event(client, &event, time_mono, time_real); |
| 111 | 120 | ||
| 112 | rcu_read_unlock(); | 121 | rcu_read_unlock(); |
| 113 | 122 | ||
| @@ -685,6 +694,14 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
| 685 | else | 694 | else |
| 686 | return evdev_ungrab(evdev, client); | 695 | return evdev_ungrab(evdev, client); |
| 687 | 696 | ||
| 697 | case EVIOCSCLOCKID: | ||
| 698 | if (copy_from_user(&i, p, sizeof(unsigned int))) | ||
| 699 | return -EFAULT; | ||
| 700 | if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME) | ||
| 701 | return -EINVAL; | ||
| 702 | client->clkid = i; | ||
| 703 | return 0; | ||
| 704 | |||
| 688 | case EVIOCGKEYCODE: | 705 | case EVIOCGKEYCODE: |
| 689 | return evdev_handle_get_keycode(dev, p); | 706 | return evdev_handle_get_keycode(dev, p); |
| 690 | 707 | ||
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index e35566aa102f..101e245944e7 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c | |||
| @@ -88,7 +88,7 @@ static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr, | |||
| 88 | * | 88 | * |
| 89 | * Enable Multi key press detection, auto scan mode | 89 | * Enable Multi key press detection, auto scan mode |
| 90 | */ | 90 | */ |
| 91 | static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad) | 91 | static int __init ske_keypad_chip_init(struct ske_keypad *keypad) |
| 92 | { | 92 | { |
| 93 | u32 value; | 93 | u32 value; |
| 94 | int timeout = 50; | 94 | int timeout = 50; |
| @@ -198,7 +198,7 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id) | |||
| 198 | return IRQ_HANDLED; | 198 | return IRQ_HANDLED; |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | static int __devinit ske_keypad_probe(struct platform_device *pdev) | 201 | static int __init ske_keypad_probe(struct platform_device *pdev) |
| 202 | { | 202 | { |
| 203 | const struct ske_keypad_platform_data *plat = pdev->dev.platform_data; | 203 | const struct ske_keypad_platform_data *plat = pdev->dev.platform_data; |
| 204 | struct ske_keypad *keypad; | 204 | struct ske_keypad *keypad; |
| @@ -344,7 +344,7 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev) | |||
| 344 | return 0; | 344 | return 0; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | #ifdef CONFIG_PM | 347 | #ifdef CONFIG_PM_SLEEP |
| 348 | static int ske_keypad_suspend(struct device *dev) | 348 | static int ske_keypad_suspend(struct device *dev) |
| 349 | { | 349 | { |
| 350 | struct platform_device *pdev = to_platform_device(dev); | 350 | struct platform_device *pdev = to_platform_device(dev); |
| @@ -372,22 +372,17 @@ static int ske_keypad_resume(struct device *dev) | |||
| 372 | 372 | ||
| 373 | return 0; | 373 | return 0; |
| 374 | } | 374 | } |
| 375 | |||
| 376 | static const struct dev_pm_ops ske_keypad_dev_pm_ops = { | ||
| 377 | .suspend = ske_keypad_suspend, | ||
| 378 | .resume = ske_keypad_resume, | ||
| 379 | }; | ||
| 380 | #endif | 375 | #endif |
| 381 | 376 | ||
| 377 | static SIMPLE_DEV_PM_OPS(ske_keypad_dev_pm_ops, | ||
| 378 | ske_keypad_suspend, ske_keypad_resume); | ||
| 379 | |||
| 382 | static struct platform_driver ske_keypad_driver = { | 380 | static struct platform_driver ske_keypad_driver = { |
| 383 | .driver = { | 381 | .driver = { |
| 384 | .name = "nmk-ske-keypad", | 382 | .name = "nmk-ske-keypad", |
| 385 | .owner = THIS_MODULE, | 383 | .owner = THIS_MODULE, |
| 386 | #ifdef CONFIG_PM | ||
| 387 | .pm = &ske_keypad_dev_pm_ops, | 384 | .pm = &ske_keypad_dev_pm_ops, |
| 388 | #endif | ||
| 389 | }, | 385 | }, |
| 390 | .probe = ske_keypad_probe, | ||
| 391 | .remove = __devexit_p(ske_keypad_remove), | 386 | .remove = __devexit_p(ske_keypad_remove), |
| 392 | }; | 387 | }; |
| 393 | 388 | ||
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 17ba7f9f80f3..2391ae884fee 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c | |||
| @@ -175,7 +175,7 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) | |||
| 175 | 175 | ||
| 176 | } while (key_down && !keypad->stopped); | 176 | } while (key_down && !keypad->stopped); |
| 177 | 177 | ||
| 178 | pm_runtime_put_sync(&keypad->pdev->dev); | 178 | pm_runtime_put(&keypad->pdev->dev); |
| 179 | 179 | ||
| 180 | return IRQ_HANDLED; | 180 | return IRQ_HANDLED; |
| 181 | } | 181 | } |
| @@ -199,7 +199,7 @@ static void samsung_keypad_start(struct samsung_keypad *keypad) | |||
| 199 | /* KEYIFCOL reg clear. */ | 199 | /* KEYIFCOL reg clear. */ |
| 200 | writel(0, keypad->base + SAMSUNG_KEYIFCOL); | 200 | writel(0, keypad->base + SAMSUNG_KEYIFCOL); |
| 201 | 201 | ||
| 202 | pm_runtime_put_sync(&keypad->pdev->dev); | 202 | pm_runtime_put(&keypad->pdev->dev); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static void samsung_keypad_stop(struct samsung_keypad *keypad) | 205 | static void samsung_keypad_stop(struct samsung_keypad *keypad) |
| @@ -229,7 +229,7 @@ static void samsung_keypad_stop(struct samsung_keypad *keypad) | |||
| 229 | */ | 229 | */ |
| 230 | enable_irq(keypad->irq); | 230 | enable_irq(keypad->irq); |
| 231 | 231 | ||
| 232 | pm_runtime_put_sync(&keypad->pdev->dev); | 232 | pm_runtime_put(&keypad->pdev->dev); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | static int samsung_keypad_open(struct input_dev *input_dev) | 235 | static int samsung_keypad_open(struct input_dev *input_dev) |
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index c88bd63dc9cc..3b6b528f02fd 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #define ROW_MASK 0xF0 | 50 | #define ROW_MASK 0xF0 |
| 51 | #define COLUMN_MASK 0x0F | 51 | #define COLUMN_MASK 0x0F |
| 52 | #define ROW_SHIFT 4 | 52 | #define ROW_SHIFT 4 |
| 53 | #define KEY_MATRIX_SHIFT 6 | ||
| 53 | 54 | ||
| 54 | struct spear_kbd { | 55 | struct spear_kbd { |
| 55 | struct input_dev *input; | 56 | struct input_dev *input; |
| @@ -57,6 +58,7 @@ struct spear_kbd { | |||
| 57 | void __iomem *io_base; | 58 | void __iomem *io_base; |
| 58 | struct clk *clk; | 59 | struct clk *clk; |
| 59 | unsigned int irq; | 60 | unsigned int irq; |
| 61 | unsigned int mode; | ||
| 60 | unsigned short last_key; | 62 | unsigned short last_key; |
| 61 | unsigned short keycodes[256]; | 63 | unsigned short keycodes[256]; |
| 62 | }; | 64 | }; |
| @@ -106,7 +108,8 @@ static int spear_kbd_open(struct input_dev *dev) | |||
| 106 | return error; | 108 | return error; |
| 107 | 109 | ||
| 108 | /* program keyboard */ | 110 | /* program keyboard */ |
| 109 | val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK; | 111 | val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK | |
| 112 | (kbd->mode << KEY_MATRIX_SHIFT); | ||
| 110 | writew(val, kbd->io_base + MODE_REG); | 113 | writew(val, kbd->io_base + MODE_REG); |
| 111 | writeb(1, kbd->io_base + STATUS_REG); | 114 | writeb(1, kbd->io_base + STATUS_REG); |
| 112 | 115 | ||
| @@ -176,6 +179,8 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev) | |||
| 176 | 179 | ||
| 177 | kbd->input = input_dev; | 180 | kbd->input = input_dev; |
| 178 | kbd->irq = irq; | 181 | kbd->irq = irq; |
| 182 | kbd->mode = pdata->mode; | ||
| 183 | |||
| 179 | kbd->res = request_mem_region(res->start, resource_size(res), | 184 | kbd->res = request_mem_region(res->start, resource_size(res), |
| 180 | pdev->name); | 185 | pdev->name); |
| 181 | if (!kbd->res) { | 186 | if (!kbd->res) { |
| @@ -308,22 +313,17 @@ static int spear_kbd_resume(struct device *dev) | |||
| 308 | 313 | ||
| 309 | return 0; | 314 | return 0; |
| 310 | } | 315 | } |
| 311 | |||
| 312 | static const struct dev_pm_ops spear_kbd_pm_ops = { | ||
| 313 | .suspend = spear_kbd_suspend, | ||
| 314 | .resume = spear_kbd_resume, | ||
| 315 | }; | ||
| 316 | #endif | 316 | #endif |
| 317 | 317 | ||
| 318 | static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume); | ||
| 319 | |||
| 318 | static struct platform_driver spear_kbd_driver = { | 320 | static struct platform_driver spear_kbd_driver = { |
| 319 | .probe = spear_kbd_probe, | 321 | .probe = spear_kbd_probe, |
| 320 | .remove = __devexit_p(spear_kbd_remove), | 322 | .remove = __devexit_p(spear_kbd_remove), |
| 321 | .driver = { | 323 | .driver = { |
| 322 | .name = "keyboard", | 324 | .name = "keyboard", |
| 323 | .owner = THIS_MODULE, | 325 | .owner = THIS_MODULE, |
| 324 | #ifdef CONFIG_PM | ||
| 325 | .pm = &spear_kbd_pm_ops, | 326 | .pm = &spear_kbd_pm_ops, |
| 326 | #endif | ||
| 327 | }, | 327 | }, |
| 328 | }; | 328 | }; |
| 329 | module_platform_driver(spear_kbd_driver); | 329 | module_platform_driver(spear_kbd_driver); |
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index a136e2e832be..dc19432c665b 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14) | 48 | #define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14) |
| 49 | #define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4) | 49 | #define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4) |
| 50 | #define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3) | 50 | #define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3) |
| 51 | #define KBC_CONTROL_KEYPRESS_INT_EN (1 << 1) | ||
| 51 | #define KBC_CONTROL_KBC_EN (1 << 0) | 52 | #define KBC_CONTROL_KBC_EN (1 << 0) |
| 52 | 53 | ||
| 53 | /* KBC Interrupt Register */ | 54 | /* KBC Interrupt Register */ |
| @@ -356,6 +357,18 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) | |||
| 356 | writel(val, kbc->mmio + KBC_CONTROL_0); | 357 | writel(val, kbc->mmio + KBC_CONTROL_0); |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 360 | static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable) | ||
| 361 | { | ||
| 362 | u32 val; | ||
| 363 | |||
| 364 | val = readl(kbc->mmio + KBC_CONTROL_0); | ||
| 365 | if (enable) | ||
| 366 | val |= KBC_CONTROL_KEYPRESS_INT_EN; | ||
| 367 | else | ||
| 368 | val &= ~KBC_CONTROL_KEYPRESS_INT_EN; | ||
| 369 | writel(val, kbc->mmio + KBC_CONTROL_0); | ||
| 370 | } | ||
| 371 | |||
| 359 | static void tegra_kbc_keypress_timer(unsigned long data) | 372 | static void tegra_kbc_keypress_timer(unsigned long data) |
| 360 | { | 373 | { |
| 361 | struct tegra_kbc *kbc = (struct tegra_kbc *)data; | 374 | struct tegra_kbc *kbc = (struct tegra_kbc *)data; |
| @@ -455,10 +468,18 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc) | |||
| 455 | row_cfg &= ~r_mask; | 468 | row_cfg &= ~r_mask; |
| 456 | col_cfg &= ~c_mask; | 469 | col_cfg &= ~c_mask; |
| 457 | 470 | ||
| 458 | if (pdata->pin_cfg[i].is_row) | 471 | switch (pdata->pin_cfg[i].type) { |
| 472 | case PIN_CFG_ROW: | ||
| 459 | row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft; | 473 | row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft; |
| 460 | else | 474 | break; |
| 475 | |||
| 476 | case PIN_CFG_COL: | ||
| 461 | col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft; | 477 | col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft; |
| 478 | break; | ||
| 479 | |||
| 480 | case PIN_CFG_IGNORE: | ||
| 481 | break; | ||
| 482 | } | ||
| 462 | 483 | ||
| 463 | writel(row_cfg, kbc->mmio + r_offs); | 484 | writel(row_cfg, kbc->mmio + r_offs); |
| 464 | writel(col_cfg, kbc->mmio + c_offs); | 485 | writel(col_cfg, kbc->mmio + c_offs); |
| @@ -563,7 +584,8 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, | |||
| 563 | for (i = 0; i < KBC_MAX_GPIO; i++) { | 584 | for (i = 0; i < KBC_MAX_GPIO; i++) { |
| 564 | const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i]; | 585 | const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i]; |
| 565 | 586 | ||
| 566 | if (pin_cfg->is_row) { | 587 | switch (pin_cfg->type) { |
| 588 | case PIN_CFG_ROW: | ||
| 567 | if (pin_cfg->num >= KBC_MAX_ROW) { | 589 | if (pin_cfg->num >= KBC_MAX_ROW) { |
| 568 | dev_err(dev, | 590 | dev_err(dev, |
| 569 | "pin_cfg[%d]: invalid row number %d\n", | 591 | "pin_cfg[%d]: invalid row number %d\n", |
| @@ -571,13 +593,25 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, | |||
| 571 | return false; | 593 | return false; |
| 572 | } | 594 | } |
| 573 | (*num_rows)++; | 595 | (*num_rows)++; |
| 574 | } else { | 596 | break; |
| 597 | |||
| 598 | case PIN_CFG_COL: | ||
| 575 | if (pin_cfg->num >= KBC_MAX_COL) { | 599 | if (pin_cfg->num >= KBC_MAX_COL) { |
| 576 | dev_err(dev, | 600 | dev_err(dev, |
| 577 | "pin_cfg[%d]: invalid column number %d\n", | 601 | "pin_cfg[%d]: invalid column number %d\n", |
| 578 | i, pin_cfg->num); | 602 | i, pin_cfg->num); |
| 579 | return false; | 603 | return false; |
| 580 | } | 604 | } |
| 605 | break; | ||
| 606 | |||
| 607 | case PIN_CFG_IGNORE: | ||
| 608 | break; | ||
| 609 | |||
| 610 | default: | ||
| 611 | dev_err(dev, | ||
| 612 | "pin_cfg[%d]: invalid entry type %d\n", | ||
| 613 | pin_cfg->type, pin_cfg->num); | ||
| 614 | return false; | ||
| 581 | } | 615 | } |
| 582 | } | 616 | } |
| 583 | 617 | ||
| @@ -594,7 +628,6 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev) | |||
| 594 | if (!np) | 628 | if (!np) |
| 595 | return NULL; | 629 | return NULL; |
| 596 | 630 | ||
| 597 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
| 598 | if (!pdata) | 631 | if (!pdata) |
| 599 | return NULL; | 632 | return NULL; |
| 600 | 633 | ||
| @@ -616,12 +649,12 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev) | |||
| 616 | */ | 649 | */ |
| 617 | for (i = 0; i < KBC_MAX_ROW; i++) { | 650 | for (i = 0; i < KBC_MAX_ROW; i++) { |
| 618 | pdata->pin_cfg[i].num = i; | 651 | pdata->pin_cfg[i].num = i; |
| 619 | pdata->pin_cfg[i].is_row = true; | 652 | pdata->pin_cfg[i].type = PIN_CFG_ROW; |
| 620 | } | 653 | } |
| 621 | 654 | ||
| 622 | for (i = 0; i < KBC_MAX_COL; i++) { | 655 | for (i = 0; i < KBC_MAX_COL; i++) { |
| 623 | pdata->pin_cfg[KBC_MAX_ROW + i].num = i; | 656 | pdata->pin_cfg[KBC_MAX_ROW + i].num = i; |
| 624 | pdata->pin_cfg[KBC_MAX_ROW + i].is_row = false; | 657 | pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL; |
| 625 | } | 658 | } |
| 626 | 659 | ||
| 627 | return pdata; | 660 | return pdata; |
| @@ -831,6 +864,8 @@ static int tegra_kbc_suspend(struct device *dev) | |||
| 831 | msleep(30); | 864 | msleep(30); |
| 832 | 865 | ||
| 833 | kbc->keypress_caused_wake = false; | 866 | kbc->keypress_caused_wake = false; |
| 867 | /* Enable keypress interrupt before going into suspend. */ | ||
| 868 | tegra_kbc_set_keypress_interrupt(kbc, true); | ||
| 834 | enable_irq(kbc->irq); | 869 | enable_irq(kbc->irq); |
| 835 | enable_irq_wake(kbc->irq); | 870 | enable_irq_wake(kbc->irq); |
| 836 | } else { | 871 | } else { |
| @@ -852,6 +887,8 @@ static int tegra_kbc_resume(struct device *dev) | |||
| 852 | if (device_may_wakeup(&pdev->dev)) { | 887 | if (device_may_wakeup(&pdev->dev)) { |
| 853 | disable_irq_wake(kbc->irq); | 888 | disable_irq_wake(kbc->irq); |
| 854 | tegra_kbc_setup_wakekeys(kbc, false); | 889 | tegra_kbc_setup_wakekeys(kbc, false); |
| 890 | /* We will use fifo interrupts for key detection. */ | ||
| 891 | tegra_kbc_set_keypress_interrupt(kbc, false); | ||
| 855 | 892 | ||
| 856 | /* Restore the resident time of continuous polling mode. */ | 893 | /* Restore the resident time of continuous polling mode. */ |
| 857 | writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0); | 894 | writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0); |
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7b46781c30c9..eb07e88162ad 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
| @@ -415,7 +415,7 @@ config INPUT_PCF8574 | |||
| 415 | tristate "PCF8574 Keypad input device" | 415 | tristate "PCF8574 Keypad input device" |
| 416 | depends on I2C && EXPERIMENTAL | 416 | depends on I2C && EXPERIMENTAL |
| 417 | help | 417 | help |
| 418 | Say Y here if you want to support a keypad connetced via I2C | 418 | Say Y here if you want to support a keypad connected via I2C |
| 419 | with a PCF8574. | 419 | with a PCF8574. |
| 420 | 420 | ||
| 421 | To compile this driver as a module, choose M here: the | 421 | To compile this driver as a module, choose M here: the |
| @@ -455,6 +455,16 @@ config INPUT_RB532_BUTTON | |||
| 455 | To compile this driver as a module, choose M here: the | 455 | To compile this driver as a module, choose M here: the |
| 456 | module will be called rb532_button. | 456 | module will be called rb532_button. |
| 457 | 457 | ||
| 458 | config INPUT_DA9052_ONKEY | ||
| 459 | tristate "Dialog DA9052/DA9053 Onkey" | ||
| 460 | depends on PMIC_DA9052 | ||
| 461 | help | ||
| 462 | Support the ONKEY of Dialog DA9052 PMICs as an input device | ||
| 463 | reporting power button status. | ||
| 464 | |||
| 465 | To compile this driver as a module, choose M here: the | ||
| 466 | module will be called da9052_onkey. | ||
| 467 | |||
| 458 | config INPUT_DM355EVM | 468 | config INPUT_DM355EVM |
| 459 | tristate "TI DaVinci DM355 EVM Keypad and IR Remote" | 469 | tristate "TI DaVinci DM355 EVM Keypad and IR Remote" |
| 460 | depends on MFD_DM355EVM_MSP | 470 | depends on MFD_DM355EVM_MSP |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 46671a875b91..a6d8de069148 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
| @@ -21,6 +21,7 @@ obj-$(CONFIG_INPUT_CM109) += cm109.o | |||
| 21 | obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o | 21 | obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o |
| 22 | obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o | 22 | obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o |
| 23 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | 23 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o |
| 24 | obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o | ||
| 24 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o | 25 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o |
| 25 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o | 26 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o |
| 26 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o | 27 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o |
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c new file mode 100644 index 000000000000..34aebb8cd080 --- /dev/null +++ b/drivers/input/misc/da9052_onkey.c | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * ON pin driver for Dialog DA9052 PMICs | ||
| 3 | * | ||
| 4 | * Copyright(c) 2012 Dialog Semiconductor Ltd. | ||
| 5 | * | ||
| 6 | * Author: David Dajun Chen <dchen@diasemi.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/input.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/workqueue.h> | ||
| 19 | |||
| 20 | #include <linux/mfd/da9052/da9052.h> | ||
| 21 | #include <linux/mfd/da9052/reg.h> | ||
| 22 | |||
| 23 | struct da9052_onkey { | ||
| 24 | struct da9052 *da9052; | ||
| 25 | struct input_dev *input; | ||
| 26 | struct delayed_work work; | ||
| 27 | unsigned int irq; | ||
| 28 | }; | ||
| 29 | |||
| 30 | static void da9052_onkey_query(struct da9052_onkey *onkey) | ||
| 31 | { | ||
| 32 | int key_stat; | ||
| 33 | |||
| 34 | key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG); | ||
| 35 | if (key_stat < 0) { | ||
| 36 | dev_err(onkey->da9052->dev, | ||
| 37 | "Failed to read onkey event %d\n", key_stat); | ||
| 38 | } else { | ||
| 39 | /* | ||
| 40 | * Since interrupt for deassertion of ONKEY pin is not | ||
| 41 | * generated, onkey event state determines the onkey | ||
| 42 | * button state. | ||
| 43 | */ | ||
| 44 | key_stat &= DA9052_EVENTB_ENONKEY; | ||
| 45 | input_report_key(onkey->input, KEY_POWER, key_stat); | ||
| 46 | input_sync(onkey->input); | ||
| 47 | } | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Interrupt is generated only when the ONKEY pin is asserted. | ||
| 51 | * Hence the deassertion of the pin is simulated through work queue. | ||
| 52 | */ | ||
| 53 | if (key_stat) | ||
| 54 | schedule_delayed_work(&onkey->work, msecs_to_jiffies(50)); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void da9052_onkey_work(struct work_struct *work) | ||
| 58 | { | ||
| 59 | struct da9052_onkey *onkey = container_of(work, struct da9052_onkey, | ||
| 60 | work.work); | ||
| 61 | |||
| 62 | da9052_onkey_query(onkey); | ||
| 63 | } | ||
| 64 | |||
| 65 | static irqreturn_t da9052_onkey_irq(int irq, void *data) | ||
| 66 | { | ||
| 67 | struct da9052_onkey *onkey = data; | ||
| 68 | |||
| 69 | da9052_onkey_query(onkey); | ||
| 70 | |||
| 71 | return IRQ_HANDLED; | ||
| 72 | } | ||
| 73 | |||
| 74 | static int __devinit da9052_onkey_probe(struct platform_device *pdev) | ||
| 75 | { | ||
| 76 | struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); | ||
| 77 | struct da9052_onkey *onkey; | ||
| 78 | struct input_dev *input_dev; | ||
| 79 | int irq; | ||
| 80 | int error; | ||
| 81 | |||
| 82 | if (!da9052) { | ||
| 83 | dev_err(&pdev->dev, "Failed to get the driver's data\n"); | ||
| 84 | return -EINVAL; | ||
| 85 | } | ||
| 86 | |||
| 87 | irq = platform_get_irq_byname(pdev, "ONKEY"); | ||
| 88 | if (irq < 0) { | ||
| 89 | dev_err(&pdev->dev, | ||
| 90 | "Failed to get an IRQ for input device, %d\n", irq); | ||
| 91 | return -EINVAL; | ||
| 92 | } | ||
| 93 | |||
| 94 | onkey = kzalloc(sizeof(*onkey), GFP_KERNEL); | ||
| 95 | input_dev = input_allocate_device(); | ||
| 96 | if (!onkey || !input_dev) { | ||
| 97 | dev_err(&pdev->dev, "Failed to allocate memory\n"); | ||
| 98 | return -ENOMEM; | ||
| 99 | } | ||
| 100 | |||
| 101 | onkey->input = input_dev; | ||
| 102 | onkey->da9052 = da9052; | ||
| 103 | onkey->irq = irq; | ||
| 104 | INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work); | ||
| 105 | |||
| 106 | input_dev->name = "da9052-onkey"; | ||
| 107 | input_dev->phys = "da9052-onkey/input0"; | ||
| 108 | input_dev->dev.parent = &pdev->dev; | ||
| 109 | |||
| 110 | input_dev->evbit[0] = BIT_MASK(EV_KEY); | ||
| 111 | __set_bit(KEY_POWER, input_dev->keybit); | ||
| 112 | |||
| 113 | error = request_threaded_irq(onkey->irq, NULL, da9052_onkey_irq, | ||
| 114 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
| 115 | "ONKEY", onkey); | ||
| 116 | if (error < 0) { | ||
| 117 | dev_err(onkey->da9052->dev, | ||
| 118 | "Failed to register ONKEY IRQ %d, error = %d\n", | ||
| 119 | onkey->irq, error); | ||
| 120 | goto err_free_mem; | ||
| 121 | } | ||
| 122 | |||
| 123 | error = input_register_device(onkey->input); | ||
| 124 | if (error) { | ||
| 125 | dev_err(&pdev->dev, "Unable to register input device, %d\n", | ||
| 126 | error); | ||
| 127 | goto err_free_irq; | ||
| 128 | } | ||
| 129 | |||
| 130 | platform_set_drvdata(pdev, onkey); | ||
| 131 | return 0; | ||
| 132 | |||
| 133 | err_free_irq: | ||
| 134 | free_irq(onkey->irq, onkey); | ||
| 135 | cancel_delayed_work_sync(&onkey->work); | ||
| 136 | err_free_mem: | ||
| 137 | input_free_device(input_dev); | ||
| 138 | kfree(onkey); | ||
| 139 | |||
| 140 | return error; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int __devexit da9052_onkey_remove(struct platform_device *pdev) | ||
| 144 | { | ||
| 145 | struct da9052_onkey *onkey = platform_get_drvdata(pdev); | ||
| 146 | |||
| 147 | free_irq(onkey->irq, onkey); | ||
| 148 | cancel_delayed_work_sync(&onkey->work); | ||
| 149 | |||
| 150 | input_unregister_device(onkey->input); | ||
| 151 | kfree(onkey); | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static struct platform_driver da9052_onkey_driver = { | ||
| 157 | .probe = da9052_onkey_probe, | ||
| 158 | .remove = __devexit_p(da9052_onkey_remove), | ||
| 159 | .driver = { | ||
| 160 | .name = "da9052-onkey", | ||
| 161 | .owner = THIS_MODULE, | ||
| 162 | }, | ||
| 163 | }; | ||
| 164 | module_platform_driver(da9052_onkey_driver); | ||
| 165 | |||
| 166 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | ||
| 167 | MODULE_DESCRIPTION("Onkey driver for DA9052"); | ||
| 168 | MODULE_LICENSE("GPL"); | ||
| 169 | MODULE_ALIAS("platform:da9052-onkey"); | ||
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c index 23cf08271049..0a12b74140d3 100644 --- a/drivers/input/misc/max8925_onkey.c +++ b/drivers/input/misc/max8925_onkey.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * max8925_onkey.c - MAX8925 ONKEY driver | 2 | * MAX8925 ONKEY driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2009 Marvell International Ltd. | 4 | * Copyright (C) 2009 Marvell International Ltd. |
| 5 | * Haojian Zhuang <haojian.zhuang@marvell.com> | 5 | * Haojian Zhuang <haojian.zhuang@marvell.com> |
| @@ -35,7 +35,7 @@ struct max8925_onkey_info { | |||
| 35 | struct input_dev *idev; | 35 | struct input_dev *idev; |
| 36 | struct i2c_client *i2c; | 36 | struct i2c_client *i2c; |
| 37 | struct device *dev; | 37 | struct device *dev; |
| 38 | int irq[2]; | 38 | unsigned int irq[2]; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | /* | 41 | /* |
| @@ -46,17 +46,14 @@ struct max8925_onkey_info { | |||
| 46 | static irqreturn_t max8925_onkey_handler(int irq, void *data) | 46 | static irqreturn_t max8925_onkey_handler(int irq, void *data) |
| 47 | { | 47 | { |
| 48 | struct max8925_onkey_info *info = data; | 48 | struct max8925_onkey_info *info = data; |
| 49 | int ret, event; | 49 | int state; |
| 50 | 50 | ||
| 51 | ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS); | 51 | state = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS); |
| 52 | if (ret & SW_INPUT) | 52 | |
| 53 | event = 1; | 53 | input_report_key(info->idev, KEY_POWER, state & SW_INPUT); |
| 54 | else | ||
| 55 | event = 0; | ||
| 56 | input_report_key(info->idev, KEY_POWER, event); | ||
| 57 | input_sync(info->idev); | 54 | input_sync(info->idev); |
| 58 | 55 | ||
| 59 | dev_dbg(info->dev, "onkey event:%d\n", event); | 56 | dev_dbg(info->dev, "onkey state:%d\n", state); |
| 60 | 57 | ||
| 61 | /* Enable hardreset to halt if system isn't shutdown on time */ | 58 | /* Enable hardreset to halt if system isn't shutdown on time */ |
| 62 | max8925_set_bits(info->i2c, MAX8925_SYSENSEL, | 59 | max8925_set_bits(info->i2c, MAX8925_SYSENSEL, |
| @@ -69,6 +66,7 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev) | |||
| 69 | { | 66 | { |
| 70 | struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); | 67 | struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); |
| 71 | struct max8925_onkey_info *info; | 68 | struct max8925_onkey_info *info; |
| 69 | struct input_dev *input; | ||
| 72 | int irq[2], error; | 70 | int irq[2], error; |
| 73 | 71 | ||
| 74 | irq[0] = platform_get_irq(pdev, 0); | 72 | irq[0] = platform_get_irq(pdev, 0); |
| @@ -76,6 +74,7 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev) | |||
| 76 | dev_err(&pdev->dev, "No IRQ resource!\n"); | 74 | dev_err(&pdev->dev, "No IRQ resource!\n"); |
| 77 | return -EINVAL; | 75 | return -EINVAL; |
| 78 | } | 76 | } |
| 77 | |||
| 79 | irq[1] = platform_get_irq(pdev, 1); | 78 | irq[1] = platform_get_irq(pdev, 1); |
| 80 | if (irq[1] < 0) { | 79 | if (irq[1] < 0) { |
| 81 | dev_err(&pdev->dev, "No IRQ resource!\n"); | 80 | dev_err(&pdev->dev, "No IRQ resource!\n"); |
| @@ -83,11 +82,24 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev) | |||
| 83 | } | 82 | } |
| 84 | 83 | ||
| 85 | info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL); | 84 | info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL); |
| 86 | if (!info) | 85 | input = input_allocate_device(); |
| 87 | return -ENOMEM; | 86 | if (!info || !input) { |
| 87 | error = -ENOMEM; | ||
| 88 | goto err_free_mem; | ||
| 89 | } | ||
| 88 | 90 | ||
| 91 | info->idev = input; | ||
| 89 | info->i2c = chip->i2c; | 92 | info->i2c = chip->i2c; |
| 90 | info->dev = &pdev->dev; | 93 | info->dev = &pdev->dev; |
| 94 | info->irq[0] = irq[0]; | ||
| 95 | info->irq[1] = irq[1]; | ||
| 96 | |||
| 97 | input->name = "max8925_on"; | ||
| 98 | input->phys = "max8925_on/input0"; | ||
| 99 | input->id.bustype = BUS_I2C; | ||
| 100 | input->dev.parent = &pdev->dev; | ||
| 101 | input_set_capability(input, EV_KEY, KEY_POWER); | ||
| 102 | |||
| 91 | irq[0] += chip->irq_base; | 103 | irq[0] += chip->irq_base; |
| 92 | irq[1] += chip->irq_base; | 104 | irq[1] += chip->irq_base; |
| 93 | 105 | ||
| @@ -96,60 +108,46 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev) | |||
| 96 | if (error < 0) { | 108 | if (error < 0) { |
| 97 | dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", | 109 | dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", |
| 98 | irq[0], error); | 110 | irq[0], error); |
| 99 | goto out; | 111 | goto err_free_mem; |
| 100 | } | 112 | } |
| 113 | |||
| 101 | error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler, | 114 | error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler, |
| 102 | IRQF_ONESHOT, "onkey-up", info); | 115 | IRQF_ONESHOT, "onkey-up", info); |
| 103 | if (error < 0) { | 116 | if (error < 0) { |
| 104 | dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", | 117 | dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", |
| 105 | irq[1], error); | 118 | irq[1], error); |
| 106 | goto out_irq; | 119 | goto err_free_irq0; |
| 107 | } | 120 | } |
| 108 | 121 | ||
| 109 | info->idev = input_allocate_device(); | ||
| 110 | if (!info->idev) { | ||
| 111 | dev_err(chip->dev, "Failed to allocate input dev\n"); | ||
| 112 | error = -ENOMEM; | ||
| 113 | goto out_input; | ||
| 114 | } | ||
| 115 | |||
| 116 | info->idev->name = "max8925_on"; | ||
| 117 | info->idev->phys = "max8925_on/input0"; | ||
| 118 | info->idev->id.bustype = BUS_I2C; | ||
| 119 | info->idev->dev.parent = &pdev->dev; | ||
| 120 | info->irq[0] = irq[0]; | ||
| 121 | info->irq[1] = irq[1]; | ||
| 122 | info->idev->evbit[0] = BIT_MASK(EV_KEY); | ||
| 123 | info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); | ||
| 124 | |||
| 125 | |||
| 126 | error = input_register_device(info->idev); | 122 | error = input_register_device(info->idev); |
| 127 | if (error) { | 123 | if (error) { |
| 128 | dev_err(chip->dev, "Can't register input device: %d\n", error); | 124 | dev_err(chip->dev, "Can't register input device: %d\n", error); |
| 129 | goto out_reg; | 125 | goto err_free_irq1; |
| 130 | } | 126 | } |
| 131 | 127 | ||
| 132 | platform_set_drvdata(pdev, info); | 128 | platform_set_drvdata(pdev, info); |
| 129 | device_init_wakeup(&pdev->dev, 1); | ||
| 133 | 130 | ||
| 134 | return 0; | 131 | return 0; |
| 135 | 132 | ||
| 136 | out_reg: | 133 | err_free_irq1: |
| 137 | input_free_device(info->idev); | 134 | free_irq(irq[1], info); |
| 138 | out_input: | 135 | err_free_irq0: |
| 139 | free_irq(info->irq[1], info); | 136 | free_irq(irq[0], info); |
| 140 | out_irq: | 137 | err_free_mem: |
| 141 | free_irq(info->irq[0], info); | 138 | input_free_device(input); |
| 142 | out: | ||
| 143 | kfree(info); | 139 | kfree(info); |
| 140 | |||
| 144 | return error; | 141 | return error; |
| 145 | } | 142 | } |
| 146 | 143 | ||
| 147 | static int __devexit max8925_onkey_remove(struct platform_device *pdev) | 144 | static int __devexit max8925_onkey_remove(struct platform_device *pdev) |
| 148 | { | 145 | { |
| 149 | struct max8925_onkey_info *info = platform_get_drvdata(pdev); | 146 | struct max8925_onkey_info *info = platform_get_drvdata(pdev); |
| 147 | struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); | ||
| 150 | 148 | ||
| 151 | free_irq(info->irq[0], info); | 149 | free_irq(info->irq[0] + chip->irq_base, info); |
| 152 | free_irq(info->irq[1], info); | 150 | free_irq(info->irq[1] + chip->irq_base, info); |
| 153 | input_unregister_device(info->idev); | 151 | input_unregister_device(info->idev); |
| 154 | kfree(info); | 152 | kfree(info); |
| 155 | 153 | ||
| @@ -158,10 +156,43 @@ static int __devexit max8925_onkey_remove(struct platform_device *pdev) | |||
| 158 | return 0; | 156 | return 0; |
| 159 | } | 157 | } |
| 160 | 158 | ||
| 159 | #ifdef CONFIG_PM_SLEEP | ||
| 160 | static int max8925_onkey_suspend(struct device *dev) | ||
| 161 | { | ||
| 162 | struct platform_device *pdev = to_platform_device(dev); | ||
| 163 | struct max8925_onkey_info *info = platform_get_drvdata(pdev); | ||
| 164 | struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); | ||
| 165 | |||
| 166 | if (device_may_wakeup(dev)) { | ||
| 167 | chip->wakeup_flag |= 1 << info->irq[0]; | ||
| 168 | chip->wakeup_flag |= 1 << info->irq[1]; | ||
| 169 | } | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static int max8925_onkey_resume(struct device *dev) | ||
| 175 | { | ||
| 176 | struct platform_device *pdev = to_platform_device(dev); | ||
| 177 | struct max8925_onkey_info *info = platform_get_drvdata(pdev); | ||
| 178 | struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); | ||
| 179 | |||
| 180 | if (device_may_wakeup(dev)) { | ||
| 181 | chip->wakeup_flag &= ~(1 << info->irq[0]); | ||
| 182 | chip->wakeup_flag &= ~(1 << info->irq[1]); | ||
| 183 | } | ||
| 184 | |||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | #endif | ||
| 188 | |||
| 189 | static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume); | ||
| 190 | |||
| 161 | static struct platform_driver max8925_onkey_driver = { | 191 | static struct platform_driver max8925_onkey_driver = { |
| 162 | .driver = { | 192 | .driver = { |
| 163 | .name = "max8925-onkey", | 193 | .name = "max8925-onkey", |
| 164 | .owner = THIS_MODULE, | 194 | .owner = THIS_MODULE, |
| 195 | .pm = &max8925_onkey_pm_ops, | ||
| 165 | }, | 196 | }, |
| 166 | .probe = max8925_onkey_probe, | 197 | .probe = max8925_onkey_probe, |
| 167 | .remove = __devexit_p(max8925_onkey_remove), | 198 | .remove = __devexit_p(max8925_onkey_remove), |
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 9c1e6ee83531..9b8db821d5f0 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
| @@ -322,4 +322,21 @@ config MOUSE_SYNAPTICS_I2C | |||
| 322 | To compile this driver as a module, choose M here: the | 322 | To compile this driver as a module, choose M here: the |
| 323 | module will be called synaptics_i2c. | 323 | module will be called synaptics_i2c. |
| 324 | 324 | ||
| 325 | config MOUSE_SYNAPTICS_USB | ||
| 326 | tristate "Synaptics USB device support" | ||
| 327 | depends on USB_ARCH_HAS_HCD | ||
| 328 | select USB | ||
| 329 | help | ||
| 330 | Say Y here if you want to use a Synaptics USB touchpad or pointing | ||
| 331 | stick. | ||
| 332 | |||
| 333 | While these devices emulate an USB mouse by default and can be used | ||
| 334 | with standard usbhid driver, this driver, together with its X.Org | ||
| 335 | counterpart, allows you to fully utilize capabilities of the device. | ||
| 336 | More information can be found at: | ||
| 337 | <http://jan-steinhoff.de/linux/synaptics-usb.html> | ||
| 338 | |||
| 339 | To compile this driver as a module, choose M here: the | ||
| 340 | module will be called synaptics_usb. | ||
| 341 | |||
| 325 | endif | 342 | endif |
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 570c84a4a654..4718effeb8d9 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile | |||
| @@ -18,6 +18,7 @@ obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o | |||
| 18 | obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o | 18 | obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o |
| 19 | obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o | 19 | obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o |
| 20 | obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o | 20 | obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o |
| 21 | obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o | ||
| 21 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o | 22 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o |
| 22 | 23 | ||
| 23 | psmouse-objs := psmouse-base.o synaptics.o | 24 | psmouse-objs := psmouse-base.o synaptics.o |
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 1c5d521de600..575f880727fe 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c | |||
| @@ -640,7 +640,6 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) | |||
| 640 | 640 | ||
| 641 | static int hgpk_force_recalibrate(struct psmouse *psmouse) | 641 | static int hgpk_force_recalibrate(struct psmouse *psmouse) |
| 642 | { | 642 | { |
| 643 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
| 644 | struct hgpk_data *priv = psmouse->private; | 643 | struct hgpk_data *priv = psmouse->private; |
| 645 | int err; | 644 | int err; |
| 646 | 645 | ||
| @@ -669,12 +668,9 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) | |||
| 669 | * we don't have a good way to deal with it. The 2s window stuff | 668 | * we don't have a good way to deal with it. The 2s window stuff |
| 670 | * (below) is our best option for now. | 669 | * (below) is our best option for now. |
| 671 | */ | 670 | */ |
| 672 | 671 | if (psmouse_activate(psmouse)) | |
| 673 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) | ||
| 674 | return -1; | 672 | return -1; |
| 675 | 673 | ||
| 676 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | ||
| 677 | |||
| 678 | if (tpdebug) | 674 | if (tpdebug) |
| 679 | psmouse_dbg(psmouse, "touchpad reactivated\n"); | 675 | psmouse_dbg(psmouse, "touchpad reactivated\n"); |
| 680 | 676 | ||
| @@ -733,8 +729,7 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable) | |||
| 733 | } | 729 | } |
| 734 | 730 | ||
| 735 | /* should be all set, enable the touchpad */ | 731 | /* should be all set, enable the touchpad */ |
| 736 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); | 732 | psmouse_activate(psmouse); |
| 737 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | ||
| 738 | psmouse_dbg(psmouse, "Touchpad powered up.\n"); | 733 | psmouse_dbg(psmouse, "Touchpad powered up.\n"); |
| 739 | } else { | 734 | } else { |
| 740 | psmouse_dbg(psmouse, "Powering off touchpad.\n"); | 735 | psmouse_dbg(psmouse, "Powering off touchpad.\n"); |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index e6c9931f02c7..22fe2547e169 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
| @@ -1092,28 +1092,33 @@ static void psmouse_initialize(struct psmouse *psmouse) | |||
| 1092 | * psmouse_activate() enables the mouse so that we get motion reports from it. | 1092 | * psmouse_activate() enables the mouse so that we get motion reports from it. |
| 1093 | */ | 1093 | */ |
| 1094 | 1094 | ||
| 1095 | static void psmouse_activate(struct psmouse *psmouse) | 1095 | int psmouse_activate(struct psmouse *psmouse) |
| 1096 | { | 1096 | { |
| 1097 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) | 1097 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { |
| 1098 | psmouse_warn(psmouse, "Failed to enable mouse on %s\n", | 1098 | psmouse_warn(psmouse, "Failed to enable mouse on %s\n", |
| 1099 | psmouse->ps2dev.serio->phys); | 1099 | psmouse->ps2dev.serio->phys); |
| 1100 | return -1; | ||
| 1101 | } | ||
| 1100 | 1102 | ||
| 1101 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | 1103 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); |
| 1104 | return 0; | ||
| 1102 | } | 1105 | } |
| 1103 | 1106 | ||
| 1104 | |||
| 1105 | /* | 1107 | /* |
| 1106 | * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion | 1108 | * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion |
| 1107 | * reports from it unless we explicitly request it. | 1109 | * reports from it unless we explicitly request it. |
| 1108 | */ | 1110 | */ |
| 1109 | 1111 | ||
| 1110 | static void psmouse_deactivate(struct psmouse *psmouse) | 1112 | int psmouse_deactivate(struct psmouse *psmouse) |
| 1111 | { | 1113 | { |
| 1112 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) | 1114 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) { |
| 1113 | psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", | 1115 | psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", |
| 1114 | psmouse->ps2dev.serio->phys); | 1116 | psmouse->ps2dev.serio->phys); |
| 1117 | return -1; | ||
| 1118 | } | ||
| 1115 | 1119 | ||
| 1116 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 1120 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
| 1121 | return 0; | ||
| 1117 | } | 1122 | } |
| 1118 | 1123 | ||
| 1119 | 1124 | ||
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 6a417092d010..fe1df231ba4c 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
| @@ -105,6 +105,8 @@ int psmouse_reset(struct psmouse *psmouse); | |||
| 105 | void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); | 105 | void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); |
| 106 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); | 106 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); |
| 107 | psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); | 107 | psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); |
| 108 | int psmouse_activate(struct psmouse *psmouse); | ||
| 109 | int psmouse_deactivate(struct psmouse *psmouse); | ||
| 108 | 110 | ||
| 109 | struct psmouse_attribute { | 111 | struct psmouse_attribute { |
| 110 | struct device_attribute dattr; | 112 | struct device_attribute dattr; |
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index e36847de7617..2a77a52d2e62 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c | |||
| @@ -90,8 +90,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) | |||
| 90 | * to do that for writes because sysfs set helper does this for | 90 | * to do that for writes because sysfs set helper does this for |
| 91 | * us. | 91 | * us. |
| 92 | */ | 92 | */ |
| 93 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); | 93 | psmouse_deactivate(psmouse); |
| 94 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
| 95 | 94 | ||
| 96 | ps2_begin_command(ps2dev); | 95 | ps2_begin_command(ps2dev); |
| 97 | 96 | ||
| @@ -128,8 +127,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) | |||
| 128 | 127 | ||
| 129 | out: | 128 | out: |
| 130 | ps2_end_command(ps2dev); | 129 | ps2_end_command(ps2dev); |
| 131 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); | 130 | psmouse_activate(psmouse); |
| 132 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | ||
| 133 | dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", | 131 | dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", |
| 134 | reg_addr, *reg_val, rc); | 132 | reg_addr, *reg_val, rc); |
| 135 | return rc; | 133 | return rc; |
| @@ -213,8 +211,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) | |||
| 213 | unsigned char param[3]; | 211 | unsigned char param[3]; |
| 214 | int rc = -1; | 212 | int rc = -1; |
| 215 | 213 | ||
| 216 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); | 214 | psmouse_deactivate(psmouse); |
| 217 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
| 218 | 215 | ||
| 219 | ps2_begin_command(ps2dev); | 216 | ps2_begin_command(ps2dev); |
| 220 | 217 | ||
| @@ -239,8 +236,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) | |||
| 239 | 236 | ||
| 240 | out: | 237 | out: |
| 241 | ps2_end_command(ps2dev); | 238 | ps2_end_command(ps2dev); |
| 242 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); | 239 | psmouse_activate(psmouse); |
| 243 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | ||
| 244 | dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", | 240 | dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", |
| 245 | *reg_val, rc); | 241 | *reg_val, rc); |
| 246 | return rc; | 242 | return rc; |
diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c new file mode 100644 index 000000000000..e559a947bb57 --- /dev/null +++ b/drivers/input/mouse/synaptics_usb.c | |||
| @@ -0,0 +1,568 @@ | |||
| 1 | /* | ||
| 2 | * USB Synaptics device driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2002 Rob Miller (rob@inpharmatica . co . uk) | ||
| 5 | * Copyright (c) 2003 Ron Lee (ron@debian.org) | ||
| 6 | * cPad driver for kernel 2.4 | ||
| 7 | * | ||
| 8 | * Copyright (c) 2004 Jan Steinhoff (cpad@jan-steinhoff . de) | ||
| 9 | * Copyright (c) 2004 Ron Lee (ron@debian.org) | ||
| 10 | * rewritten for kernel 2.6 | ||
| 11 | * | ||
| 12 | * cPad display character device part is not included. It can be found at | ||
| 13 | * http://jan-steinhoff.de/linux/synaptics-usb.html | ||
| 14 | * | ||
| 15 | * Bases on: usb_skeleton.c v2.2 by Greg Kroah-Hartman | ||
| 16 | * drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik | ||
| 17 | * drivers/input/mouse/synaptics.c by Peter Osterlund | ||
| 18 | * | ||
| 19 | * This program is free software; you can redistribute it and/or modify it | ||
| 20 | * under the terms of the GNU General Public License as published by the Free | ||
| 21 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 22 | * any later version. | ||
| 23 | * | ||
| 24 | * Trademarks are the property of their respective owners. | ||
| 25 | */ | ||
| 26 | |||
| 27 | /* | ||
| 28 | * There are three different types of Synaptics USB devices: Touchpads, | ||
| 29 | * touchsticks (or trackpoints), and touchscreens. Touchpads are well supported | ||
| 30 | * by this driver, touchstick support has not been tested much yet, and | ||
| 31 | * touchscreens have not been tested at all. | ||
| 32 | * | ||
| 33 | * Up to three alternate settings are possible: | ||
| 34 | * setting 0: one int endpoint for relative movement (used by usbhid.ko) | ||
| 35 | * setting 1: one int endpoint for absolute finger position | ||
| 36 | * setting 2 (cPad only): one int endpoint for absolute finger position and | ||
| 37 | * two bulk endpoints for the display (in/out) | ||
| 38 | * This driver uses setting 1. | ||
| 39 | */ | ||
| 40 | |||
| 41 | #include <linux/kernel.h> | ||
| 42 | #include <linux/init.h> | ||
| 43 | #include <linux/slab.h> | ||
| 44 | #include <linux/module.h> | ||
| 45 | #include <linux/moduleparam.h> | ||
| 46 | #include <linux/usb.h> | ||
| 47 | #include <linux/input.h> | ||
| 48 | #include <linux/usb/input.h> | ||
| 49 | |||
| 50 | #define USB_VENDOR_ID_SYNAPTICS 0x06cb | ||
| 51 | #define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 /* Synaptics USB TouchPad */ | ||
| 52 | #define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 /* Integrated USB TouchPad */ | ||
| 53 | #define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 /* Synaptics cPad */ | ||
| 54 | #define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 /* Synaptics TouchScreen */ | ||
| 55 | #define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 /* Synaptics USB Styk */ | ||
| 56 | #define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 /* Synaptics USB WheelPad */ | ||
| 57 | #define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 /* Composite USB TouchPad */ | ||
| 58 | #define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 /* Wireless TouchPad */ | ||
| 59 | #define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 /* DisplayPad */ | ||
| 60 | |||
| 61 | #define SYNUSB_TOUCHPAD (1 << 0) | ||
| 62 | #define SYNUSB_STICK (1 << 1) | ||
| 63 | #define SYNUSB_TOUCHSCREEN (1 << 2) | ||
| 64 | #define SYNUSB_AUXDISPLAY (1 << 3) /* For cPad */ | ||
| 65 | #define SYNUSB_COMBO (1 << 4) /* Composite device (TP + stick) */ | ||
| 66 | #define SYNUSB_IO_ALWAYS (1 << 5) | ||
| 67 | |||
| 68 | #define USB_DEVICE_SYNAPTICS(prod, kind) \ | ||
| 69 | USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, \ | ||
| 70 | USB_DEVICE_ID_SYNAPTICS_##prod), \ | ||
| 71 | .driver_info = (kind), | ||
| 72 | |||
| 73 | #define SYNUSB_RECV_SIZE 8 | ||
| 74 | |||
| 75 | #define XMIN_NOMINAL 1472 | ||
| 76 | #define XMAX_NOMINAL 5472 | ||
| 77 | #define YMIN_NOMINAL 1408 | ||
| 78 | #define YMAX_NOMINAL 4448 | ||
| 79 | |||
| 80 | struct synusb { | ||
| 81 | struct usb_device *udev; | ||
| 82 | struct usb_interface *intf; | ||
| 83 | struct urb *urb; | ||
| 84 | unsigned char *data; | ||
| 85 | |||
| 86 | /* input device related data structures */ | ||
| 87 | struct input_dev *input; | ||
| 88 | char name[128]; | ||
| 89 | char phys[64]; | ||
| 90 | |||
| 91 | /* characteristics of the device */ | ||
| 92 | unsigned long flags; | ||
| 93 | }; | ||
| 94 | |||
| 95 | static void synusb_report_buttons(struct synusb *synusb) | ||
| 96 | { | ||
| 97 | struct input_dev *input_dev = synusb->input; | ||
| 98 | |||
| 99 | input_report_key(input_dev, BTN_LEFT, synusb->data[1] & 0x04); | ||
| 100 | input_report_key(input_dev, BTN_RIGHT, synusb->data[1] & 0x01); | ||
| 101 | input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x02); | ||
| 102 | } | ||
| 103 | |||
| 104 | static void synusb_report_stick(struct synusb *synusb) | ||
| 105 | { | ||
| 106 | struct input_dev *input_dev = synusb->input; | ||
| 107 | int x, y; | ||
| 108 | unsigned int pressure; | ||
| 109 | |||
| 110 | pressure = synusb->data[6]; | ||
| 111 | x = (s16)(be16_to_cpup((__be16 *)&synusb->data[2]) << 3) >> 7; | ||
| 112 | y = (s16)(be16_to_cpup((__be16 *)&synusb->data[4]) << 3) >> 7; | ||
| 113 | |||
| 114 | if (pressure > 0) { | ||
| 115 | input_report_rel(input_dev, REL_X, x); | ||
| 116 | input_report_rel(input_dev, REL_Y, -y); | ||
| 117 | } | ||
| 118 | |||
| 119 | input_report_abs(input_dev, ABS_PRESSURE, pressure); | ||
| 120 | |||
| 121 | synusb_report_buttons(synusb); | ||
| 122 | |||
| 123 | input_sync(input_dev); | ||
| 124 | } | ||
| 125 | |||
| 126 | static void synusb_report_touchpad(struct synusb *synusb) | ||
| 127 | { | ||
| 128 | struct input_dev *input_dev = synusb->input; | ||
| 129 | unsigned int num_fingers, tool_width; | ||
| 130 | unsigned int x, y; | ||
| 131 | unsigned int pressure, w; | ||
| 132 | |||
| 133 | pressure = synusb->data[6]; | ||
| 134 | x = be16_to_cpup((__be16 *)&synusb->data[2]); | ||
| 135 | y = be16_to_cpup((__be16 *)&synusb->data[4]); | ||
| 136 | w = synusb->data[0] & 0x0f; | ||
| 137 | |||
| 138 | if (pressure > 0) { | ||
| 139 | num_fingers = 1; | ||
| 140 | tool_width = 5; | ||
| 141 | switch (w) { | ||
| 142 | case 0 ... 1: | ||
| 143 | num_fingers = 2 + w; | ||
| 144 | break; | ||
| 145 | |||
| 146 | case 2: /* pen, pretend its a finger */ | ||
| 147 | break; | ||
| 148 | |||
| 149 | case 4 ... 15: | ||
| 150 | tool_width = w; | ||
| 151 | break; | ||
| 152 | } | ||
| 153 | } else { | ||
| 154 | num_fingers = 0; | ||
| 155 | tool_width = 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Post events | ||
| 160 | * BTN_TOUCH has to be first as mousedev relies on it when doing | ||
| 161 | * absolute -> relative conversion | ||
| 162 | */ | ||
| 163 | |||
| 164 | if (pressure > 30) | ||
| 165 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
| 166 | if (pressure < 25) | ||
| 167 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
| 168 | |||
| 169 | if (num_fingers > 0) { | ||
| 170 | input_report_abs(input_dev, ABS_X, x); | ||
| 171 | input_report_abs(input_dev, ABS_Y, | ||
| 172 | YMAX_NOMINAL + YMIN_NOMINAL - y); | ||
| 173 | } | ||
| 174 | |||
| 175 | input_report_abs(input_dev, ABS_PRESSURE, pressure); | ||
| 176 | input_report_abs(input_dev, ABS_TOOL_WIDTH, tool_width); | ||
| 177 | |||
| 178 | input_report_key(input_dev, BTN_TOOL_FINGER, num_fingers == 1); | ||
| 179 | input_report_key(input_dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); | ||
| 180 | input_report_key(input_dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); | ||
| 181 | |||
| 182 | synusb_report_buttons(synusb); | ||
| 183 | if (synusb->flags & SYNUSB_AUXDISPLAY) | ||
| 184 | input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x08); | ||
| 185 | |||
| 186 | input_sync(input_dev); | ||
| 187 | } | ||
| 188 | |||
| 189 | static void synusb_irq(struct urb *urb) | ||
| 190 | { | ||
| 191 | struct synusb *synusb = urb->context; | ||
| 192 | int error; | ||
| 193 | |||
| 194 | /* Check our status in case we need to bail out early. */ | ||
| 195 | switch (urb->status) { | ||
| 196 | case 0: | ||
| 197 | usb_mark_last_busy(synusb->udev); | ||
| 198 | break; | ||
| 199 | |||
| 200 | /* Device went away so don't keep trying to read from it. */ | ||
| 201 | case -ECONNRESET: | ||
| 202 | case -ENOENT: | ||
| 203 | case -ESHUTDOWN: | ||
| 204 | return; | ||
| 205 | |||
| 206 | default: | ||
| 207 | goto resubmit; | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | |||
| 211 | if (synusb->flags & SYNUSB_STICK) | ||
| 212 | synusb_report_stick(synusb); | ||
| 213 | else | ||
| 214 | synusb_report_touchpad(synusb); | ||
| 215 | |||
| 216 | resubmit: | ||
| 217 | error = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 218 | if (error && error != -EPERM) | ||
| 219 | dev_err(&synusb->intf->dev, | ||
| 220 | "%s - usb_submit_urb failed with result: %d", | ||
| 221 | __func__, error); | ||
| 222 | } | ||
| 223 | |||
| 224 | static struct usb_endpoint_descriptor * | ||
| 225 | synusb_get_in_endpoint(struct usb_host_interface *iface) | ||
| 226 | { | ||
| 227 | |||
| 228 | struct usb_endpoint_descriptor *endpoint; | ||
| 229 | int i; | ||
| 230 | |||
| 231 | for (i = 0; i < iface->desc.bNumEndpoints; ++i) { | ||
| 232 | endpoint = &iface->endpoint[i].desc; | ||
| 233 | |||
| 234 | if (usb_endpoint_is_int_in(endpoint)) { | ||
| 235 | /* we found our interrupt in endpoint */ | ||
| 236 | return endpoint; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | return NULL; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int synusb_open(struct input_dev *dev) | ||
| 244 | { | ||
| 245 | struct synusb *synusb = input_get_drvdata(dev); | ||
| 246 | int retval; | ||
| 247 | |||
| 248 | retval = usb_autopm_get_interface(synusb->intf); | ||
| 249 | if (retval) { | ||
| 250 | dev_err(&synusb->intf->dev, | ||
| 251 | "%s - usb_autopm_get_interface failed, error: %d\n", | ||
| 252 | __func__, retval); | ||
| 253 | return retval; | ||
| 254 | } | ||
| 255 | |||
| 256 | retval = usb_submit_urb(synusb->urb, GFP_KERNEL); | ||
| 257 | if (retval) { | ||
| 258 | dev_err(&synusb->intf->dev, | ||
| 259 | "%s - usb_submit_urb failed, error: %d\n", | ||
| 260 | __func__, retval); | ||
| 261 | retval = -EIO; | ||
| 262 | goto out; | ||
| 263 | } | ||
| 264 | |||
| 265 | synusb->intf->needs_remote_wakeup = 1; | ||
| 266 | |||
| 267 | out: | ||
| 268 | usb_autopm_put_interface(synusb->intf); | ||
| 269 | return retval; | ||
| 270 | } | ||
| 271 | |||
| 272 | static void synusb_close(struct input_dev *dev) | ||
| 273 | { | ||
| 274 | struct synusb *synusb = input_get_drvdata(dev); | ||
| 275 | int autopm_error; | ||
| 276 | |||
| 277 | autopm_error = usb_autopm_get_interface(synusb->intf); | ||
| 278 | |||
| 279 | usb_kill_urb(synusb->urb); | ||
| 280 | synusb->intf->needs_remote_wakeup = 0; | ||
| 281 | |||
| 282 | if (!autopm_error) | ||
| 283 | usb_autopm_put_interface(synusb->intf); | ||
| 284 | } | ||
| 285 | |||
| 286 | static int synusb_probe(struct usb_interface *intf, | ||
| 287 | const struct usb_device_id *id) | ||
| 288 | { | ||
| 289 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 290 | struct usb_endpoint_descriptor *ep; | ||
| 291 | struct synusb *synusb; | ||
| 292 | struct input_dev *input_dev; | ||
| 293 | unsigned int intf_num = intf->cur_altsetting->desc.bInterfaceNumber; | ||
| 294 | unsigned int altsetting = min(intf->num_altsetting, 1U); | ||
| 295 | int error; | ||
| 296 | |||
| 297 | error = usb_set_interface(udev, intf_num, altsetting); | ||
| 298 | if (error) { | ||
| 299 | dev_err(&udev->dev, | ||
| 300 | "Can not set alternate setting to %i, error: %i", | ||
| 301 | altsetting, error); | ||
| 302 | return error; | ||
| 303 | } | ||
| 304 | |||
| 305 | ep = synusb_get_in_endpoint(intf->cur_altsetting); | ||
| 306 | if (!ep) | ||
| 307 | return -ENODEV; | ||
| 308 | |||
| 309 | synusb = kzalloc(sizeof(*synusb), GFP_KERNEL); | ||
| 310 | input_dev = input_allocate_device(); | ||
| 311 | if (!synusb || !input_dev) { | ||
| 312 | error = -ENOMEM; | ||
| 313 | goto err_free_mem; | ||
| 314 | } | ||
| 315 | |||
| 316 | synusb->udev = udev; | ||
| 317 | synusb->intf = intf; | ||
| 318 | synusb->input = input_dev; | ||
| 319 | |||
| 320 | synusb->flags = id->driver_info; | ||
| 321 | if (synusb->flags & SYNUSB_COMBO) { | ||
| 322 | /* | ||
| 323 | * This is a combo device, we need to set proper | ||
| 324 | * capability, depending on the interface. | ||
| 325 | */ | ||
| 326 | synusb->flags |= intf_num == 1 ? | ||
| 327 | SYNUSB_STICK : SYNUSB_TOUCHPAD; | ||
| 328 | } | ||
| 329 | |||
| 330 | synusb->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 331 | if (!synusb->urb) { | ||
| 332 | error = -ENOMEM; | ||
| 333 | goto err_free_mem; | ||
| 334 | } | ||
| 335 | |||
| 336 | synusb->data = usb_alloc_coherent(udev, SYNUSB_RECV_SIZE, GFP_KERNEL, | ||
| 337 | &synusb->urb->transfer_dma); | ||
| 338 | if (!synusb->data) { | ||
| 339 | error = -ENOMEM; | ||
| 340 | goto err_free_urb; | ||
| 341 | } | ||
| 342 | |||
| 343 | usb_fill_int_urb(synusb->urb, udev, | ||
| 344 | usb_rcvintpipe(udev, ep->bEndpointAddress), | ||
| 345 | synusb->data, SYNUSB_RECV_SIZE, | ||
| 346 | synusb_irq, synusb, | ||
| 347 | ep->bInterval); | ||
| 348 | synusb->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 349 | |||
| 350 | if (udev->manufacturer) | ||
| 351 | strlcpy(synusb->name, udev->manufacturer, | ||
| 352 | sizeof(synusb->name)); | ||
| 353 | |||
| 354 | if (udev->product) { | ||
| 355 | if (udev->manufacturer) | ||
| 356 | strlcat(synusb->name, " ", sizeof(synusb->name)); | ||
| 357 | strlcat(synusb->name, udev->product, sizeof(synusb->name)); | ||
| 358 | } | ||
| 359 | |||
| 360 | if (!strlen(synusb->name)) | ||
| 361 | snprintf(synusb->name, sizeof(synusb->name), | ||
| 362 | "USB Synaptics Device %04x:%04x", | ||
| 363 | le16_to_cpu(udev->descriptor.idVendor), | ||
| 364 | le16_to_cpu(udev->descriptor.idProduct)); | ||
| 365 | |||
| 366 | if (synusb->flags & SYNUSB_STICK) | ||
| 367 | strlcat(synusb->name, " (Stick) ", sizeof(synusb->name)); | ||
| 368 | |||
| 369 | usb_make_path(udev, synusb->phys, sizeof(synusb->phys)); | ||
| 370 | strlcat(synusb->phys, "/input0", sizeof(synusb->phys)); | ||
| 371 | |||
| 372 | input_dev->name = synusb->name; | ||
| 373 | input_dev->phys = synusb->phys; | ||
| 374 | usb_to_input_id(udev, &input_dev->id); | ||
| 375 | input_dev->dev.parent = &synusb->intf->dev; | ||
| 376 | |||
| 377 | if (!(synusb->flags & SYNUSB_IO_ALWAYS)) { | ||
| 378 | input_dev->open = synusb_open; | ||
| 379 | input_dev->close = synusb_close; | ||
| 380 | } | ||
| 381 | |||
| 382 | input_set_drvdata(input_dev, synusb); | ||
| 383 | |||
| 384 | __set_bit(EV_ABS, input_dev->evbit); | ||
| 385 | __set_bit(EV_KEY, input_dev->evbit); | ||
| 386 | |||
| 387 | if (synusb->flags & SYNUSB_STICK) { | ||
| 388 | __set_bit(EV_REL, input_dev->evbit); | ||
| 389 | __set_bit(REL_X, input_dev->relbit); | ||
| 390 | __set_bit(REL_Y, input_dev->relbit); | ||
| 391 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0); | ||
| 392 | } else { | ||
| 393 | input_set_abs_params(input_dev, ABS_X, | ||
| 394 | XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); | ||
| 395 | input_set_abs_params(input_dev, ABS_Y, | ||
| 396 | YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); | ||
| 397 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); | ||
| 398 | input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); | ||
| 399 | __set_bit(BTN_TOUCH, input_dev->keybit); | ||
| 400 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); | ||
| 401 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | ||
| 402 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | ||
| 403 | } | ||
| 404 | |||
| 405 | __set_bit(BTN_LEFT, input_dev->keybit); | ||
| 406 | __set_bit(BTN_RIGHT, input_dev->keybit); | ||
| 407 | __set_bit(BTN_MIDDLE, input_dev->keybit); | ||
| 408 | |||
| 409 | usb_set_intfdata(intf, synusb); | ||
| 410 | |||
| 411 | if (synusb->flags & SYNUSB_IO_ALWAYS) { | ||
| 412 | error = synusb_open(input_dev); | ||
| 413 | if (error) | ||
| 414 | goto err_free_dma; | ||
| 415 | } | ||
| 416 | |||
| 417 | error = input_register_device(input_dev); | ||
| 418 | if (error) { | ||
| 419 | dev_err(&udev->dev, | ||
| 420 | "Failed to register input device, error %d\n", | ||
| 421 | error); | ||
| 422 | goto err_stop_io; | ||
| 423 | } | ||
| 424 | |||
| 425 | return 0; | ||
| 426 | |||
| 427 | err_stop_io: | ||
| 428 | if (synusb->flags & SYNUSB_IO_ALWAYS) | ||
| 429 | synusb_close(synusb->input); | ||
| 430 | err_free_dma: | ||
| 431 | usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data, | ||
| 432 | synusb->urb->transfer_dma); | ||
| 433 | err_free_urb: | ||
| 434 | usb_free_urb(synusb->urb); | ||
| 435 | err_free_mem: | ||
| 436 | input_free_device(input_dev); | ||
| 437 | kfree(synusb); | ||
| 438 | usb_set_intfdata(intf, NULL); | ||
| 439 | |||
| 440 | return error; | ||
| 441 | } | ||
| 442 | |||
| 443 | static void synusb_disconnect(struct usb_interface *intf) | ||
| 444 | { | ||
| 445 | struct synusb *synusb = usb_get_intfdata(intf); | ||
| 446 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 447 | |||
| 448 | if (synusb->flags & SYNUSB_IO_ALWAYS) | ||
| 449 | synusb_close(synusb->input); | ||
| 450 | |||
| 451 | input_unregister_device(synusb->input); | ||
| 452 | |||
| 453 | usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data, | ||
| 454 | synusb->urb->transfer_dma); | ||
| 455 | usb_free_urb(synusb->urb); | ||
| 456 | kfree(synusb); | ||
| 457 | |||
| 458 | usb_set_intfdata(intf, NULL); | ||
| 459 | } | ||
| 460 | |||
| 461 | static int synusb_suspend(struct usb_interface *intf, pm_message_t message) | ||
| 462 | { | ||
| 463 | struct synusb *synusb = usb_get_intfdata(intf); | ||
| 464 | struct input_dev *input_dev = synusb->input; | ||
| 465 | |||
| 466 | mutex_lock(&input_dev->mutex); | ||
| 467 | usb_kill_urb(synusb->urb); | ||
| 468 | mutex_unlock(&input_dev->mutex); | ||
| 469 | |||
| 470 | return 0; | ||
| 471 | } | ||
| 472 | |||
| 473 | static int synusb_resume(struct usb_interface *intf) | ||
| 474 | { | ||
| 475 | struct synusb *synusb = usb_get_intfdata(intf); | ||
| 476 | struct input_dev *input_dev = synusb->input; | ||
| 477 | int retval = 0; | ||
| 478 | |||
| 479 | mutex_lock(&input_dev->mutex); | ||
| 480 | |||
| 481 | if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) && | ||
| 482 | usb_submit_urb(synusb->urb, GFP_NOIO) < 0) { | ||
| 483 | retval = -EIO; | ||
| 484 | } | ||
| 485 | |||
| 486 | mutex_unlock(&input_dev->mutex); | ||
| 487 | |||
| 488 | return retval; | ||
| 489 | } | ||
| 490 | |||
| 491 | static int synusb_pre_reset(struct usb_interface *intf) | ||
| 492 | { | ||
| 493 | struct synusb *synusb = usb_get_intfdata(intf); | ||
| 494 | struct input_dev *input_dev = synusb->input; | ||
| 495 | |||
| 496 | mutex_lock(&input_dev->mutex); | ||
| 497 | usb_kill_urb(synusb->urb); | ||
| 498 | |||
| 499 | return 0; | ||
| 500 | } | ||
| 501 | |||
| 502 | static int synusb_post_reset(struct usb_interface *intf) | ||
| 503 | { | ||
| 504 | struct synusb *synusb = usb_get_intfdata(intf); | ||
| 505 | struct input_dev *input_dev = synusb->input; | ||
| 506 | int retval = 0; | ||
| 507 | |||
| 508 | if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) && | ||
| 509 | usb_submit_urb(synusb->urb, GFP_NOIO) < 0) { | ||
| 510 | retval = -EIO; | ||
| 511 | } | ||
| 512 | |||
| 513 | mutex_unlock(&input_dev->mutex); | ||
| 514 | |||
| 515 | return retval; | ||
| 516 | } | ||
| 517 | |||
| 518 | static int synusb_reset_resume(struct usb_interface *intf) | ||
| 519 | { | ||
| 520 | return synusb_resume(intf); | ||
| 521 | } | ||
| 522 | |||
| 523 | static struct usb_device_id synusb_idtable[] = { | ||
| 524 | { USB_DEVICE_SYNAPTICS(TP, SYNUSB_TOUCHPAD) }, | ||
| 525 | { USB_DEVICE_SYNAPTICS(INT_TP, SYNUSB_TOUCHPAD) }, | ||
| 526 | { USB_DEVICE_SYNAPTICS(CPAD, | ||
| 527 | SYNUSB_TOUCHPAD | SYNUSB_AUXDISPLAY | SYNUSB_IO_ALWAYS) }, | ||
| 528 | { USB_DEVICE_SYNAPTICS(TS, SYNUSB_TOUCHSCREEN) }, | ||
| 529 | { USB_DEVICE_SYNAPTICS(STICK, SYNUSB_STICK) }, | ||
| 530 | { USB_DEVICE_SYNAPTICS(WP, SYNUSB_TOUCHPAD) }, | ||
| 531 | { USB_DEVICE_SYNAPTICS(COMP_TP, SYNUSB_COMBO) }, | ||
| 532 | { USB_DEVICE_SYNAPTICS(WTP, SYNUSB_TOUCHPAD) }, | ||
| 533 | { USB_DEVICE_SYNAPTICS(DPAD, SYNUSB_TOUCHPAD) }, | ||
| 534 | { } | ||
| 535 | }; | ||
| 536 | MODULE_DEVICE_TABLE(usb, synusb_idtable); | ||
| 537 | |||
| 538 | static struct usb_driver synusb_driver = { | ||
| 539 | .name = "synaptics_usb", | ||
| 540 | .probe = synusb_probe, | ||
| 541 | .disconnect = synusb_disconnect, | ||
| 542 | .id_table = synusb_idtable, | ||
| 543 | .suspend = synusb_suspend, | ||
| 544 | .resume = synusb_resume, | ||
| 545 | .pre_reset = synusb_pre_reset, | ||
| 546 | .post_reset = synusb_post_reset, | ||
| 547 | .reset_resume = synusb_reset_resume, | ||
| 548 | .supports_autosuspend = 1, | ||
| 549 | }; | ||
| 550 | |||
| 551 | static int __init synusb_init(void) | ||
| 552 | { | ||
| 553 | return usb_register(&synusb_driver); | ||
| 554 | } | ||
| 555 | |||
| 556 | static void __exit synusb_exit(void) | ||
| 557 | { | ||
| 558 | usb_deregister(&synusb_driver); | ||
| 559 | } | ||
| 560 | |||
| 561 | module_init(synusb_init); | ||
| 562 | module_exit(synusb_exit); | ||
| 563 | |||
| 564 | MODULE_AUTHOR("Rob Miller <rob@inpharmatica.co.uk>, " | ||
| 565 | "Ron Lee <ron@debian.org>, " | ||
| 566 | "Jan Steinhoff <cpad@jan-steinhoff.de>"); | ||
| 567 | MODULE_DESCRIPTION("Synaptics USB device driver"); | ||
| 568 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c index 95280f9207e1..36e799c31f5e 100644 --- a/drivers/input/serio/at32psif.c +++ b/drivers/input/serio/at32psif.c | |||
| @@ -98,9 +98,9 @@ struct psif { | |||
| 98 | struct serio *io; | 98 | struct serio *io; |
| 99 | void __iomem *regs; | 99 | void __iomem *regs; |
| 100 | unsigned int irq; | 100 | unsigned int irq; |
| 101 | unsigned int open; | ||
| 102 | /* Prevent concurrent writes to PSIF THR. */ | 101 | /* Prevent concurrent writes to PSIF THR. */ |
| 103 | spinlock_t lock; | 102 | spinlock_t lock; |
| 103 | bool open; | ||
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | static irqreturn_t psif_interrupt(int irq, void *_ptr) | 106 | static irqreturn_t psif_interrupt(int irq, void *_ptr) |
| @@ -164,7 +164,7 @@ static int psif_open(struct serio *io) | |||
| 164 | psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN)); | 164 | psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN)); |
| 165 | psif_writel(psif, IER, PSIF_BIT(RXRDY)); | 165 | psif_writel(psif, IER, PSIF_BIT(RXRDY)); |
| 166 | 166 | ||
| 167 | psif->open = 1; | 167 | psif->open = true; |
| 168 | out: | 168 | out: |
| 169 | return retval; | 169 | return retval; |
| 170 | } | 170 | } |
| @@ -173,7 +173,7 @@ static void psif_close(struct serio *io) | |||
| 173 | { | 173 | { |
| 174 | struct psif *psif = io->port_data; | 174 | struct psif *psif = io->port_data; |
| 175 | 175 | ||
| 176 | psif->open = 0; | 176 | psif->open = false; |
| 177 | 177 | ||
| 178 | psif_writel(psif, IDR, ~0UL); | 178 | psif_writel(psif, IDR, ~0UL); |
| 179 | psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS)); | 179 | psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS)); |
| @@ -319,9 +319,10 @@ static int __exit psif_remove(struct platform_device *pdev) | |||
| 319 | return 0; | 319 | return 0; |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | #ifdef CONFIG_PM | 322 | #ifdef CONFIG_PM_SLEEP |
| 323 | static int psif_suspend(struct platform_device *pdev, pm_message_t state) | 323 | static int psif_suspend(struct device *dev) |
| 324 | { | 324 | { |
| 325 | struct platform_device *pdev = to_platform_device(dev); | ||
| 325 | struct psif *psif = platform_get_drvdata(pdev); | 326 | struct psif *psif = platform_get_drvdata(pdev); |
| 326 | 327 | ||
| 327 | if (psif->open) { | 328 | if (psif->open) { |
| @@ -332,8 +333,9 @@ static int psif_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 332 | return 0; | 333 | return 0; |
| 333 | } | 334 | } |
| 334 | 335 | ||
| 335 | static int psif_resume(struct platform_device *pdev) | 336 | static int psif_resume(struct device *dev) |
| 336 | { | 337 | { |
| 338 | struct platform_device *pdev = to_platform_device(dev); | ||
| 337 | struct psif *psif = platform_get_drvdata(pdev); | 339 | struct psif *psif = platform_get_drvdata(pdev); |
| 338 | 340 | ||
| 339 | if (psif->open) { | 341 | if (psif->open) { |
| @@ -344,19 +346,17 @@ static int psif_resume(struct platform_device *pdev) | |||
| 344 | 346 | ||
| 345 | return 0; | 347 | return 0; |
| 346 | } | 348 | } |
| 347 | #else | ||
| 348 | #define psif_suspend NULL | ||
| 349 | #define psif_resume NULL | ||
| 350 | #endif | 349 | #endif |
| 351 | 350 | ||
| 351 | static SIMPLE_DEV_PM_OPS(psif_pm_ops, psif_suspend, psif_resume); | ||
| 352 | |||
| 352 | static struct platform_driver psif_driver = { | 353 | static struct platform_driver psif_driver = { |
| 353 | .remove = __exit_p(psif_remove), | 354 | .remove = __exit_p(psif_remove), |
| 354 | .driver = { | 355 | .driver = { |
| 355 | .name = "atmel_psif", | 356 | .name = "atmel_psif", |
| 356 | .owner = THIS_MODULE, | 357 | .owner = THIS_MODULE, |
| 358 | .pm = &psif_pm_ops, | ||
| 357 | }, | 359 | }, |
| 358 | .suspend = psif_suspend, | ||
| 359 | .resume = psif_resume, | ||
| 360 | }; | 360 | }; |
| 361 | 361 | ||
| 362 | static int __init psif_init(void) | 362 | static int __init psif_init(void) |
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 5eb84b3b67fb..0c0df7f73802 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c | |||
| @@ -44,26 +44,31 @@ | |||
| 44 | #include <asm/irq.h> | 44 | #include <asm/irq.h> |
| 45 | #include <asm/q40ints.h> | 45 | #include <asm/q40ints.h> |
| 46 | 46 | ||
| 47 | #define DRV_NAME "q40kbd" | ||
| 48 | |||
| 47 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 49 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
| 48 | MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); | 50 | MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); |
| 49 | MODULE_LICENSE("GPL"); | 51 | MODULE_LICENSE("GPL"); |
| 52 | MODULE_ALIAS("platform:" DRV_NAME); | ||
| 50 | 53 | ||
| 51 | static DEFINE_SPINLOCK(q40kbd_lock); | 54 | struct q40kbd { |
| 52 | static struct serio *q40kbd_port; | 55 | struct serio *port; |
| 53 | static struct platform_device *q40kbd_device; | 56 | spinlock_t lock; |
| 57 | }; | ||
| 54 | 58 | ||
| 55 | static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) | 59 | static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) |
| 56 | { | 60 | { |
| 61 | struct q40kbd *q40kbd = dev_id; | ||
| 57 | unsigned long flags; | 62 | unsigned long flags; |
| 58 | 63 | ||
| 59 | spin_lock_irqsave(&q40kbd_lock, flags); | 64 | spin_lock_irqsave(&q40kbd->lock, flags); |
| 60 | 65 | ||
| 61 | if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) | 66 | if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) |
| 62 | serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0); | 67 | serio_interrupt(q40kbd->port, master_inb(KEYCODE_REG), 0); |
| 63 | 68 | ||
| 64 | master_outb(-1, KEYBOARD_UNLOCK_REG); | 69 | master_outb(-1, KEYBOARD_UNLOCK_REG); |
| 65 | 70 | ||
| 66 | spin_unlock_irqrestore(&q40kbd_lock, flags); | 71 | spin_unlock_irqrestore(&q40kbd->lock, flags); |
| 67 | 72 | ||
| 68 | return IRQ_HANDLED; | 73 | return IRQ_HANDLED; |
| 69 | } | 74 | } |
| @@ -72,17 +77,23 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) | |||
| 72 | * q40kbd_flush() flushes all data that may be in the keyboard buffers | 77 | * q40kbd_flush() flushes all data that may be in the keyboard buffers |
| 73 | */ | 78 | */ |
| 74 | 79 | ||
| 75 | static void q40kbd_flush(void) | 80 | static void q40kbd_flush(struct q40kbd *q40kbd) |
| 76 | { | 81 | { |
| 77 | int maxread = 100; | 82 | int maxread = 100; |
| 78 | unsigned long flags; | 83 | unsigned long flags; |
| 79 | 84 | ||
| 80 | spin_lock_irqsave(&q40kbd_lock, flags); | 85 | spin_lock_irqsave(&q40kbd->lock, flags); |
| 81 | 86 | ||
| 82 | while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) | 87 | while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) |
| 83 | master_inb(KEYCODE_REG); | 88 | master_inb(KEYCODE_REG); |
| 84 | 89 | ||
| 85 | spin_unlock_irqrestore(&q40kbd_lock, flags); | 90 | spin_unlock_irqrestore(&q40kbd->lock, flags); |
| 91 | } | ||
| 92 | |||
| 93 | static void q40kbd_stop(void) | ||
| 94 | { | ||
| 95 | master_outb(0, KEY_IRQ_ENABLE_REG); | ||
| 96 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
| 86 | } | 97 | } |
| 87 | 98 | ||
| 88 | /* | 99 | /* |
| @@ -92,12 +103,9 @@ static void q40kbd_flush(void) | |||
| 92 | 103 | ||
| 93 | static int q40kbd_open(struct serio *port) | 104 | static int q40kbd_open(struct serio *port) |
| 94 | { | 105 | { |
| 95 | q40kbd_flush(); | 106 | struct q40kbd *q40kbd = port->port_data; |
| 96 | 107 | ||
| 97 | if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { | 108 | q40kbd_flush(q40kbd); |
| 98 | printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); | ||
| 99 | return -EBUSY; | ||
| 100 | } | ||
| 101 | 109 | ||
| 102 | /* off we go */ | 110 | /* off we go */ |
| 103 | master_outb(-1, KEYBOARD_UNLOCK_REG); | 111 | master_outb(-1, KEYBOARD_UNLOCK_REG); |
| @@ -108,36 +116,72 @@ static int q40kbd_open(struct serio *port) | |||
| 108 | 116 | ||
| 109 | static void q40kbd_close(struct serio *port) | 117 | static void q40kbd_close(struct serio *port) |
| 110 | { | 118 | { |
| 111 | master_outb(0, KEY_IRQ_ENABLE_REG); | 119 | struct q40kbd *q40kbd = port->port_data; |
| 112 | master_outb(-1, KEYBOARD_UNLOCK_REG); | ||
| 113 | free_irq(Q40_IRQ_KEYBOARD, NULL); | ||
| 114 | 120 | ||
| 115 | q40kbd_flush(); | 121 | q40kbd_stop(); |
| 122 | q40kbd_flush(q40kbd); | ||
| 116 | } | 123 | } |
| 117 | 124 | ||
| 118 | static int __devinit q40kbd_probe(struct platform_device *dev) | 125 | static int __devinit q40kbd_probe(struct platform_device *pdev) |
| 119 | { | 126 | { |
| 120 | q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL); | 127 | struct q40kbd *q40kbd; |
| 121 | if (!q40kbd_port) | 128 | struct serio *port; |
| 122 | return -ENOMEM; | 129 | int error; |
| 123 | 130 | ||
| 124 | q40kbd_port->id.type = SERIO_8042; | 131 | q40kbd = kzalloc(sizeof(struct q40kbd), GFP_KERNEL); |
| 125 | q40kbd_port->open = q40kbd_open; | 132 | port = kzalloc(sizeof(struct serio), GFP_KERNEL); |
| 126 | q40kbd_port->close = q40kbd_close; | 133 | if (!q40kbd || !port) { |
| 127 | q40kbd_port->dev.parent = &dev->dev; | 134 | error = -ENOMEM; |
| 128 | strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name)); | 135 | goto err_free_mem; |
| 129 | strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys)); | 136 | } |
| 130 | 137 | ||
| 131 | serio_register_port(q40kbd_port); | 138 | q40kbd->port = port; |
| 139 | spin_lock_init(&q40kbd->lock); | ||
| 140 | |||
| 141 | port->id.type = SERIO_8042; | ||
| 142 | port->open = q40kbd_open; | ||
| 143 | port->close = q40kbd_close; | ||
| 144 | port->port_data = q40kbd; | ||
| 145 | port->dev.parent = &pdev->dev; | ||
| 146 | strlcpy(port->name, "Q40 Kbd Port", sizeof(port->name)); | ||
| 147 | strlcpy(port->phys, "Q40", sizeof(port->phys)); | ||
| 148 | |||
| 149 | q40kbd_stop(); | ||
| 150 | |||
| 151 | error = request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, | ||
| 152 | DRV_NAME, q40kbd); | ||
| 153 | if (error) { | ||
| 154 | dev_err(&pdev->dev, "Can't get irq %d.\n", Q40_IRQ_KEYBOARD); | ||
| 155 | goto err_free_mem; | ||
| 156 | } | ||
| 157 | |||
| 158 | serio_register_port(q40kbd->port); | ||
| 159 | |||
| 160 | platform_set_drvdata(pdev, q40kbd); | ||
| 132 | printk(KERN_INFO "serio: Q40 kbd registered\n"); | 161 | printk(KERN_INFO "serio: Q40 kbd registered\n"); |
| 133 | 162 | ||
| 134 | return 0; | 163 | return 0; |
| 164 | |||
| 165 | err_free_mem: | ||
| 166 | kfree(port); | ||
| 167 | kfree(q40kbd); | ||
| 168 | return error; | ||
| 135 | } | 169 | } |
| 136 | 170 | ||
| 137 | static int __devexit q40kbd_remove(struct platform_device *dev) | 171 | static int __devexit q40kbd_remove(struct platform_device *pdev) |
| 138 | { | 172 | { |
| 139 | serio_unregister_port(q40kbd_port); | 173 | struct q40kbd *q40kbd = platform_get_drvdata(pdev); |
| 140 | 174 | ||
| 175 | /* | ||
| 176 | * q40kbd_close() will be called as part of unregistering | ||
| 177 | * and will ensure that IRQ is turned off, so it is safe | ||
| 178 | * to unregister port first and free IRQ later. | ||
| 179 | */ | ||
| 180 | serio_unregister_port(q40kbd->port); | ||
| 181 | free_irq(Q40_IRQ_KEYBOARD, q40kbd); | ||
| 182 | kfree(q40kbd); | ||
| 183 | |||
| 184 | platform_set_drvdata(pdev, NULL); | ||
| 141 | return 0; | 185 | return 0; |
| 142 | } | 186 | } |
| 143 | 187 | ||
| @@ -146,41 +190,16 @@ static struct platform_driver q40kbd_driver = { | |||
| 146 | .name = "q40kbd", | 190 | .name = "q40kbd", |
| 147 | .owner = THIS_MODULE, | 191 | .owner = THIS_MODULE, |
| 148 | }, | 192 | }, |
| 149 | .probe = q40kbd_probe, | ||
| 150 | .remove = __devexit_p(q40kbd_remove), | 193 | .remove = __devexit_p(q40kbd_remove), |
| 151 | }; | 194 | }; |
| 152 | 195 | ||
| 153 | static int __init q40kbd_init(void) | 196 | static int __init q40kbd_init(void) |
| 154 | { | 197 | { |
| 155 | int error; | 198 | return platform_driver_probe(&q40kbd_driver, q40kbd_probe); |
| 156 | |||
| 157 | if (!MACH_IS_Q40) | ||
| 158 | return -ENODEV; | ||
| 159 | |||
| 160 | error = platform_driver_register(&q40kbd_driver); | ||
| 161 | if (error) | ||
| 162 | return error; | ||
| 163 | |||
| 164 | q40kbd_device = platform_device_alloc("q40kbd", -1); | ||
| 165 | if (!q40kbd_device) | ||
| 166 | goto err_unregister_driver; | ||
| 167 | |||
| 168 | error = platform_device_add(q40kbd_device); | ||
| 169 | if (error) | ||
| 170 | goto err_free_device; | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | |||
| 174 | err_free_device: | ||
| 175 | platform_device_put(q40kbd_device); | ||
| 176 | err_unregister_driver: | ||
| 177 | platform_driver_unregister(&q40kbd_driver); | ||
| 178 | return error; | ||
| 179 | } | 199 | } |
| 180 | 200 | ||
| 181 | static void __exit q40kbd_exit(void) | 201 | static void __exit q40kbd_exit(void) |
| 182 | { | 202 | { |
| 183 | platform_device_unregister(q40kbd_device); | ||
| 184 | platform_driver_unregister(&q40kbd_driver); | 203 | platform_driver_unregister(&q40kbd_driver); |
| 185 | } | 204 | } |
| 186 | 205 | ||
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 2a97b7e76db1..39205eddf713 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c | |||
| @@ -176,7 +176,7 @@ static int wacom_parse_logical_collection(unsigned char *report, | |||
| 176 | 176 | ||
| 177 | /* Logical collection is only used by 3rd gen Bamboo Touch */ | 177 | /* Logical collection is only used by 3rd gen Bamboo Touch */ |
| 178 | features->pktlen = WACOM_PKGLEN_BBTOUCH3; | 178 | features->pktlen = WACOM_PKGLEN_BBTOUCH3; |
| 179 | features->device_type = BTN_TOOL_DOUBLETAP; | 179 | features->device_type = BTN_TOOL_FINGER; |
| 180 | 180 | ||
| 181 | /* | 181 | /* |
| 182 | * Stylus and Touch have same active area | 182 | * Stylus and Touch have same active area |
| @@ -286,12 +286,10 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
| 286 | if (features->type == TABLETPC2FG) { | 286 | if (features->type == TABLETPC2FG) { |
| 287 | /* need to reset back */ | 287 | /* need to reset back */ |
| 288 | features->pktlen = WACOM_PKGLEN_TPC2FG; | 288 | features->pktlen = WACOM_PKGLEN_TPC2FG; |
| 289 | features->device_type = BTN_TOOL_DOUBLETAP; | ||
| 290 | } | 289 | } |
| 291 | if (features->type == BAMBOO_PT) { | 290 | if (features->type == BAMBOO_PT) { |
| 292 | /* need to reset back */ | 291 | /* need to reset back */ |
| 293 | features->pktlen = WACOM_PKGLEN_BBTOUCH; | 292 | features->pktlen = WACOM_PKGLEN_BBTOUCH; |
| 294 | features->device_type = BTN_TOOL_DOUBLETAP; | ||
| 295 | features->x_phy = | 293 | features->x_phy = |
| 296 | get_unaligned_le16(&report[i + 5]); | 294 | get_unaligned_le16(&report[i + 5]); |
| 297 | features->x_max = | 295 | features->x_max = |
| @@ -325,7 +323,6 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
| 325 | if (features->type == TABLETPC2FG) { | 323 | if (features->type == TABLETPC2FG) { |
| 326 | /* need to reset back */ | 324 | /* need to reset back */ |
| 327 | features->pktlen = WACOM_PKGLEN_TPC2FG; | 325 | features->pktlen = WACOM_PKGLEN_TPC2FG; |
| 328 | features->device_type = BTN_TOOL_DOUBLETAP; | ||
| 329 | features->y_max = | 326 | features->y_max = |
| 330 | get_unaligned_le16(&report[i + 3]); | 327 | get_unaligned_le16(&report[i + 3]); |
| 331 | features->y_phy = | 328 | features->y_phy = |
| @@ -334,7 +331,6 @@ static int wacom_parse_hid(struct usb_interface *intf, | |||
| 334 | } else if (features->type == BAMBOO_PT) { | 331 | } else if (features->type == BAMBOO_PT) { |
| 335 | /* need to reset back */ | 332 | /* need to reset back */ |
| 336 | features->pktlen = WACOM_PKGLEN_BBTOUCH; | 333 | features->pktlen = WACOM_PKGLEN_BBTOUCH; |
| 337 | features->device_type = BTN_TOOL_DOUBLETAP; | ||
| 338 | features->y_phy = | 334 | features->y_phy = |
| 339 | get_unaligned_le16(&report[i + 3]); | 335 | get_unaligned_le16(&report[i + 3]); |
| 340 | features->y_max = | 336 | features->y_max = |
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 88672ec296c1..07a1f218b5c1 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c | |||
| @@ -832,12 +832,24 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) | |||
| 832 | 832 | ||
| 833 | dbg("wacom_tpc_irq: received report #%d", data[0]); | 833 | dbg("wacom_tpc_irq: received report #%d", data[0]); |
| 834 | 834 | ||
| 835 | if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG) | 835 | switch (len) { |
| 836 | return wacom_tpc_single_touch(wacom, len); | 836 | case WACOM_PKGLEN_TPC1FG: |
| 837 | else if (data[0] == WACOM_REPORT_TPC2FG) | 837 | return wacom_tpc_single_touch(wacom, len); |
| 838 | return wacom_tpc_mt_touch(wacom); | 838 | |
| 839 | else if (data[0] == WACOM_REPORT_PENABLED) | 839 | case WACOM_PKGLEN_TPC2FG: |
| 840 | return wacom_tpc_pen(wacom); | 840 | return wacom_tpc_mt_touch(wacom); |
| 841 | |||
| 842 | default: | ||
| 843 | switch (data[0]) { | ||
| 844 | case WACOM_REPORT_TPC1FG: | ||
| 845 | case WACOM_REPORT_TPCHID: | ||
| 846 | case WACOM_REPORT_TPCST: | ||
| 847 | return wacom_tpc_single_touch(wacom, len); | ||
| 848 | |||
| 849 | case WACOM_REPORT_PENABLED: | ||
| 850 | return wacom_tpc_pen(wacom); | ||
| 851 | } | ||
| 852 | } | ||
| 841 | 853 | ||
| 842 | return 0; | 854 | return 0; |
| 843 | } | 855 | } |
| @@ -1317,7 +1329,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
| 1317 | break; | 1329 | break; |
| 1318 | 1330 | ||
| 1319 | case TABLETPC2FG: | 1331 | case TABLETPC2FG: |
| 1320 | if (features->device_type == BTN_TOOL_DOUBLETAP) { | 1332 | if (features->device_type == BTN_TOOL_FINGER) { |
| 1321 | 1333 | ||
| 1322 | input_mt_init_slots(input_dev, 2); | 1334 | input_mt_init_slots(input_dev, 2); |
| 1323 | input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, | 1335 | input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, |
| @@ -1366,7 +1378,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
| 1366 | 1378 | ||
| 1367 | __set_bit(INPUT_PROP_POINTER, input_dev->propbit); | 1379 | __set_bit(INPUT_PROP_POINTER, input_dev->propbit); |
| 1368 | 1380 | ||
| 1369 | if (features->device_type == BTN_TOOL_DOUBLETAP) { | 1381 | if (features->device_type == BTN_TOOL_FINGER) { |
| 1370 | __set_bit(BTN_LEFT, input_dev->keybit); | 1382 | __set_bit(BTN_LEFT, input_dev->keybit); |
| 1371 | __set_bit(BTN_FORWARD, input_dev->keybit); | 1383 | __set_bit(BTN_FORWARD, input_dev->keybit); |
| 1372 | __set_bit(BTN_BACK, input_dev->keybit); | 1384 | __set_bit(BTN_BACK, input_dev->keybit); |
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 050acaefee7d..4f0ba21b0196 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h | |||
| @@ -39,6 +39,8 @@ | |||
| 39 | #define WACOM_REPORT_INTUOSPAD 12 | 39 | #define WACOM_REPORT_INTUOSPAD 12 |
| 40 | #define WACOM_REPORT_TPC1FG 6 | 40 | #define WACOM_REPORT_TPC1FG 6 |
| 41 | #define WACOM_REPORT_TPC2FG 13 | 41 | #define WACOM_REPORT_TPC2FG 13 |
| 42 | #define WACOM_REPORT_TPCHID 15 | ||
| 43 | #define WACOM_REPORT_TPCST 16 | ||
| 42 | 44 | ||
| 43 | /* device quirks */ | 45 | /* device quirks */ |
| 44 | #define WACOM_QUIRK_MULTI_INPUT 0x0001 | 46 | #define WACOM_QUIRK_MULTI_INPUT 0x0001 |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 4af2a18eb3ba..fc087b3c95cf 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
| @@ -139,7 +139,6 @@ config TOUCHSCREEN_CY8CTMG110 | |||
| 139 | tristate "cy8ctmg110 touchscreen" | 139 | tristate "cy8ctmg110 touchscreen" |
| 140 | depends on I2C | 140 | depends on I2C |
| 141 | depends on GPIOLIB | 141 | depends on GPIOLIB |
| 142 | |||
| 143 | help | 142 | help |
| 144 | Say Y here if you have a cy8ctmg110 capacitive touchscreen on | 143 | Say Y here if you have a cy8ctmg110 capacitive touchscreen on |
| 145 | an AAVA device. | 144 | an AAVA device. |
| @@ -149,6 +148,37 @@ config TOUCHSCREEN_CY8CTMG110 | |||
| 149 | To compile this driver as a module, choose M here: the | 148 | To compile this driver as a module, choose M here: the |
| 150 | module will be called cy8ctmg110_ts. | 149 | module will be called cy8ctmg110_ts. |
| 151 | 150 | ||
| 151 | config TOUCHSCREEN_CYTTSP_CORE | ||
| 152 | tristate "Cypress TTSP touchscreen" | ||
| 153 | help | ||
| 154 | Say Y here if you have a touchscreen using controller from | ||
| 155 | the Cypress TrueTouch(tm) Standard Product family connected | ||
| 156 | to your system. You will also need to select appropriate | ||
| 157 | bus connection below. | ||
| 158 | |||
| 159 | If unsure, say N. | ||
| 160 | |||
| 161 | To compile this driver as a module, choose M here: the | ||
| 162 | module will be called cyttsp_core. | ||
| 163 | |||
| 164 | config TOUCHSCREEN_CYTTSP_I2C | ||
| 165 | tristate "support I2C bus connection" | ||
| 166 | depends on TOUCHSCREEN_CYTTSP_CORE && I2C | ||
| 167 | help | ||
| 168 | Say Y here if the touchscreen is connected via I2C bus. | ||
| 169 | |||
| 170 | To compile this driver as a module, choose M here: the | ||
| 171 | module will be called cyttsp_i2c. | ||
| 172 | |||
| 173 | config TOUCHSCREEN_CYTTSP_SPI | ||
| 174 | tristate "support SPI bus connection" | ||
| 175 | depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER | ||
| 176 | help | ||
| 177 | Say Y here if the touchscreen is connected via SPI bus. | ||
| 178 | |||
| 179 | To compile this driver as a module, choose M here: the | ||
| 180 | module will be called cyttsp_spi. | ||
| 181 | |||
| 152 | config TOUCHSCREEN_DA9034 | 182 | config TOUCHSCREEN_DA9034 |
| 153 | tristate "Touchscreen support for Dialog Semiconductor DA9034" | 183 | tristate "Touchscreen support for Dialog Semiconductor DA9034" |
| 154 | depends on PMIC_DA903X | 184 | depends on PMIC_DA903X |
| @@ -430,6 +460,18 @@ config TOUCHSCREEN_TOUCHWIN | |||
| 430 | To compile this driver as a module, choose M here: the | 460 | To compile this driver as a module, choose M here: the |
| 431 | module will be called touchwin. | 461 | module will be called touchwin. |
| 432 | 462 | ||
| 463 | config TOUCHSCREEN_TI_TSCADC | ||
| 464 | tristate "TI Touchscreen Interface" | ||
| 465 | depends on ARCH_OMAP2PLUS | ||
| 466 | help | ||
| 467 | Say Y here if you have 4/5/8 wire touchscreen controller | ||
| 468 | to be connected to the ADC controller on your TI AM335x SoC. | ||
| 469 | |||
| 470 | If unsure, say N. | ||
| 471 | |||
| 472 | To compile this driver as a module, choose M here: the | ||
| 473 | module will be called ti_tscadc. | ||
| 474 | |||
| 433 | config TOUCHSCREEN_ATMEL_TSADCC | 475 | config TOUCHSCREEN_ATMEL_TSADCC |
| 434 | tristate "Atmel Touchscreen Interface" | 476 | tristate "Atmel Touchscreen Interface" |
| 435 | depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 | 477 | depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 |
| @@ -577,6 +619,7 @@ config TOUCHSCREEN_USB_COMPOSITE | |||
| 577 | - JASTEC USB Touch Controller/DigiTech DTR-02U | 619 | - JASTEC USB Touch Controller/DigiTech DTR-02U |
| 578 | - Zytronic controllers | 620 | - Zytronic controllers |
| 579 | - Elo TouchSystems 2700 IntelliTouch | 621 | - Elo TouchSystems 2700 IntelliTouch |
| 622 | - EasyTouch USB Touch Controller from Data Modul | ||
| 580 | 623 | ||
| 581 | Have a look at <http://linux.chapter7.ch/touchkit/> for | 624 | Have a look at <http://linux.chapter7.ch/touchkit/> for |
| 582 | a usage description and the required user-space stuff. | 625 | a usage description and the required user-space stuff. |
| @@ -681,6 +724,14 @@ config TOUCHSCREEN_USB_NEXIO | |||
| 681 | bool "NEXIO/iNexio device support" if EXPERT | 724 | bool "NEXIO/iNexio device support" if EXPERT |
| 682 | depends on TOUCHSCREEN_USB_COMPOSITE | 725 | depends on TOUCHSCREEN_USB_COMPOSITE |
| 683 | 726 | ||
| 727 | config TOUCHSCREEN_USB_EASYTOUCH | ||
| 728 | default y | ||
| 729 | bool "EasyTouch USB Touch controller device support" if EMBEDDED | ||
| 730 | depends on TOUCHSCREEN_USB_COMPOSITE | ||
| 731 | help | ||
| 732 | Say Y here if you have a EasyTouch USB Touch controller device support. | ||
| 733 | If unsure, say N. | ||
| 734 | |||
| 684 | config TOUCHSCREEN_TOUCHIT213 | 735 | config TOUCHSCREEN_TOUCHIT213 |
| 685 | tristate "Sahara TouchIT-213 touchscreen" | 736 | tristate "Sahara TouchIT-213 touchscreen" |
| 686 | select SERIO | 737 | select SERIO |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 496091e88460..e748fb837759 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
| @@ -16,8 +16,11 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o | |||
| 16 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o | 16 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o |
| 17 | obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o | 17 | obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o |
| 18 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o | 18 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o |
| 19 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o | 19 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o |
| 20 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o | 20 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o |
| 21 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o | ||
| 22 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o | ||
| 23 | obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o | ||
| 21 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o | 24 | obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o |
| 22 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o | 25 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o |
| 23 | obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o | 26 | obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o |
| @@ -45,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | |||
| 45 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 48 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
| 46 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 49 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
| 47 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 50 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
| 51 | obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o | ||
| 48 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o | 52 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o |
| 49 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o | 53 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o |
| 50 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | 54 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o |
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 8034cbb20f74..c5c2dbb93869 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c | |||
| @@ -392,9 +392,10 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev) | |||
| 392 | return 0; | 392 | return 0; |
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | #ifdef CONFIG_PM | 395 | #ifdef CONFIG_PM_SLEEP |
| 396 | static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg) | 396 | static int atmel_wm97xx_suspend(struct *dev) |
| 397 | { | 397 | { |
| 398 | struct platform_device *pdev = to_platform_device(dev); | ||
| 398 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); | 399 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); |
| 399 | 400 | ||
| 400 | ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); | 401 | ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); |
| @@ -404,8 +405,9 @@ static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg) | |||
| 404 | return 0; | 405 | return 0; |
| 405 | } | 406 | } |
| 406 | 407 | ||
| 407 | static int atmel_wm97xx_resume(struct platform_device *pdev) | 408 | static int atmel_wm97xx_resume(struct device *dev) |
| 408 | { | 409 | { |
| 410 | struct platform_device *pdev = to_platform_device(dev); | ||
| 409 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); | 411 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); |
| 410 | struct wm97xx *wm = atmel_wm97xx->wm; | 412 | struct wm97xx *wm = atmel_wm97xx->wm; |
| 411 | 413 | ||
| @@ -416,18 +418,18 @@ static int atmel_wm97xx_resume(struct platform_device *pdev) | |||
| 416 | 418 | ||
| 417 | return 0; | 419 | return 0; |
| 418 | } | 420 | } |
| 419 | #else | ||
| 420 | #define atmel_wm97xx_suspend NULL | ||
| 421 | #define atmel_wm97xx_resume NULL | ||
| 422 | #endif | 421 | #endif |
| 423 | 422 | ||
| 423 | static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops, | ||
| 424 | atmel_wm97xx_suspend, atmel_wm97xx_resume); | ||
| 425 | |||
| 424 | static struct platform_driver atmel_wm97xx_driver = { | 426 | static struct platform_driver atmel_wm97xx_driver = { |
| 425 | .remove = __exit_p(atmel_wm97xx_remove), | 427 | .remove = __exit_p(atmel_wm97xx_remove), |
| 426 | .driver = { | 428 | .driver = { |
| 427 | .name = "wm97xx-touch", | 429 | .name = "wm97xx-touch", |
| 430 | .owner = THIS_MODULE, | ||
| 431 | .pm = &atmel_wm97xx_pm_ops, | ||
| 428 | }, | 432 | }, |
| 429 | .suspend = atmel_wm97xx_suspend, | ||
| 430 | .resume = atmel_wm97xx_resume, | ||
| 431 | }; | 433 | }; |
| 432 | 434 | ||
| 433 | static int __init atmel_wm97xx_init(void) | 435 | static int __init atmel_wm97xx_init(void) |
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c new file mode 100644 index 000000000000..f030d9ec795d --- /dev/null +++ b/drivers/input/touchscreen/cyttsp_core.c | |||
| @@ -0,0 +1,625 @@ | |||
| 1 | /* | ||
| 2 | * Core Source for: | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers. | ||
| 4 | * For use with Cypress Txx3xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * CY8CTST341 | ||
| 7 | * CY8CTMA340 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU General Public License | ||
| 14 | * version 2, and only version 2, as published by the | ||
| 15 | * Free Software Foundation. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License along | ||
| 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 | * | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include <linux/delay.h> | ||
| 31 | #include <linux/input.h> | ||
| 32 | #include <linux/input/mt.h> | ||
| 33 | #include <linux/gpio.h> | ||
| 34 | #include <linux/interrupt.h> | ||
| 35 | #include <linux/slab.h> | ||
| 36 | |||
| 37 | #include "cyttsp_core.h" | ||
| 38 | |||
| 39 | /* Bootloader number of command keys */ | ||
| 40 | #define CY_NUM_BL_KEYS 8 | ||
| 41 | |||
| 42 | /* helpers */ | ||
| 43 | #define GET_NUM_TOUCHES(x) ((x) & 0x0F) | ||
| 44 | #define IS_LARGE_AREA(x) (((x) & 0x10) >> 4) | ||
| 45 | #define IS_BAD_PKT(x) ((x) & 0x20) | ||
| 46 | #define IS_VALID_APP(x) ((x) & 0x01) | ||
| 47 | #define IS_OPERATIONAL_ERR(x) ((x) & 0x3F) | ||
| 48 | #define GET_HSTMODE(reg) (((reg) & 0x70) >> 4) | ||
| 49 | #define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4) | ||
| 50 | |||
| 51 | #define CY_REG_BASE 0x00 | ||
| 52 | #define CY_REG_ACT_DIST 0x1E | ||
| 53 | #define CY_REG_ACT_INTRVL 0x1D | ||
| 54 | #define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1) | ||
| 55 | #define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1) | ||
| 56 | #define CY_MAXZ 255 | ||
| 57 | #define CY_DELAY_DFLT 20 /* ms */ | ||
| 58 | #define CY_DELAY_MAX 500 | ||
| 59 | #define CY_ACT_DIST_DFLT 0xF8 | ||
| 60 | #define CY_HNDSHK_BIT 0x80 | ||
| 61 | /* device mode bits */ | ||
| 62 | #define CY_OPERATE_MODE 0x00 | ||
| 63 | #define CY_SYSINFO_MODE 0x10 | ||
| 64 | /* power mode select bits */ | ||
| 65 | #define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */ | ||
| 66 | #define CY_DEEP_SLEEP_MODE 0x02 | ||
| 67 | #define CY_LOW_POWER_MODE 0x04 | ||
| 68 | |||
| 69 | /* Slots management */ | ||
| 70 | #define CY_MAX_FINGER 4 | ||
| 71 | #define CY_MAX_ID 16 | ||
| 72 | |||
| 73 | static const u8 bl_command[] = { | ||
| 74 | 0x00, /* file offset */ | ||
| 75 | 0xFF, /* command */ | ||
| 76 | 0xA5, /* exit bootloader command */ | ||
| 77 | 0, 1, 2, 3, 4, 5, 6, 7 /* default keys */ | ||
| 78 | }; | ||
| 79 | |||
| 80 | static int ttsp_read_block_data(struct cyttsp *ts, u8 command, | ||
| 81 | u8 length, void *buf) | ||
| 82 | { | ||
| 83 | int error; | ||
| 84 | int tries; | ||
| 85 | |||
| 86 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { | ||
| 87 | error = ts->bus_ops->read(ts, command, length, buf); | ||
| 88 | if (!error) | ||
| 89 | return 0; | ||
| 90 | |||
| 91 | msleep(CY_DELAY_DFLT); | ||
| 92 | } | ||
| 93 | |||
| 94 | return -EIO; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int ttsp_write_block_data(struct cyttsp *ts, u8 command, | ||
| 98 | u8 length, void *buf) | ||
| 99 | { | ||
| 100 | int error; | ||
| 101 | int tries; | ||
| 102 | |||
| 103 | for (tries = 0; tries < CY_NUM_RETRY; tries++) { | ||
| 104 | error = ts->bus_ops->write(ts, command, length, buf); | ||
| 105 | if (!error) | ||
| 106 | return 0; | ||
| 107 | |||
| 108 | msleep(CY_DELAY_DFLT); | ||
| 109 | } | ||
| 110 | |||
| 111 | return -EIO; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int ttsp_send_command(struct cyttsp *ts, u8 cmd) | ||
| 115 | { | ||
| 116 | return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd); | ||
| 117 | } | ||
| 118 | |||
| 119 | static int cyttsp_load_bl_regs(struct cyttsp *ts) | ||
| 120 | { | ||
| 121 | memset(&ts->bl_data, 0, sizeof(ts->bl_data)); | ||
| 122 | ts->bl_data.bl_status = 0x10; | ||
| 123 | |||
| 124 | return ttsp_read_block_data(ts, CY_REG_BASE, | ||
| 125 | sizeof(ts->bl_data), &ts->bl_data); | ||
| 126 | } | ||
| 127 | |||
| 128 | static int cyttsp_exit_bl_mode(struct cyttsp *ts) | ||
| 129 | { | ||
| 130 | int error; | ||
| 131 | u8 bl_cmd[sizeof(bl_command)]; | ||
| 132 | |||
| 133 | memcpy(bl_cmd, bl_command, sizeof(bl_command)); | ||
| 134 | if (ts->pdata->bl_keys) | ||
| 135 | memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS], | ||
| 136 | ts->pdata->bl_keys, sizeof(bl_command)); | ||
| 137 | |||
| 138 | error = ttsp_write_block_data(ts, CY_REG_BASE, | ||
| 139 | sizeof(bl_cmd), bl_cmd); | ||
| 140 | if (error) | ||
| 141 | return error; | ||
| 142 | |||
| 143 | /* wait for TTSP Device to complete the operation */ | ||
| 144 | msleep(CY_DELAY_DFLT); | ||
| 145 | |||
| 146 | error = cyttsp_load_bl_regs(ts); | ||
| 147 | if (error) | ||
| 148 | return error; | ||
| 149 | |||
| 150 | if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) | ||
| 151 | return -EIO; | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static int cyttsp_set_operational_mode(struct cyttsp *ts) | ||
| 157 | { | ||
| 158 | int error; | ||
| 159 | |||
| 160 | error = ttsp_send_command(ts, CY_OPERATE_MODE); | ||
| 161 | if (error) | ||
| 162 | return error; | ||
| 163 | |||
| 164 | /* wait for TTSP Device to complete switch to Operational mode */ | ||
| 165 | error = ttsp_read_block_data(ts, CY_REG_BASE, | ||
| 166 | sizeof(ts->xy_data), &ts->xy_data); | ||
| 167 | if (error) | ||
| 168 | return error; | ||
| 169 | |||
| 170 | return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | static int cyttsp_set_sysinfo_mode(struct cyttsp *ts) | ||
| 174 | { | ||
| 175 | int error; | ||
| 176 | |||
| 177 | memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data)); | ||
| 178 | |||
| 179 | /* switch to sysinfo mode */ | ||
| 180 | error = ttsp_send_command(ts, CY_SYSINFO_MODE); | ||
| 181 | if (error) | ||
| 182 | return error; | ||
| 183 | |||
| 184 | /* read sysinfo registers */ | ||
| 185 | msleep(CY_DELAY_DFLT); | ||
| 186 | error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data), | ||
| 187 | &ts->sysinfo_data); | ||
| 188 | if (error) | ||
| 189 | return error; | ||
| 190 | |||
| 191 | if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl) | ||
| 192 | return -EIO; | ||
| 193 | |||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static int cyttsp_set_sysinfo_regs(struct cyttsp *ts) | ||
| 198 | { | ||
| 199 | int retval = 0; | ||
| 200 | |||
| 201 | if (ts->pdata->act_intrvl != CY_ACT_INTRVL_DFLT || | ||
| 202 | ts->pdata->tch_tmout != CY_TCH_TMOUT_DFLT || | ||
| 203 | ts->pdata->lp_intrvl != CY_LP_INTRVL_DFLT) { | ||
| 204 | |||
| 205 | u8 intrvl_ray[] = { | ||
| 206 | ts->pdata->act_intrvl, | ||
| 207 | ts->pdata->tch_tmout, | ||
| 208 | ts->pdata->lp_intrvl | ||
| 209 | }; | ||
| 210 | |||
| 211 | /* set intrvl registers */ | ||
| 212 | retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL, | ||
| 213 | sizeof(intrvl_ray), intrvl_ray); | ||
| 214 | msleep(CY_DELAY_DFLT); | ||
| 215 | } | ||
| 216 | |||
| 217 | return retval; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int cyttsp_soft_reset(struct cyttsp *ts) | ||
| 221 | { | ||
| 222 | unsigned long timeout; | ||
| 223 | int retval; | ||
| 224 | |||
| 225 | /* wait for interrupt to set ready completion */ | ||
| 226 | INIT_COMPLETION(ts->bl_ready); | ||
| 227 | ts->state = CY_BL_STATE; | ||
| 228 | |||
| 229 | enable_irq(ts->irq); | ||
| 230 | |||
| 231 | retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE); | ||
| 232 | if (retval) | ||
| 233 | goto out; | ||
| 234 | |||
| 235 | timeout = wait_for_completion_timeout(&ts->bl_ready, | ||
| 236 | msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX)); | ||
| 237 | retval = timeout ? 0 : -EIO; | ||
| 238 | |||
| 239 | out: | ||
| 240 | ts->state = CY_IDLE_STATE; | ||
| 241 | disable_irq(ts->irq); | ||
| 242 | return retval; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int cyttsp_act_dist_setup(struct cyttsp *ts) | ||
| 246 | { | ||
| 247 | u8 act_dist_setup = ts->pdata->act_dist; | ||
| 248 | |||
| 249 | /* Init gesture; active distance setup */ | ||
| 250 | return ttsp_write_block_data(ts, CY_REG_ACT_DIST, | ||
| 251 | sizeof(act_dist_setup), &act_dist_setup); | ||
| 252 | } | ||
| 253 | |||
| 254 | static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids) | ||
| 255 | { | ||
| 256 | ids[0] = xy_data->touch12_id >> 4; | ||
| 257 | ids[1] = xy_data->touch12_id & 0xF; | ||
| 258 | ids[2] = xy_data->touch34_id >> 4; | ||
| 259 | ids[3] = xy_data->touch34_id & 0xF; | ||
| 260 | } | ||
| 261 | |||
| 262 | static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data, | ||
| 263 | int idx) | ||
| 264 | { | ||
| 265 | switch (idx) { | ||
| 266 | case 0: | ||
| 267 | return &xy_data->tch1; | ||
| 268 | case 1: | ||
| 269 | return &xy_data->tch2; | ||
| 270 | case 2: | ||
| 271 | return &xy_data->tch3; | ||
| 272 | case 3: | ||
| 273 | return &xy_data->tch4; | ||
| 274 | default: | ||
| 275 | return NULL; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | static void cyttsp_report_tchdata(struct cyttsp *ts) | ||
| 280 | { | ||
| 281 | struct cyttsp_xydata *xy_data = &ts->xy_data; | ||
| 282 | struct input_dev *input = ts->input; | ||
| 283 | int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat); | ||
| 284 | const struct cyttsp_tch *tch; | ||
| 285 | int ids[CY_MAX_ID]; | ||
| 286 | int i; | ||
| 287 | DECLARE_BITMAP(used, CY_MAX_ID); | ||
| 288 | |||
| 289 | if (IS_LARGE_AREA(xy_data->tt_stat) == 1) { | ||
| 290 | /* terminate all active tracks */ | ||
| 291 | num_tch = 0; | ||
| 292 | dev_dbg(ts->dev, "%s: Large area detected\n", __func__); | ||
| 293 | } else if (num_tch > CY_MAX_FINGER) { | ||
| 294 | /* terminate all active tracks */ | ||
| 295 | num_tch = 0; | ||
| 296 | dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__); | ||
| 297 | } else if (IS_BAD_PKT(xy_data->tt_mode)) { | ||
| 298 | /* terminate all active tracks */ | ||
| 299 | num_tch = 0; | ||
| 300 | dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__); | ||
| 301 | } | ||
| 302 | |||
| 303 | cyttsp_extract_track_ids(xy_data, ids); | ||
| 304 | |||
| 305 | bitmap_zero(used, CY_MAX_ID); | ||
| 306 | |||
| 307 | for (i = 0; i < num_tch; i++) { | ||
| 308 | tch = cyttsp_get_tch(xy_data, i); | ||
| 309 | |||
| 310 | input_mt_slot(input, ids[i]); | ||
| 311 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
| 312 | input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x)); | ||
| 313 | input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y)); | ||
| 314 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z); | ||
| 315 | |||
| 316 | __set_bit(ids[i], used); | ||
| 317 | } | ||
| 318 | |||
| 319 | for (i = 0; i < CY_MAX_ID; i++) { | ||
| 320 | if (test_bit(i, used)) | ||
| 321 | continue; | ||
| 322 | |||
| 323 | input_mt_slot(input, i); | ||
| 324 | input_mt_report_slot_state(input, MT_TOOL_FINGER, false); | ||
| 325 | } | ||
| 326 | |||
| 327 | input_sync(input); | ||
| 328 | } | ||
| 329 | |||
| 330 | static irqreturn_t cyttsp_irq(int irq, void *handle) | ||
| 331 | { | ||
| 332 | struct cyttsp *ts = handle; | ||
| 333 | int error; | ||
| 334 | |||
| 335 | if (unlikely(ts->state == CY_BL_STATE)) { | ||
| 336 | complete(&ts->bl_ready); | ||
| 337 | goto out; | ||
| 338 | } | ||
| 339 | |||
| 340 | /* Get touch data from CYTTSP device */ | ||
| 341 | error = ttsp_read_block_data(ts, CY_REG_BASE, | ||
| 342 | sizeof(struct cyttsp_xydata), &ts->xy_data); | ||
| 343 | if (error) | ||
| 344 | goto out; | ||
| 345 | |||
| 346 | /* provide flow control handshake */ | ||
| 347 | if (ts->pdata->use_hndshk) { | ||
| 348 | error = ttsp_send_command(ts, | ||
| 349 | ts->xy_data.hst_mode ^ CY_HNDSHK_BIT); | ||
| 350 | if (error) | ||
| 351 | goto out; | ||
| 352 | } | ||
| 353 | |||
| 354 | if (unlikely(ts->state == CY_IDLE_STATE)) | ||
| 355 | goto out; | ||
| 356 | |||
| 357 | if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) { | ||
| 358 | /* | ||
| 359 | * TTSP device has reset back to bootloader mode. | ||
| 360 | * Restore to operational mode. | ||
| 361 | */ | ||
| 362 | error = cyttsp_exit_bl_mode(ts); | ||
| 363 | if (error) { | ||
| 364 | dev_err(ts->dev, | ||
| 365 | "Could not return to operational mode, err: %d\n", | ||
| 366 | error); | ||
| 367 | ts->state = CY_IDLE_STATE; | ||
| 368 | } | ||
| 369 | } else { | ||
| 370 | cyttsp_report_tchdata(ts); | ||
| 371 | } | ||
| 372 | |||
| 373 | out: | ||
| 374 | return IRQ_HANDLED; | ||
| 375 | } | ||
| 376 | |||
| 377 | static int cyttsp_power_on(struct cyttsp *ts) | ||
| 378 | { | ||
| 379 | int error; | ||
| 380 | |||
| 381 | error = cyttsp_soft_reset(ts); | ||
| 382 | if (error) | ||
| 383 | return error; | ||
| 384 | |||
| 385 | error = cyttsp_load_bl_regs(ts); | ||
| 386 | if (error) | ||
| 387 | return error; | ||
| 388 | |||
| 389 | if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) && | ||
| 390 | IS_VALID_APP(ts->bl_data.bl_status)) { | ||
| 391 | error = cyttsp_exit_bl_mode(ts); | ||
| 392 | if (error) | ||
| 393 | return error; | ||
| 394 | } | ||
| 395 | |||
| 396 | if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE || | ||
| 397 | IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) { | ||
| 398 | return -ENODEV; | ||
| 399 | } | ||
| 400 | |||
| 401 | error = cyttsp_set_sysinfo_mode(ts); | ||
| 402 | if (error) | ||
| 403 | return error; | ||
| 404 | |||
| 405 | error = cyttsp_set_sysinfo_regs(ts); | ||
| 406 | if (error) | ||
| 407 | return error; | ||
| 408 | |||
| 409 | error = cyttsp_set_operational_mode(ts); | ||
| 410 | if (error) | ||
| 411 | return error; | ||
| 412 | |||
| 413 | /* init active distance */ | ||
| 414 | error = cyttsp_act_dist_setup(ts); | ||
| 415 | if (error) | ||
| 416 | return error; | ||
| 417 | |||
| 418 | ts->state = CY_ACTIVE_STATE; | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | static int cyttsp_enable(struct cyttsp *ts) | ||
| 424 | { | ||
| 425 | int error; | ||
| 426 | |||
| 427 | /* | ||
| 428 | * The device firmware can wake on an I2C or SPI memory slave | ||
| 429 | * address match. So just reading a register is sufficient to | ||
| 430 | * wake up the device. The first read attempt will fail but it | ||
| 431 | * will wake it up making the second read attempt successful. | ||
| 432 | */ | ||
| 433 | error = ttsp_read_block_data(ts, CY_REG_BASE, | ||
| 434 | sizeof(ts->xy_data), &ts->xy_data); | ||
| 435 | if (error) | ||
| 436 | return error; | ||
| 437 | |||
| 438 | if (GET_HSTMODE(ts->xy_data.hst_mode)) | ||
| 439 | return -EIO; | ||
| 440 | |||
| 441 | enable_irq(ts->irq); | ||
| 442 | |||
| 443 | return 0; | ||
| 444 | } | ||
| 445 | |||
| 446 | static int cyttsp_disable(struct cyttsp *ts) | ||
| 447 | { | ||
| 448 | int error; | ||
| 449 | |||
| 450 | error = ttsp_send_command(ts, CY_LOW_POWER_MODE); | ||
| 451 | if (error) | ||
| 452 | return error; | ||
| 453 | |||
| 454 | disable_irq(ts->irq); | ||
| 455 | |||
| 456 | return 0; | ||
| 457 | } | ||
| 458 | |||
| 459 | #ifdef CONFIG_PM_SLEEP | ||
| 460 | static int cyttsp_suspend(struct device *dev) | ||
| 461 | { | ||
| 462 | struct cyttsp *ts = dev_get_drvdata(dev); | ||
| 463 | int retval = 0; | ||
| 464 | |||
| 465 | mutex_lock(&ts->input->mutex); | ||
| 466 | |||
| 467 | if (ts->input->users) { | ||
| 468 | retval = cyttsp_disable(ts); | ||
| 469 | if (retval == 0) | ||
| 470 | ts->suspended = true; | ||
| 471 | } | ||
| 472 | |||
| 473 | mutex_unlock(&ts->input->mutex); | ||
| 474 | |||
| 475 | return retval; | ||
| 476 | } | ||
| 477 | |||
| 478 | static int cyttsp_resume(struct device *dev) | ||
| 479 | { | ||
| 480 | struct cyttsp *ts = dev_get_drvdata(dev); | ||
| 481 | |||
| 482 | mutex_lock(&ts->input->mutex); | ||
| 483 | |||
| 484 | if (ts->input->users) | ||
| 485 | cyttsp_enable(ts); | ||
| 486 | |||
| 487 | ts->suspended = false; | ||
| 488 | |||
| 489 | mutex_unlock(&ts->input->mutex); | ||
| 490 | |||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | #endif | ||
| 495 | |||
| 496 | SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume); | ||
| 497 | EXPORT_SYMBOL_GPL(cyttsp_pm_ops); | ||
| 498 | |||
| 499 | static int cyttsp_open(struct input_dev *dev) | ||
| 500 | { | ||
| 501 | struct cyttsp *ts = input_get_drvdata(dev); | ||
| 502 | int retval = 0; | ||
| 503 | |||
| 504 | if (!ts->suspended) | ||
| 505 | retval = cyttsp_enable(ts); | ||
| 506 | |||
| 507 | return retval; | ||
| 508 | } | ||
| 509 | |||
| 510 | static void cyttsp_close(struct input_dev *dev) | ||
| 511 | { | ||
| 512 | struct cyttsp *ts = input_get_drvdata(dev); | ||
| 513 | |||
| 514 | if (!ts->suspended) | ||
| 515 | cyttsp_disable(ts); | ||
| 516 | } | ||
| 517 | |||
| 518 | struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, | ||
| 519 | struct device *dev, int irq, size_t xfer_buf_size) | ||
| 520 | { | ||
| 521 | const struct cyttsp_platform_data *pdata = dev->platform_data; | ||
| 522 | struct cyttsp *ts; | ||
| 523 | struct input_dev *input_dev; | ||
| 524 | int error; | ||
| 525 | |||
| 526 | if (!pdata || !pdata->name || irq <= 0) { | ||
| 527 | error = -EINVAL; | ||
| 528 | goto err_out; | ||
| 529 | } | ||
| 530 | |||
| 531 | ts = kzalloc(sizeof(*ts) + xfer_buf_size, GFP_KERNEL); | ||
| 532 | input_dev = input_allocate_device(); | ||
| 533 | if (!ts || !input_dev) { | ||
| 534 | error = -ENOMEM; | ||
| 535 | goto err_free_mem; | ||
| 536 | } | ||
| 537 | |||
| 538 | ts->dev = dev; | ||
| 539 | ts->input = input_dev; | ||
| 540 | ts->pdata = dev->platform_data; | ||
| 541 | ts->bus_ops = bus_ops; | ||
| 542 | ts->irq = irq; | ||
| 543 | |||
| 544 | init_completion(&ts->bl_ready); | ||
| 545 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev)); | ||
| 546 | |||
| 547 | if (pdata->init) { | ||
| 548 | error = pdata->init(); | ||
| 549 | if (error) { | ||
| 550 | dev_err(ts->dev, "platform init failed, err: %d\n", | ||
| 551 | error); | ||
| 552 | goto err_free_mem; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | |||
| 556 | input_dev->name = pdata->name; | ||
| 557 | input_dev->phys = ts->phys; | ||
| 558 | input_dev->id.bustype = bus_ops->bustype; | ||
| 559 | input_dev->dev.parent = ts->dev; | ||
| 560 | |||
| 561 | input_dev->open = cyttsp_open; | ||
| 562 | input_dev->close = cyttsp_close; | ||
| 563 | |||
| 564 | input_set_drvdata(input_dev, ts); | ||
| 565 | |||
| 566 | __set_bit(EV_ABS, input_dev->evbit); | ||
| 567 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, | ||
| 568 | 0, pdata->maxx, 0, 0); | ||
| 569 | input_set_abs_params(input_dev, ABS_MT_POSITION_Y, | ||
| 570 | 0, pdata->maxy, 0, 0); | ||
| 571 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, | ||
| 572 | 0, CY_MAXZ, 0, 0); | ||
| 573 | |||
| 574 | input_mt_init_slots(input_dev, CY_MAX_ID); | ||
| 575 | |||
| 576 | error = request_threaded_irq(ts->irq, NULL, cyttsp_irq, | ||
| 577 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
| 578 | pdata->name, ts); | ||
| 579 | if (error) { | ||
| 580 | dev_err(ts->dev, "failed to request IRQ %d, err: %d\n", | ||
| 581 | ts->irq, error); | ||
| 582 | goto err_platform_exit; | ||
| 583 | } | ||
| 584 | |||
| 585 | disable_irq(ts->irq); | ||
| 586 | |||
| 587 | error = cyttsp_power_on(ts); | ||
| 588 | if (error) | ||
| 589 | goto err_free_irq; | ||
| 590 | |||
| 591 | error = input_register_device(input_dev); | ||
| 592 | if (error) { | ||
| 593 | dev_err(ts->dev, "failed to register input device: %d\n", | ||
| 594 | error); | ||
| 595 | goto err_free_irq; | ||
| 596 | } | ||
| 597 | |||
| 598 | return ts; | ||
| 599 | |||
| 600 | err_free_irq: | ||
| 601 | free_irq(ts->irq, ts); | ||
| 602 | err_platform_exit: | ||
| 603 | if (pdata->exit) | ||
| 604 | pdata->exit(); | ||
| 605 | err_free_mem: | ||
| 606 | input_free_device(input_dev); | ||
| 607 | kfree(ts); | ||
| 608 | err_out: | ||
| 609 | return ERR_PTR(error); | ||
| 610 | } | ||
| 611 | EXPORT_SYMBOL_GPL(cyttsp_probe); | ||
| 612 | |||
| 613 | void cyttsp_remove(struct cyttsp *ts) | ||
| 614 | { | ||
| 615 | free_irq(ts->irq, ts); | ||
| 616 | input_unregister_device(ts->input); | ||
| 617 | if (ts->pdata->exit) | ||
| 618 | ts->pdata->exit(); | ||
| 619 | kfree(ts); | ||
| 620 | } | ||
| 621 | EXPORT_SYMBOL_GPL(cyttsp_remove); | ||
| 622 | |||
| 623 | MODULE_LICENSE("GPL"); | ||
| 624 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core"); | ||
| 625 | MODULE_AUTHOR("Cypress"); | ||
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h new file mode 100644 index 000000000000..1aa3c6967e70 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp_core.h | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | /* | ||
| 2 | * Header file for: | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers. | ||
| 4 | * For use with Cypress Txx3xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * CY8CTST341 | ||
| 7 | * CY8CTMA340 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU General Public License | ||
| 14 | * version 2, and only version 2, as published by the | ||
| 15 | * Free Software Foundation. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License along | ||
| 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 | * | ||
| 28 | */ | ||
| 29 | |||
| 30 | |||
| 31 | #ifndef __CYTTSP_CORE_H__ | ||
| 32 | #define __CYTTSP_CORE_H__ | ||
| 33 | |||
| 34 | #include <linux/kernel.h> | ||
| 35 | #include <linux/err.h> | ||
| 36 | #include <linux/module.h> | ||
| 37 | #include <linux/types.h> | ||
| 38 | #include <linux/device.h> | ||
| 39 | #include <linux/input/cyttsp.h> | ||
| 40 | |||
| 41 | #define CY_NUM_RETRY 16 /* max number of retries for read ops */ | ||
| 42 | |||
| 43 | struct cyttsp_tch { | ||
| 44 | __be16 x, y; | ||
| 45 | u8 z; | ||
| 46 | } __packed; | ||
| 47 | |||
| 48 | /* TrueTouch Standard Product Gen3 interface definition */ | ||
| 49 | struct cyttsp_xydata { | ||
| 50 | u8 hst_mode; | ||
| 51 | u8 tt_mode; | ||
| 52 | u8 tt_stat; | ||
| 53 | struct cyttsp_tch tch1; | ||
| 54 | u8 touch12_id; | ||
| 55 | struct cyttsp_tch tch2; | ||
| 56 | u8 gest_cnt; | ||
| 57 | u8 gest_id; | ||
| 58 | struct cyttsp_tch tch3; | ||
| 59 | u8 touch34_id; | ||
| 60 | struct cyttsp_tch tch4; | ||
| 61 | u8 tt_undef[3]; | ||
| 62 | u8 act_dist; | ||
| 63 | u8 tt_reserved; | ||
| 64 | } __packed; | ||
| 65 | |||
| 66 | |||
| 67 | /* TTSP System Information interface definition */ | ||
| 68 | struct cyttsp_sysinfo_data { | ||
| 69 | u8 hst_mode; | ||
| 70 | u8 mfg_cmd; | ||
| 71 | u8 mfg_stat; | ||
| 72 | u8 cid[3]; | ||
| 73 | u8 tt_undef1; | ||
| 74 | u8 uid[8]; | ||
| 75 | u8 bl_verh; | ||
| 76 | u8 bl_verl; | ||
| 77 | u8 tts_verh; | ||
| 78 | u8 tts_verl; | ||
| 79 | u8 app_idh; | ||
| 80 | u8 app_idl; | ||
| 81 | u8 app_verh; | ||
| 82 | u8 app_verl; | ||
| 83 | u8 tt_undef[5]; | ||
| 84 | u8 scn_typ; | ||
| 85 | u8 act_intrvl; | ||
| 86 | u8 tch_tmout; | ||
| 87 | u8 lp_intrvl; | ||
| 88 | }; | ||
| 89 | |||
| 90 | /* TTSP Bootloader Register Map interface definition */ | ||
| 91 | #define CY_BL_CHKSUM_OK 0x01 | ||
| 92 | struct cyttsp_bootloader_data { | ||
| 93 | u8 bl_file; | ||
| 94 | u8 bl_status; | ||
| 95 | u8 bl_error; | ||
| 96 | u8 blver_hi; | ||
| 97 | u8 blver_lo; | ||
| 98 | u8 bld_blver_hi; | ||
| 99 | u8 bld_blver_lo; | ||
| 100 | u8 ttspver_hi; | ||
| 101 | u8 ttspver_lo; | ||
| 102 | u8 appid_hi; | ||
| 103 | u8 appid_lo; | ||
| 104 | u8 appver_hi; | ||
| 105 | u8 appver_lo; | ||
| 106 | u8 cid_0; | ||
| 107 | u8 cid_1; | ||
| 108 | u8 cid_2; | ||
| 109 | }; | ||
| 110 | |||
| 111 | struct cyttsp; | ||
| 112 | |||
| 113 | struct cyttsp_bus_ops { | ||
| 114 | u16 bustype; | ||
| 115 | int (*write)(struct cyttsp *ts, | ||
| 116 | u8 addr, u8 length, const void *values); | ||
| 117 | int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values); | ||
| 118 | }; | ||
| 119 | |||
| 120 | enum cyttsp_state { | ||
| 121 | CY_IDLE_STATE, | ||
| 122 | CY_ACTIVE_STATE, | ||
| 123 | CY_BL_STATE, | ||
| 124 | }; | ||
| 125 | |||
| 126 | struct cyttsp { | ||
| 127 | struct device *dev; | ||
| 128 | int irq; | ||
| 129 | struct input_dev *input; | ||
| 130 | char phys[32]; | ||
| 131 | const struct cyttsp_platform_data *pdata; | ||
| 132 | const struct cyttsp_bus_ops *bus_ops; | ||
| 133 | struct cyttsp_bootloader_data bl_data; | ||
| 134 | struct cyttsp_sysinfo_data sysinfo_data; | ||
| 135 | struct cyttsp_xydata xy_data; | ||
| 136 | struct completion bl_ready; | ||
| 137 | enum cyttsp_state state; | ||
| 138 | bool suspended; | ||
| 139 | |||
| 140 | u8 xfer_buf[] ____cacheline_aligned; | ||
| 141 | }; | ||
| 142 | |||
| 143 | struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, | ||
| 144 | struct device *dev, int irq, size_t xfer_buf_size); | ||
| 145 | void cyttsp_remove(struct cyttsp *ts); | ||
| 146 | |||
| 147 | extern const struct dev_pm_ops cyttsp_pm_ops; | ||
| 148 | |||
| 149 | #endif /* __CYTTSP_CORE_H__ */ | ||
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c new file mode 100644 index 000000000000..c7110cc06b9d --- /dev/null +++ b/drivers/input/touchscreen/cyttsp_i2c.c | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | /* | ||
| 2 | * Source for: | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. | ||
| 4 | * For use with Cypress Txx3xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * CY8CTST341 | ||
| 7 | * CY8CTMA340 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU General Public License | ||
| 14 | * version 2, and only version 2, as published by the | ||
| 15 | * Free Software Foundation. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License along | ||
| 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 | * | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "cyttsp_core.h" | ||
| 31 | |||
| 32 | #include <linux/i2c.h> | ||
| 33 | #include <linux/input.h> | ||
| 34 | |||
| 35 | #define CY_I2C_DATA_SIZE 128 | ||
| 36 | |||
| 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 = { | ||
| 79 | .bustype = BUS_I2C, | ||
| 80 | .write = cyttsp_i2c_write_block_data, | ||
| 81 | .read = cyttsp_i2c_read_block_data, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static int __devinit cyttsp_i2c_probe(struct i2c_client *client, | ||
| 85 | const struct i2c_device_id *id) | ||
| 86 | { | ||
| 87 | struct cyttsp *ts; | ||
| 88 | |||
| 89 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
| 90 | dev_err(&client->dev, "I2C functionality not Supported\n"); | ||
| 91 | return -EIO; | ||
| 92 | } | ||
| 93 | |||
| 94 | ts = cyttsp_probe(&cyttsp_i2c_bus_ops, &client->dev, client->irq, | ||
| 95 | CY_I2C_DATA_SIZE); | ||
| 96 | |||
| 97 | if (IS_ERR(ts)) | ||
| 98 | return PTR_ERR(ts); | ||
| 99 | |||
| 100 | i2c_set_clientdata(client, ts); | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int __devexit cyttsp_i2c_remove(struct i2c_client *client) | ||
| 106 | { | ||
| 107 | struct cyttsp *ts = i2c_get_clientdata(client); | ||
| 108 | |||
| 109 | cyttsp_remove(ts); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static const struct i2c_device_id cyttsp_i2c_id[] = { | ||
| 115 | { CY_I2C_NAME, 0 }, | ||
| 116 | { } | ||
| 117 | }; | ||
| 118 | MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); | ||
| 119 | |||
| 120 | static struct i2c_driver cyttsp_i2c_driver = { | ||
| 121 | .driver = { | ||
| 122 | .name = CY_I2C_NAME, | ||
| 123 | .owner = THIS_MODULE, | ||
| 124 | .pm = &cyttsp_pm_ops, | ||
| 125 | }, | ||
| 126 | .probe = cyttsp_i2c_probe, | ||
| 127 | .remove = __devexit_p(cyttsp_i2c_remove), | ||
| 128 | .id_table = cyttsp_i2c_id, | ||
| 129 | }; | ||
| 130 | |||
| 131 | static int __init cyttsp_i2c_init(void) | ||
| 132 | { | ||
| 133 | return i2c_add_driver(&cyttsp_i2c_driver); | ||
| 134 | } | ||
| 135 | module_init(cyttsp_i2c_init); | ||
| 136 | |||
| 137 | static void __exit cyttsp_i2c_exit(void) | ||
| 138 | { | ||
| 139 | return i2c_del_driver(&cyttsp_i2c_driver); | ||
| 140 | } | ||
| 141 | module_exit(cyttsp_i2c_exit); | ||
| 142 | |||
| 143 | MODULE_LICENSE("GPL"); | ||
| 144 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"); | ||
| 145 | MODULE_AUTHOR("Cypress"); | ||
| 146 | MODULE_ALIAS("i2c:cyttsp"); | ||
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c new file mode 100644 index 000000000000..9db5f8754d10 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp_spi.c | |||
| @@ -0,0 +1,210 @@ | |||
| 1 | /* | ||
| 2 | * Source for: | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver. | ||
| 4 | * For use with Cypress Txx3xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * CY8CTST341 | ||
| 7 | * CY8CTMA340 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU General Public License | ||
| 14 | * version 2, and only version 2, as published by the | ||
| 15 | * Free Software Foundation. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License along | ||
| 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 | * | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "cyttsp_core.h" | ||
| 31 | |||
| 32 | #include <linux/delay.h> | ||
| 33 | #include <linux/input.h> | ||
| 34 | #include <linux/spi/spi.h> | ||
| 35 | |||
| 36 | #define CY_SPI_WR_OP 0x00 /* r/~w */ | ||
| 37 | #define CY_SPI_RD_OP 0x01 | ||
| 38 | #define CY_SPI_CMD_BYTES 4 | ||
| 39 | #define CY_SPI_SYNC_BYTE 2 | ||
| 40 | #define CY_SPI_SYNC_ACK1 0x62 /* from protocol v.2 */ | ||
| 41 | #define CY_SPI_SYNC_ACK2 0x9D /* from protocol v.2 */ | ||
| 42 | #define CY_SPI_DATA_SIZE 128 | ||
| 43 | #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) | ||
| 44 | #define CY_SPI_BITS_PER_WORD 8 | ||
| 45 | |||
| 46 | static int cyttsp_spi_xfer(struct cyttsp *ts, | ||
| 47 | u8 op, u8 reg, u8 *buf, int length) | ||
| 48 | { | ||
| 49 | struct spi_device *spi = to_spi_device(ts->dev); | ||
| 50 | struct spi_message msg; | ||
| 51 | struct spi_transfer xfer[2]; | ||
| 52 | u8 *wr_buf = &ts->xfer_buf[0]; | ||
| 53 | u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE]; | ||
| 54 | int retval; | ||
| 55 | int i; | ||
| 56 | |||
| 57 | if (length > CY_SPI_DATA_SIZE) { | ||
| 58 | dev_err(ts->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_DATA_BUF_SIZE); | ||
| 65 | |||
| 66 | wr_buf[0] = 0x00; /* header byte 0 */ | ||
| 67 | wr_buf[1] = 0xFF; /* header byte 1 */ | ||
| 68 | wr_buf[2] = reg; /* reg index */ | ||
| 69 | wr_buf[3] = op; /* r/~w */ | ||
| 70 | if (op == CY_SPI_WR_OP) | ||
| 71 | memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); | ||
| 72 | |||
| 73 | memset(xfer, 0, sizeof(xfer)); | ||
| 74 | spi_message_init(&msg); | ||
| 75 | |||
| 76 | /* | ||
| 77 | We set both TX and RX buffers because Cypress TTSP | ||
| 78 | requires full duplex operation. | ||
| 79 | */ | ||
| 80 | xfer[0].tx_buf = wr_buf; | ||
| 81 | xfer[0].rx_buf = rd_buf; | ||
| 82 | switch (op) { | ||
| 83 | case CY_SPI_WR_OP: | ||
| 84 | xfer[0].len = length + CY_SPI_CMD_BYTES; | ||
| 85 | spi_message_add_tail(&xfer[0], &msg); | ||
| 86 | break; | ||
| 87 | |||
| 88 | case CY_SPI_RD_OP: | ||
| 89 | xfer[0].len = CY_SPI_CMD_BYTES; | ||
| 90 | spi_message_add_tail(&xfer[0], &msg); | ||
| 91 | |||
| 92 | xfer[1].rx_buf = buf; | ||
| 93 | xfer[1].len = length; | ||
| 94 | spi_message_add_tail(&xfer[1], &msg); | ||
| 95 | break; | ||
| 96 | |||
| 97 | default: | ||
| 98 | dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op); | ||
| 99 | return -EINVAL; | ||
| 100 | } | ||
| 101 | |||
| 102 | retval = spi_sync(spi, &msg); | ||
| 103 | if (retval < 0) { | ||
| 104 | dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n", | ||
| 105 | __func__, retval, xfer[1].len, op); | ||
| 106 | |||
| 107 | /* | ||
| 108 | * do not return here since was a bad ACK sequence | ||
| 109 | * let the following ACK check handle any errors and | ||
| 110 | * allow silent retries | ||
| 111 | */ | ||
| 112 | } | ||
| 113 | |||
| 114 | if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 || | ||
| 115 | rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) { | ||
| 116 | |||
| 117 | dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op); | ||
| 118 | |||
| 119 | for (i = 0; i < CY_SPI_CMD_BYTES; i++) | ||
| 120 | dev_dbg(ts->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(ts->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 cyttsp *ts, | ||
| 133 | u8 addr, u8 length, void *data) | ||
| 134 | { | ||
| 135 | return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length); | ||
| 136 | } | ||
| 137 | |||
| 138 | static int cyttsp_spi_write_block_data(struct cyttsp *ts, | ||
| 139 | u8 addr, u8 length, const void *data) | ||
| 140 | { | ||
| 141 | return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length); | ||
| 142 | } | ||
| 143 | |||
| 144 | static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = { | ||
| 145 | .bustype = BUS_SPI, | ||
| 146 | .write = cyttsp_spi_write_block_data, | ||
| 147 | .read = cyttsp_spi_read_block_data, | ||
| 148 | }; | ||
| 149 | |||
| 150 | static int __devinit cyttsp_spi_probe(struct spi_device *spi) | ||
| 151 | { | ||
| 152 | struct cyttsp *ts; | ||
| 153 | int error; | ||
| 154 | |||
| 155 | /* Set up SPI*/ | ||
| 156 | spi->bits_per_word = CY_SPI_BITS_PER_WORD; | ||
| 157 | spi->mode = SPI_MODE_0; | ||
| 158 | error = spi_setup(spi); | ||
| 159 | if (error < 0) { | ||
| 160 | dev_err(&spi->dev, "%s: SPI setup error %d\n", | ||
| 161 | __func__, error); | ||
| 162 | return error; | ||
| 163 | } | ||
| 164 | |||
| 165 | ts = cyttsp_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq, | ||
| 166 | CY_SPI_DATA_BUF_SIZE * 2); | ||
| 167 | if (IS_ERR(ts)) | ||
| 168 | return PTR_ERR(ts); | ||
| 169 | |||
| 170 | spi_set_drvdata(spi, ts); | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int __devexit cyttsp_spi_remove(struct spi_device *spi) | ||
| 176 | { | ||
| 177 | struct cyttsp *ts = spi_get_drvdata(spi); | ||
| 178 | |||
| 179 | cyttsp_remove(ts); | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static struct spi_driver cyttsp_spi_driver = { | ||
| 185 | .driver = { | ||
| 186 | .name = CY_SPI_NAME, | ||
| 187 | .owner = THIS_MODULE, | ||
| 188 | .pm = &cyttsp_pm_ops, | ||
| 189 | }, | ||
| 190 | .probe = cyttsp_spi_probe, | ||
| 191 | .remove = __devexit_p(cyttsp_spi_remove), | ||
| 192 | }; | ||
| 193 | |||
| 194 | static int __init cyttsp_spi_init(void) | ||
| 195 | { | ||
| 196 | return spi_register_driver(&cyttsp_spi_driver); | ||
| 197 | } | ||
| 198 | module_init(cyttsp_spi_init); | ||
| 199 | |||
| 200 | static void __exit cyttsp_spi_exit(void) | ||
| 201 | { | ||
| 202 | spi_unregister_driver(&cyttsp_spi_driver); | ||
| 203 | } | ||
| 204 | module_exit(cyttsp_spi_exit); | ||
| 205 | |||
| 206 | MODULE_ALIAS("spi:cyttsp"); | ||
| 207 | MODULE_LICENSE("GPL"); | ||
| 208 | MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver"); | ||
| 209 | MODULE_AUTHOR("Cypress"); | ||
| 210 | MODULE_ALIAS("spi:cyttsp"); | ||
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c new file mode 100644 index 000000000000..d229c741d544 --- /dev/null +++ b/drivers/input/touchscreen/ti_tscadc.c | |||
| @@ -0,0 +1,486 @@ | |||
| 1 | /* | ||
| 2 | * TI Touch Screen driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation version 2. | ||
| 9 | * | ||
| 10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 11 | * kind, whether express or implied; without even the implied warranty | ||
| 12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/input.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/clk.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | #include <linux/io.h> | ||
| 27 | #include <linux/input/ti_tscadc.h> | ||
| 28 | #include <linux/delay.h> | ||
| 29 | |||
| 30 | #define REG_IRQEOI 0x020 | ||
| 31 | #define REG_RAWIRQSTATUS 0x024 | ||
| 32 | #define REG_IRQSTATUS 0x028 | ||
| 33 | #define REG_IRQENABLE 0x02C | ||
| 34 | #define REG_IRQWAKEUP 0x034 | ||
| 35 | #define REG_CTRL 0x040 | ||
| 36 | #define REG_ADCFSM 0x044 | ||
| 37 | #define REG_CLKDIV 0x04C | ||
| 38 | #define REG_SE 0x054 | ||
| 39 | #define REG_IDLECONFIG 0x058 | ||
| 40 | #define REG_CHARGECONFIG 0x05C | ||
| 41 | #define REG_CHARGEDELAY 0x060 | ||
| 42 | #define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) | ||
| 43 | #define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) | ||
| 44 | #define REG_STEPCONFIG13 0x0C4 | ||
| 45 | #define REG_STEPDELAY13 0x0C8 | ||
| 46 | #define REG_STEPCONFIG14 0x0CC | ||
| 47 | #define REG_STEPDELAY14 0x0D0 | ||
| 48 | #define REG_FIFO0CNT 0xE4 | ||
| 49 | #define REG_FIFO1THR 0xF4 | ||
| 50 | #define REG_FIFO0 0x100 | ||
| 51 | #define REG_FIFO1 0x200 | ||
| 52 | |||
| 53 | /* Register Bitfields */ | ||
| 54 | #define IRQWKUP_ENB BIT(0) | ||
| 55 | #define STPENB_STEPENB 0x7FFF | ||
| 56 | #define IRQENB_FIFO1THRES BIT(5) | ||
| 57 | #define IRQENB_PENUP BIT(9) | ||
| 58 | #define STEPCONFIG_MODE_HWSYNC 0x2 | ||
| 59 | #define STEPCONFIG_SAMPLES_AVG (1 << 4) | ||
| 60 | #define STEPCONFIG_XPP (1 << 5) | ||
| 61 | #define STEPCONFIG_XNN (1 << 6) | ||
| 62 | #define STEPCONFIG_YPP (1 << 7) | ||
| 63 | #define STEPCONFIG_YNN (1 << 8) | ||
| 64 | #define STEPCONFIG_XNP (1 << 9) | ||
| 65 | #define STEPCONFIG_YPN (1 << 10) | ||
| 66 | #define STEPCONFIG_INM (1 << 18) | ||
| 67 | #define STEPCONFIG_INP (1 << 20) | ||
| 68 | #define STEPCONFIG_INP_5 (1 << 21) | ||
| 69 | #define STEPCONFIG_FIFO1 (1 << 26) | ||
| 70 | #define STEPCONFIG_OPENDLY 0xff | ||
| 71 | #define STEPCONFIG_Z1 (3 << 19) | ||
| 72 | #define STEPIDLE_INP (1 << 22) | ||
| 73 | #define STEPCHARGE_RFP (1 << 12) | ||
| 74 | #define STEPCHARGE_INM (1 << 15) | ||
| 75 | #define STEPCHARGE_INP (1 << 19) | ||
| 76 | #define STEPCHARGE_RFM (1 << 23) | ||
| 77 | #define STEPCHARGE_DELAY 0x1 | ||
| 78 | #define CNTRLREG_TSCSSENB (1 << 0) | ||
| 79 | #define CNTRLREG_STEPID (1 << 1) | ||
| 80 | #define CNTRLREG_STEPCONFIGWRT (1 << 2) | ||
| 81 | #define CNTRLREG_4WIRE (1 << 5) | ||
| 82 | #define CNTRLREG_5WIRE (1 << 6) | ||
| 83 | #define CNTRLREG_8WIRE (3 << 5) | ||
| 84 | #define CNTRLREG_TSCENB (1 << 7) | ||
| 85 | #define ADCFSM_STEPID 0x10 | ||
| 86 | |||
| 87 | #define SEQ_SETTLE 275 | ||
| 88 | #define ADC_CLK 3000000 | ||
| 89 | #define MAX_12BIT ((1 << 12) - 1) | ||
| 90 | #define TSCADC_DELTA_X 15 | ||
| 91 | #define TSCADC_DELTA_Y 15 | ||
| 92 | |||
| 93 | struct tscadc { | ||
| 94 | struct input_dev *input; | ||
| 95 | struct clk *tsc_ick; | ||
| 96 | void __iomem *tsc_base; | ||
| 97 | unsigned int irq; | ||
| 98 | unsigned int wires; | ||
| 99 | unsigned int x_plate_resistance; | ||
| 100 | bool pen_down; | ||
| 101 | }; | ||
| 102 | |||
| 103 | static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg) | ||
| 104 | { | ||
| 105 | return readl(ts->tsc_base + reg); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void tscadc_writel(struct tscadc *tsc, unsigned int reg, | ||
| 109 | unsigned int val) | ||
| 110 | { | ||
| 111 | writel(val, tsc->tsc_base + reg); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void tscadc_step_config(struct tscadc *ts_dev) | ||
| 115 | { | ||
| 116 | unsigned int config; | ||
| 117 | int i; | ||
| 118 | |||
| 119 | /* Configure the Step registers */ | ||
| 120 | |||
| 121 | config = STEPCONFIG_MODE_HWSYNC | | ||
| 122 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP; | ||
| 123 | switch (ts_dev->wires) { | ||
| 124 | case 4: | ||
| 125 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
| 126 | break; | ||
| 127 | case 5: | ||
| 128 | config |= STEPCONFIG_YNN | | ||
| 129 | STEPCONFIG_INP_5 | STEPCONFIG_XNN | | ||
| 130 | STEPCONFIG_YPP; | ||
| 131 | break; | ||
| 132 | case 8: | ||
| 133 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | |||
| 137 | for (i = 1; i < 7; i++) { | ||
| 138 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
| 139 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
| 140 | } | ||
| 141 | |||
| 142 | config = 0; | ||
| 143 | config = STEPCONFIG_MODE_HWSYNC | | ||
| 144 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN | | ||
| 145 | STEPCONFIG_INM | STEPCONFIG_FIFO1; | ||
| 146 | switch (ts_dev->wires) { | ||
| 147 | case 4: | ||
| 148 | config |= STEPCONFIG_YPP; | ||
| 149 | break; | ||
| 150 | case 5: | ||
| 151 | config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 | | ||
| 152 | STEPCONFIG_XNP | STEPCONFIG_YPN; | ||
| 153 | break; | ||
| 154 | case 8: | ||
| 155 | config |= STEPCONFIG_YPP; | ||
| 156 | break; | ||
| 157 | } | ||
| 158 | |||
| 159 | for (i = 7; i < 13; i++) { | ||
| 160 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
| 161 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
| 162 | } | ||
| 163 | |||
| 164 | config = 0; | ||
| 165 | /* Charge step configuration */ | ||
| 166 | config = STEPCONFIG_XPP | STEPCONFIG_YNN | | ||
| 167 | STEPCHARGE_RFP | STEPCHARGE_RFM | | ||
| 168 | STEPCHARGE_INM | STEPCHARGE_INP; | ||
| 169 | |||
| 170 | tscadc_writel(ts_dev, REG_CHARGECONFIG, config); | ||
| 171 | tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY); | ||
| 172 | |||
| 173 | config = 0; | ||
| 174 | /* Configure to calculate pressure */ | ||
| 175 | config = STEPCONFIG_MODE_HWSYNC | | ||
| 176 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP | | ||
| 177 | STEPCONFIG_XNN | STEPCONFIG_INM; | ||
| 178 | tscadc_writel(ts_dev, REG_STEPCONFIG13, config); | ||
| 179 | tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY); | ||
| 180 | |||
| 181 | config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1; | ||
| 182 | tscadc_writel(ts_dev, REG_STEPCONFIG14, config); | ||
| 183 | tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY); | ||
| 184 | |||
| 185 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
| 186 | } | ||
| 187 | |||
| 188 | static void tscadc_idle_config(struct tscadc *ts_config) | ||
| 189 | { | ||
| 190 | unsigned int idleconfig; | ||
| 191 | |||
| 192 | idleconfig = STEPCONFIG_YNN | | ||
| 193 | STEPCONFIG_INM | | ||
| 194 | STEPCONFIG_YPN | STEPIDLE_INP; | ||
| 195 | tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig); | ||
| 196 | } | ||
| 197 | |||
| 198 | static void tscadc_read_coordinates(struct tscadc *ts_dev, | ||
| 199 | unsigned int *x, unsigned int *y) | ||
| 200 | { | ||
| 201 | unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT); | ||
| 202 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | ||
| 203 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
| 204 | unsigned int read, diff; | ||
| 205 | unsigned int i; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * Delta filter is used to remove large variations in sampled | ||
| 209 | * values from ADC. The filter tries to predict where the next | ||
| 210 | * coordinate could be. This is done by taking a previous | ||
| 211 | * coordinate and subtracting it form current one. Further the | ||
| 212 | * algorithm compares the difference with that of a present value, | ||
| 213 | * if true the value is reported to the sub system. | ||
| 214 | */ | ||
| 215 | for (i = 0; i < fifocount - 1; i++) { | ||
| 216 | read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
| 217 | diff = abs(read - prev_val_x); | ||
| 218 | if (diff < prev_diff_x) { | ||
| 219 | prev_diff_x = diff; | ||
| 220 | *x = read; | ||
| 221 | } | ||
| 222 | prev_val_x = read; | ||
| 223 | |||
| 224 | read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
| 225 | diff = abs(read - prev_val_y); | ||
| 226 | if (diff < prev_diff_y) { | ||
| 227 | prev_diff_y = diff; | ||
| 228 | *y = read; | ||
| 229 | } | ||
| 230 | prev_val_y = read; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | static irqreturn_t tscadc_irq(int irq, void *dev) | ||
| 235 | { | ||
| 236 | struct tscadc *ts_dev = dev; | ||
| 237 | struct input_dev *input_dev = ts_dev->input; | ||
| 238 | unsigned int status, irqclr = 0; | ||
| 239 | unsigned int x = 0, y = 0; | ||
| 240 | unsigned int z1, z2, z; | ||
| 241 | unsigned int fsm; | ||
| 242 | |||
| 243 | status = tscadc_readl(ts_dev, REG_IRQSTATUS); | ||
| 244 | if (status & IRQENB_FIFO1THRES) { | ||
| 245 | tscadc_read_coordinates(ts_dev, &x, &y); | ||
| 246 | |||
| 247 | z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
| 248 | z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
| 249 | |||
| 250 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | ||
| 251 | /* | ||
| 252 | * Calculate pressure using formula | ||
| 253 | * Resistance(touch) = x plate resistance * | ||
| 254 | * x postion/4096 * ((z2 / z1) - 1) | ||
| 255 | */ | ||
| 256 | z = z2 - z1; | ||
| 257 | z *= x; | ||
| 258 | z *= ts_dev->x_plate_resistance; | ||
| 259 | z /= z1; | ||
| 260 | z = (z + 2047) >> 12; | ||
| 261 | |||
| 262 | if (z <= MAX_12BIT) { | ||
| 263 | input_report_abs(input_dev, ABS_X, x); | ||
| 264 | input_report_abs(input_dev, ABS_Y, y); | ||
| 265 | input_report_abs(input_dev, ABS_PRESSURE, z); | ||
| 266 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
| 267 | input_sync(input_dev); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | irqclr |= IRQENB_FIFO1THRES; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* | ||
| 274 | * Time for sequencer to settle, to read | ||
| 275 | * correct state of the sequencer. | ||
| 276 | */ | ||
| 277 | udelay(SEQ_SETTLE); | ||
| 278 | |||
| 279 | status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
| 280 | if (status & IRQENB_PENUP) { | ||
| 281 | /* Pen up event */ | ||
| 282 | fsm = tscadc_readl(ts_dev, REG_ADCFSM); | ||
| 283 | if (fsm == ADCFSM_STEPID) { | ||
| 284 | ts_dev->pen_down = false; | ||
| 285 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
| 286 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
| 287 | input_sync(input_dev); | ||
| 288 | } else { | ||
| 289 | ts_dev->pen_down = true; | ||
| 290 | } | ||
| 291 | irqclr |= IRQENB_PENUP; | ||
| 292 | } | ||
| 293 | |||
| 294 | tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr); | ||
| 295 | /* check pending interrupts */ | ||
| 296 | tscadc_writel(ts_dev, REG_IRQEOI, 0x0); | ||
| 297 | |||
| 298 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
| 299 | return IRQ_HANDLED; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* | ||
| 303 | * The functions for inserting/removing driver as a module. | ||
| 304 | */ | ||
| 305 | |||
| 306 | static int __devinit tscadc_probe(struct platform_device *pdev) | ||
| 307 | { | ||
| 308 | const struct tsc_data *pdata = pdev->dev.platform_data; | ||
| 309 | struct resource *res; | ||
| 310 | struct tscadc *ts_dev; | ||
| 311 | struct input_dev *input_dev; | ||
| 312 | struct clk *clk; | ||
| 313 | int err; | ||
| 314 | int clk_value, ctrl, irq; | ||
| 315 | |||
| 316 | if (!pdata) { | ||
| 317 | dev_err(&pdev->dev, "missing platform data.\n"); | ||
| 318 | return -EINVAL; | ||
| 319 | } | ||
| 320 | |||
| 321 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 322 | if (!res) { | ||
| 323 | dev_err(&pdev->dev, "no memory resource defined.\n"); | ||
| 324 | return -EINVAL; | ||
| 325 | } | ||
| 326 | |||
| 327 | irq = platform_get_irq(pdev, 0); | ||
| 328 | if (irq < 0) { | ||
| 329 | dev_err(&pdev->dev, "no irq ID is specified.\n"); | ||
| 330 | return -EINVAL; | ||
| 331 | } | ||
| 332 | |||
| 333 | /* Allocate memory for device */ | ||
| 334 | ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL); | ||
| 335 | input_dev = input_allocate_device(); | ||
| 336 | if (!ts_dev || !input_dev) { | ||
| 337 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
| 338 | err = -ENOMEM; | ||
| 339 | goto err_free_mem; | ||
| 340 | } | ||
| 341 | |||
| 342 | ts_dev->input = input_dev; | ||
| 343 | ts_dev->irq = irq; | ||
| 344 | ts_dev->wires = pdata->wires; | ||
| 345 | ts_dev->x_plate_resistance = pdata->x_plate_resistance; | ||
| 346 | |||
| 347 | res = request_mem_region(res->start, resource_size(res), pdev->name); | ||
| 348 | if (!res) { | ||
| 349 | dev_err(&pdev->dev, "failed to reserve registers.\n"); | ||
| 350 | err = -EBUSY; | ||
| 351 | goto err_free_mem; | ||
| 352 | } | ||
| 353 | |||
| 354 | ts_dev->tsc_base = ioremap(res->start, resource_size(res)); | ||
| 355 | if (!ts_dev->tsc_base) { | ||
| 356 | dev_err(&pdev->dev, "failed to map registers.\n"); | ||
| 357 | err = -ENOMEM; | ||
| 358 | goto err_release_mem_region; | ||
| 359 | } | ||
| 360 | |||
| 361 | err = request_irq(ts_dev->irq, tscadc_irq, | ||
| 362 | 0, pdev->dev.driver->name, ts_dev); | ||
| 363 | if (err) { | ||
| 364 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
| 365 | goto err_unmap_regs; | ||
| 366 | } | ||
| 367 | |||
| 368 | ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); | ||
| 369 | if (IS_ERR(ts_dev->tsc_ick)) { | ||
| 370 | dev_err(&pdev->dev, "failed to get TSC ick\n"); | ||
| 371 | goto err_free_irq; | ||
| 372 | } | ||
| 373 | clk_enable(ts_dev->tsc_ick); | ||
| 374 | |||
| 375 | clk = clk_get(&pdev->dev, "adc_tsc_fck"); | ||
| 376 | if (IS_ERR(clk)) { | ||
| 377 | dev_err(&pdev->dev, "failed to get TSC fck\n"); | ||
| 378 | err = PTR_ERR(clk); | ||
| 379 | goto err_disable_clk; | ||
| 380 | } | ||
| 381 | |||
| 382 | clk_value = clk_get_rate(clk) / ADC_CLK; | ||
| 383 | clk_put(clk); | ||
| 384 | |||
| 385 | if (clk_value < 7) { | ||
| 386 | dev_err(&pdev->dev, "clock input less than min clock requirement\n"); | ||
| 387 | goto err_disable_clk; | ||
| 388 | } | ||
| 389 | /* CLKDIV needs to be configured to the value minus 1 */ | ||
| 390 | tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1); | ||
| 391 | |||
| 392 | /* Enable wake-up of the SoC using touchscreen */ | ||
| 393 | tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
| 394 | |||
| 395 | ctrl = CNTRLREG_STEPCONFIGWRT | | ||
| 396 | CNTRLREG_TSCENB | | ||
| 397 | CNTRLREG_STEPID; | ||
| 398 | switch (ts_dev->wires) { | ||
| 399 | case 4: | ||
| 400 | ctrl |= CNTRLREG_4WIRE; | ||
| 401 | break; | ||
| 402 | case 5: | ||
| 403 | ctrl |= CNTRLREG_5WIRE; | ||
| 404 | break; | ||
| 405 | case 8: | ||
| 406 | ctrl |= CNTRLREG_8WIRE; | ||
| 407 | break; | ||
| 408 | } | ||
| 409 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
| 410 | |||
| 411 | tscadc_idle_config(ts_dev); | ||
| 412 | tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); | ||
| 413 | tscadc_step_config(ts_dev); | ||
| 414 | tscadc_writel(ts_dev, REG_FIFO1THR, 6); | ||
| 415 | |||
| 416 | ctrl |= CNTRLREG_TSCSSENB; | ||
| 417 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
| 418 | |||
| 419 | input_dev->name = "ti-tsc-adc"; | ||
| 420 | input_dev->dev.parent = &pdev->dev; | ||
| 421 | |||
| 422 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
| 423 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
| 424 | |||
| 425 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | ||
| 426 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | ||
| 427 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | ||
| 428 | |||
| 429 | /* register to the input system */ | ||
| 430 | err = input_register_device(input_dev); | ||
| 431 | if (err) | ||
| 432 | goto err_disable_clk; | ||
| 433 | |||
| 434 | platform_set_drvdata(pdev, ts_dev); | ||
| 435 | return 0; | ||
| 436 | |||
| 437 | err_disable_clk: | ||
| 438 | clk_disable(ts_dev->tsc_ick); | ||
| 439 | clk_put(ts_dev->tsc_ick); | ||
| 440 | err_free_irq: | ||
| 441 | free_irq(ts_dev->irq, ts_dev); | ||
| 442 | err_unmap_regs: | ||
| 443 | iounmap(ts_dev->tsc_base); | ||
| 444 | err_release_mem_region: | ||
| 445 | release_mem_region(res->start, resource_size(res)); | ||
| 446 | err_free_mem: | ||
| 447 | input_free_device(input_dev); | ||
| 448 | kfree(ts_dev); | ||
| 449 | return err; | ||
| 450 | } | ||
| 451 | |||
| 452 | static int __devexit tscadc_remove(struct platform_device *pdev) | ||
| 453 | { | ||
| 454 | struct tscadc *ts_dev = platform_get_drvdata(pdev); | ||
| 455 | struct resource *res; | ||
| 456 | |||
| 457 | free_irq(ts_dev->irq, ts_dev); | ||
| 458 | |||
| 459 | input_unregister_device(ts_dev->input); | ||
| 460 | |||
| 461 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 462 | iounmap(ts_dev->tsc_base); | ||
| 463 | release_mem_region(res->start, resource_size(res)); | ||
| 464 | |||
| 465 | clk_disable(ts_dev->tsc_ick); | ||
| 466 | clk_put(ts_dev->tsc_ick); | ||
| 467 | |||
| 468 | kfree(ts_dev); | ||
| 469 | |||
| 470 | platform_set_drvdata(pdev, NULL); | ||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | static struct platform_driver ti_tsc_driver = { | ||
| 475 | .probe = tscadc_probe, | ||
| 476 | .remove = __devexit_p(tscadc_remove), | ||
| 477 | .driver = { | ||
| 478 | .name = "tsc", | ||
| 479 | .owner = THIS_MODULE, | ||
| 480 | }, | ||
| 481 | }; | ||
| 482 | module_platform_driver(ti_tsc_driver); | ||
| 483 | |||
| 484 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | ||
| 485 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
| 486 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 3a5ebf452e81..22cd96f58c99 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * - Zytronic capacitive touchscreen | 17 | * - Zytronic capacitive touchscreen |
| 18 | * - NEXIO/iNexio | 18 | * - NEXIO/iNexio |
| 19 | * - Elo TouchSystems 2700 IntelliTouch | 19 | * - Elo TouchSystems 2700 IntelliTouch |
| 20 | * - EasyTouch USB Dual/Multi touch controller from Data Modul | ||
| 20 | * | 21 | * |
| 21 | * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch> | 22 | * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch> |
| 22 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) | 23 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) |
| @@ -140,6 +141,7 @@ enum { | |||
| 140 | DEVTYPE_TC45USB, | 141 | DEVTYPE_TC45USB, |
| 141 | DEVTYPE_NEXIO, | 142 | DEVTYPE_NEXIO, |
| 142 | DEVTYPE_ELO, | 143 | DEVTYPE_ELO, |
| 144 | DEVTYPE_ETOUCH, | ||
| 143 | }; | 145 | }; |
| 144 | 146 | ||
| 145 | #define USB_DEVICE_HID_CLASS(vend, prod) \ | 147 | #define USB_DEVICE_HID_CLASS(vend, prod) \ |
| @@ -245,6 +247,10 @@ static const struct usb_device_id usbtouch_devices[] = { | |||
| 245 | {USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO}, | 247 | {USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO}, |
| 246 | #endif | 248 | #endif |
| 247 | 249 | ||
| 250 | #ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH | ||
| 251 | {USB_DEVICE(0x7374, 0x0001), .driver_info = DEVTYPE_ETOUCH}, | ||
| 252 | #endif | ||
| 253 | |||
| 248 | {} | 254 | {} |
| 249 | }; | 255 | }; |
| 250 | 256 | ||
| @@ -326,6 +332,51 @@ static int egalax_get_pkt_len(unsigned char *buf, int len) | |||
| 326 | } | 332 | } |
| 327 | #endif | 333 | #endif |
| 328 | 334 | ||
| 335 | /***************************************************************************** | ||
| 336 | * EasyTouch part | ||
| 337 | */ | ||
| 338 | |||
| 339 | #ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH | ||
| 340 | |||
| 341 | #ifndef MULTI_PACKET | ||
| 342 | #define MULTI_PACKET | ||
| 343 | #endif | ||
| 344 | |||
| 345 | #define ETOUCH_PKT_TYPE_MASK 0xFE | ||
| 346 | #define ETOUCH_PKT_TYPE_REPT 0x80 | ||
| 347 | #define ETOUCH_PKT_TYPE_REPT2 0xB0 | ||
| 348 | #define ETOUCH_PKT_TYPE_DIAG 0x0A | ||
| 349 | |||
| 350 | static int etouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | ||
| 351 | { | ||
| 352 | if ((pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT && | ||
| 353 | (pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT2) | ||
| 354 | return 0; | ||
| 355 | |||
| 356 | dev->x = ((pkt[1] & 0x1F) << 7) | (pkt[2] & 0x7F); | ||
| 357 | dev->y = ((pkt[3] & 0x1F) << 7) | (pkt[4] & 0x7F); | ||
| 358 | dev->touch = pkt[0] & 0x01; | ||
| 359 | |||
| 360 | return 1; | ||
| 361 | } | ||
| 362 | |||
| 363 | static int etouch_get_pkt_len(unsigned char *buf, int len) | ||
| 364 | { | ||
| 365 | switch (buf[0] & ETOUCH_PKT_TYPE_MASK) { | ||
| 366 | case ETOUCH_PKT_TYPE_REPT: | ||
| 367 | case ETOUCH_PKT_TYPE_REPT2: | ||
| 368 | return 5; | ||
| 369 | |||
| 370 | case ETOUCH_PKT_TYPE_DIAG: | ||
| 371 | if (len < 2) | ||
| 372 | return -1; | ||
| 373 | |||
| 374 | return buf[1] + 2; | ||
| 375 | } | ||
| 376 | |||
| 377 | return 0; | ||
| 378 | } | ||
| 379 | #endif | ||
| 329 | 380 | ||
| 330 | /***************************************************************************** | 381 | /***************************************************************************** |
| 331 | * PanJit Part | 382 | * PanJit Part |
| @@ -1175,6 +1226,18 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { | |||
| 1175 | .exit = nexio_exit, | 1226 | .exit = nexio_exit, |
| 1176 | }, | 1227 | }, |
| 1177 | #endif | 1228 | #endif |
| 1229 | #ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH | ||
| 1230 | [DEVTYPE_ETOUCH] = { | ||
| 1231 | .min_xc = 0x0, | ||
| 1232 | .max_xc = 0x07ff, | ||
| 1233 | .min_yc = 0x0, | ||
| 1234 | .max_yc = 0x07ff, | ||
| 1235 | .rept_size = 16, | ||
| 1236 | .process_pkt = usbtouch_process_multi, | ||
| 1237 | .get_pkt_len = etouch_get_pkt_len, | ||
| 1238 | .read_data = etouch_read_data, | ||
| 1239 | }, | ||
| 1240 | #endif | ||
| 1178 | }; | 1241 | }; |
| 1179 | 1242 | ||
| 1180 | 1243 | ||
diff --git a/include/linux/input.h b/include/linux/input.h index 3862e32c4eeb..177261ea6f52 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
| @@ -129,6 +129,8 @@ struct input_keymap_entry { | |||
| 129 | 129 | ||
| 130 | #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ | 130 | #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ |
| 131 | 131 | ||
| 132 | #define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ | ||
| 133 | |||
| 132 | /* | 134 | /* |
| 133 | * Device properties and quirks | 135 | * Device properties and quirks |
| 134 | */ | 136 | */ |
diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h new file mode 100644 index 000000000000..5af7c66f1fca --- /dev/null +++ b/include/linux/input/cyttsp.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Header file for: | ||
| 3 | * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers. | ||
| 4 | * For use with Cypress Txx3xx parts. | ||
| 5 | * Supported parts include: | ||
| 6 | * CY8CTST341 | ||
| 7 | * CY8CTMA340 | ||
| 8 | * | ||
| 9 | * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. | ||
| 10 | * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU General Public License | ||
| 14 | * version 2, and only version 2, as published by the | ||
| 15 | * Free Software Foundation. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License along | ||
| 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 | * | ||
| 28 | */ | ||
| 29 | #ifndef _CYTTSP_H_ | ||
| 30 | #define _CYTTSP_H_ | ||
| 31 | |||
| 32 | #define CY_SPI_NAME "cyttsp-spi" | ||
| 33 | #define CY_I2C_NAME "cyttsp-i2c" | ||
| 34 | /* Active Power state scanning/processing refresh interval */ | ||
| 35 | #define CY_ACT_INTRVL_DFLT 0x00 /* ms */ | ||
| 36 | /* touch timeout for the Active power */ | ||
| 37 | #define CY_TCH_TMOUT_DFLT 0xFF /* ms */ | ||
| 38 | /* Low Power state scanning/processing refresh interval */ | ||
| 39 | #define CY_LP_INTRVL_DFLT 0x0A /* ms */ | ||
| 40 | /* Active distance in pixels for a gesture to be reported */ | ||
| 41 | #define CY_ACT_DIST_DFLT 0xF8 /* pixels */ | ||
| 42 | |||
| 43 | struct cyttsp_platform_data { | ||
| 44 | u32 maxx; | ||
| 45 | u32 maxy; | ||
| 46 | bool use_hndshk; | ||
| 47 | u8 act_dist; /* Active distance */ | ||
| 48 | u8 act_intrvl; /* Active refresh interval; ms */ | ||
| 49 | u8 tch_tmout; /* Active touch timeout; ms */ | ||
| 50 | u8 lp_intrvl; /* Low power refresh interval; ms */ | ||
| 51 | int (*init)(void); | ||
| 52 | void (*exit)(void); | ||
| 53 | char *name; | ||
| 54 | s16 irq_gpio; | ||
| 55 | u8 *bl_keys; | ||
| 56 | }; | ||
| 57 | |||
| 58 | #endif /* _CYTTSP_H_ */ | ||
diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h new file mode 100644 index 000000000000..b10a527a92a4 --- /dev/null +++ b/include/linux/input/ti_tscadc.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #ifndef __LINUX_TI_TSCADC_H | ||
| 2 | #define __LINUX_TI_TSCADC_H | ||
| 3 | |||
| 4 | /** | ||
| 5 | * struct tsc_data Touchscreen wire configuration | ||
| 6 | * @wires: Wires refer to application modes | ||
| 7 | * i.e. 4/5/8 wire touchscreen support | ||
| 8 | * on the platform. | ||
| 9 | * @x_plate_resistance: X plate resistance. | ||
| 10 | */ | ||
| 11 | |||
| 12 | struct tsc_data { | ||
| 13 | int wires; | ||
| 14 | int x_plate_resistance; | ||
| 15 | }; | ||
| 16 | |||
| 17 | #endif | ||
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 0c6358186401..e6a5a6bc2769 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -1230,6 +1230,8 @@ ktime_t ktime_get_monotonic_offset(void) | |||
| 1230 | } while (read_seqretry(&xtime_lock, seq)); | 1230 | } while (read_seqretry(&xtime_lock, seq)); |
| 1231 | return timespec_to_ktime(wtom); | 1231 | return timespec_to_ktime(wtom); |
| 1232 | } | 1232 | } |
| 1233 | EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset); | ||
| 1234 | |||
| 1233 | 1235 | ||
| 1234 | /** | 1236 | /** |
| 1235 | * xtime_update() - advances the timekeeping infrastructure | 1237 | * xtime_update() - advances the timekeeping infrastructure |
