diff options
22 files changed, 1555 insertions, 48 deletions
diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt index 686ee9932dff..b93c08442e3c 100644 --- a/Documentation/input/input.txt +++ b/Documentation/input/input.txt | |||
@@ -278,7 +278,7 @@ struct input_event { | |||
278 | }; | 278 | }; |
279 | 279 | ||
280 | 'time' is the timestamp, it returns the time at which the event happened. | 280 | 'time' is the timestamp, it returns the time at which the event happened. |
281 | Type is for example EV_REL for relative moment, REL_KEY for a keypress or | 281 | Type is for example EV_REL for relative moment, EV_KEY for a keypress or |
282 | release. More types are defined in include/linux/input.h. | 282 | release. More types are defined in include/linux/input.h. |
283 | 283 | ||
284 | 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete | 284 | 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete |
diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt index 435102a26d96..3a6aec40c0b0 100644 --- a/Documentation/input/rotary-encoder.txt +++ b/Documentation/input/rotary-encoder.txt | |||
@@ -67,7 +67,12 @@ data with it. | |||
67 | struct rotary_encoder_platform_data is declared in | 67 | struct rotary_encoder_platform_data is declared in |
68 | include/linux/rotary-encoder.h and needs to be filled with the number of | 68 | include/linux/rotary-encoder.h and needs to be filled with the number of |
69 | steps the encoder has and can carry information about externally inverted | 69 | steps the encoder has and can carry information about externally inverted |
70 | signals (because of used invertig buffer or other reasons). | 70 | signals (because of an inverting buffer or other reasons). The encoder |
71 | can be set up to deliver input information as either an absolute or relative | ||
72 | axes. For relative axes the input event returns +/-1 for each step. For | ||
73 | absolute axes the position of the encoder can either roll over between zero | ||
74 | and the number of steps or will clamp at the maximum and zero depending on | ||
75 | the configuration. | ||
71 | 76 | ||
72 | Because GPIO to IRQ mapping is platform specific, this information must | 77 | Because GPIO to IRQ mapping is platform specific, this information must |
73 | be given in seperately to the driver. See the example below. | 78 | be given in seperately to the driver. See the example below. |
@@ -85,6 +90,8 @@ be given in seperately to the driver. See the example below. | |||
85 | static struct rotary_encoder_platform_data my_rotary_encoder_info = { | 90 | static struct rotary_encoder_platform_data my_rotary_encoder_info = { |
86 | .steps = 24, | 91 | .steps = 24, |
87 | .axis = ABS_X, | 92 | .axis = ABS_X, |
93 | .relative_axis = false, | ||
94 | .rollover = false, | ||
88 | .gpio_a = GPIO_ROTARY_A, | 95 | .gpio_a = GPIO_ROTARY_A, |
89 | .gpio_b = GPIO_ROTARY_B, | 96 | .gpio_b = GPIO_ROTARY_B, |
90 | .inverted_a = 0, | 97 | .inverted_a = 0, |
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h new file mode 100644 index 000000000000..83f31cd0a274 --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h | ||
3 | */ | ||
4 | |||
5 | #ifndef __ASM_ARCH_EP93XX_KEYPAD_H | ||
6 | #define __ASM_ARCH_EP93XX_KEYPAD_H | ||
7 | |||
8 | #define MAX_MATRIX_KEY_ROWS (8) | ||
9 | #define MAX_MATRIX_KEY_COLS (8) | ||
10 | |||
11 | /* flags for the ep93xx_keypad driver */ | ||
12 | #define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */ | ||
13 | #define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */ | ||
14 | #define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */ | ||
15 | #define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */ | ||
16 | #define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */ | ||
17 | #define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */ | ||
18 | |||
19 | /** | ||
20 | * struct ep93xx_keypad_platform_data - platform specific device structure | ||
21 | * @matrix_key_rows: number of rows in the keypad matrix | ||
22 | * @matrix_key_cols: number of columns in the keypad matrix | ||
23 | * @matrix_key_map: array of keycodes defining the keypad matrix | ||
24 | * @matrix_key_map_size: ARRAY_SIZE(matrix_key_map) | ||
25 | * @debounce: debounce start count; terminal count is 0xff | ||
26 | * @prescale: row/column counter pre-scaler load value | ||
27 | * @flags: see above | ||
28 | */ | ||
29 | struct ep93xx_keypad_platform_data { | ||
30 | unsigned int matrix_key_rows; | ||
31 | unsigned int matrix_key_cols; | ||
32 | unsigned int *matrix_key_map; | ||
33 | int matrix_key_map_size; | ||
34 | unsigned int debounce; | ||
35 | unsigned int prescale; | ||
36 | unsigned int flags; | ||
37 | }; | ||
38 | |||
39 | /* macro for creating the matrix_key_map table */ | ||
40 | #define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val)) | ||
41 | |||
42 | #endif /* __ASM_ARCH_EP93XX_KEYPAD_H */ | ||
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index de26a978fbdd..737be953cc58 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -1123,8 +1123,6 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, | |||
1123 | 1123 | ||
1124 | #define HW_RAW(dev) 0 | 1124 | #define HW_RAW(dev) 0 |
1125 | 1125 | ||
1126 | #warning "Cannot generate rawmode keyboard for your architecture yet." | ||
1127 | |||
1128 | static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) | 1126 | static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) |
1129 | { | 1127 | { |
1130 | if (keycode > 127) | 1128 | if (keycode > 127) |
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 1dec00e20dbc..8a1810f88b9e 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c | |||
@@ -167,5 +167,6 @@ module_exit(fm801_gp_exit); | |||
167 | 167 | ||
168 | MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); | 168 | MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); |
169 | 169 | ||
170 | MODULE_DESCRIPTION("FM801 gameport driver"); | ||
170 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 171 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
171 | MODULE_LICENSE("GPL"); | 172 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 2d175b5928ff..0279d6983cc8 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c | |||
@@ -30,16 +30,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
30 | MODULE_DESCRIPTION("Generic gameport layer"); | 30 | MODULE_DESCRIPTION("Generic gameport layer"); |
31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
32 | 32 | ||
33 | EXPORT_SYMBOL(__gameport_register_port); | ||
34 | EXPORT_SYMBOL(gameport_unregister_port); | ||
35 | EXPORT_SYMBOL(__gameport_register_driver); | ||
36 | EXPORT_SYMBOL(gameport_unregister_driver); | ||
37 | EXPORT_SYMBOL(gameport_open); | ||
38 | EXPORT_SYMBOL(gameport_close); | ||
39 | EXPORT_SYMBOL(gameport_set_phys); | ||
40 | EXPORT_SYMBOL(gameport_start_polling); | ||
41 | EXPORT_SYMBOL(gameport_stop_polling); | ||
42 | |||
43 | /* | 33 | /* |
44 | * gameport_mutex protects entire gameport subsystem and is taken | 34 | * gameport_mutex protects entire gameport subsystem and is taken |
45 | * every time gameport port or driver registrered or unregistered. | 35 | * every time gameport port or driver registrered or unregistered. |
@@ -162,6 +152,7 @@ void gameport_start_polling(struct gameport *gameport) | |||
162 | 152 | ||
163 | spin_unlock(&gameport->timer_lock); | 153 | spin_unlock(&gameport->timer_lock); |
164 | } | 154 | } |
155 | EXPORT_SYMBOL(gameport_start_polling); | ||
165 | 156 | ||
166 | void gameport_stop_polling(struct gameport *gameport) | 157 | void gameport_stop_polling(struct gameport *gameport) |
167 | { | 158 | { |
@@ -172,6 +163,7 @@ void gameport_stop_polling(struct gameport *gameport) | |||
172 | 163 | ||
173 | spin_unlock(&gameport->timer_lock); | 164 | spin_unlock(&gameport->timer_lock); |
174 | } | 165 | } |
166 | EXPORT_SYMBOL(gameport_stop_polling); | ||
175 | 167 | ||
176 | static void gameport_run_poll_handler(unsigned long d) | 168 | static void gameport_run_poll_handler(unsigned long d) |
177 | { | 169 | { |
@@ -516,6 +508,7 @@ void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) | |||
516 | vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args); | 508 | vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args); |
517 | va_end(args); | 509 | va_end(args); |
518 | } | 510 | } |
511 | EXPORT_SYMBOL(gameport_set_phys); | ||
519 | 512 | ||
520 | /* | 513 | /* |
521 | * Prepare gameport port for registration. | 514 | * Prepare gameport port for registration. |
@@ -658,6 +651,7 @@ void __gameport_register_port(struct gameport *gameport, struct module *owner) | |||
658 | gameport_init_port(gameport); | 651 | gameport_init_port(gameport); |
659 | gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT); | 652 | gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT); |
660 | } | 653 | } |
654 | EXPORT_SYMBOL(__gameport_register_port); | ||
661 | 655 | ||
662 | /* | 656 | /* |
663 | * Synchronously unregisters gameport port. | 657 | * Synchronously unregisters gameport port. |
@@ -669,6 +663,7 @@ void gameport_unregister_port(struct gameport *gameport) | |||
669 | gameport_destroy_port(gameport); | 663 | gameport_destroy_port(gameport); |
670 | mutex_unlock(&gameport_mutex); | 664 | mutex_unlock(&gameport_mutex); |
671 | } | 665 | } |
666 | EXPORT_SYMBOL(gameport_unregister_port); | ||
672 | 667 | ||
673 | 668 | ||
674 | /* | 669 | /* |
@@ -750,6 +745,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner | |||
750 | 745 | ||
751 | return 0; | 746 | return 0; |
752 | } | 747 | } |
748 | EXPORT_SYMBOL(__gameport_register_driver); | ||
753 | 749 | ||
754 | void gameport_unregister_driver(struct gameport_driver *drv) | 750 | void gameport_unregister_driver(struct gameport_driver *drv) |
755 | { | 751 | { |
@@ -774,6 +770,7 @@ start_over: | |||
774 | 770 | ||
775 | mutex_unlock(&gameport_mutex); | 771 | mutex_unlock(&gameport_mutex); |
776 | } | 772 | } |
773 | EXPORT_SYMBOL(gameport_unregister_driver); | ||
777 | 774 | ||
778 | static int gameport_bus_match(struct device *dev, struct device_driver *drv) | 775 | static int gameport_bus_match(struct device *dev, struct device_driver *drv) |
779 | { | 776 | { |
@@ -812,6 +809,7 @@ int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mo | |||
812 | gameport_set_drv(gameport, drv); | 809 | gameport_set_drv(gameport, drv); |
813 | return 0; | 810 | return 0; |
814 | } | 811 | } |
812 | EXPORT_SYMBOL(gameport_open); | ||
815 | 813 | ||
816 | void gameport_close(struct gameport *gameport) | 814 | void gameport_close(struct gameport *gameport) |
817 | { | 815 | { |
@@ -822,6 +820,7 @@ void gameport_close(struct gameport *gameport) | |||
822 | if (gameport->close) | 820 | if (gameport->close) |
823 | gameport->close(gameport); | 821 | gameport->close(gameport); |
824 | } | 822 | } |
823 | EXPORT_SYMBOL(gameport_close); | ||
825 | 824 | ||
826 | static int __init gameport_init(void) | 825 | static int __init gameport_init(void) |
827 | { | 826 | { |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index ea2638b41982..54775aaa7be7 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -332,4 +332,14 @@ config KEYBOARD_SH_KEYSC | |||
332 | 332 | ||
333 | To compile this driver as a module, choose M here: the | 333 | To compile this driver as a module, choose M here: the |
334 | module will be called sh_keysc. | 334 | module will be called sh_keysc. |
335 | + | ||
336 | config KEYBOARD_EP93XX | ||
337 | tristate "EP93xx Matrix Keypad support" | ||
338 | depends on ARCH_EP93XX | ||
339 | help | ||
340 | Say Y here to enable the matrix keypad on the Cirrus EP93XX. | ||
341 | |||
342 | To compile this driver as a module, choose M here: the | ||
343 | module will be called ep93xx_keypad. | ||
344 | |||
335 | endif | 345 | endif |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 36351e1190f9..13ba9c954938 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -28,3 +28,4 @@ obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o | |||
28 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o | 28 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o |
29 | obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o | 29 | obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o |
30 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o | 30 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o |
31 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o | ||
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c new file mode 100644 index 000000000000..181d30e3018e --- /dev/null +++ b/drivers/input/keyboard/ep93xx_keypad.c | |||
@@ -0,0 +1,470 @@ | |||
1 | /* | ||
2 | * Driver for the Cirrus EP93xx matrix keypad controller. | ||
3 | * | ||
4 | * Copyright (c) 2008 H Hartley Sweeten <hsweeten@visionengravers.com> | ||
5 | * | ||
6 | * Based on the pxa27x matrix keypad controller by Rodolfo Giometti. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * NOTE: | ||
13 | * | ||
14 | * The 3-key reset is triggered by pressing the 3 keys in | ||
15 | * Row 0, Columns 2, 4, and 7 at the same time. This action can | ||
16 | * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag. | ||
17 | * | ||
18 | * Normal operation for the matrix does not autorepeat the key press. | ||
19 | * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT | ||
20 | * flag. | ||
21 | */ | ||
22 | |||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/input.h> | ||
26 | #include <linux/clk.h> | ||
27 | |||
28 | #include <mach/hardware.h> | ||
29 | #include <mach/gpio.h> | ||
30 | #include <mach/ep93xx_keypad.h> | ||
31 | |||
32 | /* | ||
33 | * Keypad Interface Register offsets | ||
34 | */ | ||
35 | #define KEY_INIT 0x00 /* Key Scan Initialization register */ | ||
36 | #define KEY_DIAG 0x04 /* Key Scan Diagnostic register */ | ||
37 | #define KEY_REG 0x08 /* Key Value Capture register */ | ||
38 | |||
39 | /* Key Scan Initialization Register bit defines */ | ||
40 | #define KEY_INIT_DBNC_MASK (0x00ff0000) | ||
41 | #define KEY_INIT_DBNC_SHIFT (16) | ||
42 | #define KEY_INIT_DIS3KY (1<<15) | ||
43 | #define KEY_INIT_DIAG (1<<14) | ||
44 | #define KEY_INIT_BACK (1<<13) | ||
45 | #define KEY_INIT_T2 (1<<12) | ||
46 | #define KEY_INIT_PRSCL_MASK (0x000003ff) | ||
47 | #define KEY_INIT_PRSCL_SHIFT (0) | ||
48 | |||
49 | /* Key Scan Diagnostic Register bit defines */ | ||
50 | #define KEY_DIAG_MASK (0x0000003f) | ||
51 | #define KEY_DIAG_SHIFT (0) | ||
52 | |||
53 | /* Key Value Capture Register bit defines */ | ||
54 | #define KEY_REG_K (1<<15) | ||
55 | #define KEY_REG_INT (1<<14) | ||
56 | #define KEY_REG_2KEYS (1<<13) | ||
57 | #define KEY_REG_1KEY (1<<12) | ||
58 | #define KEY_REG_KEY2_MASK (0x00000fc0) | ||
59 | #define KEY_REG_KEY2_SHIFT (6) | ||
60 | #define KEY_REG_KEY1_MASK (0x0000003f) | ||
61 | #define KEY_REG_KEY1_SHIFT (0) | ||
62 | |||
63 | #define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) | ||
64 | #define keypad_writel(v, off) __raw_writel((v), keypad->mmio_base + (off)) | ||
65 | |||
66 | #define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) | ||
67 | |||
68 | struct ep93xx_keypad { | ||
69 | struct ep93xx_keypad_platform_data *pdata; | ||
70 | |||
71 | struct clk *clk; | ||
72 | struct input_dev *input_dev; | ||
73 | void __iomem *mmio_base; | ||
74 | |||
75 | int irq; | ||
76 | int enabled; | ||
77 | |||
78 | int key1; | ||
79 | int key2; | ||
80 | |||
81 | unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; | ||
82 | }; | ||
83 | |||
84 | static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad) | ||
85 | { | ||
86 | struct ep93xx_keypad_platform_data *pdata = keypad->pdata; | ||
87 | struct input_dev *input_dev = keypad->input_dev; | ||
88 | int i; | ||
89 | |||
90 | for (i = 0; i < pdata->matrix_key_map_size; i++) { | ||
91 | unsigned int key = pdata->matrix_key_map[i]; | ||
92 | int row = (key >> 28) & 0xf; | ||
93 | int col = (key >> 24) & 0xf; | ||
94 | int code = key & 0xffffff; | ||
95 | |||
96 | keypad->matrix_keycodes[(row << 3) + col] = code; | ||
97 | __set_bit(code, input_dev->keybit); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) | ||
102 | { | ||
103 | struct ep93xx_keypad *keypad = dev_id; | ||
104 | struct input_dev *input_dev = keypad->input_dev; | ||
105 | unsigned int status = keypad_readl(KEY_REG); | ||
106 | int keycode, key1, key2; | ||
107 | |||
108 | keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT; | ||
109 | key1 = keypad->matrix_keycodes[keycode]; | ||
110 | |||
111 | keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT; | ||
112 | key2 = keypad->matrix_keycodes[keycode]; | ||
113 | |||
114 | if (status & KEY_REG_2KEYS) { | ||
115 | if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1) | ||
116 | input_report_key(input_dev, keypad->key1, 0); | ||
117 | |||
118 | if (keypad->key2 && key1 != keypad->key2 && key2 != keypad->key2) | ||
119 | input_report_key(input_dev, keypad->key2, 0); | ||
120 | |||
121 | input_report_key(input_dev, key1, 1); | ||
122 | input_report_key(input_dev, key2, 1); | ||
123 | |||
124 | keypad->key1 = key1; | ||
125 | keypad->key2 = key2; | ||
126 | |||
127 | } else if (status & KEY_REG_1KEY) { | ||
128 | if (keypad->key1 && key1 != keypad->key1) | ||
129 | input_report_key(input_dev, keypad->key1, 0); | ||
130 | |||
131 | if (keypad->key2 && key1 != keypad->key2) | ||
132 | input_report_key(input_dev, keypad->key2, 0); | ||
133 | |||
134 | input_report_key(input_dev, key1, 1); | ||
135 | |||
136 | keypad->key1 = key1; | ||
137 | keypad->key2 = 0; | ||
138 | |||
139 | } else { | ||
140 | input_report_key(input_dev, keypad->key1, 0); | ||
141 | input_report_key(input_dev, keypad->key2, 0); | ||
142 | |||
143 | keypad->key1 = keypad->key2 = 0; | ||
144 | } | ||
145 | input_sync(input_dev); | ||
146 | |||
147 | return IRQ_HANDLED; | ||
148 | } | ||
149 | |||
150 | static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) | ||
151 | { | ||
152 | struct ep93xx_keypad_platform_data *pdata = keypad->pdata; | ||
153 | unsigned int val = 0; | ||
154 | |||
155 | clk_set_rate(keypad->clk, pdata->flags & EP93XX_KEYPAD_KDIV); | ||
156 | |||
157 | if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY) | ||
158 | val |= KEY_INIT_DIS3KY; | ||
159 | if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE) | ||
160 | val |= KEY_INIT_DIAG; | ||
161 | if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE) | ||
162 | val |= KEY_INIT_BACK; | ||
163 | if (pdata->flags & EP93XX_KEYPAD_TEST_MODE) | ||
164 | val |= KEY_INIT_T2; | ||
165 | |||
166 | val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK); | ||
167 | |||
168 | val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK); | ||
169 | |||
170 | keypad_writel(val, KEY_INIT); | ||
171 | } | ||
172 | |||
173 | static int ep93xx_keypad_open(struct input_dev *pdev) | ||
174 | { | ||
175 | struct ep93xx_keypad *keypad = input_get_drvdata(pdev); | ||
176 | |||
177 | if (!keypad->enabled) { | ||
178 | ep93xx_keypad_config(keypad); | ||
179 | clk_enable(keypad->clk); | ||
180 | keypad->enabled = 1; | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static void ep93xx_keypad_close(struct input_dev *pdev) | ||
187 | { | ||
188 | struct ep93xx_keypad *keypad = input_get_drvdata(pdev); | ||
189 | |||
190 | if (keypad->enabled) { | ||
191 | clk_disable(keypad->clk); | ||
192 | keypad->enabled = 0; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | |||
197 | #ifdef CONFIG_PM | ||
198 | /* | ||
199 | * NOTE: I don't know if this is correct, or will work on the ep93xx. | ||
200 | * | ||
201 | * None of the existing ep93xx drivers have power management support. | ||
202 | * But, this is basically what the pxa27x_keypad driver does. | ||
203 | */ | ||
204 | static int ep93xx_keypad_suspend(struct platform_device *pdev, | ||
205 | pm_message_t state) | ||
206 | { | ||
207 | struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); | ||
208 | struct input_dev *input_dev = keypad->input_dev; | ||
209 | |||
210 | mutex_lock(&input_dev->mutex); | ||
211 | |||
212 | if (keypad->enabled) { | ||
213 | clk_disable(keypad->clk); | ||
214 | keypad->enabled = 0; | ||
215 | } | ||
216 | |||
217 | mutex_unlock(&input_dev->mutex); | ||
218 | |||
219 | if (device_may_wakeup(&pdev->dev)) | ||
220 | enable_irq_wake(keypad->irq); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int ep93xx_keypad_resume(struct platform_device *pdev) | ||
226 | { | ||
227 | struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); | ||
228 | struct input_dev *input_dev = keypad->input_dev; | ||
229 | |||
230 | if (device_may_wakeup(&pdev->dev)) | ||
231 | disable_irq_wake(keypad->irq); | ||
232 | |||
233 | mutex_lock(&input_dev->mutex); | ||
234 | |||
235 | if (input_dev->users) { | ||
236 | if (!keypad->enabled) { | ||
237 | ep93xx_keypad_config(keypad); | ||
238 | clk_enable(keypad->clk); | ||
239 | keypad->enabled = 1; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | mutex_unlock(&input_dev->mutex); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | #else /* !CONFIG_PM */ | ||
248 | #define ep93xx_keypad_suspend NULL | ||
249 | #define ep93xx_keypad_resume NULL | ||
250 | #endif /* !CONFIG_PM */ | ||
251 | |||
252 | static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) | ||
253 | { | ||
254 | struct ep93xx_keypad *keypad; | ||
255 | struct ep93xx_keypad_platform_data *pdata = pdev->dev.platform_data; | ||
256 | struct input_dev *input_dev; | ||
257 | struct resource *res; | ||
258 | int irq, err, i, gpio; | ||
259 | |||
260 | if (!pdata || | ||
261 | !pdata->matrix_key_rows || | ||
262 | pdata->matrix_key_rows > MAX_MATRIX_KEY_ROWS || | ||
263 | !pdata->matrix_key_cols || | ||
264 | pdata->matrix_key_cols > MAX_MATRIX_KEY_COLS) { | ||
265 | dev_err(&pdev->dev, "invalid or missing platform data\n"); | ||
266 | return -EINVAL; | ||
267 | } | ||
268 | |||
269 | keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL); | ||
270 | if (!keypad) { | ||
271 | dev_err(&pdev->dev, "failed to allocate driver data\n"); | ||
272 | return -ENOMEM; | ||
273 | } | ||
274 | |||
275 | keypad->pdata = pdata; | ||
276 | |||
277 | irq = platform_get_irq(pdev, 0); | ||
278 | if (irq < 0) { | ||
279 | dev_err(&pdev->dev, "failed to get keypad irq\n"); | ||
280 | err = -ENXIO; | ||
281 | goto failed_free; | ||
282 | } | ||
283 | |||
284 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
285 | if (!res) { | ||
286 | dev_err(&pdev->dev, "failed to get I/O memory\n"); | ||
287 | err = -ENXIO; | ||
288 | goto failed_free; | ||
289 | } | ||
290 | |||
291 | res = request_mem_region(res->start, resource_size(res), pdev->name); | ||
292 | if (!res) { | ||
293 | dev_err(&pdev->dev, "failed to request I/O memory\n"); | ||
294 | err = -EBUSY; | ||
295 | goto failed_free; | ||
296 | } | ||
297 | |||
298 | keypad->mmio_base = ioremap(res->start, resource_size(res)); | ||
299 | if (keypad->mmio_base == NULL) { | ||
300 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); | ||
301 | err = -ENXIO; | ||
302 | goto failed_free_mem; | ||
303 | } | ||
304 | |||
305 | /* Request the needed GPIO's */ | ||
306 | gpio = EP93XX_GPIO_LINE_ROW0; | ||
307 | for (i = 0; i < keypad->pdata->matrix_key_rows; i++, gpio++) { | ||
308 | err = gpio_request(gpio, pdev->name); | ||
309 | if (err) { | ||
310 | dev_err(&pdev->dev, "failed to request gpio-%d\n", | ||
311 | gpio); | ||
312 | goto failed_free_rows; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | gpio = EP93XX_GPIO_LINE_COL0; | ||
317 | for (i = 0; i < keypad->pdata->matrix_key_cols; i++, gpio++) { | ||
318 | err = gpio_request(gpio, pdev->name); | ||
319 | if (err) { | ||
320 | dev_err(&pdev->dev, "failed to request gpio-%d\n", | ||
321 | gpio); | ||
322 | goto failed_free_cols; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | keypad->clk = clk_get(&pdev->dev, "key_clk"); | ||
327 | if (IS_ERR(keypad->clk)) { | ||
328 | dev_err(&pdev->dev, "failed to get keypad clock\n"); | ||
329 | err = PTR_ERR(keypad->clk); | ||
330 | goto failed_free_io; | ||
331 | } | ||
332 | |||
333 | /* Create and register the input driver */ | ||
334 | input_dev = input_allocate_device(); | ||
335 | if (!input_dev) { | ||
336 | dev_err(&pdev->dev, "failed to allocate input device\n"); | ||
337 | err = -ENOMEM; | ||
338 | goto failed_put_clk; | ||
339 | } | ||
340 | |||
341 | keypad->input_dev = input_dev; | ||
342 | |||
343 | input_dev->name = pdev->name; | ||
344 | input_dev->id.bustype = BUS_HOST; | ||
345 | input_dev->open = ep93xx_keypad_open; | ||
346 | input_dev->close = ep93xx_keypad_close; | ||
347 | input_dev->dev.parent = &pdev->dev; | ||
348 | input_dev->keycode = keypad->matrix_keycodes; | ||
349 | input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]); | ||
350 | input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes); | ||
351 | |||
352 | input_set_drvdata(input_dev, keypad); | ||
353 | |||
354 | input_dev->evbit[0] = BIT_MASK(EV_KEY); | ||
355 | if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) | ||
356 | input_dev->evbit[0] |= BIT_MASK(EV_REP); | ||
357 | |||
358 | ep93xx_keypad_build_keycode(keypad); | ||
359 | platform_set_drvdata(pdev, keypad); | ||
360 | |||
361 | err = request_irq(irq, ep93xx_keypad_irq_handler, IRQF_DISABLED, | ||
362 | pdev->name, keypad); | ||
363 | if (err) { | ||
364 | dev_err(&pdev->dev, "failed to request IRQ\n"); | ||
365 | goto failed_free_dev; | ||
366 | } | ||
367 | |||
368 | keypad->irq = irq; | ||
369 | |||
370 | /* Register the input device */ | ||
371 | err = input_register_device(input_dev); | ||
372 | if (err) { | ||
373 | dev_err(&pdev->dev, "failed to register input device\n"); | ||
374 | goto failed_free_irq; | ||
375 | } | ||
376 | |||
377 | device_init_wakeup(&pdev->dev, 1); | ||
378 | |||
379 | return 0; | ||
380 | |||
381 | failed_free_irq: | ||
382 | free_irq(irq, pdev); | ||
383 | platform_set_drvdata(pdev, NULL); | ||
384 | failed_free_dev: | ||
385 | input_free_device(input_dev); | ||
386 | failed_put_clk: | ||
387 | clk_put(keypad->clk); | ||
388 | failed_free_io: | ||
389 | i = keypad->pdata->matrix_key_cols - 1; | ||
390 | gpio = EP93XX_GPIO_LINE_COL0 + i; | ||
391 | failed_free_cols: | ||
392 | for ( ; i >= 0; i--, gpio--) | ||
393 | gpio_free(gpio); | ||
394 | i = keypad->pdata->matrix_key_rows - 1; | ||
395 | gpio = EP93XX_GPIO_LINE_ROW0 + i; | ||
396 | failed_free_rows: | ||
397 | for ( ; i >= 0; i--, gpio--) | ||
398 | gpio_free(gpio); | ||
399 | iounmap(keypad->mmio_base); | ||
400 | failed_free_mem: | ||
401 | release_mem_region(res->start, resource_size(res)); | ||
402 | failed_free: | ||
403 | kfree(keypad); | ||
404 | return err; | ||
405 | } | ||
406 | |||
407 | static int __devexit ep93xx_keypad_remove(struct platform_device *pdev) | ||
408 | { | ||
409 | struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); | ||
410 | struct resource *res; | ||
411 | int i, gpio; | ||
412 | |||
413 | free_irq(keypad->irq, pdev); | ||
414 | |||
415 | platform_set_drvdata(pdev, NULL); | ||
416 | |||
417 | if (keypad->enabled) | ||
418 | clk_disable(keypad->clk); | ||
419 | clk_put(keypad->clk); | ||
420 | |||
421 | input_unregister_device(keypad->input_dev); | ||
422 | |||
423 | i = keypad->pdata->matrix_key_cols - 1; | ||
424 | gpio = EP93XX_GPIO_LINE_COL0 + i; | ||
425 | for ( ; i >= 0; i--, gpio--) | ||
426 | gpio_free(gpio); | ||
427 | |||
428 | i = keypad->pdata->matrix_key_rows - 1; | ||
429 | gpio = EP93XX_GPIO_LINE_ROW0 + i; | ||
430 | for ( ; i >= 0; i--, gpio--) | ||
431 | gpio_free(gpio); | ||
432 | |||
433 | iounmap(keypad->mmio_base); | ||
434 | |||
435 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
436 | release_mem_region(res->start, resource_size(res)); | ||
437 | |||
438 | kfree(keypad); | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static struct platform_driver ep93xx_keypad_driver = { | ||
444 | .driver = { | ||
445 | .name = "ep93xx-keypad", | ||
446 | .owner = THIS_MODULE, | ||
447 | }, | ||
448 | .probe = ep93xx_keypad_probe, | ||
449 | .remove = __devexit_p(ep93xx_keypad_remove), | ||
450 | .suspend = ep93xx_keypad_suspend, | ||
451 | .resume = ep93xx_keypad_resume, | ||
452 | }; | ||
453 | |||
454 | static int __init ep93xx_keypad_init(void) | ||
455 | { | ||
456 | return platform_driver_register(&ep93xx_keypad_driver); | ||
457 | } | ||
458 | |||
459 | static void __exit ep93xx_keypad_exit(void) | ||
460 | { | ||
461 | platform_driver_unregister(&ep93xx_keypad_driver); | ||
462 | } | ||
463 | |||
464 | module_init(ep93xx_keypad_init); | ||
465 | module_exit(ep93xx_keypad_exit); | ||
466 | |||
467 | MODULE_LICENSE("GPL"); | ||
468 | MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); | ||
469 | MODULE_DESCRIPTION("EP93xx Matrix Keypad Controller"); | ||
470 | MODULE_ALIAS("platform:ep93xx-keypad"); | ||
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index ad67d763fdbd..9767213b6c8f 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c | |||
@@ -142,8 +142,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
142 | } | 142 | } |
143 | 143 | ||
144 | error = request_irq(irq, gpio_keys_isr, | 144 | error = request_irq(irq, gpio_keys_isr, |
145 | IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | | 145 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
146 | IRQF_TRIGGER_FALLING, | ||
147 | button->desc ? button->desc : "gpio_keys", | 146 | button->desc ? button->desc : "gpio_keys", |
148 | bdata); | 147 | bdata); |
149 | if (error) { | 148 | if (error) { |
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 5c0a631d1455..4399f54c043c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -193,6 +193,16 @@ config INPUT_CM109 | |||
193 | To compile this driver as a module, choose M here: the module will be | 193 | To compile this driver as a module, choose M here: the module will be |
194 | called cm109. | 194 | called cm109. |
195 | 195 | ||
196 | config INPUT_TWL4030_PWRBUTTON | ||
197 | tristate "TWL4030 Power button Driver" | ||
198 | depends on TWL4030_CORE | ||
199 | help | ||
200 | Say Y here if you want to enable power key reporting via the | ||
201 | TWL4030 family of chips. | ||
202 | |||
203 | To compile this driver as a module, choose M here. The module will | ||
204 | be called twl4030_pwrbutton. | ||
205 | |||
196 | config INPUT_UINPUT | 206 | config INPUT_UINPUT |
197 | tristate "User level driver support" | 207 | tristate "User level driver support" |
198 | help | 208 | help |
@@ -250,4 +260,13 @@ config INPUT_RB532_BUTTON | |||
250 | To compile this driver as a module, choose M here: the | 260 | To compile this driver as a module, choose M here: the |
251 | module will be called rb532_button. | 261 | module will be called rb532_button. |
252 | 262 | ||
263 | config INPUT_DM355EVM | ||
264 | tristate "TI DaVinci DM355 EVM Keypad and IR Remote" | ||
265 | depends on MFD_DM355EVM_MSP | ||
266 | help | ||
267 | Supports the pushbuttons and IR remote used with | ||
268 | the DM355 EVM board. | ||
269 | |||
270 | To compile this driver as a module, choose M here: the | ||
271 | module will be called dm355evm_keys. | ||
253 | endif | 272 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index eb3f407baedf..0d979fd4cd57 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o | |||
10 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o | 10 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o |
11 | obj-$(CONFIG_INPUT_CM109) += cm109.o | 11 | obj-$(CONFIG_INPUT_CM109) += cm109.o |
12 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | 12 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o |
13 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o | ||
13 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | 14 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
14 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | 15 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o |
15 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | 16 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o |
@@ -21,6 +22,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o | |||
21 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o | 22 | obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o |
22 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o | 23 | obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o |
23 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | 24 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o |
25 | obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o | ||
24 | obj-$(CONFIG_INPUT_UINPUT) += uinput.o | 26 | obj-$(CONFIG_INPUT_UINPUT) += uinput.o |
25 | obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o | 27 | obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o |
26 | obj-$(CONFIG_INPUT_YEALINK) += yealink.o | 28 | obj-$(CONFIG_INPUT_YEALINK) += yealink.o |
diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c new file mode 100644 index 000000000000..a63315ce4a6c --- /dev/null +++ b/drivers/input/misc/dm355evm_keys.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * dm355evm_keys.c - support buttons and IR remote on DM355 EVM board | ||
3 | * | ||
4 | * Copyright (c) 2008 by David Brownell | ||
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 | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/input.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | |||
17 | #include <linux/i2c/dm355evm_msp.h> | ||
18 | |||
19 | |||
20 | /* | ||
21 | * The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons | ||
22 | * and an IR receptor used for the remote control. When any key is | ||
23 | * pressed, or its autorepeat kicks in, an event is sent. This driver | ||
24 | * read those events from the small (32 event) queue and reports them. | ||
25 | * | ||
26 | * Because we communicate with the MSP430 using I2C, and all I2C calls | ||
27 | * in Linux sleep, we need to cons up a kind of threaded IRQ handler | ||
28 | * using a work_struct. The IRQ is active low, but we use it through | ||
29 | * the GPIO controller so we can trigger on falling edges. | ||
30 | * | ||
31 | * Note that physically there can only be one of these devices. | ||
32 | * | ||
33 | * This driver was tested with firmware revision A4. | ||
34 | */ | ||
35 | struct dm355evm_keys { | ||
36 | struct work_struct work; | ||
37 | struct input_dev *input; | ||
38 | struct device *dev; | ||
39 | int irq; | ||
40 | }; | ||
41 | |||
42 | static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) | ||
43 | { | ||
44 | struct dm355evm_keys *keys = _keys; | ||
45 | |||
46 | schedule_work(&keys->work); | ||
47 | return IRQ_HANDLED; | ||
48 | } | ||
49 | |||
50 | /* These initial keycodes can be remapped by dm355evm_setkeycode(). */ | ||
51 | static struct { | ||
52 | u16 event; | ||
53 | u16 keycode; | ||
54 | } dm355evm_keys[] = { | ||
55 | |||
56 | /* | ||
57 | * Pushbuttons on the EVM board ... note that the labels for these | ||
58 | * are SW10/SW11/etc on the PC board. The left/right orientation | ||
59 | * comes only from the firmware's documentation, and presumes the | ||
60 | * power connector is immediately in front of you and the IR sensor | ||
61 | * is to the right. (That is, rotate the board counter-clockwise | ||
62 | * by 90 degrees from the SW10/etc and "DM355 EVM" labels.) | ||
63 | */ | ||
64 | { 0x00d8, KEY_OK, }, /* SW12 */ | ||
65 | { 0x00b8, KEY_UP, }, /* SW13 */ | ||
66 | { 0x00e8, KEY_DOWN, }, /* SW11 */ | ||
67 | { 0x0078, KEY_LEFT, }, /* SW14 */ | ||
68 | { 0x00f0, KEY_RIGHT, }, /* SW10 */ | ||
69 | |||
70 | /* | ||
71 | * IR buttons ... codes assigned to match the universal remote | ||
72 | * provided with the EVM (Philips PM4S) using DVD code 0020. | ||
73 | * | ||
74 | * These event codes match firmware documentation, but other | ||
75 | * remote controls could easily send more RC5-encoded events. | ||
76 | * The PM4S manual was used in several cases to help select | ||
77 | * a keycode reflecting the intended usage. | ||
78 | * | ||
79 | * RC5 codes are 14 bits, with two start bits (0x3 prefix) | ||
80 | * and a toggle bit (masked out below). | ||
81 | */ | ||
82 | { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ | ||
83 | { 0x3000, KEY_NUMERIC_0, }, | ||
84 | { 0x3001, KEY_NUMERIC_1, }, | ||
85 | { 0x3002, KEY_NUMERIC_2, }, | ||
86 | { 0x3003, KEY_NUMERIC_3, }, | ||
87 | { 0x3004, KEY_NUMERIC_4, }, | ||
88 | { 0x3005, KEY_NUMERIC_5, }, | ||
89 | { 0x3006, KEY_NUMERIC_6, }, | ||
90 | { 0x3007, KEY_NUMERIC_7, }, | ||
91 | { 0x3008, KEY_NUMERIC_8, }, | ||
92 | { 0x3009, KEY_NUMERIC_9, }, | ||
93 | { 0x3022, KEY_ENTER, }, | ||
94 | { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ | ||
95 | { 0x300f, KEY_SELECT, }, /* "info" */ | ||
96 | { 0x3020, KEY_CHANNELUP, }, /* "up" */ | ||
97 | { 0x302e, KEY_MENU, }, /* "in/out" */ | ||
98 | { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ | ||
99 | { 0x300d, KEY_MUTE, }, /* "ok" */ | ||
100 | { 0x3010, KEY_VOLUMEUP, }, /* "right" */ | ||
101 | { 0x301e, KEY_SUBTITLE, }, /* "cc" */ | ||
102 | { 0x3021, KEY_CHANNELDOWN, }, /* "down" */ | ||
103 | { 0x3022, KEY_PREVIOUS, }, | ||
104 | { 0x3026, KEY_SLEEP, }, | ||
105 | { 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */ | ||
106 | { 0x3175, KEY_PLAY, }, | ||
107 | { 0x3174, KEY_FASTFORWARD, }, | ||
108 | { 0x3177, KEY_RECORD, }, | ||
109 | { 0x3176, KEY_STOP, }, | ||
110 | { 0x3169, KEY_PAUSE, }, | ||
111 | }; | ||
112 | |||
113 | static void dm355evm_keys_work(struct work_struct *work) | ||
114 | { | ||
115 | struct dm355evm_keys *keys; | ||
116 | int status; | ||
117 | |||
118 | keys = container_of(work, struct dm355evm_keys, work); | ||
119 | |||
120 | /* For simplicity we ignore INPUT_COUNT and just read | ||
121 | * events until we get the "queue empty" indicator. | ||
122 | * Reading INPUT_LOW decrements the count. | ||
123 | */ | ||
124 | for (;;) { | ||
125 | static u16 last_event; | ||
126 | u16 event; | ||
127 | int keycode; | ||
128 | int i; | ||
129 | |||
130 | status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH); | ||
131 | if (status < 0) { | ||
132 | dev_dbg(keys->dev, "input high err %d\n", | ||
133 | status); | ||
134 | break; | ||
135 | } | ||
136 | event = status << 8; | ||
137 | |||
138 | status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW); | ||
139 | if (status < 0) { | ||
140 | dev_dbg(keys->dev, "input low err %d\n", | ||
141 | status); | ||
142 | break; | ||
143 | } | ||
144 | event |= status; | ||
145 | if (event == 0xdead) | ||
146 | break; | ||
147 | |||
148 | /* Press and release a button: two events, same code. | ||
149 | * Press and hold (autorepeat), then release: N events | ||
150 | * (N > 2), same code. For RC5 buttons the toggle bits | ||
151 | * distinguish (for example) "1-autorepeat" from "1 1"; | ||
152 | * but PCB buttons don't support that bit. | ||
153 | * | ||
154 | * So we must synthesize release events. We do that by | ||
155 | * mapping events to a press/release event pair; then | ||
156 | * to avoid adding extra events, skip the second event | ||
157 | * of each pair. | ||
158 | */ | ||
159 | if (event == last_event) { | ||
160 | last_event = 0; | ||
161 | continue; | ||
162 | } | ||
163 | last_event = event; | ||
164 | |||
165 | /* ignore the RC5 toggle bit */ | ||
166 | event &= ~0x0800; | ||
167 | |||
168 | /* find the key, or leave it as unknown */ | ||
169 | keycode = KEY_UNKNOWN; | ||
170 | for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { | ||
171 | if (dm355evm_keys[i].event != event) | ||
172 | continue; | ||
173 | keycode = dm355evm_keys[i].keycode; | ||
174 | break; | ||
175 | } | ||
176 | dev_dbg(keys->dev, | ||
177 | "input event 0x%04x--> keycode %d\n", | ||
178 | event, keycode); | ||
179 | |||
180 | /* report press + release */ | ||
181 | input_report_key(keys->input, keycode, 1); | ||
182 | input_sync(keys->input); | ||
183 | input_report_key(keys->input, keycode, 0); | ||
184 | input_sync(keys->input); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode) | ||
189 | { | ||
190 | u16 old_keycode; | ||
191 | unsigned i; | ||
192 | |||
193 | if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) | ||
194 | return -EINVAL; | ||
195 | |||
196 | old_keycode = dm355evm_keys[index].keycode; | ||
197 | dm355evm_keys[index].keycode = keycode; | ||
198 | set_bit(keycode, dev->keybit); | ||
199 | |||
200 | for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { | ||
201 | if (dm355evm_keys[index].keycode == old_keycode) | ||
202 | goto done; | ||
203 | } | ||
204 | clear_bit(old_keycode, dev->keybit); | ||
205 | done: | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode) | ||
210 | { | ||
211 | if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) | ||
212 | return -EINVAL; | ||
213 | |||
214 | return dm355evm_keys[index].keycode; | ||
215 | } | ||
216 | |||
217 | /*----------------------------------------------------------------------*/ | ||
218 | |||
219 | static int __devinit dm355evm_keys_probe(struct platform_device *pdev) | ||
220 | { | ||
221 | struct dm355evm_keys *keys; | ||
222 | struct input_dev *input; | ||
223 | int status; | ||
224 | int i; | ||
225 | |||
226 | /* allocate instance struct and input dev */ | ||
227 | keys = kzalloc(sizeof *keys, GFP_KERNEL); | ||
228 | input = input_allocate_device(); | ||
229 | if (!keys || !input) { | ||
230 | status = -ENOMEM; | ||
231 | goto fail1; | ||
232 | } | ||
233 | |||
234 | keys->dev = &pdev->dev; | ||
235 | keys->input = input; | ||
236 | INIT_WORK(&keys->work, dm355evm_keys_work); | ||
237 | |||
238 | /* set up "threaded IRQ handler" */ | ||
239 | status = platform_get_irq(pdev, 0); | ||
240 | if (status < 0) | ||
241 | goto fail1; | ||
242 | keys->irq = status; | ||
243 | |||
244 | input_set_drvdata(input, keys); | ||
245 | |||
246 | input->name = "DM355 EVM Controls"; | ||
247 | input->phys = "dm355evm/input0"; | ||
248 | input->dev.parent = &pdev->dev; | ||
249 | |||
250 | input->id.bustype = BUS_I2C; | ||
251 | input->id.product = 0x0355; | ||
252 | input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); | ||
253 | |||
254 | input->evbit[0] = BIT(EV_KEY); | ||
255 | for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) | ||
256 | __set_bit(dm355evm_keys[i].keycode, input->keybit); | ||
257 | |||
258 | input->setkeycode = dm355evm_setkeycode; | ||
259 | input->getkeycode = dm355evm_getkeycode; | ||
260 | |||
261 | /* REVISIT: flush the event queue? */ | ||
262 | |||
263 | status = request_irq(keys->irq, dm355evm_keys_irq, | ||
264 | IRQF_TRIGGER_FALLING, | ||
265 | dev_name(&pdev->dev), keys); | ||
266 | if (status < 0) | ||
267 | goto fail1; | ||
268 | |||
269 | /* register */ | ||
270 | status = input_register_device(input); | ||
271 | if (status < 0) | ||
272 | goto fail2; | ||
273 | |||
274 | platform_set_drvdata(pdev, keys); | ||
275 | |||
276 | return 0; | ||
277 | |||
278 | fail2: | ||
279 | free_irq(keys->irq, keys); | ||
280 | fail1: | ||
281 | input_free_device(input); | ||
282 | kfree(keys); | ||
283 | dev_err(&pdev->dev, "can't register, err %d\n", status); | ||
284 | |||
285 | return status; | ||
286 | } | ||
287 | |||
288 | static int __devexit dm355evm_keys_remove(struct platform_device *pdev) | ||
289 | { | ||
290 | struct dm355evm_keys *keys = platform_get_drvdata(pdev); | ||
291 | |||
292 | free_irq(keys->irq, keys); | ||
293 | input_unregister_device(keys->input); | ||
294 | kfree(keys); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should | ||
300 | * be able to wake up the system. When device_may_wakeup(&pdev->dev), call | ||
301 | * enable_irq_wake() on suspend, and disable_irq_wake() on resume. | ||
302 | */ | ||
303 | |||
304 | /* | ||
305 | * I2C is used to talk to the MSP430, but this platform device is | ||
306 | * exposed by an MFD driver that manages I2C communications. | ||
307 | */ | ||
308 | static struct platform_driver dm355evm_keys_driver = { | ||
309 | .probe = dm355evm_keys_probe, | ||
310 | .remove = __devexit_p(dm355evm_keys_remove), | ||
311 | .driver = { | ||
312 | .owner = THIS_MODULE, | ||
313 | .name = "dm355evm_keys", | ||
314 | }, | ||
315 | }; | ||
316 | |||
317 | static int __init dm355evm_keys_init(void) | ||
318 | { | ||
319 | return platform_driver_register(&dm355evm_keys_driver); | ||
320 | } | ||
321 | module_init(dm355evm_keys_init); | ||
322 | |||
323 | static void __exit dm355evm_keys_exit(void) | ||
324 | { | ||
325 | platform_driver_unregister(&dm355evm_keys_driver); | ||
326 | } | ||
327 | module_exit(dm355evm_keys_exit); | ||
328 | |||
329 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 5bb3ab51b8c6..c806fbf1e174 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c | |||
@@ -26,13 +26,17 @@ | |||
26 | #define DRV_NAME "rotary-encoder" | 26 | #define DRV_NAME "rotary-encoder" |
27 | 27 | ||
28 | struct rotary_encoder { | 28 | struct rotary_encoder { |
29 | unsigned int irq_a; | ||
30 | unsigned int irq_b; | ||
31 | unsigned int pos; | ||
32 | unsigned int armed; | ||
33 | unsigned int dir; | ||
34 | struct input_dev *input; | 29 | struct input_dev *input; |
35 | struct rotary_encoder_platform_data *pdata; | 30 | struct rotary_encoder_platform_data *pdata; |
31 | |||
32 | unsigned int axis; | ||
33 | unsigned int pos; | ||
34 | |||
35 | unsigned int irq_a; | ||
36 | unsigned int irq_b; | ||
37 | |||
38 | bool armed; | ||
39 | unsigned char dir; /* 0 - clockwise, 1 - CCW */ | ||
36 | }; | 40 | }; |
37 | 41 | ||
38 | static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) | 42 | static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) |
@@ -53,21 +57,32 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) | |||
53 | if (!encoder->armed) | 57 | if (!encoder->armed) |
54 | break; | 58 | break; |
55 | 59 | ||
56 | if (encoder->dir) { | 60 | if (pdata->relative_axis) { |
57 | /* turning counter-clockwise */ | 61 | input_report_rel(encoder->input, pdata->axis, |
58 | encoder->pos += pdata->steps; | 62 | encoder->dir ? -1 : 1); |
59 | encoder->pos--; | ||
60 | encoder->pos %= pdata->steps; | ||
61 | } else { | 63 | } else { |
62 | /* turning clockwise */ | 64 | unsigned int pos = encoder->pos; |
63 | encoder->pos++; | 65 | |
64 | encoder->pos %= pdata->steps; | 66 | if (encoder->dir) { |
67 | /* turning counter-clockwise */ | ||
68 | if (pdata->rollover) | ||
69 | pos += pdata->steps; | ||
70 | if (pos) | ||
71 | pos--; | ||
72 | } else { | ||
73 | /* turning clockwise */ | ||
74 | if (pdata->rollover || pos < pdata->steps) | ||
75 | pos++; | ||
76 | } | ||
77 | if (pdata->rollover) | ||
78 | pos %= pdata->steps; | ||
79 | encoder->pos = pos; | ||
80 | input_report_abs(encoder->input, pdata->axis, | ||
81 | encoder->pos); | ||
65 | } | 82 | } |
66 | |||
67 | input_report_abs(encoder->input, pdata->axis, encoder->pos); | ||
68 | input_sync(encoder->input); | 83 | input_sync(encoder->input); |
69 | 84 | ||
70 | encoder->armed = 0; | 85 | encoder->armed = false; |
71 | break; | 86 | break; |
72 | 87 | ||
73 | case 0x1: | 88 | case 0x1: |
@@ -77,7 +92,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) | |||
77 | break; | 92 | break; |
78 | 93 | ||
79 | case 0x3: | 94 | case 0x3: |
80 | encoder->armed = 1; | 95 | encoder->armed = true; |
81 | break; | 96 | break; |
82 | } | 97 | } |
83 | 98 | ||
@@ -113,9 +128,15 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) | |||
113 | input->name = pdev->name; | 128 | input->name = pdev->name; |
114 | input->id.bustype = BUS_HOST; | 129 | input->id.bustype = BUS_HOST; |
115 | input->dev.parent = &pdev->dev; | 130 | input->dev.parent = &pdev->dev; |
116 | input->evbit[0] = BIT_MASK(EV_ABS); | 131 | |
117 | input_set_abs_params(encoder->input, | 132 | if (pdata->relative_axis) { |
118 | pdata->axis, 0, pdata->steps, 0, 1); | 133 | input->evbit[0] = BIT_MASK(EV_REL); |
134 | input->relbit[0] = BIT_MASK(pdata->axis); | ||
135 | } else { | ||
136 | input->evbit[0] = BIT_MASK(EV_ABS); | ||
137 | input_set_abs_params(encoder->input, | ||
138 | pdata->axis, 0, pdata->steps, 0, 1); | ||
139 | } | ||
119 | 140 | ||
120 | err = input_register_device(input); | 141 | err = input_register_device(input); |
121 | if (err) { | 142 | if (err) { |
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c new file mode 100644 index 000000000000..f5fc9974a111 --- /dev/null +++ b/drivers/input/misc/twl4030-pwrbutton.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /** | ||
2 | * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Written by Peter De Schrijver <peter.de-schrijver@nokia.com> | ||
7 | * Several fixes by Felipe Balbi <felipe.balbi@nokia.com> | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General | ||
10 | * Public License. See the file "COPYING" in the main directory of this | ||
11 | * archive for more details. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/input.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/i2c/twl4030.h> | ||
31 | |||
32 | #define PWR_PWRON_IRQ (1 << 0) | ||
33 | |||
34 | #define STS_HW_CONDITIONS 0xf | ||
35 | |||
36 | static irqreturn_t powerbutton_irq(int irq, void *_pwr) | ||
37 | { | ||
38 | struct input_dev *pwr = _pwr; | ||
39 | int err; | ||
40 | u8 value; | ||
41 | |||
42 | #ifdef CONFIG_LOCKDEP | ||
43 | /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which | ||
44 | * we don't want and can't tolerate since this is a threaded | ||
45 | * IRQ and can sleep due to the i2c reads it has to issue. | ||
46 | * Although it might be friendlier not to borrow this thread | ||
47 | * context... | ||
48 | */ | ||
49 | local_irq_enable(); | ||
50 | #endif | ||
51 | |||
52 | err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, | ||
53 | STS_HW_CONDITIONS); | ||
54 | if (!err) { | ||
55 | input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); | ||
56 | input_sync(pwr); | ||
57 | } else { | ||
58 | dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" | ||
59 | " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); | ||
60 | } | ||
61 | |||
62 | return IRQ_HANDLED; | ||
63 | } | ||
64 | |||
65 | static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev) | ||
66 | { | ||
67 | struct input_dev *pwr; | ||
68 | int irq = platform_get_irq(pdev, 0); | ||
69 | int err; | ||
70 | |||
71 | pwr = input_allocate_device(); | ||
72 | if (!pwr) { | ||
73 | dev_dbg(&pdev->dev, "Can't allocate power button\n"); | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | |||
77 | pwr->evbit[0] = BIT_MASK(EV_KEY); | ||
78 | pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); | ||
79 | pwr->name = "twl4030_pwrbutton"; | ||
80 | pwr->phys = "twl4030_pwrbutton/input0"; | ||
81 | pwr->dev.parent = &pdev->dev; | ||
82 | |||
83 | err = request_irq(irq, powerbutton_irq, | ||
84 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | ||
85 | "twl4030_pwrbutton", pwr); | ||
86 | if (err < 0) { | ||
87 | dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); | ||
88 | goto free_input_dev; | ||
89 | } | ||
90 | |||
91 | err = input_register_device(pwr); | ||
92 | if (err) { | ||
93 | dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); | ||
94 | goto free_irq; | ||
95 | } | ||
96 | |||
97 | platform_set_drvdata(pdev, pwr); | ||
98 | |||
99 | return 0; | ||
100 | |||
101 | free_irq: | ||
102 | free_irq(irq, NULL); | ||
103 | free_input_dev: | ||
104 | input_free_device(pwr); | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev) | ||
109 | { | ||
110 | struct input_dev *pwr = platform_get_drvdata(pdev); | ||
111 | int irq = platform_get_irq(pdev, 0); | ||
112 | |||
113 | free_irq(irq, pwr); | ||
114 | input_unregister_device(pwr); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | struct platform_driver twl4030_pwrbutton_driver = { | ||
120 | .probe = twl4030_pwrbutton_probe, | ||
121 | .remove = __devexit_p(twl4030_pwrbutton_remove), | ||
122 | .driver = { | ||
123 | .name = "twl4030_pwrbutton", | ||
124 | .owner = THIS_MODULE, | ||
125 | }, | ||
126 | }; | ||
127 | |||
128 | static int __init twl4030_pwrbutton_init(void) | ||
129 | { | ||
130 | return platform_driver_register(&twl4030_pwrbutton_driver); | ||
131 | } | ||
132 | module_init(twl4030_pwrbutton_init); | ||
133 | |||
134 | static void __exit twl4030_pwrbutton_exit(void) | ||
135 | { | ||
136 | platform_driver_unregister(&twl4030_pwrbutton_driver); | ||
137 | } | ||
138 | module_exit(twl4030_pwrbutton_exit); | ||
139 | |||
140 | MODULE_ALIAS("platform:twl4030_pwrbutton"); | ||
141 | MODULE_DESCRIPTION("Triton2 Power Button"); | ||
142 | MODULE_LICENSE("GPL"); | ||
143 | MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>"); | ||
144 | MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); | ||
145 | |||
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index bc033250dfcd..8d2df5d2d5a2 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c | |||
@@ -41,17 +41,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
41 | MODULE_DESCRIPTION("Serio abstraction core"); | 41 | MODULE_DESCRIPTION("Serio abstraction core"); |
42 | MODULE_LICENSE("GPL"); | 42 | MODULE_LICENSE("GPL"); |
43 | 43 | ||
44 | EXPORT_SYMBOL(serio_interrupt); | ||
45 | EXPORT_SYMBOL(__serio_register_port); | ||
46 | EXPORT_SYMBOL(serio_unregister_port); | ||
47 | EXPORT_SYMBOL(serio_unregister_child_port); | ||
48 | EXPORT_SYMBOL(__serio_register_driver); | ||
49 | EXPORT_SYMBOL(serio_unregister_driver); | ||
50 | EXPORT_SYMBOL(serio_open); | ||
51 | EXPORT_SYMBOL(serio_close); | ||
52 | EXPORT_SYMBOL(serio_rescan); | ||
53 | EXPORT_SYMBOL(serio_reconnect); | ||
54 | |||
55 | /* | 44 | /* |
56 | * serio_mutex protects entire serio subsystem and is taken every time | 45 | * serio_mutex protects entire serio subsystem and is taken every time |
57 | * serio port or driver registrered or unregistered. | 46 | * serio port or driver registrered or unregistered. |
@@ -692,11 +681,13 @@ void serio_rescan(struct serio *serio) | |||
692 | { | 681 | { |
693 | serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); | 682 | serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); |
694 | } | 683 | } |
684 | EXPORT_SYMBOL(serio_rescan); | ||
695 | 685 | ||
696 | void serio_reconnect(struct serio *serio) | 686 | void serio_reconnect(struct serio *serio) |
697 | { | 687 | { |
698 | serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); | 688 | serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); |
699 | } | 689 | } |
690 | EXPORT_SYMBOL(serio_reconnect); | ||
700 | 691 | ||
701 | /* | 692 | /* |
702 | * Submits register request to kseriod for subsequent execution. | 693 | * Submits register request to kseriod for subsequent execution. |
@@ -707,6 +698,7 @@ void __serio_register_port(struct serio *serio, struct module *owner) | |||
707 | serio_init_port(serio); | 698 | serio_init_port(serio); |
708 | serio_queue_event(serio, owner, SERIO_REGISTER_PORT); | 699 | serio_queue_event(serio, owner, SERIO_REGISTER_PORT); |
709 | } | 700 | } |
701 | EXPORT_SYMBOL(__serio_register_port); | ||
710 | 702 | ||
711 | /* | 703 | /* |
712 | * Synchronously unregisters serio port. | 704 | * Synchronously unregisters serio port. |
@@ -718,6 +710,7 @@ void serio_unregister_port(struct serio *serio) | |||
718 | serio_destroy_port(serio); | 710 | serio_destroy_port(serio); |
719 | mutex_unlock(&serio_mutex); | 711 | mutex_unlock(&serio_mutex); |
720 | } | 712 | } |
713 | EXPORT_SYMBOL(serio_unregister_port); | ||
721 | 714 | ||
722 | /* | 715 | /* |
723 | * Safely unregisters child port if one is present. | 716 | * Safely unregisters child port if one is present. |
@@ -731,6 +724,7 @@ void serio_unregister_child_port(struct serio *serio) | |||
731 | } | 724 | } |
732 | mutex_unlock(&serio_mutex); | 725 | mutex_unlock(&serio_mutex); |
733 | } | 726 | } |
727 | EXPORT_SYMBOL(serio_unregister_child_port); | ||
734 | 728 | ||
735 | 729 | ||
736 | /* | 730 | /* |
@@ -854,6 +848,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons | |||
854 | 848 | ||
855 | return 0; | 849 | return 0; |
856 | } | 850 | } |
851 | EXPORT_SYMBOL(__serio_register_driver); | ||
857 | 852 | ||
858 | void serio_unregister_driver(struct serio_driver *drv) | 853 | void serio_unregister_driver(struct serio_driver *drv) |
859 | { | 854 | { |
@@ -877,6 +872,7 @@ start_over: | |||
877 | driver_unregister(&drv->driver); | 872 | driver_unregister(&drv->driver); |
878 | mutex_unlock(&serio_mutex); | 873 | mutex_unlock(&serio_mutex); |
879 | } | 874 | } |
875 | EXPORT_SYMBOL(serio_unregister_driver); | ||
880 | 876 | ||
881 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) | 877 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) |
882 | { | 878 | { |
@@ -974,6 +970,7 @@ int serio_open(struct serio *serio, struct serio_driver *drv) | |||
974 | } | 970 | } |
975 | return 0; | 971 | return 0; |
976 | } | 972 | } |
973 | EXPORT_SYMBOL(serio_open); | ||
977 | 974 | ||
978 | /* called from serio_driver->connect/disconnect methods under serio_mutex */ | 975 | /* called from serio_driver->connect/disconnect methods under serio_mutex */ |
979 | void serio_close(struct serio *serio) | 976 | void serio_close(struct serio *serio) |
@@ -983,6 +980,7 @@ void serio_close(struct serio *serio) | |||
983 | 980 | ||
984 | serio_set_drv(serio, NULL); | 981 | serio_set_drv(serio, NULL); |
985 | } | 982 | } |
983 | EXPORT_SYMBOL(serio_close); | ||
986 | 984 | ||
987 | irqreturn_t serio_interrupt(struct serio *serio, | 985 | irqreturn_t serio_interrupt(struct serio *serio, |
988 | unsigned char data, unsigned int dfl) | 986 | unsigned char data, unsigned int dfl) |
@@ -1003,6 +1001,7 @@ irqreturn_t serio_interrupt(struct serio *serio, | |||
1003 | 1001 | ||
1004 | return ret; | 1002 | return ret; |
1005 | } | 1003 | } |
1004 | EXPORT_SYMBOL(serio_interrupt); | ||
1006 | 1005 | ||
1007 | static struct bus_type serio_bus = { | 1006 | static struct bus_type serio_bus = { |
1008 | .name = "serio", | 1007 | .name = "serio", |
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 2e18a1c0c351..3d32d3f4e486 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c | |||
@@ -1050,4 +1050,5 @@ static void __exit gtco_exit(void) | |||
1050 | module_init(gtco_init); | 1050 | module_init(gtco_init); |
1051 | module_exit(gtco_exit); | 1051 | module_exit(gtco_exit); |
1052 | 1052 | ||
1053 | MODULE_DESCRIPTION("GTCO digitizer USB driver"); | ||
1053 | MODULE_LICENSE("GPL"); | 1054 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b01fd61dadcc..82c388e0fe3e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -341,6 +341,21 @@ config TOUCHSCREEN_WM9713 | |||
341 | Say Y here to enable support for the Wolfson Microelectronics | 341 | Say Y here to enable support for the Wolfson Microelectronics |
342 | WM9713 touchscreen controller. | 342 | WM9713 touchscreen controller. |
343 | 343 | ||
344 | config TOUCHSCREEN_WM97XX_ATMEL | ||
345 | tristate "WM97xx Atmel accelerated touch" | ||
346 | depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91) | ||
347 | help | ||
348 | Say Y here for support for streaming mode with WM97xx touchscreens | ||
349 | on Atmel AT91 or AVR32 systems with an AC97C module. | ||
350 | |||
351 | Be aware that this will use channel B in the controller for | ||
352 | streaming data, this must not conflict with other AC97C drivers. | ||
353 | |||
354 | If unsure, say N. | ||
355 | |||
356 | To compile this driver as a module, choose M here: the module will | ||
357 | be called atmel-wm97xx. | ||
358 | |||
344 | config TOUCHSCREEN_WM97XX_MAINSTONE | 359 | config TOUCHSCREEN_WM97XX_MAINSTONE |
345 | tristate "WM97xx Mainstone accelerated touch" | 360 | tristate "WM97xx Mainstone accelerated touch" |
346 | depends on TOUCHSCREEN_WM97XX && ARCH_PXA | 361 | depends on TOUCHSCREEN_WM97XX && ARCH_PXA |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 6700f7b9d165..bef741522954 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -35,5 +35,6 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o | |||
35 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o | 35 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o |
36 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o | 36 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o |
37 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o | 37 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o |
38 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o | ||
38 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o | 39 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o |
39 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o | 40 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o |
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c new file mode 100644 index 000000000000..35377f583e28 --- /dev/null +++ b/drivers/input/touchscreen/atmel-wm97xx.c | |||
@@ -0,0 +1,446 @@ | |||
1 | /* | ||
2 | * Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97 | ||
3 | * codecs. | ||
4 | * | ||
5 | * Copyright (C) 2008 - 2009 Atmel Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/moduleparam.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/wm97xx.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/io.h> | ||
22 | |||
23 | #define AC97C_ICA 0x10 | ||
24 | #define AC97C_CBRHR 0x30 | ||
25 | #define AC97C_CBSR 0x38 | ||
26 | #define AC97C_CBMR 0x3c | ||
27 | #define AC97C_IER 0x54 | ||
28 | #define AC97C_IDR 0x58 | ||
29 | |||
30 | #define AC97C_RXRDY (1 << 4) | ||
31 | #define AC97C_OVRUN (1 << 5) | ||
32 | |||
33 | #define AC97C_CMR_SIZE_20 (0 << 16) | ||
34 | #define AC97C_CMR_SIZE_18 (1 << 16) | ||
35 | #define AC97C_CMR_SIZE_16 (2 << 16) | ||
36 | #define AC97C_CMR_SIZE_10 (3 << 16) | ||
37 | #define AC97C_CMR_CEM_LITTLE (1 << 18) | ||
38 | #define AC97C_CMR_CEM_BIG (0 << 18) | ||
39 | #define AC97C_CMR_CENA (1 << 21) | ||
40 | |||
41 | #define AC97C_INT_CBEVT (1 << 4) | ||
42 | |||
43 | #define AC97C_SR_CAEVT (1 << 3) | ||
44 | |||
45 | #define AC97C_CH_MASK(slot) \ | ||
46 | (0x7 << (3 * (slot - 3))) | ||
47 | #define AC97C_CH_ASSIGN(slot, channel) \ | ||
48 | (AC97C_CHANNEL_##channel << (3 * (slot - 3))) | ||
49 | #define AC97C_CHANNEL_NONE 0x0 | ||
50 | #define AC97C_CHANNEL_B 0x2 | ||
51 | |||
52 | #define ac97c_writel(chip, reg, val) \ | ||
53 | __raw_writel((val), (chip)->regs + AC97C_##reg) | ||
54 | #define ac97c_readl(chip, reg) \ | ||
55 | __raw_readl((chip)->regs + AC97C_##reg) | ||
56 | |||
57 | #ifdef CONFIG_CPU_AT32AP700X | ||
58 | #define ATMEL_WM97XX_AC97C_IOMEM (0xfff02800) | ||
59 | #define ATMEL_WM97XX_AC97C_IRQ (29) | ||
60 | #define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */ | ||
61 | #else | ||
62 | #error Unkown CPU, this driver only supports AT32AP700X CPUs. | ||
63 | #endif | ||
64 | |||
65 | struct continuous { | ||
66 | u16 id; /* codec id */ | ||
67 | u8 code; /* continuous code */ | ||
68 | u8 reads; /* number of coord reads per read cycle */ | ||
69 | u32 speed; /* number of coords per second */ | ||
70 | }; | ||
71 | |||
72 | #define WM_READS(sp) ((sp / HZ) + 1) | ||
73 | |||
74 | static const struct continuous cinfo[] = { | ||
75 | {WM9705_ID2, 0, WM_READS(94), 94}, | ||
76 | {WM9705_ID2, 1, WM_READS(188), 188}, | ||
77 | {WM9705_ID2, 2, WM_READS(375), 375}, | ||
78 | {WM9705_ID2, 3, WM_READS(750), 750}, | ||
79 | {WM9712_ID2, 0, WM_READS(94), 94}, | ||
80 | {WM9712_ID2, 1, WM_READS(188), 188}, | ||
81 | {WM9712_ID2, 2, WM_READS(375), 375}, | ||
82 | {WM9712_ID2, 3, WM_READS(750), 750}, | ||
83 | {WM9713_ID2, 0, WM_READS(94), 94}, | ||
84 | {WM9713_ID2, 1, WM_READS(120), 120}, | ||
85 | {WM9713_ID2, 2, WM_READS(154), 154}, | ||
86 | {WM9713_ID2, 3, WM_READS(188), 188}, | ||
87 | }; | ||
88 | |||
89 | /* Continuous speed index. */ | ||
90 | static int sp_idx; | ||
91 | |||
92 | /* | ||
93 | * Pen sampling frequency (Hz) in continuous mode. | ||
94 | */ | ||
95 | static int cont_rate = 188; | ||
96 | module_param(cont_rate, int, 0); | ||
97 | MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)"); | ||
98 | |||
99 | /* | ||
100 | * Pen down detection. | ||
101 | * | ||
102 | * This driver can either poll or use an interrupt to indicate a pen down | ||
103 | * event. If the irq request fails then it will fall back to polling mode. | ||
104 | */ | ||
105 | static int pen_int = 1; | ||
106 | module_param(pen_int, int, 0); | ||
107 | MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)"); | ||
108 | |||
109 | /* | ||
110 | * Pressure readback. | ||
111 | * | ||
112 | * Set to 1 to read back pen down pressure. | ||
113 | */ | ||
114 | static int pressure; | ||
115 | module_param(pressure, int, 0); | ||
116 | MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)"); | ||
117 | |||
118 | /* | ||
119 | * AC97 touch data slot. | ||
120 | * | ||
121 | * Touch screen readback data ac97 slot. | ||
122 | */ | ||
123 | static int ac97_touch_slot = 5; | ||
124 | module_param(ac97_touch_slot, int, 0); | ||
125 | MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number"); | ||
126 | |||
127 | /* | ||
128 | * GPIO line number. | ||
129 | * | ||
130 | * Set to GPIO number where the signal from the WM97xx device is hooked up. | ||
131 | */ | ||
132 | static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT; | ||
133 | module_param(atmel_gpio_line, int, 0); | ||
134 | MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx"); | ||
135 | |||
136 | struct atmel_wm97xx { | ||
137 | struct wm97xx *wm; | ||
138 | struct timer_list pen_timer; | ||
139 | void __iomem *regs; | ||
140 | unsigned long ac97c_irq; | ||
141 | unsigned long gpio_pen; | ||
142 | unsigned long gpio_irq; | ||
143 | unsigned short x; | ||
144 | unsigned short y; | ||
145 | }; | ||
146 | |||
147 | static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id) | ||
148 | { | ||
149 | struct atmel_wm97xx *atmel_wm97xx = dev_id; | ||
150 | struct wm97xx *wm = atmel_wm97xx->wm; | ||
151 | int status = ac97c_readl(atmel_wm97xx, CBSR); | ||
152 | irqreturn_t retval = IRQ_NONE; | ||
153 | |||
154 | if (status & AC97C_OVRUN) { | ||
155 | dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n"); | ||
156 | ac97c_readl(atmel_wm97xx, CBRHR); | ||
157 | retval = IRQ_HANDLED; | ||
158 | } else if (status & AC97C_RXRDY) { | ||
159 | u16 data; | ||
160 | u16 value; | ||
161 | u16 source; | ||
162 | u16 pen_down; | ||
163 | |||
164 | data = ac97c_readl(atmel_wm97xx, CBRHR); | ||
165 | value = data & 0x0fff; | ||
166 | source = data & WM97XX_ADCSRC_MASK; | ||
167 | pen_down = (data & WM97XX_PEN_DOWN) >> 8; | ||
168 | |||
169 | if (source == WM97XX_ADCSEL_X) | ||
170 | atmel_wm97xx->x = value; | ||
171 | if (source == WM97XX_ADCSEL_Y) | ||
172 | atmel_wm97xx->y = value; | ||
173 | |||
174 | if (!pressure && source == WM97XX_ADCSEL_Y) { | ||
175 | input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x); | ||
176 | input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y); | ||
177 | input_report_key(wm->input_dev, BTN_TOUCH, pen_down); | ||
178 | input_sync(wm->input_dev); | ||
179 | } else if (pressure && source == WM97XX_ADCSEL_PRES) { | ||
180 | input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x); | ||
181 | input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y); | ||
182 | input_report_abs(wm->input_dev, ABS_PRESSURE, value); | ||
183 | input_report_key(wm->input_dev, BTN_TOUCH, value); | ||
184 | input_sync(wm->input_dev); | ||
185 | } | ||
186 | |||
187 | retval = IRQ_HANDLED; | ||
188 | } | ||
189 | |||
190 | return retval; | ||
191 | } | ||
192 | |||
193 | static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm) | ||
194 | { | ||
195 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev); | ||
196 | struct input_dev *input_dev = wm->input_dev; | ||
197 | int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen); | ||
198 | |||
199 | if (pen_down != 0) { | ||
200 | mod_timer(&atmel_wm97xx->pen_timer, | ||
201 | jiffies + msecs_to_jiffies(1)); | ||
202 | } else { | ||
203 | if (pressure) | ||
204 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
205 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
206 | input_sync(input_dev); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | static void atmel_wm97xx_pen_timer(unsigned long data) | ||
211 | { | ||
212 | atmel_wm97xx_acc_pen_up((struct wm97xx *)data); | ||
213 | } | ||
214 | |||
215 | static int atmel_wm97xx_acc_startup(struct wm97xx *wm) | ||
216 | { | ||
217 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev); | ||
218 | int idx = 0; | ||
219 | |||
220 | if (wm->ac97 == NULL) | ||
221 | return -ENODEV; | ||
222 | |||
223 | for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) { | ||
224 | if (wm->id != cinfo[idx].id) | ||
225 | continue; | ||
226 | |||
227 | sp_idx = idx; | ||
228 | |||
229 | if (cont_rate <= cinfo[idx].speed) | ||
230 | break; | ||
231 | } | ||
232 | |||
233 | wm->acc_rate = cinfo[sp_idx].code; | ||
234 | wm->acc_slot = ac97_touch_slot; | ||
235 | dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, " | ||
236 | "%d samples/sec\n", cinfo[sp_idx].speed); | ||
237 | |||
238 | if (pen_int) { | ||
239 | unsigned long reg; | ||
240 | |||
241 | wm->pen_irq = atmel_wm97xx->gpio_irq; | ||
242 | |||
243 | switch (wm->id) { | ||
244 | case WM9712_ID2: /* Fall through. */ | ||
245 | case WM9713_ID2: | ||
246 | /* | ||
247 | * Use GPIO 13 (PEN_DOWN) to assert GPIO line 3 | ||
248 | * (PENDOWN). | ||
249 | */ | ||
250 | wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, | ||
251 | WM97XX_GPIO_POL_HIGH, | ||
252 | WM97XX_GPIO_STICKY, | ||
253 | WM97XX_GPIO_WAKE); | ||
254 | wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT, | ||
255 | WM97XX_GPIO_POL_HIGH, | ||
256 | WM97XX_GPIO_NOTSTICKY, | ||
257 | WM97XX_GPIO_NOWAKE); | ||
258 | case WM9705_ID2: /* Fall through. */ | ||
259 | /* | ||
260 | * Enable touch data slot in AC97 controller channel B. | ||
261 | */ | ||
262 | reg = ac97c_readl(atmel_wm97xx, ICA); | ||
263 | reg &= ~AC97C_CH_MASK(wm->acc_slot); | ||
264 | reg |= AC97C_CH_ASSIGN(wm->acc_slot, B); | ||
265 | ac97c_writel(atmel_wm97xx, ICA, reg); | ||
266 | |||
267 | /* | ||
268 | * Enable channel and interrupt for RXRDY and OVERRUN. | ||
269 | */ | ||
270 | ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA | ||
271 | | AC97C_CMR_CEM_BIG | ||
272 | | AC97C_CMR_SIZE_16 | ||
273 | | AC97C_OVRUN | ||
274 | | AC97C_RXRDY); | ||
275 | /* Dummy read to empty RXRHR. */ | ||
276 | ac97c_readl(atmel_wm97xx, CBRHR); | ||
277 | /* | ||
278 | * Enable interrupt for channel B in the AC97 | ||
279 | * controller. | ||
280 | */ | ||
281 | ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT); | ||
282 | break; | ||
283 | default: | ||
284 | dev_err(&wm->touch_dev->dev, "pen down irq not " | ||
285 | "supported on this device\n"); | ||
286 | pen_int = 0; | ||
287 | break; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm) | ||
295 | { | ||
296 | if (pen_int) { | ||
297 | struct atmel_wm97xx *atmel_wm97xx = | ||
298 | platform_get_drvdata(wm->touch_dev); | ||
299 | unsigned long ica; | ||
300 | |||
301 | switch (wm->id & 0xffff) { | ||
302 | case WM9705_ID2: /* Fall through. */ | ||
303 | case WM9712_ID2: /* Fall through. */ | ||
304 | case WM9713_ID2: | ||
305 | /* Disable slot and turn off channel B interrupts. */ | ||
306 | ica = ac97c_readl(atmel_wm97xx, ICA); | ||
307 | ica &= ~AC97C_CH_MASK(wm->acc_slot); | ||
308 | ac97c_writel(atmel_wm97xx, ICA, ica); | ||
309 | ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); | ||
310 | ac97c_writel(atmel_wm97xx, CBMR, 0); | ||
311 | wm->pen_irq = 0; | ||
312 | break; | ||
313 | default: | ||
314 | dev_err(&wm->touch_dev->dev, "unknown codec\n"); | ||
315 | break; | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | |||
320 | static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable) | ||
321 | { | ||
322 | /* Intentionally left empty. */ | ||
323 | } | ||
324 | |||
325 | static struct wm97xx_mach_ops atmel_mach_ops = { | ||
326 | .acc_enabled = 1, | ||
327 | .acc_pen_up = atmel_wm97xx_acc_pen_up, | ||
328 | .acc_startup = atmel_wm97xx_acc_startup, | ||
329 | .acc_shutdown = atmel_wm97xx_acc_shutdown, | ||
330 | .irq_enable = atmel_wm97xx_irq_enable, | ||
331 | .irq_gpio = WM97XX_GPIO_3, | ||
332 | }; | ||
333 | |||
334 | static int __init atmel_wm97xx_probe(struct platform_device *pdev) | ||
335 | { | ||
336 | struct wm97xx *wm = platform_get_drvdata(pdev); | ||
337 | struct atmel_wm97xx *atmel_wm97xx; | ||
338 | int ret; | ||
339 | |||
340 | atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL); | ||
341 | if (!atmel_wm97xx) { | ||
342 | dev_dbg(&pdev->dev, "out of memory\n"); | ||
343 | return -ENOMEM; | ||
344 | } | ||
345 | |||
346 | atmel_wm97xx->wm = wm; | ||
347 | atmel_wm97xx->regs = (void *)ATMEL_WM97XX_AC97C_IOMEM; | ||
348 | atmel_wm97xx->ac97c_irq = ATMEL_WM97XX_AC97C_IRQ; | ||
349 | atmel_wm97xx->gpio_pen = atmel_gpio_line; | ||
350 | atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen); | ||
351 | |||
352 | setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, | ||
353 | (unsigned long)wm); | ||
354 | |||
355 | ret = request_irq(atmel_wm97xx->ac97c_irq, | ||
356 | atmel_wm97xx_channel_b_interrupt, | ||
357 | IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx); | ||
358 | if (ret) { | ||
359 | dev_dbg(&pdev->dev, "could not request ac97c irq\n"); | ||
360 | goto err; | ||
361 | } | ||
362 | |||
363 | platform_set_drvdata(pdev, atmel_wm97xx); | ||
364 | |||
365 | ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops); | ||
366 | if (ret) | ||
367 | goto err_irq; | ||
368 | |||
369 | return ret; | ||
370 | |||
371 | err_irq: | ||
372 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); | ||
373 | err: | ||
374 | platform_set_drvdata(pdev, NULL); | ||
375 | kfree(atmel_wm97xx); | ||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | static int __exit atmel_wm97xx_remove(struct platform_device *pdev) | ||
380 | { | ||
381 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); | ||
382 | struct wm97xx *wm = atmel_wm97xx->wm; | ||
383 | |||
384 | ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); | ||
385 | free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); | ||
386 | del_timer_sync(&atmel_wm97xx->pen_timer); | ||
387 | wm97xx_unregister_mach_ops(wm); | ||
388 | platform_set_drvdata(pdev, NULL); | ||
389 | kfree(atmel_wm97xx); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | #ifdef CONFIG_PM | ||
395 | static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg) | ||
396 | { | ||
397 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); | ||
398 | |||
399 | ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); | ||
400 | disable_irq(atmel_wm97xx->gpio_irq); | ||
401 | del_timer_sync(&atmel_wm97xx->pen_timer); | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int atmel_wm97xx_resume(struct platform_device *pdev) | ||
407 | { | ||
408 | struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); | ||
409 | struct wm97xx *wm = atmel_wm97xx->wm; | ||
410 | |||
411 | if (wm->input_dev->users) { | ||
412 | enable_irq(atmel_wm97xx->gpio_irq); | ||
413 | ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT); | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | #else | ||
419 | #define atmel_wm97xx_suspend NULL | ||
420 | #define atmel_wm97xx_resume NULL | ||
421 | #endif | ||
422 | |||
423 | static struct platform_driver atmel_wm97xx_driver = { | ||
424 | .remove = __exit_p(atmel_wm97xx_remove), | ||
425 | .driver = { | ||
426 | .name = "wm97xx-touch", | ||
427 | }, | ||
428 | .suspend = atmel_wm97xx_suspend, | ||
429 | .resume = atmel_wm97xx_resume, | ||
430 | }; | ||
431 | |||
432 | static int __init atmel_wm97xx_init(void) | ||
433 | { | ||
434 | return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe); | ||
435 | } | ||
436 | module_init(atmel_wm97xx_init); | ||
437 | |||
438 | static void __exit atmel_wm97xx_exit(void) | ||
439 | { | ||
440 | platform_driver_unregister(&atmel_wm97xx_driver); | ||
441 | } | ||
442 | module_exit(atmel_wm97xx_exit); | ||
443 | |||
444 | MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>"); | ||
445 | MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32"); | ||
446 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 69af8385ab14..2957d48e0045 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c | |||
@@ -569,7 +569,7 @@ static int wm97xx_probe(struct device *dev) | |||
569 | mutex_init(&wm->codec_mutex); | 569 | mutex_init(&wm->codec_mutex); |
570 | 570 | ||
571 | wm->dev = dev; | 571 | wm->dev = dev; |
572 | dev->driver_data = wm; | 572 | dev_set_drvdata(dev, wm); |
573 | wm->ac97 = to_ac97_t(dev); | 573 | wm->ac97 = to_ac97_t(dev); |
574 | 574 | ||
575 | /* check that we have a supported codec */ | 575 | /* check that we have a supported codec */ |
diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index 12d63a30c347..215278b8df2a 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h | |||
@@ -8,6 +8,8 @@ struct rotary_encoder_platform_data { | |||
8 | unsigned int gpio_b; | 8 | unsigned int gpio_b; |
9 | unsigned int inverted_a; | 9 | unsigned int inverted_a; |
10 | unsigned int inverted_b; | 10 | unsigned int inverted_b; |
11 | bool relative_axis; | ||
12 | bool rollover; | ||
11 | }; | 13 | }; |
12 | 14 | ||
13 | #endif /* __ROTARY_ENCODER_H__ */ | 15 | #endif /* __ROTARY_ENCODER_H__ */ |