diff options
Diffstat (limited to 'drivers/input')
25 files changed, 2526 insertions, 171 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index de055451d1af..bc203485716d 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -738,20 +738,23 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p) | |||
738 | */ | 738 | */ |
739 | static int evdev_handle_get_val(struct evdev_client *client, | 739 | static int evdev_handle_get_val(struct evdev_client *client, |
740 | struct input_dev *dev, unsigned int type, | 740 | struct input_dev *dev, unsigned int type, |
741 | unsigned long *bits, unsigned int max, | 741 | unsigned long *bits, unsigned int maxbit, |
742 | unsigned int size, void __user *p, int compat) | 742 | unsigned int maxlen, void __user *p, |
743 | int compat) | ||
743 | { | 744 | { |
744 | int ret; | 745 | int ret; |
745 | unsigned long *mem; | 746 | unsigned long *mem; |
747 | size_t len; | ||
746 | 748 | ||
747 | mem = kmalloc(sizeof(unsigned long) * max, GFP_KERNEL); | 749 | len = BITS_TO_LONGS(maxbit) * sizeof(unsigned long); |
750 | mem = kmalloc(len, GFP_KERNEL); | ||
748 | if (!mem) | 751 | if (!mem) |
749 | return -ENOMEM; | 752 | return -ENOMEM; |
750 | 753 | ||
751 | spin_lock_irq(&dev->event_lock); | 754 | spin_lock_irq(&dev->event_lock); |
752 | spin_lock(&client->buffer_lock); | 755 | spin_lock(&client->buffer_lock); |
753 | 756 | ||
754 | memcpy(mem, bits, sizeof(unsigned long) * max); | 757 | memcpy(mem, bits, len); |
755 | 758 | ||
756 | spin_unlock(&dev->event_lock); | 759 | spin_unlock(&dev->event_lock); |
757 | 760 | ||
@@ -759,7 +762,7 @@ static int evdev_handle_get_val(struct evdev_client *client, | |||
759 | 762 | ||
760 | spin_unlock_irq(&client->buffer_lock); | 763 | spin_unlock_irq(&client->buffer_lock); |
761 | 764 | ||
762 | ret = bits_to_user(mem, max, size, p, compat); | 765 | ret = bits_to_user(mem, maxbit, maxlen, p, compat); |
763 | if (ret < 0) | 766 | if (ret < 0) |
764 | evdev_queue_syn_dropped(client); | 767 | evdev_queue_syn_dropped(client); |
765 | 768 | ||
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 24c41ba7d4e0..e29c04e2aff4 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
24 | #include <linux/sched.h> /* HZ */ | 24 | #include <linux/sched.h> /* HZ */ |
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/timekeeping.h> | ||
26 | 27 | ||
27 | /*#include <asm/io.h>*/ | 28 | /*#include <asm/io.h>*/ |
28 | 29 | ||
@@ -30,6 +31,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
30 | MODULE_DESCRIPTION("Generic gameport layer"); | 31 | MODULE_DESCRIPTION("Generic gameport layer"); |
31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
32 | 33 | ||
34 | static bool use_ktime = true; | ||
35 | module_param(use_ktime, bool, 0400); | ||
36 | MODULE_PARM_DESC(use_ktime, "Use ktime for measuring I/O speed"); | ||
37 | |||
33 | /* | 38 | /* |
34 | * gameport_mutex protects entire gameport subsystem and is taken | 39 | * gameport_mutex protects entire gameport subsystem and is taken |
35 | * every time gameport port or driver registrered or unregistered. | 40 | * every time gameport port or driver registrered or unregistered. |
@@ -76,6 +81,38 @@ static unsigned int get_time_pit(void) | |||
76 | 81 | ||
77 | static int gameport_measure_speed(struct gameport *gameport) | 82 | static int gameport_measure_speed(struct gameport *gameport) |
78 | { | 83 | { |
84 | unsigned int i, t, tx; | ||
85 | u64 t1, t2, t3; | ||
86 | unsigned long flags; | ||
87 | |||
88 | if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW)) | ||
89 | return 0; | ||
90 | |||
91 | tx = ~0; | ||
92 | |||
93 | for (i = 0; i < 50; i++) { | ||
94 | local_irq_save(flags); | ||
95 | t1 = ktime_get_ns(); | ||
96 | for (t = 0; t < 50; t++) | ||
97 | gameport_read(gameport); | ||
98 | t2 = ktime_get_ns(); | ||
99 | t3 = ktime_get_ns(); | ||
100 | local_irq_restore(flags); | ||
101 | udelay(i * 10); | ||
102 | t = (t2 - t1) - (t3 - t2); | ||
103 | if (t < tx) | ||
104 | tx = t; | ||
105 | } | ||
106 | |||
107 | gameport_close(gameport); | ||
108 | t = 1000000 * 50; | ||
109 | if (tx) | ||
110 | t /= tx; | ||
111 | return t; | ||
112 | } | ||
113 | |||
114 | static int old_gameport_measure_speed(struct gameport *gameport) | ||
115 | { | ||
79 | #if defined(__i386__) | 116 | #if defined(__i386__) |
80 | 117 | ||
81 | unsigned int i, t, t1, t2, t3, tx; | 118 | unsigned int i, t, t1, t2, t3, tx; |
@@ -521,7 +558,9 @@ static void gameport_add_port(struct gameport *gameport) | |||
521 | if (gameport->parent) | 558 | if (gameport->parent) |
522 | gameport->parent->child = gameport; | 559 | gameport->parent->child = gameport; |
523 | 560 | ||
524 | gameport->speed = gameport_measure_speed(gameport); | 561 | gameport->speed = use_ktime ? |
562 | gameport_measure_speed(gameport) : | ||
563 | old_gameport_measure_speed(gameport); | ||
525 | 564 | ||
526 | list_add_tail(&gameport->node, &gameport_list); | 565 | list_add_tail(&gameport->node, &gameport_list); |
527 | 566 | ||
diff --git a/drivers/input/input.c b/drivers/input/input.c index 29ca0bb4f561..0f175f55782b 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -498,7 +498,8 @@ void input_set_abs_params(struct input_dev *dev, unsigned int axis, | |||
498 | absinfo->fuzz = fuzz; | 498 | absinfo->fuzz = fuzz; |
499 | absinfo->flat = flat; | 499 | absinfo->flat = flat; |
500 | 500 | ||
501 | dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); | 501 | __set_bit(EV_ABS, dev->evbit); |
502 | __set_bit(axis, dev->absbit); | ||
502 | } | 503 | } |
503 | EXPORT_SYMBOL(input_set_abs_params); | 504 | EXPORT_SYMBOL(input_set_abs_params); |
504 | 505 | ||
@@ -1788,7 +1789,7 @@ struct input_dev *input_allocate_device(void) | |||
1788 | INIT_LIST_HEAD(&dev->h_list); | 1789 | INIT_LIST_HEAD(&dev->h_list); |
1789 | INIT_LIST_HEAD(&dev->node); | 1790 | INIT_LIST_HEAD(&dev->node); |
1790 | 1791 | ||
1791 | dev_set_name(&dev->dev, "input%ld", | 1792 | dev_set_name(&dev->dev, "input%lu", |
1792 | (unsigned long) atomic_inc_return(&input_no) - 1); | 1793 | (unsigned long) atomic_inc_return(&input_no) - 1); |
1793 | 1794 | ||
1794 | __module_get(THIS_MODULE); | 1795 | __module_get(THIS_MODULE); |
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index ab0fdcd36e18..4284080e481d 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/gameport.h> | 36 | #include <linux/gameport.h> |
37 | #include <linux/jiffies.h> | 37 | #include <linux/jiffies.h> |
38 | #include <linux/timex.h> | 38 | #include <linux/timex.h> |
39 | #include <linux/timekeeping.h> | ||
39 | 40 | ||
40 | #define DRIVER_DESC "Analog joystick and gamepad driver" | 41 | #define DRIVER_DESC "Analog joystick and gamepad driver" |
41 | 42 | ||
@@ -43,6 +44,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
43 | MODULE_DESCRIPTION(DRIVER_DESC); | 44 | MODULE_DESCRIPTION(DRIVER_DESC); |
44 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
45 | 46 | ||
47 | static bool use_ktime = true; | ||
48 | module_param(use_ktime, bool, 0400); | ||
49 | MODULE_PARM_DESC(use_ktime, "Use ktime for measuring I/O speed"); | ||
50 | |||
46 | /* | 51 | /* |
47 | * Option parsing. | 52 | * Option parsing. |
48 | */ | 53 | */ |
@@ -171,6 +176,25 @@ static unsigned long analog_faketime = 0; | |||
171 | #warning Precise timer not defined for this architecture. | 176 | #warning Precise timer not defined for this architecture. |
172 | #endif | 177 | #endif |
173 | 178 | ||
179 | static inline u64 get_time(void) | ||
180 | { | ||
181 | if (use_ktime) { | ||
182 | return ktime_get_ns(); | ||
183 | } else { | ||
184 | unsigned int x; | ||
185 | GET_TIME(x); | ||
186 | return x; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | static inline unsigned int delta(u64 x, u64 y) | ||
191 | { | ||
192 | if (use_ktime) | ||
193 | return y - x; | ||
194 | else | ||
195 | return DELTA((unsigned int)x, (unsigned int)y); | ||
196 | } | ||
197 | |||
174 | /* | 198 | /* |
175 | * analog_decode() decodes analog joystick data and reports input events. | 199 | * analog_decode() decodes analog joystick data and reports input events. |
176 | */ | 200 | */ |
@@ -226,7 +250,8 @@ static void analog_decode(struct analog *analog, int *axes, int *initial, int bu | |||
226 | static int analog_cooked_read(struct analog_port *port) | 250 | static int analog_cooked_read(struct analog_port *port) |
227 | { | 251 | { |
228 | struct gameport *gameport = port->gameport; | 252 | struct gameport *gameport = port->gameport; |
229 | unsigned int time[4], start, loop, now, loopout, timeout; | 253 | u64 time[4], start, loop, now; |
254 | unsigned int loopout, timeout; | ||
230 | unsigned char data[4], this, last; | 255 | unsigned char data[4], this, last; |
231 | unsigned long flags; | 256 | unsigned long flags; |
232 | int i, j; | 257 | int i, j; |
@@ -236,7 +261,7 @@ static int analog_cooked_read(struct analog_port *port) | |||
236 | 261 | ||
237 | local_irq_save(flags); | 262 | local_irq_save(flags); |
238 | gameport_trigger(gameport); | 263 | gameport_trigger(gameport); |
239 | GET_TIME(now); | 264 | now = get_time(); |
240 | local_irq_restore(flags); | 265 | local_irq_restore(flags); |
241 | 266 | ||
242 | start = now; | 267 | start = now; |
@@ -249,16 +274,16 @@ static int analog_cooked_read(struct analog_port *port) | |||
249 | 274 | ||
250 | local_irq_disable(); | 275 | local_irq_disable(); |
251 | this = gameport_read(gameport) & port->mask; | 276 | this = gameport_read(gameport) & port->mask; |
252 | GET_TIME(now); | 277 | now = get_time(); |
253 | local_irq_restore(flags); | 278 | local_irq_restore(flags); |
254 | 279 | ||
255 | if ((last ^ this) && (DELTA(loop, now) < loopout)) { | 280 | if ((last ^ this) && (delta(loop, now) < loopout)) { |
256 | data[i] = last ^ this; | 281 | data[i] = last ^ this; |
257 | time[i] = now; | 282 | time[i] = now; |
258 | i++; | 283 | i++; |
259 | } | 284 | } |
260 | 285 | ||
261 | } while (this && (i < 4) && (DELTA(start, now) < timeout)); | 286 | } while (this && (i < 4) && (delta(start, now) < timeout)); |
262 | 287 | ||
263 | this <<= 4; | 288 | this <<= 4; |
264 | 289 | ||
@@ -266,7 +291,7 @@ static int analog_cooked_read(struct analog_port *port) | |||
266 | this |= data[i]; | 291 | this |= data[i]; |
267 | for (j = 0; j < 4; j++) | 292 | for (j = 0; j < 4; j++) |
268 | if (data[i] & (1 << j)) | 293 | if (data[i] & (1 << j)) |
269 | port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; | 294 | port->axes[j] = (delta(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop; |
270 | } | 295 | } |
271 | 296 | ||
272 | return -(this != port->mask); | 297 | return -(this != port->mask); |
@@ -365,31 +390,39 @@ static void analog_close(struct input_dev *dev) | |||
365 | static void analog_calibrate_timer(struct analog_port *port) | 390 | static void analog_calibrate_timer(struct analog_port *port) |
366 | { | 391 | { |
367 | struct gameport *gameport = port->gameport; | 392 | struct gameport *gameport = port->gameport; |
368 | unsigned int i, t, tx, t1, t2, t3; | 393 | unsigned int i, t, tx; |
394 | u64 t1, t2, t3; | ||
369 | unsigned long flags; | 395 | unsigned long flags; |
370 | 396 | ||
371 | local_irq_save(flags); | 397 | if (use_ktime) { |
372 | GET_TIME(t1); | 398 | port->speed = 1000000; |
399 | } else { | ||
400 | local_irq_save(flags); | ||
401 | t1 = get_time(); | ||
373 | #ifdef FAKE_TIME | 402 | #ifdef FAKE_TIME |
374 | analog_faketime += 830; | 403 | analog_faketime += 830; |
375 | #endif | 404 | #endif |
376 | mdelay(1); | 405 | mdelay(1); |
377 | GET_TIME(t2); | 406 | t2 = get_time(); |
378 | GET_TIME(t3); | 407 | t3 = get_time(); |
379 | local_irq_restore(flags); | 408 | local_irq_restore(flags); |
380 | 409 | ||
381 | port->speed = DELTA(t1, t2) - DELTA(t2, t3); | 410 | port->speed = delta(t1, t2) - delta(t2, t3); |
411 | } | ||
382 | 412 | ||
383 | tx = ~0; | 413 | tx = ~0; |
384 | 414 | ||
385 | for (i = 0; i < 50; i++) { | 415 | for (i = 0; i < 50; i++) { |
386 | local_irq_save(flags); | 416 | local_irq_save(flags); |
387 | GET_TIME(t1); | 417 | t1 = get_time(); |
388 | for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); } | 418 | for (t = 0; t < 50; t++) { |
389 | GET_TIME(t3); | 419 | gameport_read(gameport); |
420 | t2 = get_time(); | ||
421 | } | ||
422 | t3 = get_time(); | ||
390 | local_irq_restore(flags); | 423 | local_irq_restore(flags); |
391 | udelay(i); | 424 | udelay(i); |
392 | t = DELTA(t1, t2) - DELTA(t2, t3); | 425 | t = delta(t1, t2) - delta(t2, t3); |
393 | if (t < tx) tx = t; | 426 | if (t < tx) tx = t; |
394 | } | 427 | } |
395 | 428 | ||
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 177602cf7079..cd13c82ca0a1 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
@@ -126,7 +126,9 @@ static const struct xpad_device { | |||
126 | { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, | 126 | { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, |
127 | { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, | 127 | { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, |
128 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, | 128 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, |
129 | { 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 }, | ||
129 | { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, | 130 | { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, |
131 | { 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 }, | ||
130 | { 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 }, | 132 | { 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 }, |
131 | { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, | 133 | { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, |
132 | { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, | 134 | { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, |
@@ -140,10 +142,17 @@ static const struct xpad_device { | |||
140 | { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, | 142 | { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
141 | { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, | 143 | { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, |
142 | { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, | 144 | { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, |
145 | { 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 }, | ||
146 | { 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, | ||
143 | { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, | 147 | { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, |
144 | { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, | 148 | { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, |
149 | { 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 }, | ||
145 | { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, | 150 | { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
151 | { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 }, | ||
146 | { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, | 152 | { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, |
153 | { 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, | ||
154 | { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, | ||
155 | { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, | ||
147 | { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, | 156 | { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, |
148 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, | 157 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, |
149 | { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, | 158 | { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, |
@@ -156,28 +165,50 @@ static const struct xpad_device { | |||
156 | { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, | 165 | { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, |
157 | { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, | 166 | { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, |
158 | { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, | 167 | { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, |
168 | { 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, | ||
159 | { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, | 169 | { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, |
160 | { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, | 170 | { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, |
171 | { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, | ||
172 | { 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 }, | ||
173 | { 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 }, | ||
161 | { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, | 174 | { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, |
175 | { 0x0e8f, 0x3008, "Generic xbox control (dealextreme)", 0, XTYPE_XBOX }, | ||
176 | { 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 }, | ||
162 | { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, | 177 | { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, |
163 | { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, | 178 | { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, |
164 | { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, | 179 | { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, |
165 | { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, | 180 | { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, |
166 | { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, | 181 | { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, |
167 | { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, | 182 | { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, |
183 | { 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 }, | ||
168 | { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, | 184 | { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
169 | { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, | 185 | { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, |
170 | { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, | 186 | { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
171 | { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, | 187 | { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, |
188 | { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 }, | ||
189 | { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, | ||
190 | { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, | ||
191 | { 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 }, | ||
192 | { 0x162e, 0xbeef, "Joytech Neo-Se Take2", 0, XTYPE_XBOX360 }, | ||
172 | { 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 }, | 193 | { 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 }, |
173 | { 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 }, | 194 | { 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 }, |
195 | { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, | ||
174 | { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, | 196 | { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, |
175 | { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, | 197 | { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, |
176 | { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, | 198 | { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, |
199 | { 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)", 0, XTYPE_XBOX360 }, | ||
177 | { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 }, | 200 | { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 }, |
201 | { 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 }, | ||
202 | { 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 }, | ||
178 | { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 }, | 203 | { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 }, |
179 | { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 }, | 204 | { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 }, |
205 | { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", 0, XTYPE_XBOX360 }, | ||
180 | { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, | 206 | { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, |
207 | { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, | ||
208 | { 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 }, | ||
209 | { 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 }, | ||
210 | { 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 }, | ||
211 | { 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 }, | ||
181 | { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, | 212 | { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, |
182 | { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } | 213 | { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } |
183 | }; | 214 | }; |
@@ -274,6 +305,9 @@ static struct usb_device_id xpad_table[] = { | |||
274 | XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ | 305 | XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ |
275 | XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ | 306 | XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ |
276 | XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */ | 307 | XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */ |
308 | XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */ | ||
309 | XPAD_XBOX360_VENDOR(0x15e4), /* Numark X-Box 360 controllers */ | ||
310 | XPAD_XBOX360_VENDOR(0x162e), /* Joytech X-Box 360 controllers */ | ||
277 | { } | 311 | { } |
278 | }; | 312 | }; |
279 | 313 | ||
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 5ef7fcf0e250..728133ec6d7b 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c | |||
@@ -589,6 +589,7 @@ static int adp5588_probe(struct i2c_client *client, | |||
589 | 589 | ||
590 | err_free_irq: | 590 | err_free_irq: |
591 | free_irq(client->irq, kpad); | 591 | free_irq(client->irq, kpad); |
592 | cancel_delayed_work_sync(&kpad->work); | ||
592 | err_unreg_dev: | 593 | err_unreg_dev: |
593 | input_unregister_device(input); | 594 | input_unregister_device(input); |
594 | input = NULL; | 595 | input = NULL; |
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 791781ade4e7..1e83ef99098e 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/bitops.h> | ||
25 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
26 | #include <linux/input.h> | 27 | #include <linux/input.h> |
27 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
@@ -38,6 +39,7 @@ | |||
38 | * @row_shift: log2 or number of rows, rounded up | 39 | * @row_shift: log2 or number of rows, rounded up |
39 | * @keymap_data: Matrix keymap data used to convert to keyscan values | 40 | * @keymap_data: Matrix keymap data used to convert to keyscan values |
40 | * @ghost_filter: true to enable the matrix key-ghosting filter | 41 | * @ghost_filter: true to enable the matrix key-ghosting filter |
42 | * @valid_keys: bitmap of existing keys for each matrix column | ||
41 | * @old_kb_state: bitmap of keys pressed last scan | 43 | * @old_kb_state: bitmap of keys pressed last scan |
42 | * @dev: Device pointer | 44 | * @dev: Device pointer |
43 | * @idev: Input device | 45 | * @idev: Input device |
@@ -49,6 +51,7 @@ struct cros_ec_keyb { | |||
49 | int row_shift; | 51 | int row_shift; |
50 | const struct matrix_keymap_data *keymap_data; | 52 | const struct matrix_keymap_data *keymap_data; |
51 | bool ghost_filter; | 53 | bool ghost_filter; |
54 | uint8_t *valid_keys; | ||
52 | uint8_t *old_kb_state; | 55 | uint8_t *old_kb_state; |
53 | 56 | ||
54 | struct device *dev; | 57 | struct device *dev; |
@@ -57,39 +60,15 @@ struct cros_ec_keyb { | |||
57 | }; | 60 | }; |
58 | 61 | ||
59 | 62 | ||
60 | static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev, | ||
61 | uint8_t *buf, int row) | ||
62 | { | ||
63 | int pressed_in_row = 0; | ||
64 | int row_has_teeth = 0; | ||
65 | int col, mask; | ||
66 | |||
67 | mask = 1 << row; | ||
68 | for (col = 0; col < ckdev->cols; col++) { | ||
69 | if (buf[col] & mask) { | ||
70 | pressed_in_row++; | ||
71 | row_has_teeth |= buf[col] & ~mask; | ||
72 | if (pressed_in_row > 1 && row_has_teeth) { | ||
73 | /* ghosting */ | ||
74 | dev_dbg(ckdev->dev, | ||
75 | "ghost found at: r%d c%d, pressed %d, teeth 0x%x\n", | ||
76 | row, col, pressed_in_row, | ||
77 | row_has_teeth); | ||
78 | return true; | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return false; | ||
84 | } | ||
85 | |||
86 | /* | 63 | /* |
87 | * Returns true when there is at least one combination of pressed keys that | 64 | * Returns true when there is at least one combination of pressed keys that |
88 | * results in ghosting. | 65 | * results in ghosting. |
89 | */ | 66 | */ |
90 | static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) | 67 | static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) |
91 | { | 68 | { |
92 | int row; | 69 | int col1, col2, buf1, buf2; |
70 | struct device *dev = ckdev->dev; | ||
71 | uint8_t *valid_keys = ckdev->valid_keys; | ||
93 | 72 | ||
94 | /* | 73 | /* |
95 | * Ghosting happens if for any pressed key X there are other keys | 74 | * Ghosting happens if for any pressed key X there are other keys |
@@ -103,27 +82,23 @@ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) | |||
103 | * | 82 | * |
104 | * In this case only X, Y, and Z are pressed, but g appears to be | 83 | * In this case only X, Y, and Z are pressed, but g appears to be |
105 | * pressed too (see Wikipedia). | 84 | * pressed too (see Wikipedia). |
106 | * | ||
107 | * We can detect ghosting in a single pass (*) over the keyboard state | ||
108 | * by maintaining two arrays. pressed_in_row counts how many pressed | ||
109 | * keys we have found in a row. row_has_teeth is true if any of the | ||
110 | * pressed keys for this row has other pressed keys in its column. If | ||
111 | * at any point of the scan we find that a row has multiple pressed | ||
112 | * keys, and at least one of them is at the intersection with a column | ||
113 | * with multiple pressed keys, we're sure there is ghosting. | ||
114 | * Conversely, if there is ghosting, we will detect such situation for | ||
115 | * at least one key during the pass. | ||
116 | * | ||
117 | * (*) This looks linear in the number of keys, but it's not. We can | ||
118 | * cheat because the number of rows is small. | ||
119 | */ | 85 | */ |
120 | for (row = 0; row < ckdev->rows; row++) | 86 | for (col1 = 0; col1 < ckdev->cols; col1++) { |
121 | if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row)) | 87 | buf1 = buf[col1] & valid_keys[col1]; |
122 | return true; | 88 | for (col2 = col1 + 1; col2 < ckdev->cols; col2++) { |
89 | buf2 = buf[col2] & valid_keys[col2]; | ||
90 | if (hweight8(buf1 & buf2) > 1) { | ||
91 | dev_dbg(dev, "ghost found at: B[%02d]:0x%02x & B[%02d]:0x%02x", | ||
92 | col1, buf1, col2, buf2); | ||
93 | return true; | ||
94 | } | ||
95 | } | ||
96 | } | ||
123 | 97 | ||
124 | return false; | 98 | return false; |
125 | } | 99 | } |
126 | 100 | ||
101 | |||
127 | /* | 102 | /* |
128 | * Compares the new keyboard state to the old one and produces key | 103 | * Compares the new keyboard state to the old one and produces key |
129 | * press/release events accordingly. The keyboard state is 13 bytes (one byte | 104 | * press/release events accordingly. The keyboard state is 13 bytes (one byte |
@@ -222,6 +197,30 @@ static void cros_ec_keyb_close(struct input_dev *dev) | |||
222 | free_irq(ec->irq, ckdev); | 197 | free_irq(ec->irq, ckdev); |
223 | } | 198 | } |
224 | 199 | ||
200 | /* | ||
201 | * Walks keycodes flipping bit in buffer COLUMNS deep where bit is ROW. Used by | ||
202 | * ghosting logic to ignore NULL or virtual keys. | ||
203 | */ | ||
204 | static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev) | ||
205 | { | ||
206 | int row, col; | ||
207 | int row_shift = ckdev->row_shift; | ||
208 | unsigned short *keymap = ckdev->idev->keycode; | ||
209 | unsigned short code; | ||
210 | |||
211 | BUG_ON(ckdev->idev->keycodesize != sizeof(*keymap)); | ||
212 | |||
213 | for (col = 0; col < ckdev->cols; col++) { | ||
214 | for (row = 0; row < ckdev->rows; row++) { | ||
215 | code = keymap[MATRIX_SCAN_CODE(row, col, row_shift)]; | ||
216 | if (code && (code != KEY_BATTERY)) | ||
217 | ckdev->valid_keys[col] |= 1 << row; | ||
218 | } | ||
219 | dev_dbg(ckdev->dev, "valid_keys[%02d] = 0x%02x\n", | ||
220 | col, ckdev->valid_keys[col]); | ||
221 | } | ||
222 | } | ||
223 | |||
225 | static int cros_ec_keyb_probe(struct platform_device *pdev) | 224 | static int cros_ec_keyb_probe(struct platform_device *pdev) |
226 | { | 225 | { |
227 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | 226 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); |
@@ -242,6 +241,11 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
242 | &ckdev->cols); | 241 | &ckdev->cols); |
243 | if (err) | 242 | if (err) |
244 | return err; | 243 | return err; |
244 | |||
245 | ckdev->valid_keys = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); | ||
246 | if (!ckdev->valid_keys) | ||
247 | return -ENOMEM; | ||
248 | |||
245 | ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); | 249 | ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); |
246 | if (!ckdev->old_kb_state) | 250 | if (!ckdev->old_kb_state) |
247 | return -ENOMEM; | 251 | return -ENOMEM; |
@@ -285,6 +289,8 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
285 | input_set_capability(idev, EV_MSC, MSC_SCAN); | 289 | input_set_capability(idev, EV_MSC, MSC_SCAN); |
286 | input_set_drvdata(idev, ckdev); | 290 | input_set_drvdata(idev, ckdev); |
287 | ckdev->idev = idev; | 291 | ckdev->idev = idev; |
292 | cros_ec_keyb_compute_valid_keys(ckdev); | ||
293 | |||
288 | err = input_register_device(ckdev->idev); | 294 | err = input_register_device(ckdev->idev); |
289 | if (err) { | 295 | if (err) { |
290 | dev_err(dev, "cannot register input device\n"); | 296 | dev_err(dev, "cannot register input device\n"); |
@@ -342,10 +348,19 @@ static int cros_ec_keyb_resume(struct device *dev) | |||
342 | 348 | ||
343 | static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); | 349 | static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); |
344 | 350 | ||
351 | #ifdef CONFIG_OF | ||
352 | static const struct of_device_id cros_ec_keyb_of_match[] = { | ||
353 | { .compatible = "google,cros-ec-keyb" }, | ||
354 | {}, | ||
355 | }; | ||
356 | MODULE_DEVICE_TABLE(of, cros_ec_keyb_of_match); | ||
357 | #endif | ||
358 | |||
345 | static struct platform_driver cros_ec_keyb_driver = { | 359 | static struct platform_driver cros_ec_keyb_driver = { |
346 | .probe = cros_ec_keyb_probe, | 360 | .probe = cros_ec_keyb_probe, |
347 | .driver = { | 361 | .driver = { |
348 | .name = "cros-ec-keyb", | 362 | .name = "cros-ec-keyb", |
363 | .of_match_table = of_match_ptr(cros_ec_keyb_of_match), | ||
349 | .pm = &cros_ec_keyb_pm_ops, | 364 | .pm = &cros_ec_keyb_pm_ops, |
350 | }, | 365 | }, |
351 | }; | 366 | }; |
diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index 7b9b44158ad1..62abe2c16670 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c | |||
@@ -18,7 +18,6 @@ | |||
18 | 18 | ||
19 | struct opencores_kbd { | 19 | struct opencores_kbd { |
20 | struct input_dev *input; | 20 | struct input_dev *input; |
21 | struct resource *addr_res; | ||
22 | void __iomem *addr; | 21 | void __iomem *addr; |
23 | int irq; | 22 | int irq; |
24 | unsigned short keycodes[128]; | 23 | unsigned short keycodes[128]; |
@@ -56,35 +55,25 @@ static int opencores_kbd_probe(struct platform_device *pdev) | |||
56 | return -EINVAL; | 55 | return -EINVAL; |
57 | } | 56 | } |
58 | 57 | ||
59 | opencores_kbd = kzalloc(sizeof(*opencores_kbd), GFP_KERNEL); | 58 | opencores_kbd = devm_kzalloc(&pdev->dev, sizeof(*opencores_kbd), |
60 | input = input_allocate_device(); | 59 | GFP_KERNEL); |
61 | if (!opencores_kbd || !input) { | 60 | if (!opencores_kbd) |
62 | dev_err(&pdev->dev, "failed to allocate device structures\n"); | 61 | return -ENOMEM; |
63 | error = -ENOMEM; | ||
64 | goto err_free_mem; | ||
65 | } | ||
66 | |||
67 | opencores_kbd->addr_res = res; | ||
68 | res = request_mem_region(res->start, resource_size(res), pdev->name); | ||
69 | if (!res) { | ||
70 | dev_err(&pdev->dev, "failed to request I/O memory\n"); | ||
71 | error = -EBUSY; | ||
72 | goto err_free_mem; | ||
73 | } | ||
74 | 62 | ||
75 | opencores_kbd->addr = ioremap(res->start, resource_size(res)); | 63 | input = devm_input_allocate_device(&pdev->dev); |
76 | if (!opencores_kbd->addr) { | 64 | if (!input) { |
77 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); | 65 | dev_err(&pdev->dev, "failed to allocate input device\n"); |
78 | error = -ENXIO; | 66 | return -ENOMEM; |
79 | goto err_rel_mem; | ||
80 | } | 67 | } |
81 | 68 | ||
82 | opencores_kbd->input = input; | 69 | opencores_kbd->input = input; |
83 | opencores_kbd->irq = irq; | 70 | |
71 | opencores_kbd->addr = devm_ioremap_resource(&pdev->dev, res); | ||
72 | if (IS_ERR(opencores_kbd->addr)) | ||
73 | error = PTR_ERR(opencores_kbd->addr); | ||
84 | 74 | ||
85 | input->name = pdev->name; | 75 | input->name = pdev->name; |
86 | input->phys = "opencores-kbd/input0"; | 76 | input->phys = "opencores-kbd/input0"; |
87 | input->dev.parent = &pdev->dev; | ||
88 | 77 | ||
89 | input_set_drvdata(input, opencores_kbd); | 78 | input_set_drvdata(input, opencores_kbd); |
90 | 79 | ||
@@ -109,54 +98,27 @@ static int opencores_kbd_probe(struct platform_device *pdev) | |||
109 | } | 98 | } |
110 | __clear_bit(KEY_RESERVED, input->keybit); | 99 | __clear_bit(KEY_RESERVED, input->keybit); |
111 | 100 | ||
112 | error = request_irq(irq, &opencores_kbd_isr, | 101 | error = devm_request_irq(&pdev->dev, irq, &opencores_kbd_isr, |
113 | IRQF_TRIGGER_RISING, pdev->name, opencores_kbd); | 102 | IRQF_TRIGGER_RISING, |
103 | pdev->name, opencores_kbd); | ||
114 | if (error) { | 104 | if (error) { |
115 | dev_err(&pdev->dev, "unable to claim irq %d\n", irq); | 105 | dev_err(&pdev->dev, "unable to claim irq %d\n", irq); |
116 | goto err_unmap_mem; | 106 | return error; |
117 | } | 107 | } |
118 | 108 | ||
119 | error = input_register_device(input); | 109 | error = input_register_device(input); |
120 | if (error) { | 110 | if (error) { |
121 | dev_err(&pdev->dev, "unable to register input device\n"); | 111 | dev_err(&pdev->dev, "unable to register input device\n"); |
122 | goto err_free_irq; | 112 | return error; |
123 | } | 113 | } |
124 | 114 | ||
125 | platform_set_drvdata(pdev, opencores_kbd); | 115 | platform_set_drvdata(pdev, opencores_kbd); |
126 | 116 | ||
127 | return 0; | 117 | return 0; |
128 | |||
129 | err_free_irq: | ||
130 | free_irq(irq, opencores_kbd); | ||
131 | err_unmap_mem: | ||
132 | iounmap(opencores_kbd->addr); | ||
133 | err_rel_mem: | ||
134 | release_mem_region(res->start, resource_size(res)); | ||
135 | err_free_mem: | ||
136 | input_free_device(input); | ||
137 | kfree(opencores_kbd); | ||
138 | |||
139 | return error; | ||
140 | } | ||
141 | |||
142 | static int opencores_kbd_remove(struct platform_device *pdev) | ||
143 | { | ||
144 | struct opencores_kbd *opencores_kbd = platform_get_drvdata(pdev); | ||
145 | |||
146 | free_irq(opencores_kbd->irq, opencores_kbd); | ||
147 | |||
148 | iounmap(opencores_kbd->addr); | ||
149 | release_mem_region(opencores_kbd->addr_res->start, | ||
150 | resource_size(opencores_kbd->addr_res)); | ||
151 | input_unregister_device(opencores_kbd->input); | ||
152 | kfree(opencores_kbd); | ||
153 | |||
154 | return 0; | ||
155 | } | 118 | } |
156 | 119 | ||
157 | static struct platform_driver opencores_kbd_device_driver = { | 120 | static struct platform_driver opencores_kbd_device_driver = { |
158 | .probe = opencores_kbd_probe, | 121 | .probe = opencores_kbd_probe, |
159 | .remove = opencores_kbd_remove, | ||
160 | .driver = { | 122 | .driver = { |
161 | .name = "opencores-kbd", | 123 | .name = "opencores-kbd", |
162 | }, | 124 | }, |
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 2ff4425a893b..23297ab6163f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -144,6 +144,17 @@ config INPUT_M68K_BEEP | |||
144 | tristate "M68k Beeper support" | 144 | tristate "M68k Beeper support" |
145 | depends on M68K | 145 | depends on M68K |
146 | 146 | ||
147 | config INPUT_MAX77693_HAPTIC | ||
148 | tristate "MAXIM MAX77693 haptic controller support" | ||
149 | depends on MFD_MAX77693 && PWM | ||
150 | select INPUT_FF_MEMLESS | ||
151 | help | ||
152 | This option enables support for the haptic controller on | ||
153 | MAXIM MAX77693 chip. | ||
154 | |||
155 | To compile this driver as module, choose M here: the | ||
156 | module will be called max77693-haptic. | ||
157 | |||
147 | config INPUT_MAX8925_ONKEY | 158 | config INPUT_MAX8925_ONKEY |
148 | tristate "MAX8925 ONKEY support" | 159 | tristate "MAX8925 ONKEY support" |
149 | depends on MFD_MAX8925 | 160 | depends on MFD_MAX8925 |
@@ -451,6 +462,16 @@ config HP_SDC_RTC | |||
451 | Say Y here if you want to support the built-in real time clock | 462 | Say Y here if you want to support the built-in real time clock |
452 | of the HP SDC controller. | 463 | of the HP SDC controller. |
453 | 464 | ||
465 | config INPUT_PALMAS_PWRBUTTON | ||
466 | tristate "Palmas Power button Driver" | ||
467 | depends on MFD_PALMAS | ||
468 | help | ||
469 | Say Y here if you want to enable power key reporting via the | ||
470 | Palmas family of PMICs. | ||
471 | |||
472 | To compile this driver as a module, choose M here. The module will | ||
473 | be called palmas_pwrbutton. | ||
474 | |||
454 | config INPUT_PCF50633_PMU | 475 | config INPUT_PCF50633_PMU |
455 | tristate "PCF50633 PMU events" | 476 | tristate "PCF50633 PMU events" |
456 | depends on MFD_PCF50633 | 477 | depends on MFD_PCF50633 |
@@ -676,4 +697,26 @@ config INPUT_SOC_BUTTON_ARRAY | |||
676 | To compile this driver as a module, choose M here: the | 697 | To compile this driver as a module, choose M here: the |
677 | module will be called soc_button_array. | 698 | module will be called soc_button_array. |
678 | 699 | ||
700 | config INPUT_DRV260X_HAPTICS | ||
701 | tristate "TI DRV260X haptics support" | ||
702 | depends on INPUT && I2C && GPIOLIB | ||
703 | select INPUT_FF_MEMLESS | ||
704 | select REGMAP_I2C | ||
705 | help | ||
706 | Say Y to enable support for the TI DRV260X haptics driver. | ||
707 | |||
708 | To compile this driver as a module, choose M here: the | ||
709 | module will be called drv260x-haptics. | ||
710 | |||
711 | config INPUT_DRV2667_HAPTICS | ||
712 | tristate "TI DRV2667 haptics support" | ||
713 | depends on INPUT && I2C | ||
714 | select INPUT_FF_MEMLESS | ||
715 | select REGMAP_I2C | ||
716 | help | ||
717 | Say Y to enable support for the TI DRV2667 haptics driver. | ||
718 | |||
719 | To compile this driver as a module, choose M here: the | ||
720 | module will be called drv260x-haptics. | ||
721 | |||
679 | endif | 722 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 4955ad322a01..19c760361f80 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -26,6 +26,8 @@ obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | |||
26 | obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o | 26 | obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o |
27 | obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o | 27 | obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o |
28 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o | 28 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o |
29 | obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o | ||
30 | obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o | ||
29 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o | 31 | obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o |
30 | obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o | 32 | obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o |
31 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o | 33 | obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o |
@@ -35,11 +37,13 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | |||
35 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | 37 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o |
36 | obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o | 38 | obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o |
37 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | 39 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o |
40 | obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o | ||
38 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o | 41 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o |
39 | obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o | 42 | obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o |
40 | obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o | 43 | obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o |
41 | obj-$(CONFIG_INPUT_MMA8450) += mma8450.o | 44 | obj-$(CONFIG_INPUT_MMA8450) += mma8450.o |
42 | obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o | 45 | obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o |
46 | obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o | ||
43 | obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o | 47 | obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o |
44 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o | 48 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o |
45 | obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o | 49 | obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o |
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c new file mode 100644 index 000000000000..cab87f5ce6d3 --- /dev/null +++ b/drivers/input/misc/drv260x.c | |||
@@ -0,0 +1,741 @@ | |||
1 | /* | ||
2 | * DRV260X haptics driver family | ||
3 | * | ||
4 | * Author: Dan Murphy <dmurphy@ti.com> | ||
5 | * | ||
6 | * Copyright: (C) 2014 Texas Instruments, Inc. | ||
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 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of_gpio.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/gpio/consumer.h> | ||
27 | #include <linux/regulator/consumer.h> | ||
28 | |||
29 | #include <dt-bindings/input/ti-drv260x.h> | ||
30 | #include <linux/platform_data/drv260x-pdata.h> | ||
31 | |||
32 | #define DRV260X_STATUS 0x0 | ||
33 | #define DRV260X_MODE 0x1 | ||
34 | #define DRV260X_RT_PB_IN 0x2 | ||
35 | #define DRV260X_LIB_SEL 0x3 | ||
36 | #define DRV260X_WV_SEQ_1 0x4 | ||
37 | #define DRV260X_WV_SEQ_2 0x5 | ||
38 | #define DRV260X_WV_SEQ_3 0x6 | ||
39 | #define DRV260X_WV_SEQ_4 0x7 | ||
40 | #define DRV260X_WV_SEQ_5 0x8 | ||
41 | #define DRV260X_WV_SEQ_6 0x9 | ||
42 | #define DRV260X_WV_SEQ_7 0xa | ||
43 | #define DRV260X_WV_SEQ_8 0xb | ||
44 | #define DRV260X_GO 0xc | ||
45 | #define DRV260X_OVERDRIVE_OFF 0xd | ||
46 | #define DRV260X_SUSTAIN_P_OFF 0xe | ||
47 | #define DRV260X_SUSTAIN_N_OFF 0xf | ||
48 | #define DRV260X_BRAKE_OFF 0x10 | ||
49 | #define DRV260X_A_TO_V_CTRL 0x11 | ||
50 | #define DRV260X_A_TO_V_MIN_INPUT 0x12 | ||
51 | #define DRV260X_A_TO_V_MAX_INPUT 0x13 | ||
52 | #define DRV260X_A_TO_V_MIN_OUT 0x14 | ||
53 | #define DRV260X_A_TO_V_MAX_OUT 0x15 | ||
54 | #define DRV260X_RATED_VOLT 0x16 | ||
55 | #define DRV260X_OD_CLAMP_VOLT 0x17 | ||
56 | #define DRV260X_CAL_COMP 0x18 | ||
57 | #define DRV260X_CAL_BACK_EMF 0x19 | ||
58 | #define DRV260X_FEEDBACK_CTRL 0x1a | ||
59 | #define DRV260X_CTRL1 0x1b | ||
60 | #define DRV260X_CTRL2 0x1c | ||
61 | #define DRV260X_CTRL3 0x1d | ||
62 | #define DRV260X_CTRL4 0x1e | ||
63 | #define DRV260X_CTRL5 0x1f | ||
64 | #define DRV260X_LRA_LOOP_PERIOD 0x20 | ||
65 | #define DRV260X_VBAT_MON 0x21 | ||
66 | #define DRV260X_LRA_RES_PERIOD 0x22 | ||
67 | #define DRV260X_MAX_REG 0x23 | ||
68 | |||
69 | #define DRV260X_GO_BIT 0x01 | ||
70 | |||
71 | /* Library Selection */ | ||
72 | #define DRV260X_LIB_SEL_MASK 0x07 | ||
73 | #define DRV260X_LIB_SEL_RAM 0x0 | ||
74 | #define DRV260X_LIB_SEL_OD 0x1 | ||
75 | #define DRV260X_LIB_SEL_40_60 0x2 | ||
76 | #define DRV260X_LIB_SEL_60_80 0x3 | ||
77 | #define DRV260X_LIB_SEL_100_140 0x4 | ||
78 | #define DRV260X_LIB_SEL_140_PLUS 0x5 | ||
79 | |||
80 | #define DRV260X_LIB_SEL_HIZ_MASK 0x10 | ||
81 | #define DRV260X_LIB_SEL_HIZ_EN 0x01 | ||
82 | #define DRV260X_LIB_SEL_HIZ_DIS 0 | ||
83 | |||
84 | /* Mode register */ | ||
85 | #define DRV260X_STANDBY (1 << 6) | ||
86 | #define DRV260X_STANDBY_MASK 0x40 | ||
87 | #define DRV260X_INTERNAL_TRIGGER 0x00 | ||
88 | #define DRV260X_EXT_TRIGGER_EDGE 0x01 | ||
89 | #define DRV260X_EXT_TRIGGER_LEVEL 0x02 | ||
90 | #define DRV260X_PWM_ANALOG_IN 0x03 | ||
91 | #define DRV260X_AUDIOHAPTIC 0x04 | ||
92 | #define DRV260X_RT_PLAYBACK 0x05 | ||
93 | #define DRV260X_DIAGNOSTICS 0x06 | ||
94 | #define DRV260X_AUTO_CAL 0x07 | ||
95 | |||
96 | /* Audio to Haptics Control */ | ||
97 | #define DRV260X_AUDIO_HAPTICS_PEAK_10MS (0 << 2) | ||
98 | #define DRV260X_AUDIO_HAPTICS_PEAK_20MS (1 << 2) | ||
99 | #define DRV260X_AUDIO_HAPTICS_PEAK_30MS (2 << 2) | ||
100 | #define DRV260X_AUDIO_HAPTICS_PEAK_40MS (3 << 2) | ||
101 | |||
102 | #define DRV260X_AUDIO_HAPTICS_FILTER_100HZ 0x00 | ||
103 | #define DRV260X_AUDIO_HAPTICS_FILTER_125HZ 0x01 | ||
104 | #define DRV260X_AUDIO_HAPTICS_FILTER_150HZ 0x02 | ||
105 | #define DRV260X_AUDIO_HAPTICS_FILTER_200HZ 0x03 | ||
106 | |||
107 | /* Min/Max Input/Output Voltages */ | ||
108 | #define DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT 0x19 | ||
109 | #define DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT 0x64 | ||
110 | #define DRV260X_AUDIO_HAPTICS_MIN_OUT_VOLT 0x19 | ||
111 | #define DRV260X_AUDIO_HAPTICS_MAX_OUT_VOLT 0xFF | ||
112 | |||
113 | /* Feedback register */ | ||
114 | #define DRV260X_FB_REG_ERM_MODE 0x7f | ||
115 | #define DRV260X_FB_REG_LRA_MODE (1 << 7) | ||
116 | |||
117 | #define DRV260X_BRAKE_FACTOR_MASK 0x1f | ||
118 | #define DRV260X_BRAKE_FACTOR_2X (1 << 0) | ||
119 | #define DRV260X_BRAKE_FACTOR_3X (2 << 4) | ||
120 | #define DRV260X_BRAKE_FACTOR_4X (3 << 4) | ||
121 | #define DRV260X_BRAKE_FACTOR_6X (4 << 4) | ||
122 | #define DRV260X_BRAKE_FACTOR_8X (5 << 4) | ||
123 | #define DRV260X_BRAKE_FACTOR_16 (6 << 4) | ||
124 | #define DRV260X_BRAKE_FACTOR_DIS (7 << 4) | ||
125 | |||
126 | #define DRV260X_LOOP_GAIN_LOW 0xf3 | ||
127 | #define DRV260X_LOOP_GAIN_MED (1 << 2) | ||
128 | #define DRV260X_LOOP_GAIN_HIGH (2 << 2) | ||
129 | #define DRV260X_LOOP_GAIN_VERY_HIGH (3 << 2) | ||
130 | |||
131 | #define DRV260X_BEMF_GAIN_0 0xfc | ||
132 | #define DRV260X_BEMF_GAIN_1 (1 << 0) | ||
133 | #define DRV260X_BEMF_GAIN_2 (2 << 0) | ||
134 | #define DRV260X_BEMF_GAIN_3 (3 << 0) | ||
135 | |||
136 | /* Control 1 register */ | ||
137 | #define DRV260X_AC_CPLE_EN (1 << 5) | ||
138 | #define DRV260X_STARTUP_BOOST (1 << 7) | ||
139 | |||
140 | /* Control 2 register */ | ||
141 | |||
142 | #define DRV260X_IDISS_TIME_45 0 | ||
143 | #define DRV260X_IDISS_TIME_75 (1 << 0) | ||
144 | #define DRV260X_IDISS_TIME_150 (1 << 1) | ||
145 | #define DRV260X_IDISS_TIME_225 0x03 | ||
146 | |||
147 | #define DRV260X_BLANK_TIME_45 (0 << 2) | ||
148 | #define DRV260X_BLANK_TIME_75 (1 << 2) | ||
149 | #define DRV260X_BLANK_TIME_150 (2 << 2) | ||
150 | #define DRV260X_BLANK_TIME_225 (3 << 2) | ||
151 | |||
152 | #define DRV260X_SAMP_TIME_150 (0 << 4) | ||
153 | #define DRV260X_SAMP_TIME_200 (1 << 4) | ||
154 | #define DRV260X_SAMP_TIME_250 (2 << 4) | ||
155 | #define DRV260X_SAMP_TIME_300 (3 << 4) | ||
156 | |||
157 | #define DRV260X_BRAKE_STABILIZER (1 << 6) | ||
158 | #define DRV260X_UNIDIR_IN (0 << 7) | ||
159 | #define DRV260X_BIDIR_IN (1 << 7) | ||
160 | |||
161 | /* Control 3 Register */ | ||
162 | #define DRV260X_LRA_OPEN_LOOP (1 << 0) | ||
163 | #define DRV260X_ANANLOG_IN (1 << 1) | ||
164 | #define DRV260X_LRA_DRV_MODE (1 << 2) | ||
165 | #define DRV260X_RTP_UNSIGNED_DATA (1 << 3) | ||
166 | #define DRV260X_SUPPLY_COMP_DIS (1 << 4) | ||
167 | #define DRV260X_ERM_OPEN_LOOP (1 << 5) | ||
168 | #define DRV260X_NG_THRESH_0 (0 << 6) | ||
169 | #define DRV260X_NG_THRESH_2 (1 << 6) | ||
170 | #define DRV260X_NG_THRESH_4 (2 << 6) | ||
171 | #define DRV260X_NG_THRESH_8 (3 << 6) | ||
172 | |||
173 | /* Control 4 Register */ | ||
174 | #define DRV260X_AUTOCAL_TIME_150MS (0 << 4) | ||
175 | #define DRV260X_AUTOCAL_TIME_250MS (1 << 4) | ||
176 | #define DRV260X_AUTOCAL_TIME_500MS (2 << 4) | ||
177 | #define DRV260X_AUTOCAL_TIME_1000MS (3 << 4) | ||
178 | |||
179 | /** | ||
180 | * struct drv260x_data - | ||
181 | * @input_dev - Pointer to the input device | ||
182 | * @client - Pointer to the I2C client | ||
183 | * @regmap - Register map of the device | ||
184 | * @work - Work item used to off load the enable/disable of the vibration | ||
185 | * @enable_gpio - Pointer to the gpio used for enable/disabling | ||
186 | * @regulator - Pointer to the regulator for the IC | ||
187 | * @magnitude - Magnitude of the vibration event | ||
188 | * @mode - The operating mode of the IC (LRA_NO_CAL, ERM or LRA) | ||
189 | * @library - The vibration library to be used | ||
190 | * @rated_voltage - The rated_voltage of the actuator | ||
191 | * @overdriver_voltage - The over drive voltage of the actuator | ||
192 | **/ | ||
193 | struct drv260x_data { | ||
194 | struct input_dev *input_dev; | ||
195 | struct i2c_client *client; | ||
196 | struct regmap *regmap; | ||
197 | struct work_struct work; | ||
198 | struct gpio_desc *enable_gpio; | ||
199 | struct regulator *regulator; | ||
200 | u32 magnitude; | ||
201 | u32 mode; | ||
202 | u32 library; | ||
203 | int rated_voltage; | ||
204 | int overdrive_voltage; | ||
205 | }; | ||
206 | |||
207 | static struct reg_default drv260x_reg_defs[] = { | ||
208 | { DRV260X_STATUS, 0xe0 }, | ||
209 | { DRV260X_MODE, 0x40 }, | ||
210 | { DRV260X_RT_PB_IN, 0x00 }, | ||
211 | { DRV260X_LIB_SEL, 0x00 }, | ||
212 | { DRV260X_WV_SEQ_1, 0x01 }, | ||
213 | { DRV260X_WV_SEQ_2, 0x00 }, | ||
214 | { DRV260X_WV_SEQ_3, 0x00 }, | ||
215 | { DRV260X_WV_SEQ_4, 0x00 }, | ||
216 | { DRV260X_WV_SEQ_5, 0x00 }, | ||
217 | { DRV260X_WV_SEQ_6, 0x00 }, | ||
218 | { DRV260X_WV_SEQ_7, 0x00 }, | ||
219 | { DRV260X_WV_SEQ_8, 0x00 }, | ||
220 | { DRV260X_GO, 0x00 }, | ||
221 | { DRV260X_OVERDRIVE_OFF, 0x00 }, | ||
222 | { DRV260X_SUSTAIN_P_OFF, 0x00 }, | ||
223 | { DRV260X_SUSTAIN_N_OFF, 0x00 }, | ||
224 | { DRV260X_BRAKE_OFF, 0x00 }, | ||
225 | { DRV260X_A_TO_V_CTRL, 0x05 }, | ||
226 | { DRV260X_A_TO_V_MIN_INPUT, 0x19 }, | ||
227 | { DRV260X_A_TO_V_MAX_INPUT, 0xff }, | ||
228 | { DRV260X_A_TO_V_MIN_OUT, 0x19 }, | ||
229 | { DRV260X_A_TO_V_MAX_OUT, 0xff }, | ||
230 | { DRV260X_RATED_VOLT, 0x3e }, | ||
231 | { DRV260X_OD_CLAMP_VOLT, 0x8c }, | ||
232 | { DRV260X_CAL_COMP, 0x0c }, | ||
233 | { DRV260X_CAL_BACK_EMF, 0x6c }, | ||
234 | { DRV260X_FEEDBACK_CTRL, 0x36 }, | ||
235 | { DRV260X_CTRL1, 0x93 }, | ||
236 | { DRV260X_CTRL2, 0xfa }, | ||
237 | { DRV260X_CTRL3, 0xa0 }, | ||
238 | { DRV260X_CTRL4, 0x20 }, | ||
239 | { DRV260X_CTRL5, 0x80 }, | ||
240 | { DRV260X_LRA_LOOP_PERIOD, 0x33 }, | ||
241 | { DRV260X_VBAT_MON, 0x00 }, | ||
242 | { DRV260X_LRA_RES_PERIOD, 0x00 }, | ||
243 | }; | ||
244 | |||
245 | #define DRV260X_DEF_RATED_VOLT 0x90 | ||
246 | #define DRV260X_DEF_OD_CLAMP_VOLT 0x90 | ||
247 | |||
248 | /** | ||
249 | * Rated and Overdriver Voltages: | ||
250 | * Calculated using the formula r = v * 255 / 5.6 | ||
251 | * where r is what will be written to the register | ||
252 | * and v is the rated or overdriver voltage of the actuator | ||
253 | **/ | ||
254 | static int drv260x_calculate_voltage(unsigned int voltage) | ||
255 | { | ||
256 | return (voltage * 255 / 5600); | ||
257 | } | ||
258 | |||
259 | static void drv260x_worker(struct work_struct *work) | ||
260 | { | ||
261 | struct drv260x_data *haptics = container_of(work, struct drv260x_data, work); | ||
262 | int error; | ||
263 | |||
264 | gpiod_set_value(haptics->enable_gpio, 1); | ||
265 | /* Data sheet says to wait 250us before trying to communicate */ | ||
266 | udelay(250); | ||
267 | |||
268 | error = regmap_write(haptics->regmap, | ||
269 | DRV260X_MODE, DRV260X_RT_PLAYBACK); | ||
270 | if (error) { | ||
271 | dev_err(&haptics->client->dev, | ||
272 | "Failed to write set mode: %d\n", error); | ||
273 | } else { | ||
274 | error = regmap_write(haptics->regmap, | ||
275 | DRV260X_RT_PB_IN, haptics->magnitude); | ||
276 | if (error) | ||
277 | dev_err(&haptics->client->dev, | ||
278 | "Failed to set magnitude: %d\n", error); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static int drv260x_haptics_play(struct input_dev *input, void *data, | ||
283 | struct ff_effect *effect) | ||
284 | { | ||
285 | struct drv260x_data *haptics = input_get_drvdata(input); | ||
286 | |||
287 | haptics->mode = DRV260X_LRA_NO_CAL_MODE; | ||
288 | |||
289 | if (effect->u.rumble.strong_magnitude > 0) | ||
290 | haptics->magnitude = effect->u.rumble.strong_magnitude; | ||
291 | else if (effect->u.rumble.weak_magnitude > 0) | ||
292 | haptics->magnitude = effect->u.rumble.weak_magnitude; | ||
293 | else | ||
294 | haptics->magnitude = 0; | ||
295 | |||
296 | schedule_work(&haptics->work); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static void drv260x_close(struct input_dev *input) | ||
302 | { | ||
303 | struct drv260x_data *haptics = input_get_drvdata(input); | ||
304 | int error; | ||
305 | |||
306 | cancel_work_sync(&haptics->work); | ||
307 | |||
308 | error = regmap_write(haptics->regmap, DRV260X_MODE, DRV260X_STANDBY); | ||
309 | if (error) | ||
310 | dev_err(&haptics->client->dev, | ||
311 | "Failed to enter standby mode: %d\n", error); | ||
312 | |||
313 | gpiod_set_value(haptics->enable_gpio, 0); | ||
314 | } | ||
315 | |||
316 | static const struct reg_default drv260x_lra_cal_regs[] = { | ||
317 | { DRV260X_MODE, DRV260X_AUTO_CAL }, | ||
318 | { DRV260X_CTRL3, DRV260X_NG_THRESH_2 }, | ||
319 | { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | | ||
320 | DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH }, | ||
321 | }; | ||
322 | |||
323 | static const struct reg_default drv260x_lra_init_regs[] = { | ||
324 | { DRV260X_MODE, DRV260X_RT_PLAYBACK }, | ||
325 | { DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS | | ||
326 | DRV260X_AUDIO_HAPTICS_FILTER_125HZ }, | ||
327 | { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT }, | ||
328 | { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT }, | ||
329 | { DRV260X_A_TO_V_MIN_OUT, DRV260X_AUDIO_HAPTICS_MIN_OUT_VOLT }, | ||
330 | { DRV260X_A_TO_V_MAX_OUT, DRV260X_AUDIO_HAPTICS_MAX_OUT_VOLT }, | ||
331 | { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | | ||
332 | DRV260X_BRAKE_FACTOR_2X | DRV260X_LOOP_GAIN_MED | | ||
333 | DRV260X_BEMF_GAIN_3 }, | ||
334 | { DRV260X_CTRL1, DRV260X_STARTUP_BOOST }, | ||
335 | { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 }, | ||
336 | { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ANANLOG_IN }, | ||
337 | { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS }, | ||
338 | }; | ||
339 | |||
340 | static const struct reg_default drv260x_erm_cal_regs[] = { | ||
341 | { DRV260X_MODE, DRV260X_AUTO_CAL }, | ||
342 | { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT }, | ||
343 | { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT }, | ||
344 | { DRV260X_A_TO_V_MIN_OUT, DRV260X_AUDIO_HAPTICS_MIN_OUT_VOLT }, | ||
345 | { DRV260X_A_TO_V_MAX_OUT, DRV260X_AUDIO_HAPTICS_MAX_OUT_VOLT }, | ||
346 | { DRV260X_FEEDBACK_CTRL, DRV260X_BRAKE_FACTOR_3X | | ||
347 | DRV260X_LOOP_GAIN_MED | DRV260X_BEMF_GAIN_2 }, | ||
348 | { DRV260X_CTRL1, DRV260X_STARTUP_BOOST }, | ||
349 | { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 | DRV260X_BLANK_TIME_75 | | ||
350 | DRV260X_IDISS_TIME_75 }, | ||
351 | { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ERM_OPEN_LOOP }, | ||
352 | { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS }, | ||
353 | }; | ||
354 | |||
355 | static int drv260x_init(struct drv260x_data *haptics) | ||
356 | { | ||
357 | int error; | ||
358 | unsigned int cal_buf; | ||
359 | |||
360 | error = regmap_write(haptics->regmap, | ||
361 | DRV260X_RATED_VOLT, haptics->rated_voltage); | ||
362 | if (error) { | ||
363 | dev_err(&haptics->client->dev, | ||
364 | "Failed to write DRV260X_RATED_VOLT register: %d\n", | ||
365 | error); | ||
366 | return error; | ||
367 | } | ||
368 | |||
369 | error = regmap_write(haptics->regmap, | ||
370 | DRV260X_OD_CLAMP_VOLT, haptics->overdrive_voltage); | ||
371 | if (error) { | ||
372 | dev_err(&haptics->client->dev, | ||
373 | "Failed to write DRV260X_OD_CLAMP_VOLT register: %d\n", | ||
374 | error); | ||
375 | return error; | ||
376 | } | ||
377 | |||
378 | switch (haptics->mode) { | ||
379 | case DRV260X_LRA_MODE: | ||
380 | error = regmap_register_patch(haptics->regmap, | ||
381 | drv260x_lra_cal_regs, | ||
382 | ARRAY_SIZE(drv260x_lra_cal_regs)); | ||
383 | if (error) { | ||
384 | dev_err(&haptics->client->dev, | ||
385 | "Failed to write LRA calibration registers: %d\n", | ||
386 | error); | ||
387 | return error; | ||
388 | } | ||
389 | |||
390 | break; | ||
391 | |||
392 | case DRV260X_ERM_MODE: | ||
393 | error = regmap_register_patch(haptics->regmap, | ||
394 | drv260x_erm_cal_regs, | ||
395 | ARRAY_SIZE(drv260x_erm_cal_regs)); | ||
396 | if (error) { | ||
397 | dev_err(&haptics->client->dev, | ||
398 | "Failed to write ERM calibration registers: %d\n", | ||
399 | error); | ||
400 | return error; | ||
401 | } | ||
402 | |||
403 | error = regmap_update_bits(haptics->regmap, DRV260X_LIB_SEL, | ||
404 | DRV260X_LIB_SEL_MASK, | ||
405 | haptics->library); | ||
406 | if (error) { | ||
407 | dev_err(&haptics->client->dev, | ||
408 | "Failed to write DRV260X_LIB_SEL register: %d\n", | ||
409 | error); | ||
410 | return error; | ||
411 | } | ||
412 | |||
413 | break; | ||
414 | |||
415 | default: | ||
416 | error = regmap_register_patch(haptics->regmap, | ||
417 | drv260x_lra_init_regs, | ||
418 | ARRAY_SIZE(drv260x_lra_init_regs)); | ||
419 | if (error) { | ||
420 | dev_err(&haptics->client->dev, | ||
421 | "Failed to write LRA init registers: %d\n", | ||
422 | error); | ||
423 | return error; | ||
424 | } | ||
425 | |||
426 | error = regmap_update_bits(haptics->regmap, DRV260X_LIB_SEL, | ||
427 | DRV260X_LIB_SEL_MASK, | ||
428 | haptics->library); | ||
429 | if (error) { | ||
430 | dev_err(&haptics->client->dev, | ||
431 | "Failed to write DRV260X_LIB_SEL register: %d\n", | ||
432 | error); | ||
433 | return error; | ||
434 | } | ||
435 | |||
436 | /* No need to set GO bit here */ | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | error = regmap_write(haptics->regmap, DRV260X_GO, DRV260X_GO_BIT); | ||
441 | if (error) { | ||
442 | dev_err(&haptics->client->dev, | ||
443 | "Failed to write GO register: %d\n", | ||
444 | error); | ||
445 | return error; | ||
446 | } | ||
447 | |||
448 | do { | ||
449 | error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf); | ||
450 | if (error) { | ||
451 | dev_err(&haptics->client->dev, | ||
452 | "Failed to read GO register: %d\n", | ||
453 | error); | ||
454 | return error; | ||
455 | } | ||
456 | } while (cal_buf == DRV260X_GO_BIT); | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static const struct regmap_config drv260x_regmap_config = { | ||
462 | .reg_bits = 8, | ||
463 | .val_bits = 8, | ||
464 | |||
465 | .max_register = DRV260X_MAX_REG, | ||
466 | .reg_defaults = drv260x_reg_defs, | ||
467 | .num_reg_defaults = ARRAY_SIZE(drv260x_reg_defs), | ||
468 | .cache_type = REGCACHE_NONE, | ||
469 | }; | ||
470 | |||
471 | #ifdef CONFIG_OF | ||
472 | static int drv260x_parse_dt(struct device *dev, | ||
473 | struct drv260x_data *haptics) | ||
474 | { | ||
475 | struct device_node *np = dev->of_node; | ||
476 | unsigned int voltage; | ||
477 | int error; | ||
478 | |||
479 | error = of_property_read_u32(np, "mode", &haptics->mode); | ||
480 | if (error) { | ||
481 | dev_err(dev, "%s: No entry for mode\n", __func__); | ||
482 | return error; | ||
483 | } | ||
484 | |||
485 | error = of_property_read_u32(np, "library-sel", &haptics->library); | ||
486 | if (error) { | ||
487 | dev_err(dev, "%s: No entry for library selection\n", | ||
488 | __func__); | ||
489 | return error; | ||
490 | } | ||
491 | |||
492 | error = of_property_read_u32(np, "vib-rated-mv", &voltage); | ||
493 | if (!error) | ||
494 | haptics->rated_voltage = drv260x_calculate_voltage(voltage); | ||
495 | |||
496 | |||
497 | error = of_property_read_u32(np, "vib-overdrive-mv", &voltage); | ||
498 | if (!error) | ||
499 | haptics->overdrive_voltage = drv260x_calculate_voltage(voltage); | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | #else | ||
504 | static inline int drv260x_parse_dt(struct device *dev, | ||
505 | struct drv260x_data *haptics) | ||
506 | { | ||
507 | dev_err(dev, "no platform data defined\n"); | ||
508 | |||
509 | return -EINVAL; | ||
510 | } | ||
511 | #endif | ||
512 | |||
513 | static int drv260x_probe(struct i2c_client *client, | ||
514 | const struct i2c_device_id *id) | ||
515 | { | ||
516 | const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev); | ||
517 | struct drv260x_data *haptics; | ||
518 | int error; | ||
519 | |||
520 | haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL); | ||
521 | if (!haptics) | ||
522 | return -ENOMEM; | ||
523 | |||
524 | haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT; | ||
525 | haptics->rated_voltage = DRV260X_DEF_RATED_VOLT; | ||
526 | |||
527 | if (pdata) { | ||
528 | haptics->mode = pdata->mode; | ||
529 | haptics->library = pdata->library_selection; | ||
530 | if (pdata->vib_overdrive_voltage) | ||
531 | haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage); | ||
532 | if (pdata->vib_rated_voltage) | ||
533 | haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage); | ||
534 | } else if (client->dev.of_node) { | ||
535 | error = drv260x_parse_dt(&client->dev, haptics); | ||
536 | if (error) | ||
537 | return error; | ||
538 | } else { | ||
539 | dev_err(&client->dev, "Platform data not set\n"); | ||
540 | return -ENODEV; | ||
541 | } | ||
542 | |||
543 | |||
544 | if (haptics->mode < DRV260X_LRA_MODE || | ||
545 | haptics->mode > DRV260X_ERM_MODE) { | ||
546 | dev_err(&client->dev, | ||
547 | "Vibrator mode is invalid: %i\n", | ||
548 | haptics->mode); | ||
549 | return -EINVAL; | ||
550 | } | ||
551 | |||
552 | if (haptics->library < DRV260X_LIB_EMPTY || | ||
553 | haptics->library > DRV260X_ERM_LIB_F) { | ||
554 | dev_err(&client->dev, | ||
555 | "Library value is invalid: %i\n", haptics->library); | ||
556 | return -EINVAL; | ||
557 | } | ||
558 | |||
559 | if (haptics->mode == DRV260X_LRA_MODE && | ||
560 | haptics->library != DRV260X_LIB_EMPTY && | ||
561 | haptics->library != DRV260X_LIB_LRA) { | ||
562 | dev_err(&client->dev, | ||
563 | "LRA Mode with ERM Library mismatch\n"); | ||
564 | return -EINVAL; | ||
565 | } | ||
566 | |||
567 | if (haptics->mode == DRV260X_ERM_MODE && | ||
568 | (haptics->library == DRV260X_LIB_EMPTY || | ||
569 | haptics->library == DRV260X_LIB_LRA)) { | ||
570 | dev_err(&client->dev, | ||
571 | "ERM Mode with LRA Library mismatch\n"); | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | |||
575 | haptics->regulator = devm_regulator_get(&client->dev, "vbat"); | ||
576 | if (IS_ERR(haptics->regulator)) { | ||
577 | error = PTR_ERR(haptics->regulator); | ||
578 | dev_err(&client->dev, | ||
579 | "unable to get regulator, error: %d\n", error); | ||
580 | return error; | ||
581 | } | ||
582 | |||
583 | haptics->enable_gpio = devm_gpiod_get(&client->dev, "enable"); | ||
584 | if (IS_ERR(haptics->enable_gpio)) { | ||
585 | error = PTR_ERR(haptics->enable_gpio); | ||
586 | if (error != -ENOENT && error != -ENOSYS) | ||
587 | return error; | ||
588 | haptics->enable_gpio = NULL; | ||
589 | } else { | ||
590 | gpiod_direction_output(haptics->enable_gpio, 1); | ||
591 | } | ||
592 | |||
593 | haptics->input_dev = devm_input_allocate_device(&client->dev); | ||
594 | if (!haptics->input_dev) { | ||
595 | dev_err(&client->dev, "Failed to allocate input device\n"); | ||
596 | return -ENOMEM; | ||
597 | } | ||
598 | |||
599 | haptics->input_dev->name = "drv260x:haptics"; | ||
600 | haptics->input_dev->dev.parent = client->dev.parent; | ||
601 | haptics->input_dev->close = drv260x_close; | ||
602 | input_set_drvdata(haptics->input_dev, haptics); | ||
603 | input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); | ||
604 | |||
605 | error = input_ff_create_memless(haptics->input_dev, NULL, | ||
606 | drv260x_haptics_play); | ||
607 | if (error) { | ||
608 | dev_err(&client->dev, "input_ff_create() failed: %d\n", | ||
609 | error); | ||
610 | return error; | ||
611 | } | ||
612 | |||
613 | INIT_WORK(&haptics->work, drv260x_worker); | ||
614 | |||
615 | haptics->client = client; | ||
616 | i2c_set_clientdata(client, haptics); | ||
617 | |||
618 | haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config); | ||
619 | if (IS_ERR(haptics->regmap)) { | ||
620 | error = PTR_ERR(haptics->regmap); | ||
621 | dev_err(&client->dev, "Failed to allocate register map: %d\n", | ||
622 | error); | ||
623 | return error; | ||
624 | } | ||
625 | |||
626 | error = drv260x_init(haptics); | ||
627 | if (error) { | ||
628 | dev_err(&client->dev, "Device init failed: %d\n", error); | ||
629 | return error; | ||
630 | } | ||
631 | |||
632 | error = input_register_device(haptics->input_dev); | ||
633 | if (error) { | ||
634 | dev_err(&client->dev, "couldn't register input device: %d\n", | ||
635 | error); | ||
636 | return error; | ||
637 | } | ||
638 | |||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | #ifdef CONFIG_PM_SLEEP | ||
643 | static int drv260x_suspend(struct device *dev) | ||
644 | { | ||
645 | struct drv260x_data *haptics = dev_get_drvdata(dev); | ||
646 | int ret = 0; | ||
647 | |||
648 | mutex_lock(&haptics->input_dev->mutex); | ||
649 | |||
650 | if (haptics->input_dev->users) { | ||
651 | ret = regmap_update_bits(haptics->regmap, | ||
652 | DRV260X_MODE, | ||
653 | DRV260X_STANDBY_MASK, | ||
654 | DRV260X_STANDBY); | ||
655 | if (ret) { | ||
656 | dev_err(dev, "Failed to set standby mode\n"); | ||
657 | goto out; | ||
658 | } | ||
659 | |||
660 | gpiod_set_value(haptics->enable_gpio, 0); | ||
661 | |||
662 | ret = regulator_disable(haptics->regulator); | ||
663 | if (ret) { | ||
664 | dev_err(dev, "Failed to disable regulator\n"); | ||
665 | regmap_update_bits(haptics->regmap, | ||
666 | DRV260X_MODE, | ||
667 | DRV260X_STANDBY_MASK, 0); | ||
668 | } | ||
669 | } | ||
670 | out: | ||
671 | mutex_unlock(&haptics->input_dev->mutex); | ||
672 | return ret; | ||
673 | } | ||
674 | |||
675 | static int drv260x_resume(struct device *dev) | ||
676 | { | ||
677 | struct drv260x_data *haptics = dev_get_drvdata(dev); | ||
678 | int ret = 0; | ||
679 | |||
680 | mutex_lock(&haptics->input_dev->mutex); | ||
681 | |||
682 | if (haptics->input_dev->users) { | ||
683 | ret = regulator_enable(haptics->regulator); | ||
684 | if (ret) { | ||
685 | dev_err(dev, "Failed to enable regulator\n"); | ||
686 | goto out; | ||
687 | } | ||
688 | |||
689 | ret = regmap_update_bits(haptics->regmap, | ||
690 | DRV260X_MODE, | ||
691 | DRV260X_STANDBY_MASK, 0); | ||
692 | if (ret) { | ||
693 | dev_err(dev, "Failed to unset standby mode\n"); | ||
694 | regulator_disable(haptics->regulator); | ||
695 | goto out; | ||
696 | } | ||
697 | |||
698 | gpiod_set_value(haptics->enable_gpio, 1); | ||
699 | } | ||
700 | |||
701 | out: | ||
702 | mutex_unlock(&haptics->input_dev->mutex); | ||
703 | return ret; | ||
704 | } | ||
705 | #endif | ||
706 | |||
707 | static SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume); | ||
708 | |||
709 | static const struct i2c_device_id drv260x_id[] = { | ||
710 | { "drv2605l", 0 }, | ||
711 | { } | ||
712 | }; | ||
713 | MODULE_DEVICE_TABLE(i2c, drv260x_id); | ||
714 | |||
715 | #ifdef CONFIG_OF | ||
716 | static const struct of_device_id drv260x_of_match[] = { | ||
717 | { .compatible = "ti,drv2604", }, | ||
718 | { .compatible = "ti,drv2604l", }, | ||
719 | { .compatible = "ti,drv2605", }, | ||
720 | { .compatible = "ti,drv2605l", }, | ||
721 | { } | ||
722 | }; | ||
723 | MODULE_DEVICE_TABLE(of, drv260x_of_match); | ||
724 | #endif | ||
725 | |||
726 | static struct i2c_driver drv260x_driver = { | ||
727 | .probe = drv260x_probe, | ||
728 | .driver = { | ||
729 | .name = "drv260x-haptics", | ||
730 | .owner = THIS_MODULE, | ||
731 | .of_match_table = of_match_ptr(drv260x_of_match), | ||
732 | .pm = &drv260x_pm_ops, | ||
733 | }, | ||
734 | .id_table = drv260x_id, | ||
735 | }; | ||
736 | module_i2c_driver(drv260x_driver); | ||
737 | |||
738 | MODULE_ALIAS("platform:drv260x-haptics"); | ||
739 | MODULE_DESCRIPTION("TI DRV260x haptics driver"); | ||
740 | MODULE_LICENSE("GPL"); | ||
741 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); | ||
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c new file mode 100644 index 000000000000..0f437581cc04 --- /dev/null +++ b/drivers/input/misc/drv2667.c | |||
@@ -0,0 +1,500 @@ | |||
1 | /* | ||
2 | * DRV2667 haptics driver family | ||
3 | * | ||
4 | * Author: Dan Murphy <dmurphy@ti.com> | ||
5 | * | ||
6 | * Copyright: (C) 2014 Texas Instruments, Inc. | ||
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 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/regulator/consumer.h> | ||
26 | |||
27 | /* Contol registers */ | ||
28 | #define DRV2667_STATUS 0x00 | ||
29 | #define DRV2667_CTRL_1 0x01 | ||
30 | #define DRV2667_CTRL_2 0x02 | ||
31 | /* Waveform sequencer */ | ||
32 | #define DRV2667_WV_SEQ_0 0x03 | ||
33 | #define DRV2667_WV_SEQ_1 0x04 | ||
34 | #define DRV2667_WV_SEQ_2 0x05 | ||
35 | #define DRV2667_WV_SEQ_3 0x06 | ||
36 | #define DRV2667_WV_SEQ_4 0x07 | ||
37 | #define DRV2667_WV_SEQ_5 0x08 | ||
38 | #define DRV2667_WV_SEQ_6 0x09 | ||
39 | #define DRV2667_WV_SEQ_7 0x0A | ||
40 | #define DRV2667_FIFO 0x0B | ||
41 | #define DRV2667_PAGE 0xFF | ||
42 | #define DRV2667_MAX_REG DRV2667_PAGE | ||
43 | |||
44 | #define DRV2667_PAGE_0 0x00 | ||
45 | #define DRV2667_PAGE_1 0x01 | ||
46 | #define DRV2667_PAGE_2 0x02 | ||
47 | #define DRV2667_PAGE_3 0x03 | ||
48 | #define DRV2667_PAGE_4 0x04 | ||
49 | #define DRV2667_PAGE_5 0x05 | ||
50 | #define DRV2667_PAGE_6 0x06 | ||
51 | #define DRV2667_PAGE_7 0x07 | ||
52 | #define DRV2667_PAGE_8 0x08 | ||
53 | |||
54 | /* RAM fields */ | ||
55 | #define DRV2667_RAM_HDR_SZ 0x0 | ||
56 | /* RAM Header addresses */ | ||
57 | #define DRV2667_RAM_START_HI 0x01 | ||
58 | #define DRV2667_RAM_START_LO 0x02 | ||
59 | #define DRV2667_RAM_STOP_HI 0x03 | ||
60 | #define DRV2667_RAM_STOP_LO 0x04 | ||
61 | #define DRV2667_RAM_REPEAT_CT 0x05 | ||
62 | /* RAM data addresses */ | ||
63 | #define DRV2667_RAM_AMP 0x06 | ||
64 | #define DRV2667_RAM_FREQ 0x07 | ||
65 | #define DRV2667_RAM_DURATION 0x08 | ||
66 | #define DRV2667_RAM_ENVELOPE 0x09 | ||
67 | |||
68 | /* Control 1 Register */ | ||
69 | #define DRV2667_25_VPP_GAIN 0x00 | ||
70 | #define DRV2667_50_VPP_GAIN 0x01 | ||
71 | #define DRV2667_75_VPP_GAIN 0x02 | ||
72 | #define DRV2667_100_VPP_GAIN 0x03 | ||
73 | #define DRV2667_DIGITAL_IN 0xfc | ||
74 | #define DRV2667_ANALOG_IN (1 << 2) | ||
75 | |||
76 | /* Control 2 Register */ | ||
77 | #define DRV2667_GO (1 << 0) | ||
78 | #define DRV2667_STANDBY (1 << 6) | ||
79 | #define DRV2667_DEV_RST (1 << 7) | ||
80 | |||
81 | /* RAM Envelope settings */ | ||
82 | #define DRV2667_NO_ENV 0x00 | ||
83 | #define DRV2667_32_MS_ENV 0x01 | ||
84 | #define DRV2667_64_MS_ENV 0x02 | ||
85 | #define DRV2667_96_MS_ENV 0x03 | ||
86 | #define DRV2667_128_MS_ENV 0x04 | ||
87 | #define DRV2667_160_MS_ENV 0x05 | ||
88 | #define DRV2667_192_MS_ENV 0x06 | ||
89 | #define DRV2667_224_MS_ENV 0x07 | ||
90 | #define DRV2667_256_MS_ENV 0x08 | ||
91 | #define DRV2667_512_MS_ENV 0x09 | ||
92 | #define DRV2667_768_MS_ENV 0x0a | ||
93 | #define DRV2667_1024_MS_ENV 0x0b | ||
94 | #define DRV2667_1280_MS_ENV 0x0c | ||
95 | #define DRV2667_1536_MS_ENV 0x0d | ||
96 | #define DRV2667_1792_MS_ENV 0x0e | ||
97 | #define DRV2667_2048_MS_ENV 0x0f | ||
98 | |||
99 | /** | ||
100 | * struct drv2667_data - | ||
101 | * @input_dev - Pointer to the input device | ||
102 | * @client - Pointer to the I2C client | ||
103 | * @regmap - Register map of the device | ||
104 | * @work - Work item used to off load the enable/disable of the vibration | ||
105 | * @regulator - Pointer to the regulator for the IC | ||
106 | * @magnitude - Magnitude of the vibration event | ||
107 | **/ | ||
108 | struct drv2667_data { | ||
109 | struct input_dev *input_dev; | ||
110 | struct i2c_client *client; | ||
111 | struct regmap *regmap; | ||
112 | struct work_struct work; | ||
113 | struct regulator *regulator; | ||
114 | u32 page; | ||
115 | u32 magnitude; | ||
116 | u32 frequency; | ||
117 | }; | ||
118 | |||
119 | static struct reg_default drv2667_reg_defs[] = { | ||
120 | { DRV2667_STATUS, 0x02 }, | ||
121 | { DRV2667_CTRL_1, 0x28 }, | ||
122 | { DRV2667_CTRL_2, 0x40 }, | ||
123 | { DRV2667_WV_SEQ_0, 0x00 }, | ||
124 | { DRV2667_WV_SEQ_1, 0x00 }, | ||
125 | { DRV2667_WV_SEQ_2, 0x00 }, | ||
126 | { DRV2667_WV_SEQ_3, 0x00 }, | ||
127 | { DRV2667_WV_SEQ_4, 0x00 }, | ||
128 | { DRV2667_WV_SEQ_5, 0x00 }, | ||
129 | { DRV2667_WV_SEQ_6, 0x00 }, | ||
130 | { DRV2667_WV_SEQ_7, 0x00 }, | ||
131 | { DRV2667_FIFO, 0x00 }, | ||
132 | { DRV2667_PAGE, 0x00 }, | ||
133 | }; | ||
134 | |||
135 | static int drv2667_set_waveform_freq(struct drv2667_data *haptics) | ||
136 | { | ||
137 | unsigned int read_buf; | ||
138 | int freq; | ||
139 | int error; | ||
140 | |||
141 | /* Per the data sheet: | ||
142 | * Sinusoid Frequency (Hz) = 7.8125 x Frequency | ||
143 | */ | ||
144 | freq = (haptics->frequency * 1000) / 78125; | ||
145 | if (freq <= 0) { | ||
146 | dev_err(&haptics->client->dev, | ||
147 | "ERROR: Frequency calculated to %i\n", freq); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | error = regmap_read(haptics->regmap, DRV2667_PAGE, &read_buf); | ||
152 | if (error) { | ||
153 | dev_err(&haptics->client->dev, | ||
154 | "Failed to read the page number: %d\n", error); | ||
155 | return -EIO; | ||
156 | } | ||
157 | |||
158 | if (read_buf == DRV2667_PAGE_0 || | ||
159 | haptics->page != read_buf) { | ||
160 | error = regmap_write(haptics->regmap, | ||
161 | DRV2667_PAGE, haptics->page); | ||
162 | if (error) { | ||
163 | dev_err(&haptics->client->dev, | ||
164 | "Failed to set the page: %d\n", error); | ||
165 | return -EIO; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | error = regmap_write(haptics->regmap, DRV2667_RAM_FREQ, freq); | ||
170 | if (error) | ||
171 | dev_err(&haptics->client->dev, | ||
172 | "Failed to set the frequency: %d\n", error); | ||
173 | |||
174 | /* Reset back to original page */ | ||
175 | if (read_buf == DRV2667_PAGE_0 || | ||
176 | haptics->page != read_buf) { | ||
177 | error = regmap_write(haptics->regmap, DRV2667_PAGE, read_buf); | ||
178 | if (error) { | ||
179 | dev_err(&haptics->client->dev, | ||
180 | "Failed to set the page: %d\n", error); | ||
181 | return -EIO; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | return error; | ||
186 | } | ||
187 | |||
188 | static void drv2667_worker(struct work_struct *work) | ||
189 | { | ||
190 | struct drv2667_data *haptics = container_of(work, struct drv2667_data, work); | ||
191 | int error; | ||
192 | |||
193 | if (haptics->magnitude) { | ||
194 | error = regmap_write(haptics->regmap, | ||
195 | DRV2667_PAGE, haptics->page); | ||
196 | if (error) { | ||
197 | dev_err(&haptics->client->dev, | ||
198 | "Failed to set the page: %d\n", error); | ||
199 | return; | ||
200 | } | ||
201 | |||
202 | error = regmap_write(haptics->regmap, DRV2667_RAM_AMP, | ||
203 | haptics->magnitude); | ||
204 | if (error) { | ||
205 | dev_err(&haptics->client->dev, | ||
206 | "Failed to set the amplitude: %d\n", error); | ||
207 | return; | ||
208 | } | ||
209 | |||
210 | error = regmap_write(haptics->regmap, | ||
211 | DRV2667_PAGE, DRV2667_PAGE_0); | ||
212 | if (error) { | ||
213 | dev_err(&haptics->client->dev, | ||
214 | "Failed to set the page: %d\n", error); | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | error = regmap_write(haptics->regmap, | ||
219 | DRV2667_CTRL_2, DRV2667_GO); | ||
220 | if (error) { | ||
221 | dev_err(&haptics->client->dev, | ||
222 | "Failed to set the GO bit: %d\n", error); | ||
223 | } | ||
224 | } else { | ||
225 | error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, | ||
226 | DRV2667_GO, 0); | ||
227 | if (error) { | ||
228 | dev_err(&haptics->client->dev, | ||
229 | "Failed to unset the GO bit: %d\n", error); | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static int drv2667_haptics_play(struct input_dev *input, void *data, | ||
235 | struct ff_effect *effect) | ||
236 | { | ||
237 | struct drv2667_data *haptics = input_get_drvdata(input); | ||
238 | |||
239 | if (effect->u.rumble.strong_magnitude > 0) | ||
240 | haptics->magnitude = effect->u.rumble.strong_magnitude; | ||
241 | else if (effect->u.rumble.weak_magnitude > 0) | ||
242 | haptics->magnitude = effect->u.rumble.weak_magnitude; | ||
243 | else | ||
244 | haptics->magnitude = 0; | ||
245 | |||
246 | schedule_work(&haptics->work); | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static void drv2667_close(struct input_dev *input) | ||
252 | { | ||
253 | struct drv2667_data *haptics = input_get_drvdata(input); | ||
254 | int error; | ||
255 | |||
256 | cancel_work_sync(&haptics->work); | ||
257 | |||
258 | error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, | ||
259 | DRV2667_STANDBY, 1); | ||
260 | if (error) | ||
261 | dev_err(&haptics->client->dev, | ||
262 | "Failed to enter standby mode: %d\n", error); | ||
263 | } | ||
264 | |||
265 | static const struct reg_default drv2667_init_regs[] = { | ||
266 | { DRV2667_CTRL_2, 0 }, | ||
267 | { DRV2667_CTRL_1, DRV2667_25_VPP_GAIN }, | ||
268 | { DRV2667_WV_SEQ_0, 1 }, | ||
269 | { DRV2667_WV_SEQ_1, 0 } | ||
270 | }; | ||
271 | |||
272 | static const struct reg_default drv2667_page1_init[] = { | ||
273 | { DRV2667_RAM_HDR_SZ, 0x05 }, | ||
274 | { DRV2667_RAM_START_HI, 0x80 }, | ||
275 | { DRV2667_RAM_START_LO, 0x06 }, | ||
276 | { DRV2667_RAM_STOP_HI, 0x00 }, | ||
277 | { DRV2667_RAM_STOP_LO, 0x09 }, | ||
278 | { DRV2667_RAM_REPEAT_CT, 0 }, | ||
279 | { DRV2667_RAM_DURATION, 0x05 }, | ||
280 | { DRV2667_RAM_ENVELOPE, DRV2667_NO_ENV }, | ||
281 | { DRV2667_RAM_AMP, 0x60 }, | ||
282 | }; | ||
283 | |||
284 | static int drv2667_init(struct drv2667_data *haptics) | ||
285 | { | ||
286 | int error; | ||
287 | |||
288 | /* Set default haptic frequency to 195Hz on Page 1*/ | ||
289 | haptics->frequency = 195; | ||
290 | haptics->page = DRV2667_PAGE_1; | ||
291 | |||
292 | error = regmap_register_patch(haptics->regmap, | ||
293 | drv2667_init_regs, | ||
294 | ARRAY_SIZE(drv2667_init_regs)); | ||
295 | if (error) { | ||
296 | dev_err(&haptics->client->dev, | ||
297 | "Failed to write init registers: %d\n", | ||
298 | error); | ||
299 | return error; | ||
300 | } | ||
301 | |||
302 | error = regmap_write(haptics->regmap, DRV2667_PAGE, haptics->page); | ||
303 | if (error) { | ||
304 | dev_err(&haptics->client->dev, "Failed to set page: %d\n", | ||
305 | error); | ||
306 | goto error_out; | ||
307 | } | ||
308 | |||
309 | error = drv2667_set_waveform_freq(haptics); | ||
310 | if (error) | ||
311 | goto error_page; | ||
312 | |||
313 | error = regmap_register_patch(haptics->regmap, | ||
314 | drv2667_page1_init, | ||
315 | ARRAY_SIZE(drv2667_page1_init)); | ||
316 | if (error) { | ||
317 | dev_err(&haptics->client->dev, | ||
318 | "Failed to write page registers: %d\n", | ||
319 | error); | ||
320 | return error; | ||
321 | } | ||
322 | |||
323 | error = regmap_write(haptics->regmap, DRV2667_PAGE, DRV2667_PAGE_0); | ||
324 | return error; | ||
325 | |||
326 | error_page: | ||
327 | regmap_write(haptics->regmap, DRV2667_PAGE, DRV2667_PAGE_0); | ||
328 | error_out: | ||
329 | return error; | ||
330 | } | ||
331 | |||
332 | static const struct regmap_config drv2667_regmap_config = { | ||
333 | .reg_bits = 8, | ||
334 | .val_bits = 8, | ||
335 | |||
336 | .max_register = DRV2667_MAX_REG, | ||
337 | .reg_defaults = drv2667_reg_defs, | ||
338 | .num_reg_defaults = ARRAY_SIZE(drv2667_reg_defs), | ||
339 | .cache_type = REGCACHE_NONE, | ||
340 | }; | ||
341 | |||
342 | static int drv2667_probe(struct i2c_client *client, | ||
343 | const struct i2c_device_id *id) | ||
344 | { | ||
345 | struct drv2667_data *haptics; | ||
346 | int error; | ||
347 | |||
348 | haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL); | ||
349 | if (!haptics) | ||
350 | return -ENOMEM; | ||
351 | |||
352 | haptics->regulator = devm_regulator_get(&client->dev, "vbat"); | ||
353 | if (IS_ERR(haptics->regulator)) { | ||
354 | error = PTR_ERR(haptics->regulator); | ||
355 | dev_err(&client->dev, | ||
356 | "unable to get regulator, error: %d\n", error); | ||
357 | return error; | ||
358 | } | ||
359 | |||
360 | haptics->input_dev = devm_input_allocate_device(&client->dev); | ||
361 | if (!haptics->input_dev) { | ||
362 | dev_err(&client->dev, "Failed to allocate input device\n"); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | |||
366 | haptics->input_dev->name = "drv2667:haptics"; | ||
367 | haptics->input_dev->dev.parent = client->dev.parent; | ||
368 | haptics->input_dev->close = drv2667_close; | ||
369 | input_set_drvdata(haptics->input_dev, haptics); | ||
370 | input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); | ||
371 | |||
372 | error = input_ff_create_memless(haptics->input_dev, NULL, | ||
373 | drv2667_haptics_play); | ||
374 | if (error) { | ||
375 | dev_err(&client->dev, "input_ff_create() failed: %d\n", | ||
376 | error); | ||
377 | return error; | ||
378 | } | ||
379 | |||
380 | INIT_WORK(&haptics->work, drv2667_worker); | ||
381 | |||
382 | haptics->client = client; | ||
383 | i2c_set_clientdata(client, haptics); | ||
384 | |||
385 | haptics->regmap = devm_regmap_init_i2c(client, &drv2667_regmap_config); | ||
386 | if (IS_ERR(haptics->regmap)) { | ||
387 | error = PTR_ERR(haptics->regmap); | ||
388 | dev_err(&client->dev, "Failed to allocate register map: %d\n", | ||
389 | error); | ||
390 | return error; | ||
391 | } | ||
392 | |||
393 | error = drv2667_init(haptics); | ||
394 | if (error) { | ||
395 | dev_err(&client->dev, "Device init failed: %d\n", error); | ||
396 | return error; | ||
397 | } | ||
398 | |||
399 | error = input_register_device(haptics->input_dev); | ||
400 | if (error) { | ||
401 | dev_err(&client->dev, "couldn't register input device: %d\n", | ||
402 | error); | ||
403 | return error; | ||
404 | } | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | #ifdef CONFIG_PM_SLEEP | ||
410 | static int drv2667_suspend(struct device *dev) | ||
411 | { | ||
412 | struct drv2667_data *haptics = dev_get_drvdata(dev); | ||
413 | int ret = 0; | ||
414 | |||
415 | mutex_lock(&haptics->input_dev->mutex); | ||
416 | |||
417 | if (haptics->input_dev->users) { | ||
418 | ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, | ||
419 | DRV2667_STANDBY, 1); | ||
420 | if (ret) { | ||
421 | dev_err(dev, "Failed to set standby mode\n"); | ||
422 | regulator_disable(haptics->regulator); | ||
423 | goto out; | ||
424 | } | ||
425 | |||
426 | ret = regulator_disable(haptics->regulator); | ||
427 | if (ret) { | ||
428 | dev_err(dev, "Failed to disable regulator\n"); | ||
429 | regmap_update_bits(haptics->regmap, | ||
430 | DRV2667_CTRL_2, | ||
431 | DRV2667_STANDBY, 0); | ||
432 | } | ||
433 | } | ||
434 | out: | ||
435 | mutex_unlock(&haptics->input_dev->mutex); | ||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | static int drv2667_resume(struct device *dev) | ||
440 | { | ||
441 | struct drv2667_data *haptics = dev_get_drvdata(dev); | ||
442 | int ret = 0; | ||
443 | |||
444 | mutex_lock(&haptics->input_dev->mutex); | ||
445 | |||
446 | if (haptics->input_dev->users) { | ||
447 | ret = regulator_enable(haptics->regulator); | ||
448 | if (ret) { | ||
449 | dev_err(dev, "Failed to enable regulator\n"); | ||
450 | goto out; | ||
451 | } | ||
452 | |||
453 | ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, | ||
454 | DRV2667_STANDBY, 0); | ||
455 | if (ret) { | ||
456 | dev_err(dev, "Failed to unset standby mode\n"); | ||
457 | regulator_disable(haptics->regulator); | ||
458 | goto out; | ||
459 | } | ||
460 | |||
461 | } | ||
462 | |||
463 | out: | ||
464 | mutex_unlock(&haptics->input_dev->mutex); | ||
465 | return ret; | ||
466 | } | ||
467 | #endif | ||
468 | |||
469 | static SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume); | ||
470 | |||
471 | static const struct i2c_device_id drv2667_id[] = { | ||
472 | { "drv2667", 0 }, | ||
473 | { } | ||
474 | }; | ||
475 | MODULE_DEVICE_TABLE(i2c, drv2667_id); | ||
476 | |||
477 | #ifdef CONFIG_OF | ||
478 | static const struct of_device_id drv2667_of_match[] = { | ||
479 | { .compatible = "ti,drv2667", }, | ||
480 | { } | ||
481 | }; | ||
482 | MODULE_DEVICE_TABLE(of, drv2667_of_match); | ||
483 | #endif | ||
484 | |||
485 | static struct i2c_driver drv2667_driver = { | ||
486 | .probe = drv2667_probe, | ||
487 | .driver = { | ||
488 | .name = "drv2667-haptics", | ||
489 | .owner = THIS_MODULE, | ||
490 | .of_match_table = of_match_ptr(drv2667_of_match), | ||
491 | .pm = &drv2667_pm_ops, | ||
492 | }, | ||
493 | .id_table = drv2667_id, | ||
494 | }; | ||
495 | module_i2c_driver(drv2667_driver); | ||
496 | |||
497 | MODULE_ALIAS("platform:drv2667-haptics"); | ||
498 | MODULE_DESCRIPTION("TI DRV2667 haptics driver"); | ||
499 | MODULE_LICENSE("GPL"); | ||
500 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); | ||
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c new file mode 100644 index 000000000000..d605db4d2f39 --- /dev/null +++ b/drivers/input/misc/max77693-haptic.c | |||
@@ -0,0 +1,357 @@ | |||
1 | /* | ||
2 | * MAXIM MAX77693 Haptic device driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Samsung Electronics | ||
5 | * Jaewon Kim <jaewon02.kim@samsung.com> | ||
6 | * | ||
7 | * This program is not provided / owned by Maxim Integrated Products. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/err.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/pwm.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/regulator/consumer.h> | ||
26 | #include <linux/mfd/max77693.h> | ||
27 | #include <linux/mfd/max77693-private.h> | ||
28 | |||
29 | #define MAX_MAGNITUDE_SHIFT 16 | ||
30 | |||
31 | enum max77693_haptic_motor_type { | ||
32 | MAX77693_HAPTIC_ERM = 0, | ||
33 | MAX77693_HAPTIC_LRA, | ||
34 | }; | ||
35 | |||
36 | enum max77693_haptic_pulse_mode { | ||
37 | MAX77693_HAPTIC_EXTERNAL_MODE = 0, | ||
38 | MAX77693_HAPTIC_INTERNAL_MODE, | ||
39 | }; | ||
40 | |||
41 | enum max77693_haptic_pwm_divisor { | ||
42 | MAX77693_HAPTIC_PWM_DIVISOR_32 = 0, | ||
43 | MAX77693_HAPTIC_PWM_DIVISOR_64, | ||
44 | MAX77693_HAPTIC_PWM_DIVISOR_128, | ||
45 | MAX77693_HAPTIC_PWM_DIVISOR_256, | ||
46 | }; | ||
47 | |||
48 | struct max77693_haptic { | ||
49 | struct regmap *regmap_pmic; | ||
50 | struct regmap *regmap_haptic; | ||
51 | struct device *dev; | ||
52 | struct input_dev *input_dev; | ||
53 | struct pwm_device *pwm_dev; | ||
54 | struct regulator *motor_reg; | ||
55 | |||
56 | bool enabled; | ||
57 | bool suspend_state; | ||
58 | unsigned int magnitude; | ||
59 | unsigned int pwm_duty; | ||
60 | enum max77693_haptic_motor_type type; | ||
61 | enum max77693_haptic_pulse_mode mode; | ||
62 | enum max77693_haptic_pwm_divisor pwm_divisor; | ||
63 | |||
64 | struct work_struct work; | ||
65 | }; | ||
66 | |||
67 | static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) | ||
68 | { | ||
69 | int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2; | ||
70 | int error; | ||
71 | |||
72 | error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period); | ||
73 | if (error) { | ||
74 | dev_err(haptic->dev, "failed to configure pwm: %d\n", error); | ||
75 | return error; | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int max77693_haptic_configure(struct max77693_haptic *haptic, | ||
82 | bool enable) | ||
83 | { | ||
84 | unsigned int value; | ||
85 | int error; | ||
86 | |||
87 | value = ((haptic->type << MAX77693_CONFIG2_MODE) | | ||
88 | (enable << MAX77693_CONFIG2_MEN) | | ||
89 | (haptic->mode << MAX77693_CONFIG2_HTYP) | | ||
90 | (haptic->pwm_divisor)); | ||
91 | |||
92 | error = regmap_write(haptic->regmap_haptic, | ||
93 | MAX77693_HAPTIC_REG_CONFIG2, value); | ||
94 | if (error) { | ||
95 | dev_err(haptic->dev, | ||
96 | "failed to update haptic config: %d\n", error); | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable) | ||
104 | { | ||
105 | int error; | ||
106 | |||
107 | error = regmap_update_bits(haptic->regmap_pmic, | ||
108 | MAX77693_PMIC_REG_LSCNFG, | ||
109 | MAX77693_PMIC_LOW_SYS_MASK, | ||
110 | enable << MAX77693_PMIC_LOW_SYS_SHIFT); | ||
111 | if (error) { | ||
112 | dev_err(haptic->dev, "cannot update pmic regmap: %d\n", error); | ||
113 | return error; | ||
114 | } | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void max77693_haptic_enable(struct max77693_haptic *haptic) | ||
120 | { | ||
121 | int error; | ||
122 | |||
123 | if (haptic->enabled) | ||
124 | return; | ||
125 | |||
126 | error = pwm_enable(haptic->pwm_dev); | ||
127 | if (error) { | ||
128 | dev_err(haptic->dev, | ||
129 | "failed to enable haptic pwm device: %d\n", error); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | error = max77693_haptic_lowsys(haptic, true); | ||
134 | if (error) | ||
135 | goto err_enable_lowsys; | ||
136 | |||
137 | error = max77693_haptic_configure(haptic, true); | ||
138 | if (error) | ||
139 | goto err_enable_config; | ||
140 | |||
141 | haptic->enabled = true; | ||
142 | |||
143 | return; | ||
144 | |||
145 | err_enable_config: | ||
146 | max77693_haptic_lowsys(haptic, false); | ||
147 | err_enable_lowsys: | ||
148 | pwm_disable(haptic->pwm_dev); | ||
149 | } | ||
150 | |||
151 | static void max77693_haptic_disable(struct max77693_haptic *haptic) | ||
152 | { | ||
153 | int error; | ||
154 | |||
155 | if (haptic->enabled) | ||
156 | return; | ||
157 | |||
158 | error = max77693_haptic_configure(haptic, false); | ||
159 | if (error) | ||
160 | return; | ||
161 | |||
162 | error = max77693_haptic_lowsys(haptic, false); | ||
163 | if (error) | ||
164 | goto err_disable_lowsys; | ||
165 | |||
166 | pwm_disable(haptic->pwm_dev); | ||
167 | haptic->enabled = false; | ||
168 | |||
169 | return; | ||
170 | |||
171 | err_disable_lowsys: | ||
172 | max77693_haptic_configure(haptic, true); | ||
173 | } | ||
174 | |||
175 | static void max77693_haptic_play_work(struct work_struct *work) | ||
176 | { | ||
177 | struct max77693_haptic *haptic = | ||
178 | container_of(work, struct max77693_haptic, work); | ||
179 | int error; | ||
180 | |||
181 | error = max77693_haptic_set_duty_cycle(haptic); | ||
182 | if (error) { | ||
183 | dev_err(haptic->dev, "failed to set duty cycle: %d\n", error); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | if (haptic->magnitude) | ||
188 | max77693_haptic_enable(haptic); | ||
189 | else | ||
190 | max77693_haptic_disable(haptic); | ||
191 | } | ||
192 | |||
193 | static int max77693_haptic_play_effect(struct input_dev *dev, void *data, | ||
194 | struct ff_effect *effect) | ||
195 | { | ||
196 | struct max77693_haptic *haptic = input_get_drvdata(dev); | ||
197 | uint64_t period_mag_multi; | ||
198 | |||
199 | haptic->magnitude = effect->u.rumble.strong_magnitude; | ||
200 | if (!haptic->magnitude) | ||
201 | haptic->magnitude = effect->u.rumble.weak_magnitude; | ||
202 | |||
203 | /* | ||
204 | * The magnitude comes from force-feedback interface. | ||
205 | * The formula to convert magnitude to pwm_duty as follows: | ||
206 | * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF) | ||
207 | */ | ||
208 | period_mag_multi = (int64_t)(haptic->pwm_dev->period * | ||
209 | haptic->magnitude); | ||
210 | haptic->pwm_duty = (unsigned int)(period_mag_multi >> | ||
211 | MAX_MAGNITUDE_SHIFT); | ||
212 | |||
213 | schedule_work(&haptic->work); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int max77693_haptic_open(struct input_dev *dev) | ||
219 | { | ||
220 | struct max77693_haptic *haptic = input_get_drvdata(dev); | ||
221 | int error; | ||
222 | |||
223 | error = regulator_enable(haptic->motor_reg); | ||
224 | if (error) { | ||
225 | dev_err(haptic->dev, | ||
226 | "failed to enable regulator: %d\n", error); | ||
227 | return error; | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static void max77693_haptic_close(struct input_dev *dev) | ||
234 | { | ||
235 | struct max77693_haptic *haptic = input_get_drvdata(dev); | ||
236 | int error; | ||
237 | |||
238 | cancel_work_sync(&haptic->work); | ||
239 | max77693_haptic_disable(haptic); | ||
240 | |||
241 | error = regulator_disable(haptic->motor_reg); | ||
242 | if (error) | ||
243 | dev_err(haptic->dev, | ||
244 | "failed to disable regulator: %d\n", error); | ||
245 | } | ||
246 | |||
247 | static int max77693_haptic_probe(struct platform_device *pdev) | ||
248 | { | ||
249 | struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); | ||
250 | struct max77693_haptic *haptic; | ||
251 | int error; | ||
252 | |||
253 | haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); | ||
254 | if (!haptic) | ||
255 | return -ENOMEM; | ||
256 | |||
257 | haptic->regmap_pmic = max77693->regmap; | ||
258 | haptic->regmap_haptic = max77693->regmap_haptic; | ||
259 | haptic->dev = &pdev->dev; | ||
260 | haptic->type = MAX77693_HAPTIC_LRA; | ||
261 | haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE; | ||
262 | haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128; | ||
263 | haptic->suspend_state = false; | ||
264 | |||
265 | INIT_WORK(&haptic->work, max77693_haptic_play_work); | ||
266 | |||
267 | /* Get pwm and regulatot for haptic device */ | ||
268 | haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL); | ||
269 | if (IS_ERR(haptic->pwm_dev)) { | ||
270 | dev_err(&pdev->dev, "failed to get pwm device\n"); | ||
271 | return PTR_ERR(haptic->pwm_dev); | ||
272 | } | ||
273 | |||
274 | haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic"); | ||
275 | if (IS_ERR(haptic->motor_reg)) { | ||
276 | dev_err(&pdev->dev, "failed to get regulator\n"); | ||
277 | return PTR_ERR(haptic->motor_reg); | ||
278 | } | ||
279 | |||
280 | /* Initialize input device for haptic device */ | ||
281 | haptic->input_dev = devm_input_allocate_device(&pdev->dev); | ||
282 | if (!haptic->input_dev) { | ||
283 | dev_err(&pdev->dev, "failed to allocate input device\n"); | ||
284 | return -ENOMEM; | ||
285 | } | ||
286 | |||
287 | haptic->input_dev->name = "max77693-haptic"; | ||
288 | haptic->input_dev->id.version = 1; | ||
289 | haptic->input_dev->dev.parent = &pdev->dev; | ||
290 | haptic->input_dev->open = max77693_haptic_open; | ||
291 | haptic->input_dev->close = max77693_haptic_close; | ||
292 | input_set_drvdata(haptic->input_dev, haptic); | ||
293 | input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); | ||
294 | |||
295 | error = input_ff_create_memless(haptic->input_dev, NULL, | ||
296 | max77693_haptic_play_effect); | ||
297 | if (error) { | ||
298 | dev_err(&pdev->dev, "failed to create force-feedback\n"); | ||
299 | return error; | ||
300 | } | ||
301 | |||
302 | error = input_register_device(haptic->input_dev); | ||
303 | if (error) { | ||
304 | dev_err(&pdev->dev, "failed to register input device\n"); | ||
305 | return error; | ||
306 | } | ||
307 | |||
308 | platform_set_drvdata(pdev, haptic); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | #ifdef CONFIG_PM_SLEEP | ||
314 | static int max77693_haptic_suspend(struct device *dev) | ||
315 | { | ||
316 | struct platform_device *pdev = to_platform_device(dev); | ||
317 | struct max77693_haptic *haptic = platform_get_drvdata(pdev); | ||
318 | |||
319 | if (haptic->enabled) { | ||
320 | max77693_haptic_disable(haptic); | ||
321 | haptic->suspend_state = true; | ||
322 | } | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int max77693_haptic_resume(struct device *dev) | ||
328 | { | ||
329 | struct platform_device *pdev = to_platform_device(dev); | ||
330 | struct max77693_haptic *haptic = platform_get_drvdata(pdev); | ||
331 | |||
332 | if (haptic->suspend_state) { | ||
333 | max77693_haptic_enable(haptic); | ||
334 | haptic->suspend_state = false; | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | #endif | ||
340 | |||
341 | static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, | ||
342 | max77693_haptic_suspend, max77693_haptic_resume); | ||
343 | |||
344 | static struct platform_driver max77693_haptic_driver = { | ||
345 | .driver = { | ||
346 | .name = "max77693-haptic", | ||
347 | .owner = THIS_MODULE, | ||
348 | .pm = &max77693_haptic_pm_ops, | ||
349 | }, | ||
350 | .probe = max77693_haptic_probe, | ||
351 | }; | ||
352 | module_platform_driver(max77693_haptic_driver); | ||
353 | |||
354 | MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); | ||
355 | MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver"); | ||
356 | MODULE_ALIAS("platform:max77693-haptic"); | ||
357 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c new file mode 100644 index 000000000000..f505ac3a8d87 --- /dev/null +++ b/drivers/input/misc/palmas-pwrbutton.c | |||
@@ -0,0 +1,332 @@ | |||
1 | /* | ||
2 | * Texas Instruments' Palmas Power Button Input Driver | ||
3 | * | ||
4 | * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Girish S Ghongdemath | ||
6 | * Nishanth Menon | ||
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 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
13 | * kind, whether express or implied; without even the implied warranty | ||
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/mfd/palmas.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #define PALMAS_LPK_TIME_MASK 0x0c | ||
29 | #define PALMAS_PWRON_DEBOUNCE_MASK 0x03 | ||
30 | #define PALMAS_PWR_KEY_Q_TIME_MS 20 | ||
31 | |||
32 | /** | ||
33 | * struct palmas_pwron - Palmas power on data | ||
34 | * @palmas: pointer to palmas device | ||
35 | * @input_dev: pointer to input device | ||
36 | * @input_work: work for detecting release of key | ||
37 | * @irq: irq that we are hooked on to | ||
38 | */ | ||
39 | struct palmas_pwron { | ||
40 | struct palmas *palmas; | ||
41 | struct input_dev *input_dev; | ||
42 | struct delayed_work input_work; | ||
43 | int irq; | ||
44 | }; | ||
45 | |||
46 | /** | ||
47 | * struct palmas_pwron_config - configuration of palmas power on | ||
48 | * @long_press_time_val: value for long press h/w shutdown event | ||
49 | * @pwron_debounce_val: value for debounce of power button | ||
50 | */ | ||
51 | struct palmas_pwron_config { | ||
52 | u8 long_press_time_val; | ||
53 | u8 pwron_debounce_val; | ||
54 | }; | ||
55 | |||
56 | /** | ||
57 | * palmas_power_button_work() - Detects the button release event | ||
58 | * @work: work item to detect button release | ||
59 | */ | ||
60 | static void palmas_power_button_work(struct work_struct *work) | ||
61 | { | ||
62 | struct palmas_pwron *pwron = container_of(work, | ||
63 | struct palmas_pwron, | ||
64 | input_work.work); | ||
65 | struct input_dev *input_dev = pwron->input_dev; | ||
66 | unsigned int reg; | ||
67 | int error; | ||
68 | |||
69 | error = palmas_read(pwron->palmas, PALMAS_INTERRUPT_BASE, | ||
70 | PALMAS_INT1_LINE_STATE, ®); | ||
71 | if (error) { | ||
72 | dev_err(input_dev->dev.parent, | ||
73 | "Cannot read palmas PWRON status: %d\n", error); | ||
74 | } else if (reg & BIT(1)) { | ||
75 | /* The button is released, report event. */ | ||
76 | input_report_key(input_dev, KEY_POWER, 0); | ||
77 | input_sync(input_dev); | ||
78 | } else { | ||
79 | /* The button is still depressed, keep checking. */ | ||
80 | schedule_delayed_work(&pwron->input_work, | ||
81 | msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS)); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * pwron_irq() - button press isr | ||
87 | * @irq: irq | ||
88 | * @palmas_pwron: pwron struct | ||
89 | * | ||
90 | * Return: IRQ_HANDLED | ||
91 | */ | ||
92 | static irqreturn_t pwron_irq(int irq, void *palmas_pwron) | ||
93 | { | ||
94 | struct palmas_pwron *pwron = palmas_pwron; | ||
95 | struct input_dev *input_dev = pwron->input_dev; | ||
96 | |||
97 | input_report_key(input_dev, KEY_POWER, 1); | ||
98 | pm_wakeup_event(input_dev->dev.parent, 0); | ||
99 | input_sync(input_dev); | ||
100 | |||
101 | mod_delayed_work(system_wq, &pwron->input_work, | ||
102 | msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS)); | ||
103 | |||
104 | return IRQ_HANDLED; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * palmas_pwron_params_ofinit() - device tree parameter parser | ||
109 | * @dev: palmas button device | ||
110 | * @config: configuration params that this fills up | ||
111 | */ | ||
112 | static void palmas_pwron_params_ofinit(struct device *dev, | ||
113 | struct palmas_pwron_config *config) | ||
114 | { | ||
115 | struct device_node *np; | ||
116 | u32 val; | ||
117 | int i, error; | ||
118 | u8 lpk_times[] = { 6, 8, 10, 12 }; | ||
119 | int pwr_on_deb_ms[] = { 15, 100, 500, 1000 }; | ||
120 | |||
121 | memset(config, 0, sizeof(*config)); | ||
122 | |||
123 | /* Default config parameters */ | ||
124 | config->long_press_time_val = ARRAY_SIZE(lpk_times) - 1; | ||
125 | |||
126 | np = dev->of_node; | ||
127 | if (!np) | ||
128 | return; | ||
129 | |||
130 | error = of_property_read_u32(np, "ti,palmas-long-press-seconds", &val); | ||
131 | if (!error) { | ||
132 | for (i = 0; i < ARRAY_SIZE(lpk_times); i++) { | ||
133 | if (val <= lpk_times[i]) { | ||
134 | config->long_press_time_val = i; | ||
135 | break; | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | error = of_property_read_u32(np, | ||
141 | "ti,palmas-pwron-debounce-milli-seconds", | ||
142 | &val); | ||
143 | if (!error) { | ||
144 | for (i = 0; i < ARRAY_SIZE(pwr_on_deb_ms); i++) { | ||
145 | if (val <= pwr_on_deb_ms[i]) { | ||
146 | config->pwron_debounce_val = i; | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | dev_info(dev, "h/w controlled shutdown duration=%d seconds\n", | ||
153 | lpk_times[config->long_press_time_val]); | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * palmas_pwron_probe() - probe | ||
158 | * @pdev: platform device for the button | ||
159 | * | ||
160 | * Return: 0 for successful probe else appropriate error | ||
161 | */ | ||
162 | static int palmas_pwron_probe(struct platform_device *pdev) | ||
163 | { | ||
164 | struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); | ||
165 | struct device *dev = &pdev->dev; | ||
166 | struct input_dev *input_dev; | ||
167 | struct palmas_pwron *pwron; | ||
168 | struct palmas_pwron_config config; | ||
169 | int val; | ||
170 | int error; | ||
171 | |||
172 | palmas_pwron_params_ofinit(dev, &config); | ||
173 | |||
174 | pwron = kzalloc(sizeof(*pwron), GFP_KERNEL); | ||
175 | if (!pwron) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | input_dev = input_allocate_device(); | ||
179 | if (!input_dev) { | ||
180 | dev_err(dev, "Can't allocate power button\n"); | ||
181 | error = -ENOMEM; | ||
182 | goto err_free_mem; | ||
183 | } | ||
184 | |||
185 | input_dev->name = "palmas_pwron"; | ||
186 | input_dev->phys = "palmas_pwron/input0"; | ||
187 | input_dev->dev.parent = dev; | ||
188 | |||
189 | input_set_capability(input_dev, EV_KEY, KEY_POWER); | ||
190 | |||
191 | /* | ||
192 | * Setup default hardware shutdown option (long key press) | ||
193 | * and debounce. | ||
194 | */ | ||
195 | val = config.long_press_time_val << __ffs(PALMAS_LPK_TIME_MASK); | ||
196 | val |= config.pwron_debounce_val << __ffs(PALMAS_PWRON_DEBOUNCE_MASK); | ||
197 | error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, | ||
198 | PALMAS_LONG_PRESS_KEY, | ||
199 | PALMAS_LPK_TIME_MASK | | ||
200 | PALMAS_PWRON_DEBOUNCE_MASK, | ||
201 | val); | ||
202 | if (error) { | ||
203 | dev_err(dev, "LONG_PRESS_KEY_UPDATE failed: %d\n", error); | ||
204 | goto err_free_input; | ||
205 | } | ||
206 | |||
207 | pwron->palmas = palmas; | ||
208 | pwron->input_dev = input_dev; | ||
209 | |||
210 | INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work); | ||
211 | |||
212 | pwron->irq = platform_get_irq(pdev, 0); | ||
213 | error = request_threaded_irq(pwron->irq, NULL, pwron_irq, | ||
214 | IRQF_TRIGGER_HIGH | | ||
215 | IRQF_TRIGGER_LOW | | ||
216 | IRQF_ONESHOT, | ||
217 | dev_name(dev), pwron); | ||
218 | if (error) { | ||
219 | dev_err(dev, "Can't get IRQ for pwron: %d\n", error); | ||
220 | goto err_free_input; | ||
221 | } | ||
222 | |||
223 | error = input_register_device(input_dev); | ||
224 | if (error) { | ||
225 | dev_err(dev, "Can't register power button: %d\n", error); | ||
226 | goto err_free_irq; | ||
227 | } | ||
228 | |||
229 | platform_set_drvdata(pdev, pwron); | ||
230 | device_init_wakeup(dev, true); | ||
231 | |||
232 | return 0; | ||
233 | |||
234 | err_free_irq: | ||
235 | cancel_delayed_work_sync(&pwron->input_work); | ||
236 | free_irq(pwron->irq, pwron); | ||
237 | err_free_input: | ||
238 | input_free_device(input_dev); | ||
239 | err_free_mem: | ||
240 | kfree(pwron); | ||
241 | return error; | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * palmas_pwron_remove() - Cleanup on removal | ||
246 | * @pdev: platform device for the button | ||
247 | * | ||
248 | * Return: 0 | ||
249 | */ | ||
250 | static int palmas_pwron_remove(struct platform_device *pdev) | ||
251 | { | ||
252 | struct palmas_pwron *pwron = platform_get_drvdata(pdev); | ||
253 | |||
254 | free_irq(pwron->irq, pwron); | ||
255 | cancel_delayed_work_sync(&pwron->input_work); | ||
256 | |||
257 | input_unregister_device(pwron->input_dev); | ||
258 | kfree(pwron); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | #ifdef CONFIG_PM_SLEEP | ||
264 | /** | ||
265 | * palmas_pwron_suspend() - suspend handler | ||
266 | * @dev: power button device | ||
267 | * | ||
268 | * Cancel all pending work items for the power button, setup irq for wakeup | ||
269 | * | ||
270 | * Return: 0 | ||
271 | */ | ||
272 | static int palmas_pwron_suspend(struct device *dev) | ||
273 | { | ||
274 | struct platform_device *pdev = to_platform_device(dev); | ||
275 | struct palmas_pwron *pwron = platform_get_drvdata(pdev); | ||
276 | |||
277 | cancel_delayed_work_sync(&pwron->input_work); | ||
278 | |||
279 | if (device_may_wakeup(dev)) | ||
280 | enable_irq_wake(pwron->irq); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * palmas_pwron_resume() - resume handler | ||
287 | * @dev: power button device | ||
288 | * | ||
289 | * Just disable the wakeup capability of irq here. | ||
290 | * | ||
291 | * Return: 0 | ||
292 | */ | ||
293 | static int palmas_pwron_resume(struct device *dev) | ||
294 | { | ||
295 | struct platform_device *pdev = to_platform_device(dev); | ||
296 | struct palmas_pwron *pwron = platform_get_drvdata(pdev); | ||
297 | |||
298 | if (device_may_wakeup(dev)) | ||
299 | disable_irq_wake(pwron->irq); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | #endif | ||
304 | |||
305 | static SIMPLE_DEV_PM_OPS(palmas_pwron_pm, | ||
306 | palmas_pwron_suspend, palmas_pwron_resume); | ||
307 | |||
308 | #ifdef CONFIG_OF | ||
309 | static struct of_device_id of_palmas_pwr_match[] = { | ||
310 | { .compatible = "ti,palmas-pwrbutton" }, | ||
311 | { }, | ||
312 | }; | ||
313 | |||
314 | MODULE_DEVICE_TABLE(of, of_palmas_pwr_match); | ||
315 | #endif | ||
316 | |||
317 | static struct platform_driver palmas_pwron_driver = { | ||
318 | .probe = palmas_pwron_probe, | ||
319 | .remove = palmas_pwron_remove, | ||
320 | .driver = { | ||
321 | .name = "palmas_pwrbutton", | ||
322 | .owner = THIS_MODULE, | ||
323 | .of_match_table = of_match_ptr(of_palmas_pwr_match), | ||
324 | .pm = &palmas_pwron_pm, | ||
325 | }, | ||
326 | }; | ||
327 | module_platform_driver(palmas_pwron_driver); | ||
328 | |||
329 | MODULE_ALIAS("platform:palmas-pwrbutton"); | ||
330 | MODULE_DESCRIPTION("Palmas Power Button"); | ||
331 | MODULE_LICENSE("GPL v2"); | ||
332 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index e34dfc29beb3..735604753568 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/gpio/consumer.h> | 18 | #include <linux/gpio/consumer.h> |
19 | #include <linux/gpio_keys.h> | 19 | #include <linux/gpio_keys.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/pnp.h> | 21 | #include <linux/acpi.h> |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * Definition of buttons on the tablet. The ACPI index of each button | 24 | * Definition of buttons on the tablet. The ACPI index of each button |
@@ -67,7 +67,7 @@ static int soc_button_lookup_gpio(struct device *dev, int acpi_index) | |||
67 | } | 67 | } |
68 | 68 | ||
69 | static struct platform_device * | 69 | static struct platform_device * |
70 | soc_button_device_create(struct pnp_dev *pdev, | 70 | soc_button_device_create(struct platform_device *pdev, |
71 | const struct soc_button_info *button_info, | 71 | const struct soc_button_info *button_info, |
72 | bool autorepeat) | 72 | bool autorepeat) |
73 | { | 73 | { |
@@ -138,30 +138,40 @@ err_free_mem: | |||
138 | return ERR_PTR(error); | 138 | return ERR_PTR(error); |
139 | } | 139 | } |
140 | 140 | ||
141 | static void soc_button_remove(struct pnp_dev *pdev) | 141 | static int soc_button_remove(struct platform_device *pdev) |
142 | { | 142 | { |
143 | struct soc_button_data *priv = pnp_get_drvdata(pdev); | 143 | struct soc_button_data *priv = platform_get_drvdata(pdev); |
144 | |||
144 | int i; | 145 | int i; |
145 | 146 | ||
146 | for (i = 0; i < BUTTON_TYPES; i++) | 147 | for (i = 0; i < BUTTON_TYPES; i++) |
147 | if (priv->children[i]) | 148 | if (priv->children[i]) |
148 | platform_device_unregister(priv->children[i]); | 149 | platform_device_unregister(priv->children[i]); |
150 | |||
151 | return 0; | ||
149 | } | 152 | } |
150 | 153 | ||
151 | static int soc_button_pnp_probe(struct pnp_dev *pdev, | 154 | static int soc_button_probe(struct platform_device *pdev) |
152 | const struct pnp_device_id *id) | ||
153 | { | 155 | { |
154 | const struct soc_button_info *button_info = (void *)id->driver_data; | 156 | struct device *dev = &pdev->dev; |
157 | const struct acpi_device_id *id; | ||
158 | struct soc_button_info *button_info; | ||
155 | struct soc_button_data *priv; | 159 | struct soc_button_data *priv; |
156 | struct platform_device *pd; | 160 | struct platform_device *pd; |
157 | int i; | 161 | int i; |
158 | int error; | 162 | int error; |
159 | 163 | ||
164 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
165 | if (!id) | ||
166 | return -ENODEV; | ||
167 | |||
168 | button_info = (struct soc_button_info *)id->driver_data; | ||
169 | |||
160 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | 170 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
161 | if (!priv) | 171 | if (!priv) |
162 | return -ENOMEM; | 172 | return -ENOMEM; |
163 | 173 | ||
164 | pnp_set_drvdata(pdev, priv); | 174 | platform_set_drvdata(pdev, priv); |
165 | 175 | ||
166 | for (i = 0; i < BUTTON_TYPES; i++) { | 176 | for (i = 0; i < BUTTON_TYPES; i++) { |
167 | pd = soc_button_device_create(pdev, button_info, i == 0); | 177 | pd = soc_button_device_create(pdev, button_info, i == 0); |
@@ -192,30 +202,22 @@ static struct soc_button_info soc_button_PNP0C40[] = { | |||
192 | { } | 202 | { } |
193 | }; | 203 | }; |
194 | 204 | ||
195 | static const struct pnp_device_id soc_button_pnp_match[] = { | 205 | static const struct acpi_device_id soc_button_acpi_match[] = { |
196 | { .id = "PNP0C40", .driver_data = (long)soc_button_PNP0C40 }, | 206 | { "PNP0C40", (unsigned long)soc_button_PNP0C40 }, |
197 | { .id = "" } | 207 | { } |
198 | }; | 208 | }; |
199 | MODULE_DEVICE_TABLE(pnp, soc_button_pnp_match); | ||
200 | 209 | ||
201 | static struct pnp_driver soc_button_pnp_driver = { | 210 | MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match); |
202 | .name = KBUILD_MODNAME, | 211 | |
203 | .id_table = soc_button_pnp_match, | 212 | static struct platform_driver soc_button_driver = { |
204 | .probe = soc_button_pnp_probe, | 213 | .probe = soc_button_probe, |
205 | .remove = soc_button_remove, | 214 | .remove = soc_button_remove, |
215 | .driver = { | ||
216 | .name = KBUILD_MODNAME, | ||
217 | .owner = THIS_MODULE, | ||
218 | .acpi_match_table = ACPI_PTR(soc_button_acpi_match), | ||
219 | }, | ||
206 | }; | 220 | }; |
207 | 221 | module_platform_driver(soc_button_driver); | |
208 | static int __init soc_button_init(void) | ||
209 | { | ||
210 | return pnp_register_driver(&soc_button_pnp_driver); | ||
211 | } | ||
212 | |||
213 | static void __exit soc_button_exit(void) | ||
214 | { | ||
215 | pnp_unregister_driver(&soc_button_pnp_driver); | ||
216 | } | ||
217 | |||
218 | module_init(soc_button_init); | ||
219 | module_exit(soc_button_exit); | ||
220 | 222 | ||
221 | MODULE_LICENSE("GPL"); | 223 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index c25efdb3f288..dda507f8b3a2 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile | |||
@@ -23,7 +23,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o | |||
23 | obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o | 23 | obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o |
24 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o | 24 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o |
25 | 25 | ||
26 | psmouse-objs := psmouse-base.o synaptics.o | 26 | psmouse-objs := psmouse-base.o synaptics.o focaltech.o |
27 | 27 | ||
28 | psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o | 28 | psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o |
29 | psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o | 29 | psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o |
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c new file mode 100644 index 000000000000..f4d657ee1cc0 --- /dev/null +++ b/drivers/input/mouse/focaltech.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Focaltech TouchPad PS/2 mouse driver | ||
3 | * | ||
4 | * Copyright (c) 2014 Red Hat Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * Red Hat authors: | ||
12 | * | ||
13 | * Hans de Goede <hdegoede@redhat.com> | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * The Focaltech PS/2 touchpad protocol is unknown. This drivers deals with | ||
18 | * detection only, to avoid further detection attempts confusing the touchpad | ||
19 | * this way it at least works in PS/2 mouse compatibility mode. | ||
20 | */ | ||
21 | |||
22 | #include <linux/device.h> | ||
23 | #include <linux/libps2.h> | ||
24 | #include "psmouse.h" | ||
25 | |||
26 | static const char * const focaltech_pnp_ids[] = { | ||
27 | "FLT0101", | ||
28 | "FLT0102", | ||
29 | "FLT0103", | ||
30 | NULL | ||
31 | }; | ||
32 | |||
33 | int focaltech_detect(struct psmouse *psmouse, bool set_properties) | ||
34 | { | ||
35 | if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) | ||
36 | return -ENODEV; | ||
37 | |||
38 | if (set_properties) { | ||
39 | psmouse->vendor = "FocalTech"; | ||
40 | psmouse->name = "FocalTech Touchpad in mouse emulation mode"; | ||
41 | } | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | int focaltech_init(struct psmouse *psmouse) | ||
47 | { | ||
48 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); | ||
49 | psmouse_reset(psmouse); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h new file mode 100644 index 000000000000..498650c61e28 --- /dev/null +++ b/drivers/input/mouse/focaltech.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Focaltech TouchPad PS/2 mouse driver | ||
3 | * | ||
4 | * Copyright (c) 2014 Red Hat Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * Red Hat authors: | ||
12 | * | ||
13 | * Hans de Goede <hdegoede@redhat.com> | ||
14 | */ | ||
15 | |||
16 | #ifndef _FOCALTECH_H | ||
17 | #define _FOCALTECH_H | ||
18 | |||
19 | int focaltech_detect(struct psmouse *psmouse, bool set_properties); | ||
20 | int focaltech_init(struct psmouse *psmouse); | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index b4e1f014ddc2..26994f6a2b2a 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "elantech.h" | 35 | #include "elantech.h" |
36 | #include "sentelic.h" | 36 | #include "sentelic.h" |
37 | #include "cypress_ps2.h" | 37 | #include "cypress_ps2.h" |
38 | #include "focaltech.h" | ||
38 | 39 | ||
39 | #define DRIVER_DESC "PS/2 mouse driver" | 40 | #define DRIVER_DESC "PS/2 mouse driver" |
40 | 41 | ||
@@ -462,6 +463,20 @@ static int psmouse_poll(struct psmouse *psmouse) | |||
462 | PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); | 463 | PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); |
463 | } | 464 | } |
464 | 465 | ||
466 | /* | ||
467 | * psmouse_matches_pnp_id - check if psmouse matches one of the passed in ids. | ||
468 | */ | ||
469 | bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) | ||
470 | { | ||
471 | int i; | ||
472 | |||
473 | if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) | ||
474 | for (i = 0; ids[i]; i++) | ||
475 | if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i])) | ||
476 | return true; | ||
477 | |||
478 | return false; | ||
479 | } | ||
465 | 480 | ||
466 | /* | 481 | /* |
467 | * Genius NetMouse magic init. | 482 | * Genius NetMouse magic init. |
@@ -708,6 +723,21 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
708 | { | 723 | { |
709 | bool synaptics_hardware = false; | 724 | bool synaptics_hardware = false; |
710 | 725 | ||
726 | /* Always check for focaltech, this is safe as it uses pnp-id matching */ | ||
727 | if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) { | ||
728 | if (!set_properties || focaltech_init(psmouse) == 0) { | ||
729 | /* | ||
730 | * Not supported yet, use bare protocol. | ||
731 | * Note that we need to also restrict | ||
732 | * psmouse_max_proto so that psmouse_initialize() | ||
733 | * does not try to reset rate and resolution, | ||
734 | * because even that upsets the device. | ||
735 | */ | ||
736 | psmouse_max_proto = PSMOUSE_PS2; | ||
737 | return PSMOUSE_PS2; | ||
738 | } | ||
739 | } | ||
740 | |||
711 | /* | 741 | /* |
712 | * We always check for lifebook because it does not disturb mouse | 742 | * We always check for lifebook because it does not disturb mouse |
713 | * (it only checks DMI information). | 743 | * (it only checks DMI information). |
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 2f0b39d59a9b..f4cf664c7db3 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
@@ -108,6 +108,7 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); | |||
108 | psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); | 108 | psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); |
109 | int psmouse_activate(struct psmouse *psmouse); | 109 | int psmouse_activate(struct psmouse *psmouse); |
110 | int psmouse_deactivate(struct psmouse *psmouse); | 110 | int psmouse_deactivate(struct psmouse *psmouse); |
111 | bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]); | ||
111 | 112 | ||
112 | struct psmouse_attribute { | 113 | struct psmouse_attribute { |
113 | struct device_attribute dattr; | 114 | struct device_attribute dattr; |
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index fd23181c1fb7..6394d9b5bfd3 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -185,18 +185,6 @@ static const char * const topbuttonpad_pnp_ids[] = { | |||
185 | NULL | 185 | NULL |
186 | }; | 186 | }; |
187 | 187 | ||
188 | static bool matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) | ||
189 | { | ||
190 | int i; | ||
191 | |||
192 | if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) | ||
193 | for (i = 0; ids[i]; i++) | ||
194 | if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i])) | ||
195 | return true; | ||
196 | |||
197 | return false; | ||
198 | } | ||
199 | |||
200 | /***************************************************************************** | 188 | /***************************************************************************** |
201 | * Synaptics communications functions | 189 | * Synaptics communications functions |
202 | ****************************************************************************/ | 190 | ****************************************************************************/ |
@@ -362,7 +350,8 @@ static int synaptics_resolution(struct psmouse *psmouse) | |||
362 | } | 350 | } |
363 | 351 | ||
364 | for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { | 352 | for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { |
365 | if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) { | 353 | if (psmouse_matches_pnp_id(psmouse, |
354 | min_max_pnpid_table[i].pnp_ids)) { | ||
366 | priv->x_min = min_max_pnpid_table[i].x_min; | 355 | priv->x_min = min_max_pnpid_table[i].x_min; |
367 | priv->x_max = min_max_pnpid_table[i].x_max; | 356 | priv->x_max = min_max_pnpid_table[i].x_max; |
368 | priv->y_min = min_max_pnpid_table[i].y_min; | 357 | priv->y_min = min_max_pnpid_table[i].y_min; |
@@ -1492,7 +1481,7 @@ static void set_input_params(struct psmouse *psmouse, | |||
1492 | 1481 | ||
1493 | if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { | 1482 | if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { |
1494 | __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); | 1483 | __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); |
1495 | if (matches_pnp_id(psmouse, topbuttonpad_pnp_ids)) | 1484 | if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids)) |
1496 | __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); | 1485 | __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); |
1497 | /* Clickpads report only left button */ | 1486 | /* Clickpads report only left button */ |
1498 | __clear_bit(BTN_RIGHT, dev->keybit); | 1487 | __clear_bit(BTN_RIGHT, dev->keybit); |
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index b29134de983b..d399b8b0f000 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c | |||
@@ -524,8 +524,8 @@ static void serio_init_port(struct serio *serio) | |||
524 | spin_lock_init(&serio->lock); | 524 | spin_lock_init(&serio->lock); |
525 | mutex_init(&serio->drv_mutex); | 525 | mutex_init(&serio->drv_mutex); |
526 | device_initialize(&serio->dev); | 526 | device_initialize(&serio->dev); |
527 | dev_set_name(&serio->dev, "serio%ld", | 527 | dev_set_name(&serio->dev, "serio%lu", |
528 | (long)atomic_inc_return(&serio_no) - 1); | 528 | (unsigned long)atomic_inc_return(&serio_no) - 1); |
529 | serio->dev.bus = &serio_bus; | 529 | serio->dev.bus = &serio_bus; |
530 | serio->dev.release = serio_release_port; | 530 | serio->dev.release = serio_release_port; |
531 | serio->dev.groups = serio_device_attr_groups; | 531 | serio->dev.groups = serio_device_attr_groups; |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6bb9a7dd23b6..e1d8003d01f8 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -90,6 +90,18 @@ config TOUCHSCREEN_AD7879_SPI | |||
90 | To compile this driver as a module, choose M here: the | 90 | To compile this driver as a module, choose M here: the |
91 | module will be called ad7879-spi. | 91 | module will be called ad7879-spi. |
92 | 92 | ||
93 | config TOUCHSCREEN_AR1021_I2C | ||
94 | tristate "Microchip AR1021 i2c touchscreen" | ||
95 | depends on I2C && OF | ||
96 | help | ||
97 | Say Y here if you have the Microchip AR1021 touchscreen controller | ||
98 | chip in your system. | ||
99 | |||
100 | If unsure, say N. | ||
101 | |||
102 | To compile this driver as a module, choose M here: the | ||
103 | module will be called ar1021_i2c. | ||
104 | |||
93 | config TOUCHSCREEN_ATMEL_MXT | 105 | config TOUCHSCREEN_ATMEL_MXT |
94 | tristate "Atmel mXT I2C Touchscreen" | 106 | tristate "Atmel mXT I2C Touchscreen" |
95 | depends on I2C | 107 | depends on I2C |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 4be94fce41af..090e61cc9171 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o | |||
13 | obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o | 13 | obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o |
14 | obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o | 14 | obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o |
15 | obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o | 15 | obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o |
16 | obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o | ||
16 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o | 17 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o |
17 | obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o | 18 | obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o |
18 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o | 19 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o |
diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c new file mode 100644 index 000000000000..ba30578e296e --- /dev/null +++ b/drivers/input/touchscreen/ar1021_i2c.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Microchip AR1021 driver for I2C | ||
3 | * | ||
4 | * Author: Christian Gmeiner <christian.gmeiner@gmail.com> | ||
5 | * | ||
6 | * License: GPLv2 as published by the FSF. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/input.h> | ||
11 | #include <linux/of.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | |||
16 | #define AR1021_TOCUH_PKG_SIZE 5 | ||
17 | |||
18 | #define AR1021_MAX_X 4095 | ||
19 | #define AR1021_MAX_Y 4095 | ||
20 | |||
21 | struct ar1021_i2c { | ||
22 | struct i2c_client *client; | ||
23 | struct input_dev *input; | ||
24 | u8 data[AR1021_TOCUH_PKG_SIZE]; | ||
25 | }; | ||
26 | |||
27 | static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id) | ||
28 | { | ||
29 | struct ar1021_i2c *ar1021 = dev_id; | ||
30 | struct input_dev *input = ar1021->input; | ||
31 | u8 *data = ar1021->data; | ||
32 | unsigned int x, y, button; | ||
33 | int retval; | ||
34 | |||
35 | retval = i2c_master_recv(ar1021->client, | ||
36 | ar1021->data, sizeof(ar1021->data)); | ||
37 | if (retval != sizeof(ar1021->data)) | ||
38 | goto out; | ||
39 | |||
40 | /* sync bit set ? */ | ||
41 | if ((data[0] & 0x80) == 0) | ||
42 | goto out; | ||
43 | |||
44 | button = data[0] & BIT(0); | ||
45 | x = ((data[2] & 0x1f) << 7) | (data[1] & 0x7f); | ||
46 | y = ((data[4] & 0x1f) << 7) | (data[3] & 0x7f); | ||
47 | |||
48 | input_report_abs(input, ABS_X, x); | ||
49 | input_report_abs(input, ABS_Y, y); | ||
50 | input_report_key(input, BTN_TOUCH, button); | ||
51 | input_sync(input); | ||
52 | |||
53 | out: | ||
54 | return IRQ_HANDLED; | ||
55 | } | ||
56 | |||
57 | static int ar1021_i2c_open(struct input_dev *dev) | ||
58 | { | ||
59 | struct ar1021_i2c *ar1021 = input_get_drvdata(dev); | ||
60 | struct i2c_client *client = ar1021->client; | ||
61 | |||
62 | enable_irq(client->irq); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static void ar1021_i2c_close(struct input_dev *dev) | ||
68 | { | ||
69 | struct ar1021_i2c *ar1021 = input_get_drvdata(dev); | ||
70 | struct i2c_client *client = ar1021->client; | ||
71 | |||
72 | disable_irq(client->irq); | ||
73 | } | ||
74 | |||
75 | static int ar1021_i2c_probe(struct i2c_client *client, | ||
76 | const struct i2c_device_id *id) | ||
77 | { | ||
78 | struct ar1021_i2c *ar1021; | ||
79 | struct input_dev *input; | ||
80 | int error; | ||
81 | |||
82 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
83 | dev_err(&client->dev, "i2c_check_functionality error\n"); | ||
84 | return -ENXIO; | ||
85 | } | ||
86 | |||
87 | ar1021 = devm_kzalloc(&client->dev, sizeof(*ar1021), GFP_KERNEL); | ||
88 | if (!ar1021) | ||
89 | return -ENOMEM; | ||
90 | |||
91 | input = devm_input_allocate_device(&client->dev); | ||
92 | if (!input) | ||
93 | return -ENOMEM; | ||
94 | |||
95 | ar1021->client = client; | ||
96 | ar1021->input = input; | ||
97 | |||
98 | input->name = "ar1021 I2C Touchscreen"; | ||
99 | input->id.bustype = BUS_I2C; | ||
100 | input->dev.parent = &client->dev; | ||
101 | input->open = ar1021_i2c_open; | ||
102 | input->close = ar1021_i2c_close; | ||
103 | |||
104 | input_set_capability(input, EV_KEY, BTN_TOUCH); | ||
105 | input_set_abs_params(input, ABS_X, 0, AR1021_MAX_X, 0, 0); | ||
106 | input_set_abs_params(input, ABS_Y, 0, AR1021_MAX_Y, 0, 0); | ||
107 | |||
108 | input_set_drvdata(input, ar1021); | ||
109 | |||
110 | error = devm_request_threaded_irq(&client->dev, client->irq, | ||
111 | NULL, ar1021_i2c_irq, | ||
112 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
113 | "ar1021_i2c", ar1021); | ||
114 | if (error) { | ||
115 | dev_err(&client->dev, | ||
116 | "Failed to enable IRQ, error: %d\n", error); | ||
117 | return error; | ||
118 | } | ||
119 | |||
120 | /* Disable the IRQ, we'll enable it in ar1021_i2c_open() */ | ||
121 | disable_irq(client->irq); | ||
122 | |||
123 | error = input_register_device(ar1021->input); | ||
124 | if (error) { | ||
125 | dev_err(&client->dev, | ||
126 | "Failed to register input device, error: %d\n", error); | ||
127 | return error; | ||
128 | } | ||
129 | |||
130 | i2c_set_clientdata(client, ar1021); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int __maybe_unused ar1021_i2c_suspend(struct device *dev) | ||
135 | { | ||
136 | struct i2c_client *client = to_i2c_client(dev); | ||
137 | |||
138 | disable_irq(client->irq); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int __maybe_unused ar1021_i2c_resume(struct device *dev) | ||
144 | { | ||
145 | struct i2c_client *client = to_i2c_client(dev); | ||
146 | |||
147 | enable_irq(client->irq); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume); | ||
153 | |||
154 | static const struct i2c_device_id ar1021_i2c_id[] = { | ||
155 | { "MICROCHIP_AR1021_I2C", 0 }, | ||
156 | { }, | ||
157 | }; | ||
158 | MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); | ||
159 | |||
160 | static struct of_device_id ar1021_i2c_of_match[] = { | ||
161 | { .compatible = "microchip,ar1021-i2c", }, | ||
162 | { } | ||
163 | }; | ||
164 | MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match); | ||
165 | |||
166 | static struct i2c_driver ar1021_i2c_driver = { | ||
167 | .driver = { | ||
168 | .name = "ar1021_i2c", | ||
169 | .owner = THIS_MODULE, | ||
170 | .pm = &ar1021_i2c_pm, | ||
171 | .of_match_table = ar1021_i2c_of_match, | ||
172 | }, | ||
173 | |||
174 | .probe = ar1021_i2c_probe, | ||
175 | .id_table = ar1021_i2c_id, | ||
176 | }; | ||
177 | module_i2c_driver(ar1021_i2c_driver); | ||
178 | |||
179 | MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>"); | ||
180 | MODULE_DESCRIPTION("Microchip AR1021 I2C Driver"); | ||
181 | MODULE_LICENSE("GPL"); | ||