Commit ba28f22e7cf16cb310bb491cbb3f7d0d5d1f5c5d
Exists in
master
and in
39 other branches
Merge branch 'next' into for-linus
Showing 28 changed files Side-by-side Diff
- Documentation/input/rotary-encoder.txt
- arch/mips/include/asm/mach-rc32434/gpio.h
- arch/mips/rb532/devices.c
- drivers/input/input.c
- drivers/input/keyboard/atkbd.c
- drivers/input/keyboard/bf54x-keys.c
- drivers/input/keyboard/hilkbd.c
- drivers/input/misc/Kconfig
- drivers/input/misc/Makefile
- drivers/input/misc/ati_remote2.c
- drivers/input/misc/rb532_button.c
- drivers/input/misc/rotary_encoder.c
- drivers/input/mouse/Kconfig
- drivers/input/mouse/Makefile
- drivers/input/mouse/hgpk.c
- drivers/input/mouse/maplemouse.c
- drivers/input/mouse/pc110pad.c
- drivers/input/serio/i8042-x86ia64io.h
- drivers/input/touchscreen/Kconfig
- drivers/input/touchscreen/Makefile
- drivers/input/touchscreen/ad7877.c
- drivers/input/touchscreen/ad7879.c
- drivers/input/touchscreen/mainstone-wm97xx.c
- drivers/input/touchscreen/ucb1400_ts.c
- drivers/input/touchscreen/wm97xx-core.c
- drivers/input/touchscreen/zylonite-wm97xx.c
- include/linux/rotary_encoder.h
- include/linux/spi/ad7879.h
Documentation/input/rotary-encoder.txt
1 | +rotary-encoder - a generic driver for GPIO connected devices | |
2 | +Daniel Mack <daniel@caiaq.de>, Feb 2009 | |
3 | + | |
4 | +0. Function | |
5 | +----------- | |
6 | + | |
7 | +Rotary encoders are devices which are connected to the CPU or other | |
8 | +peripherals with two wires. The outputs are phase-shifted by 90 degrees | |
9 | +and by triggering on falling and rising edges, the turn direction can | |
10 | +be determined. | |
11 | + | |
12 | +The phase diagram of these two outputs look like this: | |
13 | + | |
14 | + _____ _____ _____ | |
15 | + | | | | | | | |
16 | + Channel A ____| |_____| |_____| |____ | |
17 | + | |
18 | + : : : : : : : : : : : : | |
19 | + __ _____ _____ _____ | |
20 | + | | | | | | | | |
21 | + Channel B |_____| |_____| |_____| |__ | |
22 | + | |
23 | + : : : : : : : : : : : : | |
24 | + Event a b c d a b c d a b c d | |
25 | + | |
26 | + |<-------->| | |
27 | + one step | |
28 | + | |
29 | + | |
30 | +For more information, please see | |
31 | + http://en.wikipedia.org/wiki/Rotary_encoder | |
32 | + | |
33 | + | |
34 | +1. Events / state machine | |
35 | +------------------------- | |
36 | + | |
37 | +a) Rising edge on channel A, channel B in low state | |
38 | + This state is used to recognize a clockwise turn | |
39 | + | |
40 | +b) Rising edge on channel B, channel A in high state | |
41 | + When entering this state, the encoder is put into 'armed' state, | |
42 | + meaning that there it has seen half the way of a one-step transition. | |
43 | + | |
44 | +c) Falling edge on channel A, channel B in high state | |
45 | + This state is used to recognize a counter-clockwise turn | |
46 | + | |
47 | +d) Falling edge on channel B, channel A in low state | |
48 | + Parking position. If the encoder enters this state, a full transition | |
49 | + should have happend, unless it flipped back on half the way. The | |
50 | + 'armed' state tells us about that. | |
51 | + | |
52 | +2. Platform requirements | |
53 | +------------------------ | |
54 | + | |
55 | +As there is no hardware dependent call in this driver, the platform it is | |
56 | +used with must support gpiolib. Another requirement is that IRQs must be | |
57 | +able to fire on both edges. | |
58 | + | |
59 | + | |
60 | +3. Board integration | |
61 | +-------------------- | |
62 | + | |
63 | +To use this driver in your system, register a platform_device with the | |
64 | +name 'rotary-encoder' and associate the IRQs and some specific platform | |
65 | +data with it. | |
66 | + | |
67 | +struct rotary_encoder_platform_data is declared in | |
68 | +include/linux/rotary-encoder.h and needs to be filled with the number of | |
69 | +steps the encoder has and can carry information about externally inverted | |
70 | +signals (because of used invertig buffer or other reasons). | |
71 | + | |
72 | +Because GPIO to IRQ mapping is platform specific, this information must | |
73 | +be given in seperately to the driver. See the example below. | |
74 | + | |
75 | +---------<snip>--------- | |
76 | + | |
77 | +/* board support file example */ | |
78 | + | |
79 | +#include <linux/input.h> | |
80 | +#include <linux/rotary_encoder.h> | |
81 | + | |
82 | +#define GPIO_ROTARY_A 1 | |
83 | +#define GPIO_ROTARY_B 2 | |
84 | + | |
85 | +static struct rotary_encoder_platform_data my_rotary_encoder_info = { | |
86 | + .steps = 24, | |
87 | + .axis = ABS_X, | |
88 | + .gpio_a = GPIO_ROTARY_A, | |
89 | + .gpio_b = GPIO_ROTARY_B, | |
90 | + .inverted_a = 0, | |
91 | + .inverted_b = 0, | |
92 | +}; | |
93 | + | |
94 | +static struct platform_device rotary_encoder_device = { | |
95 | + .name = "rotary-encoder", | |
96 | + .id = 0, | |
97 | + .dev = { | |
98 | + .platform_data = &my_rotary_encoder_info, | |
99 | + } | |
100 | +}; |
arch/mips/include/asm/mach-rc32434/gpio.h
... | ... | @@ -80,6 +80,9 @@ |
80 | 80 | /* Compact Flash GPIO pin */ |
81 | 81 | #define CF_GPIO_NUM 13 |
82 | 82 | |
83 | +/* S1 button GPIO (shared with UART0_SIN) */ | |
84 | +#define GPIO_BTN_S1 1 | |
85 | + | |
83 | 86 | extern void rb532_gpio_set_ilevel(int bit, unsigned gpio); |
84 | 87 | extern void rb532_gpio_set_istat(int bit, unsigned gpio); |
85 | 88 | extern void rb532_gpio_set_func(unsigned gpio); |
arch/mips/rb532/devices.c
... | ... | @@ -200,26 +200,9 @@ |
200 | 200 | .id = -1, |
201 | 201 | }; |
202 | 202 | |
203 | -static struct gpio_keys_button rb532_gpio_btn[] = { | |
204 | - { | |
205 | - .gpio = 1, | |
206 | - .code = BTN_0, | |
207 | - .desc = "S1", | |
208 | - .active_low = 1, | |
209 | - } | |
210 | -}; | |
211 | - | |
212 | -static struct gpio_keys_platform_data rb532_gpio_btn_data = { | |
213 | - .buttons = rb532_gpio_btn, | |
214 | - .nbuttons = ARRAY_SIZE(rb532_gpio_btn), | |
215 | -}; | |
216 | - | |
217 | 203 | static struct platform_device rb532_button = { |
218 | - .name = "gpio-keys", | |
204 | + .name = "rb532-button", | |
219 | 205 | .id = -1, |
220 | - .dev = { | |
221 | - .platform_data = &rb532_gpio_btn_data, | |
222 | - } | |
223 | 206 | }; |
224 | 207 | |
225 | 208 | static struct resource rb532_wdt_res[] = { |
drivers/input/input.c
... | ... | @@ -132,6 +132,11 @@ |
132 | 132 | } |
133 | 133 | } |
134 | 134 | |
135 | +static void input_stop_autorepeat(struct input_dev *dev) | |
136 | +{ | |
137 | + del_timer(&dev->timer); | |
138 | +} | |
139 | + | |
135 | 140 | #define INPUT_IGNORE_EVENT 0 |
136 | 141 | #define INPUT_PASS_TO_HANDLERS 1 |
137 | 142 | #define INPUT_PASS_TO_DEVICE 2 |
... | ... | @@ -167,6 +172,8 @@ |
167 | 172 | __change_bit(code, dev->key); |
168 | 173 | if (value) |
169 | 174 | input_start_autorepeat(dev, code); |
175 | + else | |
176 | + input_stop_autorepeat(dev); | |
170 | 177 | } |
171 | 178 | |
172 | 179 | disposition = INPUT_PASS_TO_HANDLERS; |
173 | 180 | |
174 | 181 | |
... | ... | @@ -737,11 +744,11 @@ |
737 | 744 | |
738 | 745 | static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) |
739 | 746 | { |
740 | - int state = input_devices_state; | |
741 | - | |
742 | 747 | poll_wait(file, &input_devices_poll_wait, wait); |
743 | - if (state != input_devices_state) | |
748 | + if (file->f_version != input_devices_state) { | |
749 | + file->f_version = input_devices_state; | |
744 | 750 | return POLLIN | POLLRDNORM; |
751 | + } | |
745 | 752 | |
746 | 753 | return 0; |
747 | 754 | } |
drivers/input/keyboard/atkbd.c
... | ... | @@ -229,7 +229,8 @@ |
229 | 229 | /* |
230 | 230 | * System-specific ketymap fixup routine |
231 | 231 | */ |
232 | -static void (*atkbd_platform_fixup)(struct atkbd *); | |
232 | +static void (*atkbd_platform_fixup)(struct atkbd *, const void *data); | |
233 | +static void *atkbd_platform_fixup_data; | |
233 | 234 | |
234 | 235 | static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, |
235 | 236 | ssize_t (*handler)(struct atkbd *, char *)); |
236 | 237 | |
237 | 238 | |
238 | 239 | |
239 | 240 | |
240 | 241 | |
241 | 242 | |
242 | 243 | |
243 | 244 | |
244 | 245 | |
245 | 246 | |
246 | 247 | |
247 | 248 | |
... | ... | @@ -834,87 +835,64 @@ |
834 | 835 | } |
835 | 836 | |
836 | 837 | /* |
837 | - * Most special keys (Fn+F?) on Dell laptops do not generate release | |
838 | - * events so we have to do it ourselves. | |
838 | + * generate release events for the keycodes given in data | |
839 | 839 | */ |
840 | -static void atkbd_dell_laptop_keymap_fixup(struct atkbd *atkbd) | |
840 | +static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd, | |
841 | + const void *data) | |
841 | 842 | { |
842 | - static const unsigned int forced_release_keys[] = { | |
843 | - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, | |
844 | - }; | |
845 | - int i; | |
843 | + const unsigned int *keys = data; | |
844 | + unsigned int i; | |
846 | 845 | |
847 | 846 | if (atkbd->set == 2) |
848 | - for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) | |
849 | - __set_bit(forced_release_keys[i], | |
850 | - atkbd->force_release_mask); | |
847 | + for (i = 0; keys[i] != -1U; i++) | |
848 | + __set_bit(keys[i], atkbd->force_release_mask); | |
851 | 849 | } |
852 | 850 | |
853 | 851 | /* |
852 | + * Most special keys (Fn+F?) on Dell laptops do not generate release | |
853 | + * events so we have to do it ourselves. | |
854 | + */ | |
855 | +static unsigned int atkbd_dell_laptop_forced_release_keys[] = { | |
856 | + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U | |
857 | +}; | |
858 | + | |
859 | +/* | |
854 | 860 | * Perform fixup for HP system that doesn't generate release |
855 | 861 | * for its video switch |
856 | 862 | */ |
857 | -static void atkbd_hp_keymap_fixup(struct atkbd *atkbd) | |
858 | -{ | |
859 | - static const unsigned int forced_release_keys[] = { | |
860 | - 0x94, | |
861 | - }; | |
862 | - int i; | |
863 | +static unsigned int atkbd_hp_forced_release_keys[] = { | |
864 | + 0x94, -1U | |
865 | +}; | |
863 | 866 | |
864 | - if (atkbd->set == 2) | |
865 | - for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) | |
866 | - __set_bit(forced_release_keys[i], | |
867 | - atkbd->force_release_mask); | |
868 | -} | |
869 | - | |
870 | 867 | /* |
871 | 868 | * Inventec system with broken key release on volume keys |
872 | 869 | */ |
873 | -static void atkbd_inventec_keymap_fixup(struct atkbd *atkbd) | |
874 | -{ | |
875 | - const unsigned int forced_release_keys[] = { | |
876 | - 0xae, 0xb0, | |
877 | - }; | |
878 | - int i; | |
870 | +static unsigned int atkbd_inventec_forced_release_keys[] = { | |
871 | + 0xae, 0xb0, -1U | |
872 | +}; | |
879 | 873 | |
880 | - if (atkbd->set == 2) | |
881 | - for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) | |
882 | - __set_bit(forced_release_keys[i], | |
883 | - atkbd->force_release_mask); | |
884 | -} | |
885 | - | |
886 | 874 | /* |
887 | 875 | * Perform fixup for HP Pavilion ZV6100 laptop that doesn't generate release |
888 | 876 | * for its volume buttons |
889 | 877 | */ |
890 | -static void atkbd_hp_zv6100_keymap_fixup(struct atkbd *atkbd) | |
891 | -{ | |
892 | - const unsigned int forced_release_keys[] = { | |
893 | - 0xae, 0xb0, | |
894 | - }; | |
895 | - int i; | |
878 | +static unsigned int atkbd_hp_zv6100_forced_release_keys[] = { | |
879 | + 0xae, 0xb0, -1U | |
880 | +}; | |
896 | 881 | |
897 | - if (atkbd->set == 2) | |
898 | - for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) | |
899 | - __set_bit(forced_release_keys[i], | |
900 | - atkbd->force_release_mask); | |
901 | -} | |
902 | - | |
903 | 882 | /* |
904 | 883 | * Samsung NC10 with Fn+F? key release not working |
905 | 884 | */ |
906 | -static void atkbd_samsung_keymap_fixup(struct atkbd *atkbd) | |
907 | -{ | |
908 | - const unsigned int forced_release_keys[] = { | |
909 | - 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, | |
910 | - }; | |
911 | - int i; | |
885 | +static unsigned int atkbd_samsung_forced_release_keys[] = { | |
886 | + 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U | |
887 | +}; | |
912 | 888 | |
913 | - if (atkbd->set == 2) | |
914 | - for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) | |
915 | - __set_bit(forced_release_keys[i], | |
916 | - atkbd->force_release_mask); | |
917 | -} | |
889 | +/* | |
890 | + * The volume up and volume down special keys on a Fujitsu Amilo PA 1510 laptop | |
891 | + * do not generate release events so we have to do it ourselves. | |
892 | + */ | |
893 | +static unsigned int atkbd_amilo_pa1510_forced_release_keys[] = { | |
894 | + 0xb0, 0xae, -1U | |
895 | +}; | |
918 | 896 | |
919 | 897 | /* |
920 | 898 | * atkbd_set_keycode_table() initializes keyboard's keycode table |
... | ... | @@ -967,7 +945,7 @@ |
967 | 945 | * Perform additional fixups |
968 | 946 | */ |
969 | 947 | if (atkbd_platform_fixup) |
970 | - atkbd_platform_fixup(atkbd); | |
948 | + atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data); | |
971 | 949 | } |
972 | 950 | |
973 | 951 | /* |
974 | 952 | |
... | ... | @@ -1492,9 +1470,11 @@ |
1492 | 1470 | return sprintf(buf, "%lu\n", atkbd->err_count); |
1493 | 1471 | } |
1494 | 1472 | |
1495 | -static int __init atkbd_setup_fixup(const struct dmi_system_id *id) | |
1473 | +static int __init atkbd_setup_forced_release(const struct dmi_system_id *id) | |
1496 | 1474 | { |
1497 | - atkbd_platform_fixup = id->driver_data; | |
1475 | + atkbd_platform_fixup = atkbd_apply_forced_release_keylist; | |
1476 | + atkbd_platform_fixup_data = id->driver_data; | |
1477 | + | |
1498 | 1478 | return 0; |
1499 | 1479 | } |
1500 | 1480 | |
... | ... | @@ -1505,8 +1485,8 @@ |
1505 | 1485 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
1506 | 1486 | DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ |
1507 | 1487 | }, |
1508 | - .callback = atkbd_setup_fixup, | |
1509 | - .driver_data = atkbd_dell_laptop_keymap_fixup, | |
1488 | + .callback = atkbd_setup_forced_release, | |
1489 | + .driver_data = atkbd_dell_laptop_forced_release_keys, | |
1510 | 1490 | }, |
1511 | 1491 | { |
1512 | 1492 | .ident = "Dell Laptop", |
... | ... | @@ -1514,8 +1494,8 @@ |
1514 | 1494 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
1515 | 1495 | DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ |
1516 | 1496 | }, |
1517 | - .callback = atkbd_setup_fixup, | |
1518 | - .driver_data = atkbd_dell_laptop_keymap_fixup, | |
1497 | + .callback = atkbd_setup_forced_release, | |
1498 | + .driver_data = atkbd_dell_laptop_forced_release_keys, | |
1519 | 1499 | }, |
1520 | 1500 | { |
1521 | 1501 | .ident = "HP 2133", |
... | ... | @@ -1523,8 +1503,8 @@ |
1523 | 1503 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
1524 | 1504 | DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"), |
1525 | 1505 | }, |
1526 | - .callback = atkbd_setup_fixup, | |
1527 | - .driver_data = atkbd_hp_keymap_fixup, | |
1506 | + .callback = atkbd_setup_forced_release, | |
1507 | + .driver_data = atkbd_hp_forced_release_keys, | |
1528 | 1508 | }, |
1529 | 1509 | { |
1530 | 1510 | .ident = "HP Pavilion ZV6100", |
... | ... | @@ -1532,8 +1512,8 @@ |
1532 | 1512 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
1533 | 1513 | DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), |
1534 | 1514 | }, |
1535 | - .callback = atkbd_setup_fixup, | |
1536 | - .driver_data = atkbd_hp_zv6100_keymap_fixup, | |
1515 | + .callback = atkbd_setup_forced_release, | |
1516 | + .driver_data = atkbd_hp_zv6100_forced_release_keys, | |
1537 | 1517 | }, |
1538 | 1518 | { |
1539 | 1519 | .ident = "Inventec Symphony", |
... | ... | @@ -1541,8 +1521,8 @@ |
1541 | 1521 | DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), |
1542 | 1522 | DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), |
1543 | 1523 | }, |
1544 | - .callback = atkbd_setup_fixup, | |
1545 | - .driver_data = atkbd_inventec_keymap_fixup, | |
1524 | + .callback = atkbd_setup_forced_release, | |
1525 | + .driver_data = atkbd_inventec_forced_release_keys, | |
1546 | 1526 | }, |
1547 | 1527 | { |
1548 | 1528 | .ident = "Samsung NC10", |
... | ... | @@ -1550,8 +1530,17 @@ |
1550 | 1530 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), |
1551 | 1531 | DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), |
1552 | 1532 | }, |
1553 | - .callback = atkbd_setup_fixup, | |
1554 | - .driver_data = atkbd_samsung_keymap_fixup, | |
1533 | + .callback = atkbd_setup_forced_release, | |
1534 | + .driver_data = atkbd_samsung_forced_release_keys, | |
1535 | + }, | |
1536 | + { | |
1537 | + .ident = "Fujitsu Amilo PA 1510", | |
1538 | + .matches = { | |
1539 | + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | |
1540 | + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), | |
1541 | + }, | |
1542 | + .callback = atkbd_setup_forced_release, | |
1543 | + .driver_data = atkbd_amilo_pa1510_forced_release_keys, | |
1555 | 1544 | }, |
1556 | 1545 | { } |
1557 | 1546 | }; |
drivers/input/keyboard/bf54x-keys.c
... | ... | @@ -211,8 +211,8 @@ |
211 | 211 | |
212 | 212 | if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT || |
213 | 213 | !pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) { |
214 | - printk(KERN_ERR DRV_NAME | |
215 | - ": Invalid Debounce/Columdrive Time from pdata\n"); | |
214 | + printk(KERN_WARNING DRV_NAME | |
215 | + ": Invalid Debounce/Columndrive Time in platform data\n"); | |
216 | 216 | bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */ |
217 | 217 | } else { |
218 | 218 | bfin_write_KPAD_MSEL( |
drivers/input/keyboard/hilkbd.c
... | ... | @@ -198,45 +198,28 @@ |
198 | 198 | } |
199 | 199 | |
200 | 200 | |
201 | -/* initialise HIL */ | |
202 | -static int __init | |
203 | -hil_keyb_init(void) | |
201 | +/* initialize HIL */ | |
202 | +static int __devinit hil_keyb_init(void) | |
204 | 203 | { |
205 | 204 | unsigned char c; |
206 | 205 | unsigned int i, kbid; |
207 | 206 | wait_queue_head_t hil_wait; |
208 | 207 | int err; |
209 | 208 | |
210 | - if (hil_dev.dev) { | |
209 | + if (hil_dev.dev) | |
211 | 210 | return -ENODEV; /* already initialized */ |
212 | - } | |
213 | 211 | |
212 | + init_waitqueue_head(&hil_wait); | |
214 | 213 | spin_lock_init(&hil_dev.lock); |
214 | + | |
215 | 215 | hil_dev.dev = input_allocate_device(); |
216 | 216 | if (!hil_dev.dev) |
217 | 217 | return -ENOMEM; |
218 | 218 | |
219 | -#if defined(CONFIG_HP300) | |
220 | - if (!MACH_IS_HP300) { | |
221 | - err = -ENODEV; | |
222 | - goto err1; | |
223 | - } | |
224 | - if (!hwreg_present((void *)(HILBASE + HIL_DATA))) { | |
225 | - printk(KERN_ERR "HIL: hardware register was not found\n"); | |
226 | - err = -ENODEV; | |
227 | - goto err1; | |
228 | - } | |
229 | - if (!request_region(HILBASE + HIL_DATA, 2, "hil")) { | |
230 | - printk(KERN_ERR "HIL: IOPORT region already used\n"); | |
231 | - err = -EIO; | |
232 | - goto err1; | |
233 | - } | |
234 | -#endif | |
235 | - | |
236 | 219 | err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); |
237 | 220 | if (err) { |
238 | 221 | printk(KERN_ERR "HIL: Can't get IRQ\n"); |
239 | - goto err2; | |
222 | + goto err1; | |
240 | 223 | } |
241 | 224 | |
242 | 225 | /* Turn on interrupts */ |
243 | 226 | |
... | ... | @@ -246,11 +229,9 @@ |
246 | 229 | hil_dev.valid = 0; /* clear any pending data */ |
247 | 230 | hil_do(HIL_READKBDSADR, NULL, 0); |
248 | 231 | |
249 | - init_waitqueue_head(&hil_wait); | |
250 | - wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ); | |
251 | - if (!hil_dev.valid) { | |
232 | + wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3 * HZ); | |
233 | + if (!hil_dev.valid) | |
252 | 234 | printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n"); |
253 | - } | |
254 | 235 | |
255 | 236 | c = hil_dev.c; |
256 | 237 | hil_dev.valid = 0; |
... | ... | @@ -268,7 +249,7 @@ |
268 | 249 | |
269 | 250 | for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) |
270 | 251 | if (hphilkeyb_keycode[i] != KEY_RESERVED) |
271 | - set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit); | |
252 | + __set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit); | |
272 | 253 | |
273 | 254 | hil_dev.dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); |
274 | 255 | hil_dev.dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | |
275 | 256 | |
276 | 257 | |
277 | 258 | |
278 | 259 | |
279 | 260 | |
280 | 261 | |
281 | 262 | |
282 | 263 | |
283 | 264 | |
284 | 265 | |
... | ... | @@ -287,34 +268,45 @@ |
287 | 268 | err = input_register_device(hil_dev.dev); |
288 | 269 | if (err) { |
289 | 270 | printk(KERN_ERR "HIL: Can't register device\n"); |
290 | - goto err3; | |
271 | + goto err2; | |
291 | 272 | } |
273 | + | |
292 | 274 | printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n", |
293 | 275 | hil_dev.dev->name, kbid, HILBASE, HIL_IRQ); |
294 | 276 | |
295 | 277 | return 0; |
296 | 278 | |
297 | -err3: | |
279 | +err2: | |
298 | 280 | hil_do(HIL_INTOFF, NULL, 0); |
299 | - disable_irq(HIL_IRQ); | |
300 | 281 | free_irq(HIL_IRQ, hil_dev.dev_id); |
301 | -err2: | |
302 | -#if defined(CONFIG_HP300) | |
303 | - release_region(HILBASE + HIL_DATA, 2); | |
304 | 282 | err1: |
305 | -#endif | |
306 | 283 | input_free_device(hil_dev.dev); |
307 | 284 | hil_dev.dev = NULL; |
308 | 285 | return err; |
309 | 286 | } |
310 | 287 | |
288 | +static void __devexit hil_keyb_exit(void) | |
289 | +{ | |
290 | + if (HIL_IRQ) | |
291 | + free_irq(HIL_IRQ, hil_dev.dev_id); | |
311 | 292 | |
293 | + /* Turn off interrupts */ | |
294 | + hil_do(HIL_INTOFF, NULL, 0); | |
295 | + | |
296 | + input_unregister_device(hil_dev.dev); | |
297 | + hil_dev.dev = NULL; | |
298 | +} | |
299 | + | |
312 | 300 | #if defined(CONFIG_PARISC) |
313 | -static int __init | |
314 | -hil_init_chip(struct parisc_device *dev) | |
301 | +static int __devinit hil_probe_chip(struct parisc_device *dev) | |
315 | 302 | { |
303 | + /* Only allow one HIL keyboard */ | |
304 | + if (hil_dev.dev) | |
305 | + return -ENODEV; | |
306 | + | |
316 | 307 | if (!dev->irq) { |
317 | - printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa.start); | |
308 | + printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%p\n", | |
309 | + (void *)dev->hpa.start); | |
318 | 310 | return -ENODEV; |
319 | 311 | } |
320 | 312 | |
321 | 313 | |
322 | 314 | |
323 | 315 | |
324 | 316 | |
325 | 317 | |
326 | 318 | |
327 | 319 | |
328 | 320 | |
329 | 321 | |
330 | 322 | |
331 | 323 | |
332 | 324 | |
333 | 325 | |
334 | 326 | |
... | ... | @@ -327,51 +319,79 @@ |
327 | 319 | return hil_keyb_init(); |
328 | 320 | } |
329 | 321 | |
322 | +static int __devexit hil_remove_chip(struct parisc_device *dev) | |
323 | +{ | |
324 | + hil_keyb_exit(); | |
325 | + | |
326 | + return 0; | |
327 | +} | |
328 | + | |
330 | 329 | static struct parisc_device_id hil_tbl[] = { |
331 | 330 | { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 }, |
332 | 331 | { 0, } |
333 | 332 | }; |
334 | 333 | |
334 | +#if 0 | |
335 | +/* Disabled to avoid conflicts with the HP SDC HIL drivers */ | |
335 | 336 | MODULE_DEVICE_TABLE(parisc, hil_tbl); |
337 | +#endif | |
336 | 338 | |
337 | 339 | static struct parisc_driver hil_driver = { |
338 | - .name = "hil", | |
339 | - .id_table = hil_tbl, | |
340 | - .probe = hil_init_chip, | |
340 | + .name = "hil", | |
341 | + .id_table = hil_tbl, | |
342 | + .probe = hil_probe_chip, | |
343 | + .remove = __devexit_p(hil_remove_chip), | |
341 | 344 | }; |
342 | -#endif /* CONFIG_PARISC */ | |
343 | 345 | |
344 | - | |
345 | 346 | static int __init hil_init(void) |
346 | 347 | { |
347 | -#if defined(CONFIG_PARISC) | |
348 | 348 | return register_parisc_driver(&hil_driver); |
349 | -#else | |
350 | - return hil_keyb_init(); | |
351 | -#endif | |
352 | 349 | } |
353 | 350 | |
354 | - | |
355 | 351 | static void __exit hil_exit(void) |
356 | 352 | { |
357 | - if (HIL_IRQ) { | |
358 | - disable_irq(HIL_IRQ); | |
359 | - free_irq(HIL_IRQ, hil_dev.dev_id); | |
353 | + unregister_parisc_driver(&hil_driver); | |
354 | +} | |
355 | + | |
356 | +#else /* !CONFIG_PARISC */ | |
357 | + | |
358 | +static int __init hil_init(void) | |
359 | +{ | |
360 | + int error; | |
361 | + | |
362 | + /* Only allow one HIL keyboard */ | |
363 | + if (hil_dev.dev) | |
364 | + return -EBUSY; | |
365 | + | |
366 | + if (!MACH_IS_HP300) | |
367 | + return -ENODEV; | |
368 | + | |
369 | + if (!hwreg_present((void *)(HILBASE + HIL_DATA))) { | |
370 | + printk(KERN_ERR "HIL: hardware register was not found\n"); | |
371 | + return -ENODEV; | |
360 | 372 | } |
361 | 373 | |
362 | - /* Turn off interrupts */ | |
363 | - hil_do(HIL_INTOFF, NULL, 0); | |
374 | + if (!request_region(HILBASE + HIL_DATA, 2, "hil")) { | |
375 | + printk(KERN_ERR "HIL: IOPORT region already used\n"); | |
376 | + return -EIO; | |
377 | + } | |
364 | 378 | |
365 | - input_unregister_device(hil_dev.dev); | |
379 | + error = hil_keyb_init(); | |
380 | + if (error) { | |
381 | + release_region(HILBASE + HIL_DATA, 2); | |
382 | + return error; | |
383 | + } | |
366 | 384 | |
367 | - hil_dev.dev = NULL; | |
385 | + return 0; | |
386 | +} | |
368 | 387 | |
369 | -#if defined(CONFIG_PARISC) | |
370 | - unregister_parisc_driver(&hil_driver); | |
371 | -#else | |
372 | - release_region(HILBASE+HIL_DATA, 2); | |
373 | -#endif | |
388 | +static void __exit hil_exit(void) | |
389 | +{ | |
390 | + hil_keyb_exit(); | |
391 | + release_region(HILBASE + HIL_DATA, 2); | |
374 | 392 | } |
393 | + | |
394 | +#endif /* CONFIG_PARISC */ | |
375 | 395 | |
376 | 396 | module_init(hil_init); |
377 | 397 | module_exit(hil_exit); |
drivers/input/misc/Kconfig
... | ... | @@ -227,5 +227,28 @@ |
227 | 227 | Say Y to include support for delivering PMU events via input |
228 | 228 | layer on NXP PCF50633. |
229 | 229 | |
230 | +config INPUT_GPIO_ROTARY_ENCODER | |
231 | + tristate "Rotary encoders connected to GPIO pins" | |
232 | + depends on GPIOLIB && GENERIC_GPIO | |
233 | + help | |
234 | + Say Y here to add support for rotary encoders connected to GPIO lines. | |
235 | + Check file:Documentation/incput/rotary_encoder.txt for more | |
236 | + information. | |
237 | + | |
238 | + To compile this driver as a module, choose M here: the | |
239 | + module will be called rotary_encoder. | |
240 | + | |
241 | +config INPUT_RB532_BUTTON | |
242 | + tristate "Mikrotik Routerboard 532 button interface" | |
243 | + depends on MIKROTIK_RB532 | |
244 | + depends on GPIOLIB && GENERIC_GPIO | |
245 | + select INPUT_POLLDEV | |
246 | + help | |
247 | + Say Y here if you want support for the S1 button built into | |
248 | + Mikrotik's Routerboard 532. | |
249 | + | |
250 | + To compile this driver as a module, choose M here: the | |
251 | + module will be called rb532_button. | |
252 | + | |
230 | 253 | endif |
drivers/input/misc/Makefile
... | ... | @@ -4,22 +4,24 @@ |
4 | 4 | |
5 | 5 | # Each configuration option enables a list of files. |
6 | 6 | |
7 | -obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | |
8 | -obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o | |
9 | -obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | |
10 | -obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | |
11 | -obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | |
12 | -obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o | |
13 | -obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o | |
7 | +obj-$(CONFIG_INPUT_APANEL) += apanel.o | |
14 | 8 | obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o |
15 | 9 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o |
16 | -obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | |
17 | -obj-$(CONFIG_INPUT_POWERMATE) += powermate.o | |
18 | -obj-$(CONFIG_INPUT_YEALINK) += yealink.o | |
10 | +obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o | |
19 | 11 | obj-$(CONFIG_INPUT_CM109) += cm109.o |
12 | +obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | |
20 | 13 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
21 | -obj-$(CONFIG_INPUT_UINPUT) += uinput.o | |
22 | -obj-$(CONFIG_INPUT_APANEL) += apanel.o | |
23 | -obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o | |
14 | +obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | |
15 | +obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | |
16 | +obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | |
24 | 17 | obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o |
18 | +obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o | |
19 | +obj-$(CONFIG_INPUT_POWERMATE) += powermate.o | |
20 | +obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o | |
21 | +obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o | |
22 | +obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o | |
23 | +obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | |
24 | +obj-$(CONFIG_INPUT_UINPUT) += uinput.o | |
25 | +obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o | |
26 | +obj-$(CONFIG_INPUT_YEALINK) += yealink.o |
drivers/input/misc/ati_remote2.c
... | ... | @@ -31,12 +31,73 @@ |
31 | 31 | * newly configured "channel". |
32 | 32 | */ |
33 | 33 | |
34 | -static unsigned int channel_mask = 0xFFFF; | |
35 | -module_param(channel_mask, uint, 0644); | |
34 | +enum { | |
35 | + ATI_REMOTE2_MAX_CHANNEL_MASK = 0xFFFF, | |
36 | + ATI_REMOTE2_MAX_MODE_MASK = 0x1F, | |
37 | +}; | |
38 | + | |
39 | +static int ati_remote2_set_mask(const char *val, | |
40 | + struct kernel_param *kp, unsigned int max) | |
41 | +{ | |
42 | + unsigned long mask; | |
43 | + int ret; | |
44 | + | |
45 | + if (!val) | |
46 | + return -EINVAL; | |
47 | + | |
48 | + ret = strict_strtoul(val, 0, &mask); | |
49 | + if (ret) | |
50 | + return ret; | |
51 | + | |
52 | + if (mask & ~max) | |
53 | + return -EINVAL; | |
54 | + | |
55 | + *(unsigned int *)kp->arg = mask; | |
56 | + | |
57 | + return 0; | |
58 | +} | |
59 | + | |
60 | +static int ati_remote2_set_channel_mask(const char *val, | |
61 | + struct kernel_param *kp) | |
62 | +{ | |
63 | + pr_debug("%s()\n", __func__); | |
64 | + | |
65 | + return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK); | |
66 | +} | |
67 | + | |
68 | +static int ati_remote2_get_channel_mask(char *buffer, struct kernel_param *kp) | |
69 | +{ | |
70 | + pr_debug("%s()\n", __func__); | |
71 | + | |
72 | + return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg); | |
73 | +} | |
74 | + | |
75 | +static int ati_remote2_set_mode_mask(const char *val, struct kernel_param *kp) | |
76 | +{ | |
77 | + pr_debug("%s()\n", __func__); | |
78 | + | |
79 | + return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK); | |
80 | +} | |
81 | + | |
82 | +static int ati_remote2_get_mode_mask(char *buffer, struct kernel_param *kp) | |
83 | +{ | |
84 | + pr_debug("%s()\n", __func__); | |
85 | + | |
86 | + return sprintf(buffer, "0x%02x", *(unsigned int *)kp->arg); | |
87 | +} | |
88 | + | |
89 | +static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK; | |
90 | +#define param_check_channel_mask(name, p) __param_check(name, p, unsigned int) | |
91 | +#define param_set_channel_mask ati_remote2_set_channel_mask | |
92 | +#define param_get_channel_mask ati_remote2_get_channel_mask | |
93 | +module_param(channel_mask, channel_mask, 0644); | |
36 | 94 | MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>"); |
37 | 95 | |
38 | -static unsigned int mode_mask = 0x1F; | |
39 | -module_param(mode_mask, uint, 0644); | |
96 | +static unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK; | |
97 | +#define param_check_mode_mask(name, p) __param_check(name, p, unsigned int) | |
98 | +#define param_set_mode_mask ati_remote2_set_mode_mask | |
99 | +#define param_get_mode_mask ati_remote2_get_mode_mask | |
100 | +module_param(mode_mask, mode_mask, 0644); | |
40 | 101 | MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>"); |
41 | 102 | |
42 | 103 | static struct usb_device_id ati_remote2_id_table[] = { |
43 | 104 | |
... | ... | @@ -133,12 +194,18 @@ |
133 | 194 | u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)]; |
134 | 195 | |
135 | 196 | unsigned int flags; |
197 | + | |
198 | + unsigned int channel_mask; | |
199 | + unsigned int mode_mask; | |
136 | 200 | }; |
137 | 201 | |
138 | 202 | static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id); |
139 | 203 | static void ati_remote2_disconnect(struct usb_interface *interface); |
140 | 204 | static int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message); |
141 | 205 | static int ati_remote2_resume(struct usb_interface *interface); |
206 | +static int ati_remote2_reset_resume(struct usb_interface *interface); | |
207 | +static int ati_remote2_pre_reset(struct usb_interface *interface); | |
208 | +static int ati_remote2_post_reset(struct usb_interface *interface); | |
142 | 209 | |
143 | 210 | static struct usb_driver ati_remote2_driver = { |
144 | 211 | .name = "ati_remote2", |
... | ... | @@ -147,6 +214,9 @@ |
147 | 214 | .id_table = ati_remote2_id_table, |
148 | 215 | .suspend = ati_remote2_suspend, |
149 | 216 | .resume = ati_remote2_resume, |
217 | + .reset_resume = ati_remote2_reset_resume, | |
218 | + .pre_reset = ati_remote2_pre_reset, | |
219 | + .post_reset = ati_remote2_post_reset, | |
150 | 220 | .supports_autosuspend = 1, |
151 | 221 | }; |
152 | 222 | |
... | ... | @@ -238,7 +308,7 @@ |
238 | 308 | |
239 | 309 | channel = data[0] >> 4; |
240 | 310 | |
241 | - if (!((1 << channel) & channel_mask)) | |
311 | + if (!((1 << channel) & ar2->channel_mask)) | |
242 | 312 | return; |
243 | 313 | |
244 | 314 | mode = data[0] & 0x0F; |
... | ... | @@ -250,7 +320,7 @@ |
250 | 320 | return; |
251 | 321 | } |
252 | 322 | |
253 | - if (!((1 << mode) & mode_mask)) | |
323 | + if (!((1 << mode) & ar2->mode_mask)) | |
254 | 324 | return; |
255 | 325 | |
256 | 326 | input_event(idev, EV_REL, REL_X, (s8) data[1]); |
... | ... | @@ -277,7 +347,7 @@ |
277 | 347 | |
278 | 348 | channel = data[0] >> 4; |
279 | 349 | |
280 | - if (!((1 << channel) & channel_mask)) | |
350 | + if (!((1 << channel) & ar2->channel_mask)) | |
281 | 351 | return; |
282 | 352 | |
283 | 353 | mode = data[0] & 0x0F; |
... | ... | @@ -305,7 +375,7 @@ |
305 | 375 | ar2->mode = mode; |
306 | 376 | } |
307 | 377 | |
308 | - if (!((1 << mode) & mode_mask)) | |
378 | + if (!((1 << mode) & ar2->mode_mask)) | |
309 | 379 | return; |
310 | 380 | |
311 | 381 | index = ati_remote2_lookup(hw_code); |
... | ... | @@ -410,7 +480,7 @@ |
410 | 480 | int index, mode; |
411 | 481 | |
412 | 482 | mode = scancode >> 8; |
413 | - if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask)) | |
483 | + if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask)) | |
414 | 484 | return -EINVAL; |
415 | 485 | |
416 | 486 | index = ati_remote2_lookup(scancode & 0xFF); |
... | ... | @@ -427,7 +497,7 @@ |
427 | 497 | int index, mode, old_keycode; |
428 | 498 | |
429 | 499 | mode = scancode >> 8; |
430 | - if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask)) | |
500 | + if (mode > ATI_REMOTE2_PC || !((1 << mode) & ar2->mode_mask)) | |
431 | 501 | return -EINVAL; |
432 | 502 | |
433 | 503 | index = ati_remote2_lookup(scancode & 0xFF); |
... | ... | @@ -550,7 +620,7 @@ |
550 | 620 | } |
551 | 621 | } |
552 | 622 | |
553 | -static int ati_remote2_setup(struct ati_remote2 *ar2) | |
623 | +static int ati_remote2_setup(struct ati_remote2 *ar2, unsigned int ch_mask) | |
554 | 624 | { |
555 | 625 | int r, i, channel; |
556 | 626 | |
... | ... | @@ -565,8 +635,8 @@ |
565 | 635 | |
566 | 636 | channel = 0; |
567 | 637 | for (i = 0; i < 16; i++) { |
568 | - if ((1 << i) & channel_mask) { | |
569 | - if (!(~(1 << i) & 0xFFFF & channel_mask)) | |
638 | + if ((1 << i) & ch_mask) { | |
639 | + if (!(~(1 << i) & ch_mask)) | |
570 | 640 | channel = i + 1; |
571 | 641 | break; |
572 | 642 | } |
... | ... | @@ -585,6 +655,99 @@ |
585 | 655 | return 0; |
586 | 656 | } |
587 | 657 | |
658 | +static ssize_t ati_remote2_show_channel_mask(struct device *dev, | |
659 | + struct device_attribute *attr, | |
660 | + char *buf) | |
661 | +{ | |
662 | + struct usb_device *udev = to_usb_device(dev); | |
663 | + struct usb_interface *intf = usb_ifnum_to_if(udev, 0); | |
664 | + struct ati_remote2 *ar2 = usb_get_intfdata(intf); | |
665 | + | |
666 | + return sprintf(buf, "0x%04x\n", ar2->channel_mask); | |
667 | +} | |
668 | + | |
669 | +static ssize_t ati_remote2_store_channel_mask(struct device *dev, | |
670 | + struct device_attribute *attr, | |
671 | + const char *buf, size_t count) | |
672 | +{ | |
673 | + struct usb_device *udev = to_usb_device(dev); | |
674 | + struct usb_interface *intf = usb_ifnum_to_if(udev, 0); | |
675 | + struct ati_remote2 *ar2 = usb_get_intfdata(intf); | |
676 | + unsigned long mask; | |
677 | + int r; | |
678 | + | |
679 | + if (strict_strtoul(buf, 0, &mask)) | |
680 | + return -EINVAL; | |
681 | + | |
682 | + if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK) | |
683 | + return -EINVAL; | |
684 | + | |
685 | + r = usb_autopm_get_interface(ar2->intf[0]); | |
686 | + if (r) { | |
687 | + dev_err(&ar2->intf[0]->dev, | |
688 | + "%s(): usb_autopm_get_interface() = %d\n", __func__, r); | |
689 | + return r; | |
690 | + } | |
691 | + | |
692 | + mutex_lock(&ati_remote2_mutex); | |
693 | + | |
694 | + if (mask != ar2->channel_mask && !ati_remote2_setup(ar2, mask)) | |
695 | + ar2->channel_mask = mask; | |
696 | + | |
697 | + mutex_unlock(&ati_remote2_mutex); | |
698 | + | |
699 | + usb_autopm_put_interface(ar2->intf[0]); | |
700 | + | |
701 | + return count; | |
702 | +} | |
703 | + | |
704 | +static ssize_t ati_remote2_show_mode_mask(struct device *dev, | |
705 | + struct device_attribute *attr, | |
706 | + char *buf) | |
707 | +{ | |
708 | + struct usb_device *udev = to_usb_device(dev); | |
709 | + struct usb_interface *intf = usb_ifnum_to_if(udev, 0); | |
710 | + struct ati_remote2 *ar2 = usb_get_intfdata(intf); | |
711 | + | |
712 | + return sprintf(buf, "0x%02x\n", ar2->mode_mask); | |
713 | +} | |
714 | + | |
715 | +static ssize_t ati_remote2_store_mode_mask(struct device *dev, | |
716 | + struct device_attribute *attr, | |
717 | + const char *buf, size_t count) | |
718 | +{ | |
719 | + struct usb_device *udev = to_usb_device(dev); | |
720 | + struct usb_interface *intf = usb_ifnum_to_if(udev, 0); | |
721 | + struct ati_remote2 *ar2 = usb_get_intfdata(intf); | |
722 | + unsigned long mask; | |
723 | + | |
724 | + if (strict_strtoul(buf, 0, &mask)) | |
725 | + return -EINVAL; | |
726 | + | |
727 | + if (mask & ~ATI_REMOTE2_MAX_MODE_MASK) | |
728 | + return -EINVAL; | |
729 | + | |
730 | + ar2->mode_mask = mask; | |
731 | + | |
732 | + return count; | |
733 | +} | |
734 | + | |
735 | +static DEVICE_ATTR(channel_mask, 0644, ati_remote2_show_channel_mask, | |
736 | + ati_remote2_store_channel_mask); | |
737 | + | |
738 | +static DEVICE_ATTR(mode_mask, 0644, ati_remote2_show_mode_mask, | |
739 | + ati_remote2_store_mode_mask); | |
740 | + | |
741 | +static struct attribute *ati_remote2_attrs[] = { | |
742 | + &dev_attr_channel_mask.attr, | |
743 | + &dev_attr_mode_mask.attr, | |
744 | + NULL, | |
745 | +}; | |
746 | + | |
747 | +static struct attribute_group ati_remote2_attr_group = { | |
748 | + .attrs = ati_remote2_attrs, | |
749 | +}; | |
750 | + | |
588 | 751 | static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id) |
589 | 752 | { |
590 | 753 | struct usb_device *udev = interface_to_usbdev(interface); |
... | ... | @@ -615,7 +778,10 @@ |
615 | 778 | if (r) |
616 | 779 | goto fail2; |
617 | 780 | |
618 | - r = ati_remote2_setup(ar2); | |
781 | + ar2->channel_mask = channel_mask; | |
782 | + ar2->mode_mask = mode_mask; | |
783 | + | |
784 | + r = ati_remote2_setup(ar2, ar2->channel_mask); | |
619 | 785 | if (r) |
620 | 786 | goto fail2; |
621 | 787 | |
622 | 788 | |
623 | 789 | |
624 | 790 | |
... | ... | @@ -624,19 +790,24 @@ |
624 | 790 | |
625 | 791 | strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name)); |
626 | 792 | |
627 | - r = ati_remote2_input_init(ar2); | |
793 | + r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group); | |
628 | 794 | if (r) |
629 | 795 | goto fail2; |
630 | 796 | |
797 | + r = ati_remote2_input_init(ar2); | |
798 | + if (r) | |
799 | + goto fail3; | |
800 | + | |
631 | 801 | usb_set_intfdata(interface, ar2); |
632 | 802 | |
633 | 803 | interface->needs_remote_wakeup = 1; |
634 | 804 | |
635 | 805 | return 0; |
636 | 806 | |
807 | + fail3: | |
808 | + sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group); | |
637 | 809 | fail2: |
638 | 810 | ati_remote2_urb_cleanup(ar2); |
639 | - | |
640 | 811 | usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); |
641 | 812 | fail1: |
642 | 813 | kfree(ar2); |
... | ... | @@ -657,6 +828,8 @@ |
657 | 828 | |
658 | 829 | input_unregister_device(ar2->idev); |
659 | 830 | |
831 | + sysfs_remove_group(&ar2->udev->dev.kobj, &ati_remote2_attr_group); | |
832 | + | |
660 | 833 | ati_remote2_urb_cleanup(ar2); |
661 | 834 | |
662 | 835 | usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); |
... | ... | @@ -709,6 +882,78 @@ |
709 | 882 | |
710 | 883 | if (!r) |
711 | 884 | ar2->flags &= ~ATI_REMOTE2_SUSPENDED; |
885 | + | |
886 | + mutex_unlock(&ati_remote2_mutex); | |
887 | + | |
888 | + return r; | |
889 | +} | |
890 | + | |
891 | +static int ati_remote2_reset_resume(struct usb_interface *interface) | |
892 | +{ | |
893 | + struct ati_remote2 *ar2; | |
894 | + struct usb_host_interface *alt = interface->cur_altsetting; | |
895 | + int r = 0; | |
896 | + | |
897 | + if (alt->desc.bInterfaceNumber) | |
898 | + return 0; | |
899 | + | |
900 | + ar2 = usb_get_intfdata(interface); | |
901 | + | |
902 | + dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); | |
903 | + | |
904 | + mutex_lock(&ati_remote2_mutex); | |
905 | + | |
906 | + r = ati_remote2_setup(ar2, ar2->channel_mask); | |
907 | + if (r) | |
908 | + goto out; | |
909 | + | |
910 | + if (ar2->flags & ATI_REMOTE2_OPENED) | |
911 | + r = ati_remote2_submit_urbs(ar2); | |
912 | + | |
913 | + if (!r) | |
914 | + ar2->flags &= ~ATI_REMOTE2_SUSPENDED; | |
915 | + | |
916 | + out: | |
917 | + mutex_unlock(&ati_remote2_mutex); | |
918 | + | |
919 | + return r; | |
920 | +} | |
921 | + | |
922 | +static int ati_remote2_pre_reset(struct usb_interface *interface) | |
923 | +{ | |
924 | + struct ati_remote2 *ar2; | |
925 | + struct usb_host_interface *alt = interface->cur_altsetting; | |
926 | + | |
927 | + if (alt->desc.bInterfaceNumber) | |
928 | + return 0; | |
929 | + | |
930 | + ar2 = usb_get_intfdata(interface); | |
931 | + | |
932 | + dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); | |
933 | + | |
934 | + mutex_lock(&ati_remote2_mutex); | |
935 | + | |
936 | + if (ar2->flags == ATI_REMOTE2_OPENED) | |
937 | + ati_remote2_kill_urbs(ar2); | |
938 | + | |
939 | + return 0; | |
940 | +} | |
941 | + | |
942 | +static int ati_remote2_post_reset(struct usb_interface *interface) | |
943 | +{ | |
944 | + struct ati_remote2 *ar2; | |
945 | + struct usb_host_interface *alt = interface->cur_altsetting; | |
946 | + int r = 0; | |
947 | + | |
948 | + if (alt->desc.bInterfaceNumber) | |
949 | + return 0; | |
950 | + | |
951 | + ar2 = usb_get_intfdata(interface); | |
952 | + | |
953 | + dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); | |
954 | + | |
955 | + if (ar2->flags == ATI_REMOTE2_OPENED) | |
956 | + r = ati_remote2_submit_urbs(ar2); | |
712 | 957 | |
713 | 958 | mutex_unlock(&ati_remote2_mutex); |
714 | 959 |
drivers/input/misc/rb532_button.c
1 | +/* | |
2 | + * Support for the S1 button on Routerboard 532 | |
3 | + * | |
4 | + * Copyright (C) 2009 Phil Sutter <n0-1@freewrt.org> | |
5 | + */ | |
6 | + | |
7 | +#include <linux/input-polldev.h> | |
8 | +#include <linux/module.h> | |
9 | +#include <linux/platform_device.h> | |
10 | + | |
11 | +#include <asm/mach-rc32434/gpio.h> | |
12 | +#include <asm/mach-rc32434/rb.h> | |
13 | + | |
14 | +#define DRV_NAME "rb532-button" | |
15 | + | |
16 | +#define RB532_BTN_RATE 100 /* msec */ | |
17 | +#define RB532_BTN_KSYM BTN_0 | |
18 | + | |
19 | +/* The S1 button state is provided by GPIO pin 1. But as this | |
20 | + * pin is also used for uart input as alternate function, the | |
21 | + * operational modes must be switched first: | |
22 | + * 1) disable uart using set_latch_u5() | |
23 | + * 2) turn off alternate function implicitly through | |
24 | + * gpio_direction_input() | |
25 | + * 3) read the GPIO's current value | |
26 | + * 4) undo step 2 by enabling alternate function (in this | |
27 | + * mode the GPIO direction is fixed, so no change needed) | |
28 | + * 5) turn on uart again | |
29 | + * The GPIO value occurs to be inverted, so pin high means | |
30 | + * button is not pressed. | |
31 | + */ | |
32 | +static bool rb532_button_pressed(void) | |
33 | +{ | |
34 | + int val; | |
35 | + | |
36 | + set_latch_u5(0, LO_FOFF); | |
37 | + gpio_direction_input(GPIO_BTN_S1); | |
38 | + | |
39 | + val = gpio_get_value(GPIO_BTN_S1); | |
40 | + | |
41 | + rb532_gpio_set_func(GPIO_BTN_S1); | |
42 | + set_latch_u5(LO_FOFF, 0); | |
43 | + | |
44 | + return !val; | |
45 | +} | |
46 | + | |
47 | +static void rb532_button_poll(struct input_polled_dev *poll_dev) | |
48 | +{ | |
49 | + input_report_key(poll_dev->input, RB532_BTN_KSYM, | |
50 | + rb532_button_pressed()); | |
51 | + input_sync(poll_dev->input); | |
52 | +} | |
53 | + | |
54 | +static int __devinit rb532_button_probe(struct platform_device *pdev) | |
55 | +{ | |
56 | + struct input_polled_dev *poll_dev; | |
57 | + int error; | |
58 | + | |
59 | + poll_dev = input_allocate_polled_device(); | |
60 | + if (!poll_dev) | |
61 | + return -ENOMEM; | |
62 | + | |
63 | + poll_dev->poll = rb532_button_poll; | |
64 | + poll_dev->poll_interval = RB532_BTN_RATE; | |
65 | + | |
66 | + poll_dev->input->name = "rb532 button"; | |
67 | + poll_dev->input->phys = "rb532/button0"; | |
68 | + poll_dev->input->id.bustype = BUS_HOST; | |
69 | + poll_dev->input->dev.parent = &pdev->dev; | |
70 | + | |
71 | + dev_set_drvdata(&pdev->dev, poll_dev); | |
72 | + | |
73 | + input_set_capability(poll_dev->input, EV_KEY, RB532_BTN_KSYM); | |
74 | + | |
75 | + error = input_register_polled_device(poll_dev); | |
76 | + if (error) { | |
77 | + input_free_polled_device(poll_dev); | |
78 | + return error; | |
79 | + } | |
80 | + | |
81 | + return 0; | |
82 | +} | |
83 | + | |
84 | +static int __devexit rb532_button_remove(struct platform_device *pdev) | |
85 | +{ | |
86 | + struct input_polled_dev *poll_dev = dev_get_drvdata(&pdev->dev); | |
87 | + | |
88 | + input_unregister_polled_device(poll_dev); | |
89 | + input_free_polled_device(poll_dev); | |
90 | + dev_set_drvdata(&pdev->dev, NULL); | |
91 | + | |
92 | + return 0; | |
93 | +} | |
94 | + | |
95 | +static struct platform_driver rb532_button_driver = { | |
96 | + .probe = rb532_button_probe, | |
97 | + .remove = __devexit_p(rb532_button_remove), | |
98 | + .driver = { | |
99 | + .name = DRV_NAME, | |
100 | + .owner = THIS_MODULE, | |
101 | + }, | |
102 | +}; | |
103 | + | |
104 | +static int __init rb532_button_init(void) | |
105 | +{ | |
106 | + return platform_driver_register(&rb532_button_driver); | |
107 | +} | |
108 | + | |
109 | +static void __exit rb532_button_exit(void) | |
110 | +{ | |
111 | + platform_driver_unregister(&rb532_button_driver); | |
112 | +} | |
113 | + | |
114 | +module_init(rb532_button_init); | |
115 | +module_exit(rb532_button_exit); | |
116 | + | |
117 | +MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>"); | |
118 | +MODULE_LICENSE("GPL"); | |
119 | +MODULE_DESCRIPTION("Support for S1 button on Routerboard 532"); | |
120 | +MODULE_ALIAS("platform:" DRV_NAME); |
drivers/input/misc/rotary_encoder.c
1 | +/* | |
2 | + * rotary_encoder.c | |
3 | + * | |
4 | + * (c) 2009 Daniel Mack <daniel@caiaq.de> | |
5 | + * | |
6 | + * state machine code inspired by code from Tim Ruetz | |
7 | + * | |
8 | + * A generic driver for rotary encoders connected to GPIO lines. | |
9 | + * See file:Documentation/input/rotary_encoder.txt for more information | |
10 | + * | |
11 | + * This program is free software; you can redistribute it and/or modify | |
12 | + * it under the terms of the GNU General Public License version 2 as | |
13 | + * published by the Free Software Foundation. | |
14 | + */ | |
15 | + | |
16 | +#include <linux/kernel.h> | |
17 | +#include <linux/module.h> | |
18 | +#include <linux/init.h> | |
19 | +#include <linux/interrupt.h> | |
20 | +#include <linux/input.h> | |
21 | +#include <linux/device.h> | |
22 | +#include <linux/platform_device.h> | |
23 | +#include <linux/gpio.h> | |
24 | +#include <linux/rotary_encoder.h> | |
25 | + | |
26 | +#define DRV_NAME "rotary-encoder" | |
27 | + | |
28 | +struct rotary_encoder { | |
29 | + unsigned int irq_a; | |
30 | + unsigned int irq_b; | |
31 | + unsigned int pos; | |
32 | + unsigned int armed; | |
33 | + unsigned int dir; | |
34 | + struct input_dev *input; | |
35 | + struct rotary_encoder_platform_data *pdata; | |
36 | +}; | |
37 | + | |
38 | +static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) | |
39 | +{ | |
40 | + struct rotary_encoder *encoder = dev_id; | |
41 | + struct rotary_encoder_platform_data *pdata = encoder->pdata; | |
42 | + int a = !!gpio_get_value(pdata->gpio_a); | |
43 | + int b = !!gpio_get_value(pdata->gpio_b); | |
44 | + int state; | |
45 | + | |
46 | + a ^= pdata->inverted_a; | |
47 | + b ^= pdata->inverted_b; | |
48 | + state = (a << 1) | b; | |
49 | + | |
50 | + switch (state) { | |
51 | + | |
52 | + case 0x0: | |
53 | + if (!encoder->armed) | |
54 | + break; | |
55 | + | |
56 | + if (encoder->dir) { | |
57 | + /* turning counter-clockwise */ | |
58 | + encoder->pos += pdata->steps; | |
59 | + encoder->pos--; | |
60 | + encoder->pos %= pdata->steps; | |
61 | + } else { | |
62 | + /* turning clockwise */ | |
63 | + encoder->pos++; | |
64 | + encoder->pos %= pdata->steps; | |
65 | + } | |
66 | + | |
67 | + input_report_abs(encoder->input, pdata->axis, encoder->pos); | |
68 | + input_sync(encoder->input); | |
69 | + | |
70 | + encoder->armed = 0; | |
71 | + break; | |
72 | + | |
73 | + case 0x1: | |
74 | + case 0x2: | |
75 | + if (encoder->armed) | |
76 | + encoder->dir = state - 1; | |
77 | + break; | |
78 | + | |
79 | + case 0x3: | |
80 | + encoder->armed = 1; | |
81 | + break; | |
82 | + } | |
83 | + | |
84 | + return IRQ_HANDLED; | |
85 | +} | |
86 | + | |
87 | +static int __devinit rotary_encoder_probe(struct platform_device *pdev) | |
88 | +{ | |
89 | + struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; | |
90 | + struct rotary_encoder *encoder; | |
91 | + struct input_dev *input; | |
92 | + int err; | |
93 | + | |
94 | + if (!pdata || !pdata->steps) { | |
95 | + dev_err(&pdev->dev, "invalid platform data\n"); | |
96 | + return -ENOENT; | |
97 | + } | |
98 | + | |
99 | + encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); | |
100 | + input = input_allocate_device(); | |
101 | + if (!encoder || !input) { | |
102 | + dev_err(&pdev->dev, "failed to allocate memory for device\n"); | |
103 | + err = -ENOMEM; | |
104 | + goto exit_free_mem; | |
105 | + } | |
106 | + | |
107 | + encoder->input = input; | |
108 | + encoder->pdata = pdata; | |
109 | + encoder->irq_a = gpio_to_irq(pdata->gpio_a); | |
110 | + encoder->irq_b = gpio_to_irq(pdata->gpio_b); | |
111 | + | |
112 | + /* create and register the input driver */ | |
113 | + input->name = pdev->name; | |
114 | + input->id.bustype = BUS_HOST; | |
115 | + input->dev.parent = &pdev->dev; | |
116 | + input->evbit[0] = BIT_MASK(EV_ABS); | |
117 | + input_set_abs_params(encoder->input, | |
118 | + pdata->axis, 0, pdata->steps, 0, 1); | |
119 | + | |
120 | + err = input_register_device(input); | |
121 | + if (err) { | |
122 | + dev_err(&pdev->dev, "failed to register input device\n"); | |
123 | + goto exit_free_mem; | |
124 | + } | |
125 | + | |
126 | + /* request the GPIOs */ | |
127 | + err = gpio_request(pdata->gpio_a, DRV_NAME); | |
128 | + if (err) { | |
129 | + dev_err(&pdev->dev, "unable to request GPIO %d\n", | |
130 | + pdata->gpio_a); | |
131 | + goto exit_unregister_input; | |
132 | + } | |
133 | + | |
134 | + err = gpio_request(pdata->gpio_b, DRV_NAME); | |
135 | + if (err) { | |
136 | + dev_err(&pdev->dev, "unable to request GPIO %d\n", | |
137 | + pdata->gpio_b); | |
138 | + goto exit_free_gpio_a; | |
139 | + } | |
140 | + | |
141 | + /* request the IRQs */ | |
142 | + err = request_irq(encoder->irq_a, &rotary_encoder_irq, | |
143 | + IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE, | |
144 | + DRV_NAME, encoder); | |
145 | + if (err) { | |
146 | + dev_err(&pdev->dev, "unable to request IRQ %d\n", | |
147 | + encoder->irq_a); | |
148 | + goto exit_free_gpio_b; | |
149 | + } | |
150 | + | |
151 | + err = request_irq(encoder->irq_b, &rotary_encoder_irq, | |
152 | + IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE, | |
153 | + DRV_NAME, encoder); | |
154 | + if (err) { | |
155 | + dev_err(&pdev->dev, "unable to request IRQ %d\n", | |
156 | + encoder->irq_b); | |
157 | + goto exit_free_irq_a; | |
158 | + } | |
159 | + | |
160 | + platform_set_drvdata(pdev, encoder); | |
161 | + | |
162 | + return 0; | |
163 | + | |
164 | +exit_free_irq_a: | |
165 | + free_irq(encoder->irq_a, encoder); | |
166 | +exit_free_gpio_b: | |
167 | + gpio_free(pdata->gpio_b); | |
168 | +exit_free_gpio_a: | |
169 | + gpio_free(pdata->gpio_a); | |
170 | +exit_unregister_input: | |
171 | + input_unregister_device(input); | |
172 | + input = NULL; /* so we don't try to free it */ | |
173 | +exit_free_mem: | |
174 | + input_free_device(input); | |
175 | + kfree(encoder); | |
176 | + return err; | |
177 | +} | |
178 | + | |
179 | +static int __devexit rotary_encoder_remove(struct platform_device *pdev) | |
180 | +{ | |
181 | + struct rotary_encoder *encoder = platform_get_drvdata(pdev); | |
182 | + struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; | |
183 | + | |
184 | + free_irq(encoder->irq_a, encoder); | |
185 | + free_irq(encoder->irq_b, encoder); | |
186 | + gpio_free(pdata->gpio_a); | |
187 | + gpio_free(pdata->gpio_b); | |
188 | + input_unregister_device(encoder->input); | |
189 | + platform_set_drvdata(pdev, NULL); | |
190 | + kfree(encoder); | |
191 | + | |
192 | + return 0; | |
193 | +} | |
194 | + | |
195 | +static struct platform_driver rotary_encoder_driver = { | |
196 | + .probe = rotary_encoder_probe, | |
197 | + .remove = __devexit_p(rotary_encoder_remove), | |
198 | + .driver = { | |
199 | + .name = DRV_NAME, | |
200 | + .owner = THIS_MODULE, | |
201 | + } | |
202 | +}; | |
203 | + | |
204 | +static int __init rotary_encoder_init(void) | |
205 | +{ | |
206 | + return platform_driver_register(&rotary_encoder_driver); | |
207 | +} | |
208 | + | |
209 | +static void __exit rotary_encoder_exit(void) | |
210 | +{ | |
211 | + platform_driver_unregister(&rotary_encoder_driver); | |
212 | +} | |
213 | + | |
214 | +module_init(rotary_encoder_init); | |
215 | +module_exit(rotary_encoder_exit); | |
216 | + | |
217 | +MODULE_ALIAS("platform:" DRV_NAME); | |
218 | +MODULE_DESCRIPTION("GPIO rotary encoder driver"); | |
219 | +MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | |
220 | +MODULE_LICENSE("GPL v2"); |
drivers/input/mouse/Kconfig
... | ... | @@ -292,5 +292,16 @@ |
292 | 292 | help |
293 | 293 | Say Y here to support PXA930 Trackball mouse. |
294 | 294 | |
295 | +config MOUSE_MAPLE | |
296 | + tristate "Maple mouse (for the Dreamcast)" | |
297 | + depends on MAPLE | |
298 | + help | |
299 | + This driver supports the Maple mouse on the SEGA Dreamcast. | |
300 | + | |
301 | + Most Dreamcast users, who have a mouse, will say Y here. | |
302 | + | |
303 | + To compile this driver as a module choose M here: the module will be | |
304 | + called maplemouse. | |
305 | + | |
295 | 306 | endif |
drivers/input/mouse/Makefile
... | ... | @@ -6,18 +6,19 @@ |
6 | 6 | |
7 | 7 | obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o |
8 | 8 | obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o |
9 | -obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o | |
10 | 9 | obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o |
11 | -obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o | |
10 | +obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o | |
11 | +obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o | |
12 | +obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o | |
12 | 13 | obj-$(CONFIG_MOUSE_INPORT) += inport.o |
13 | 14 | obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o |
15 | +obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o | |
14 | 16 | obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o |
15 | 17 | obj-$(CONFIG_MOUSE_PS2) += psmouse.o |
16 | 18 | obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o |
19 | +obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o | |
17 | 20 | obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o |
18 | -obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o | |
19 | 21 | obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o |
20 | -obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o | |
21 | 22 | |
22 | 23 | psmouse-objs := psmouse-base.o synaptics.o |
23 | 24 |
drivers/input/mouse/hgpk.c
... | ... | @@ -472,7 +472,7 @@ |
472 | 472 | return -EIO; |
473 | 473 | } |
474 | 474 | |
475 | - hgpk_dbg(psmouse, "ID: %02x %02x %02x", param[0], param[1], param[2]); | |
475 | + hgpk_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]); | |
476 | 476 | |
477 | 477 | /* HGPK signature: 0x67, 0x00, 0x<model> */ |
478 | 478 | if (param[0] != 0x67 || param[1] != 0x00) |
drivers/input/mouse/maplemouse.c
1 | +/* | |
2 | + * SEGA Dreamcast mouse driver | |
3 | + * Based on drivers/usb/usbmouse.c | |
4 | + * | |
5 | + * Copyright Yaegashi Takeshi, 2001 | |
6 | + * Adrian McMenamin, 2008 | |
7 | + */ | |
8 | + | |
9 | +#include <linux/kernel.h> | |
10 | +#include <linux/slab.h> | |
11 | +#include <linux/input.h> | |
12 | +#include <linux/module.h> | |
13 | +#include <linux/init.h> | |
14 | +#include <linux/timer.h> | |
15 | +#include <linux/maple.h> | |
16 | + | |
17 | +MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); | |
18 | +MODULE_DESCRIPTION("SEGA Dreamcast mouse driver"); | |
19 | +MODULE_LICENSE("GPL"); | |
20 | + | |
21 | +struct dc_mouse { | |
22 | + struct input_dev *dev; | |
23 | + struct maple_device *mdev; | |
24 | +}; | |
25 | + | |
26 | +static void dc_mouse_callback(struct mapleq *mq) | |
27 | +{ | |
28 | + int buttons, relx, rely, relz; | |
29 | + struct maple_device *mapledev = mq->dev; | |
30 | + struct dc_mouse *mse = maple_get_drvdata(mapledev); | |
31 | + struct input_dev *dev = mse->dev; | |
32 | + unsigned char *res = mq->recvbuf; | |
33 | + | |
34 | + buttons = ~res[8]; | |
35 | + relx = *(unsigned short *)(res + 12) - 512; | |
36 | + rely = *(unsigned short *)(res + 14) - 512; | |
37 | + relz = *(unsigned short *)(res + 16) - 512; | |
38 | + | |
39 | + input_report_key(dev, BTN_LEFT, buttons & 4); | |
40 | + input_report_key(dev, BTN_MIDDLE, buttons & 9); | |
41 | + input_report_key(dev, BTN_RIGHT, buttons & 2); | |
42 | + input_report_rel(dev, REL_X, relx); | |
43 | + input_report_rel(dev, REL_Y, rely); | |
44 | + input_report_rel(dev, REL_WHEEL, relz); | |
45 | + input_sync(dev); | |
46 | +} | |
47 | + | |
48 | +static int dc_mouse_open(struct input_dev *dev) | |
49 | +{ | |
50 | + struct dc_mouse *mse = dev->dev.platform_data; | |
51 | + | |
52 | + maple_getcond_callback(mse->mdev, dc_mouse_callback, HZ/50, | |
53 | + MAPLE_FUNC_MOUSE); | |
54 | + | |
55 | + return 0; | |
56 | +} | |
57 | + | |
58 | +static void dc_mouse_close(struct input_dev *dev) | |
59 | +{ | |
60 | + struct dc_mouse *mse = dev->dev.platform_data; | |
61 | + | |
62 | + maple_getcond_callback(mse->mdev, dc_mouse_callback, 0, | |
63 | + MAPLE_FUNC_MOUSE); | |
64 | +} | |
65 | + | |
66 | + | |
67 | +static int __devinit probe_maple_mouse(struct device *dev) | |
68 | +{ | |
69 | + struct maple_device *mdev = to_maple_dev(dev); | |
70 | + struct maple_driver *mdrv = to_maple_driver(dev->driver); | |
71 | + struct input_dev *input_dev; | |
72 | + struct dc_mouse *mse; | |
73 | + int error; | |
74 | + | |
75 | + mse = kzalloc(sizeof(struct dc_mouse), GFP_KERNEL); | |
76 | + input_dev = input_allocate_device(); | |
77 | + | |
78 | + if (!mse || !input_dev) { | |
79 | + error = -ENOMEM; | |
80 | + goto fail; | |
81 | + } | |
82 | + | |
83 | + mse->dev = input_dev; | |
84 | + mse->mdev = mdev; | |
85 | + | |
86 | + input_set_drvdata(input_dev, mse); | |
87 | + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | |
88 | + input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | | |
89 | + BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); | |
90 | + input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | | |
91 | + BIT_MASK(REL_WHEEL); | |
92 | + input_dev->name = mdev->product_name; | |
93 | + input_dev->id.bustype = BUS_HOST; | |
94 | + input_dev->open = dc_mouse_open; | |
95 | + input_dev->close = dc_mouse_close; | |
96 | + | |
97 | + mdev->driver = mdrv; | |
98 | + maple_set_drvdata(mdev, mse); | |
99 | + | |
100 | + error = input_register_device(input_dev); | |
101 | + if (error) | |
102 | + goto fail; | |
103 | + | |
104 | + return 0; | |
105 | + | |
106 | +fail: | |
107 | + input_free_device(input_dev); | |
108 | + maple_set_drvdata(mdev, NULL); | |
109 | + kfree(mse); | |
110 | + mdev->driver = NULL; | |
111 | + return error; | |
112 | +} | |
113 | + | |
114 | +static int __devexit remove_maple_mouse(struct device *dev) | |
115 | +{ | |
116 | + struct maple_device *mdev = to_maple_dev(dev); | |
117 | + struct dc_mouse *mse = maple_get_drvdata(mdev); | |
118 | + | |
119 | + mdev->callback = NULL; | |
120 | + input_unregister_device(mse->dev); | |
121 | + maple_set_drvdata(mdev, NULL); | |
122 | + kfree(mse); | |
123 | + | |
124 | + return 0; | |
125 | +} | |
126 | + | |
127 | +static struct maple_driver dc_mouse_driver = { | |
128 | + .function = MAPLE_FUNC_MOUSE, | |
129 | + .drv = { | |
130 | + .name = "Dreamcast_mouse", | |
131 | + .probe = probe_maple_mouse, | |
132 | + .remove = __devexit_p(remove_maple_mouse), | |
133 | + }, | |
134 | +}; | |
135 | + | |
136 | +static int __init dc_mouse_init(void) | |
137 | +{ | |
138 | + return maple_driver_register(&dc_mouse_driver); | |
139 | +} | |
140 | + | |
141 | +static void __exit dc_mouse_exit(void) | |
142 | +{ | |
143 | + maple_driver_unregister(&dc_mouse_driver); | |
144 | +} | |
145 | + | |
146 | +module_init(dc_mouse_init); | |
147 | +module_exit(dc_mouse_exit); |
drivers/input/mouse/pc110pad.c
... | ... | @@ -111,11 +111,8 @@ |
111 | 111 | struct pci_dev *dev; |
112 | 112 | int err; |
113 | 113 | |
114 | - dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); | |
115 | - if (dev) { | |
116 | - pci_dev_put(dev); | |
114 | + if (!no_pci_devices()) | |
117 | 115 | return -ENODEV; |
118 | - } | |
119 | 116 | |
120 | 117 | if (!request_region(pc110pad_io, 4, "pc110pad")) { |
121 | 118 | printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", |
drivers/input/serio/i8042-x86ia64io.h
... | ... | @@ -151,6 +151,14 @@ |
151 | 151 | DMI_MATCH(DMI_PRODUCT_VERSION, "01"), |
152 | 152 | }, |
153 | 153 | }, |
154 | + { | |
155 | + .ident = "HP DV9700", | |
156 | + .matches = { | |
157 | + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | |
158 | + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), | |
159 | + DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"), | |
160 | + }, | |
161 | + }, | |
154 | 162 | { } |
155 | 163 | }; |
156 | 164 |
drivers/input/touchscreen/Kconfig
... | ... | @@ -29,6 +29,51 @@ |
29 | 29 | To compile this driver as a module, choose M here: the |
30 | 30 | module will be called ads7846. |
31 | 31 | |
32 | +config TOUCHSCREEN_AD7877 | |
33 | + tristate "AD7877 based touchscreens" | |
34 | + depends on SPI_MASTER | |
35 | + help | |
36 | + Say Y here if you have a touchscreen interface using the | |
37 | + AD7877 controller, and your board-specific initialization | |
38 | + code includes that in its table of SPI devices. | |
39 | + | |
40 | + If unsure, say N (but it's safe to say "Y"). | |
41 | + | |
42 | + To compile this driver as a module, choose M here: the | |
43 | + module will be called ad7877. | |
44 | + | |
45 | +config TOUCHSCREEN_AD7879_I2C | |
46 | + tristate "AD7879 based touchscreens: AD7879-1 I2C Interface" | |
47 | + depends on I2C | |
48 | + select TOUCHSCREEN_AD7879 | |
49 | + help | |
50 | + Say Y here if you have a touchscreen interface using the | |
51 | + AD7879-1 controller, and your board-specific initialization | |
52 | + code includes that in its table of I2C devices. | |
53 | + | |
54 | + If unsure, say N (but it's safe to say "Y"). | |
55 | + | |
56 | + To compile this driver as a module, choose M here: the | |
57 | + module will be called ad7879. | |
58 | + | |
59 | +config TOUCHSCREEN_AD7879_SPI | |
60 | + tristate "AD7879 based touchscreens: AD7879 SPI Interface" | |
61 | + depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n | |
62 | + select TOUCHSCREEN_AD7879 | |
63 | + help | |
64 | + Say Y here if you have a touchscreen interface using the | |
65 | + AD7879 controller, and your board-specific initialization | |
66 | + code includes that in its table of SPI devices. | |
67 | + | |
68 | + If unsure, say N (but it's safe to say "Y"). | |
69 | + | |
70 | + To compile this driver as a module, choose M here: the | |
71 | + module will be called ad7879. | |
72 | + | |
73 | +config TOUCHSCREEN_AD7879 | |
74 | + tristate | |
75 | + default n | |
76 | + | |
32 | 77 | config TOUCHSCREEN_BITSY |
33 | 78 | tristate "Compaq iPAQ H3600 (Bitsy) touchscreen" |
34 | 79 | depends on SA1100_BITSY |
... | ... | @@ -307,6 +352,19 @@ |
307 | 352 | |
308 | 353 | To compile this driver as a module, choose M here: the |
309 | 354 | module will be called mainstone-wm97xx. |
355 | + | |
356 | +config TOUCHSCREEN_WM97XX_ZYLONITE | |
357 | + tristate "Zylonite accelerated touch" | |
358 | + depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE | |
359 | + select TOUCHSCREEN_WM9713 | |
360 | + help | |
361 | + Say Y here for support for streaming mode with the touchscreen | |
362 | + on Zylonite systems. | |
363 | + | |
364 | + If unsure, say N. | |
365 | + | |
366 | + To compile this driver as a module, choose M here: the | |
367 | + module will be called zylonite-wm97xx. | |
310 | 368 | |
311 | 369 | config TOUCHSCREEN_USB_COMPOSITE |
312 | 370 | tristate "USB Touchscreen Driver" |
drivers/input/touchscreen/Makefile
... | ... | @@ -6,6 +6,8 @@ |
6 | 6 | |
7 | 7 | wm97xx-ts-y := wm97xx-core.o |
8 | 8 | |
9 | +obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o | |
10 | +obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o | |
9 | 11 | obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o |
10 | 12 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o |
11 | 13 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o |
... | ... | @@ -34,4 +36,5 @@ |
34 | 36 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o |
35 | 37 | wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o |
36 | 38 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o |
39 | +obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o |
drivers/input/touchscreen/ad7877.c
1 | +/* | |
2 | + * Copyright (C) 2006-2008 Michael Hennerich, Analog Devices Inc. | |
3 | + * | |
4 | + * Description: AD7877 based touchscreen, sensor (ADCs), DAC and GPIO driver | |
5 | + * Based on: ads7846.c | |
6 | + * | |
7 | + * Bugs: Enter bugs at http://blackfin.uclinux.org/ | |
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 | + * This program is distributed in the hope that it will be useful, | |
15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | + * GNU General Public License for more details. | |
18 | + * | |
19 | + * You should have received a copy of the GNU General Public License | |
20 | + * along with this program; if not, see the file COPYING, or write | |
21 | + * to the Free Software Foundation, Inc., | |
22 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | + * | |
24 | + * History: | |
25 | + * Copyright (c) 2005 David Brownell | |
26 | + * Copyright (c) 2006 Nokia Corporation | |
27 | + * Various changes: Imre Deak <imre.deak@nokia.com> | |
28 | + * | |
29 | + * Using code from: | |
30 | + * - corgi_ts.c | |
31 | + * Copyright (C) 2004-2005 Richard Purdie | |
32 | + * - omap_ts.[hc], ads7846.h, ts_osk.c | |
33 | + * Copyright (C) 2002 MontaVista Software | |
34 | + * Copyright (C) 2004 Texas Instruments | |
35 | + * Copyright (C) 2005 Dirk Behme | |
36 | + */ | |
37 | + | |
38 | + | |
39 | +#include <linux/device.h> | |
40 | +#include <linux/init.h> | |
41 | +#include <linux/delay.h> | |
42 | +#include <linux/input.h> | |
43 | +#include <linux/interrupt.h> | |
44 | +#include <linux/slab.h> | |
45 | +#include <linux/spi/spi.h> | |
46 | +#include <linux/spi/ad7877.h> | |
47 | +#include <asm/irq.h> | |
48 | + | |
49 | +#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50) | |
50 | + | |
51 | +#define MAX_SPI_FREQ_HZ 20000000 | |
52 | +#define MAX_12BIT ((1<<12)-1) | |
53 | + | |
54 | +#define AD7877_REG_ZEROS 0 | |
55 | +#define AD7877_REG_CTRL1 1 | |
56 | +#define AD7877_REG_CTRL2 2 | |
57 | +#define AD7877_REG_ALERT 3 | |
58 | +#define AD7877_REG_AUX1HIGH 4 | |
59 | +#define AD7877_REG_AUX1LOW 5 | |
60 | +#define AD7877_REG_BAT1HIGH 6 | |
61 | +#define AD7877_REG_BAT1LOW 7 | |
62 | +#define AD7877_REG_BAT2HIGH 8 | |
63 | +#define AD7877_REG_BAT2LOW 9 | |
64 | +#define AD7877_REG_TEMP1HIGH 10 | |
65 | +#define AD7877_REG_TEMP1LOW 11 | |
66 | +#define AD7877_REG_SEQ0 12 | |
67 | +#define AD7877_REG_SEQ1 13 | |
68 | +#define AD7877_REG_DAC 14 | |
69 | +#define AD7877_REG_NONE1 15 | |
70 | +#define AD7877_REG_EXTWRITE 15 | |
71 | +#define AD7877_REG_XPLUS 16 | |
72 | +#define AD7877_REG_YPLUS 17 | |
73 | +#define AD7877_REG_Z2 18 | |
74 | +#define AD7877_REG_aux1 19 | |
75 | +#define AD7877_REG_aux2 20 | |
76 | +#define AD7877_REG_aux3 21 | |
77 | +#define AD7877_REG_bat1 22 | |
78 | +#define AD7877_REG_bat2 23 | |
79 | +#define AD7877_REG_temp1 24 | |
80 | +#define AD7877_REG_temp2 25 | |
81 | +#define AD7877_REG_Z1 26 | |
82 | +#define AD7877_REG_GPIOCTRL1 27 | |
83 | +#define AD7877_REG_GPIOCTRL2 28 | |
84 | +#define AD7877_REG_GPIODATA 29 | |
85 | +#define AD7877_REG_NONE2 30 | |
86 | +#define AD7877_REG_NONE3 31 | |
87 | + | |
88 | +#define AD7877_SEQ_YPLUS_BIT (1<<11) | |
89 | +#define AD7877_SEQ_XPLUS_BIT (1<<10) | |
90 | +#define AD7877_SEQ_Z2_BIT (1<<9) | |
91 | +#define AD7877_SEQ_AUX1_BIT (1<<8) | |
92 | +#define AD7877_SEQ_AUX2_BIT (1<<7) | |
93 | +#define AD7877_SEQ_AUX3_BIT (1<<6) | |
94 | +#define AD7877_SEQ_BAT1_BIT (1<<5) | |
95 | +#define AD7877_SEQ_BAT2_BIT (1<<4) | |
96 | +#define AD7877_SEQ_TEMP1_BIT (1<<3) | |
97 | +#define AD7877_SEQ_TEMP2_BIT (1<<2) | |
98 | +#define AD7877_SEQ_Z1_BIT (1<<1) | |
99 | + | |
100 | +enum { | |
101 | + AD7877_SEQ_YPOS = 0, | |
102 | + AD7877_SEQ_XPOS = 1, | |
103 | + AD7877_SEQ_Z2 = 2, | |
104 | + AD7877_SEQ_AUX1 = 3, | |
105 | + AD7877_SEQ_AUX2 = 4, | |
106 | + AD7877_SEQ_AUX3 = 5, | |
107 | + AD7877_SEQ_BAT1 = 6, | |
108 | + AD7877_SEQ_BAT2 = 7, | |
109 | + AD7877_SEQ_TEMP1 = 8, | |
110 | + AD7877_SEQ_TEMP2 = 9, | |
111 | + AD7877_SEQ_Z1 = 10, | |
112 | + AD7877_NR_SENSE = 11, | |
113 | +}; | |
114 | + | |
115 | +/* DAC Register Default RANGE 0 to Vcc, Volatge Mode, DAC On */ | |
116 | +#define AD7877_DAC_CONF 0x1 | |
117 | + | |
118 | +/* If gpio3 is set AUX3/GPIO3 acts as GPIO Output */ | |
119 | +#define AD7877_EXTW_GPIO_3_CONF 0x1C4 | |
120 | +#define AD7877_EXTW_GPIO_DATA 0x200 | |
121 | + | |
122 | +/* Control REG 2 */ | |
123 | +#define AD7877_TMR(x) ((x & 0x3) << 0) | |
124 | +#define AD7877_REF(x) ((x & 0x1) << 2) | |
125 | +#define AD7877_POL(x) ((x & 0x1) << 3) | |
126 | +#define AD7877_FCD(x) ((x & 0x3) << 4) | |
127 | +#define AD7877_PM(x) ((x & 0x3) << 6) | |
128 | +#define AD7877_ACQ(x) ((x & 0x3) << 8) | |
129 | +#define AD7877_AVG(x) ((x & 0x3) << 10) | |
130 | + | |
131 | +/* Control REG 1 */ | |
132 | +#define AD7877_SER (1 << 11) /* non-differential */ | |
133 | +#define AD7877_DFR (0 << 11) /* differential */ | |
134 | + | |
135 | +#define AD7877_MODE_NOC (0) /* Do not convert */ | |
136 | +#define AD7877_MODE_SCC (1) /* Single channel conversion */ | |
137 | +#define AD7877_MODE_SEQ0 (2) /* Sequence 0 in Slave Mode */ | |
138 | +#define AD7877_MODE_SEQ1 (3) /* Sequence 1 in Master Mode */ | |
139 | + | |
140 | +#define AD7877_CHANADD(x) ((x&0xF)<<7) | |
141 | +#define AD7877_READADD(x) ((x)<<2) | |
142 | +#define AD7877_WRITEADD(x) ((x)<<12) | |
143 | + | |
144 | +#define AD7877_READ_CHAN(x) (AD7877_WRITEADD(AD7877_REG_CTRL1) | AD7877_SER | \ | |
145 | + AD7877_MODE_SCC | AD7877_CHANADD(AD7877_REG_ ## x) | \ | |
146 | + AD7877_READADD(AD7877_REG_ ## x)) | |
147 | + | |
148 | +#define AD7877_MM_SEQUENCE (AD7877_SEQ_YPLUS_BIT | AD7877_SEQ_XPLUS_BIT | \ | |
149 | + AD7877_SEQ_Z2_BIT | AD7877_SEQ_Z1_BIT) | |
150 | + | |
151 | +/* | |
152 | + * Non-touchscreen sensors only use single-ended conversions. | |
153 | + */ | |
154 | + | |
155 | +struct ser_req { | |
156 | + u16 reset; | |
157 | + u16 ref_on; | |
158 | + u16 command; | |
159 | + u16 sample; | |
160 | + struct spi_message msg; | |
161 | + struct spi_transfer xfer[6]; | |
162 | +}; | |
163 | + | |
164 | +struct ad7877 { | |
165 | + struct input_dev *input; | |
166 | + char phys[32]; | |
167 | + | |
168 | + struct spi_device *spi; | |
169 | + u16 model; | |
170 | + u16 vref_delay_usecs; | |
171 | + u16 x_plate_ohms; | |
172 | + u16 pressure_max; | |
173 | + | |
174 | + u16 cmd_crtl1; | |
175 | + u16 cmd_crtl2; | |
176 | + u16 cmd_dummy; | |
177 | + u16 dac; | |
178 | + | |
179 | + u8 stopacq_polarity; | |
180 | + u8 first_conversion_delay; | |
181 | + u8 acquisition_time; | |
182 | + u8 averaging; | |
183 | + u8 pen_down_acc_interval; | |
184 | + | |
185 | + u16 conversion_data[AD7877_NR_SENSE]; | |
186 | + | |
187 | + struct spi_transfer xfer[AD7877_NR_SENSE + 2]; | |
188 | + struct spi_message msg; | |
189 | + | |
190 | + struct mutex mutex; | |
191 | + unsigned disabled:1; /* P: mutex */ | |
192 | + unsigned gpio3:1; /* P: mutex */ | |
193 | + unsigned gpio4:1; /* P: mutex */ | |
194 | + | |
195 | + spinlock_t lock; | |
196 | + struct timer_list timer; /* P: lock */ | |
197 | + unsigned pending:1; /* P: lock */ | |
198 | +}; | |
199 | + | |
200 | +static int gpio3; | |
201 | +module_param(gpio3, int, 0); | |
202 | +MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3"); | |
203 | + | |
204 | +/* | |
205 | + * ad7877_read/write are only used for initial setup and for sysfs controls. | |
206 | + * The main traffic is done using spi_async() in the interrupt handler. | |
207 | + */ | |
208 | + | |
209 | +static int ad7877_read(struct spi_device *spi, u16 reg) | |
210 | +{ | |
211 | + struct ser_req *req; | |
212 | + int status, ret; | |
213 | + | |
214 | + req = kzalloc(sizeof *req, GFP_KERNEL); | |
215 | + if (!req) | |
216 | + return -ENOMEM; | |
217 | + | |
218 | + spi_message_init(&req->msg); | |
219 | + | |
220 | + req->command = (u16) (AD7877_WRITEADD(AD7877_REG_CTRL1) | | |
221 | + AD7877_READADD(reg)); | |
222 | + req->xfer[0].tx_buf = &req->command; | |
223 | + req->xfer[0].len = 2; | |
224 | + | |
225 | + req->xfer[1].rx_buf = &req->sample; | |
226 | + req->xfer[1].len = 2; | |
227 | + | |
228 | + spi_message_add_tail(&req->xfer[0], &req->msg); | |
229 | + spi_message_add_tail(&req->xfer[1], &req->msg); | |
230 | + | |
231 | + status = spi_sync(spi, &req->msg); | |
232 | + ret = status ? : req->sample; | |
233 | + | |
234 | + kfree(req); | |
235 | + | |
236 | + return ret; | |
237 | +} | |
238 | + | |
239 | +static int ad7877_write(struct spi_device *spi, u16 reg, u16 val) | |
240 | +{ | |
241 | + struct ser_req *req; | |
242 | + int status; | |
243 | + | |
244 | + req = kzalloc(sizeof *req, GFP_KERNEL); | |
245 | + if (!req) | |
246 | + return -ENOMEM; | |
247 | + | |
248 | + spi_message_init(&req->msg); | |
249 | + | |
250 | + req->command = (u16) (AD7877_WRITEADD(reg) | (val & MAX_12BIT)); | |
251 | + req->xfer[0].tx_buf = &req->command; | |
252 | + req->xfer[0].len = 2; | |
253 | + | |
254 | + spi_message_add_tail(&req->xfer[0], &req->msg); | |
255 | + | |
256 | + status = spi_sync(spi, &req->msg); | |
257 | + | |
258 | + kfree(req); | |
259 | + | |
260 | + return status; | |
261 | +} | |
262 | + | |
263 | +static int ad7877_read_adc(struct spi_device *spi, unsigned command) | |
264 | +{ | |
265 | + struct ad7877 *ts = dev_get_drvdata(&spi->dev); | |
266 | + struct ser_req *req; | |
267 | + int status; | |
268 | + int sample; | |
269 | + int i; | |
270 | + | |
271 | + req = kzalloc(sizeof *req, GFP_KERNEL); | |
272 | + if (!req) | |
273 | + return -ENOMEM; | |
274 | + | |
275 | + spi_message_init(&req->msg); | |
276 | + | |
277 | + /* activate reference, so it has time to settle; */ | |
278 | + req->ref_on = AD7877_WRITEADD(AD7877_REG_CTRL2) | | |
279 | + AD7877_POL(ts->stopacq_polarity) | | |
280 | + AD7877_AVG(0) | AD7877_PM(2) | AD7877_TMR(0) | | |
281 | + AD7877_ACQ(ts->acquisition_time) | AD7877_FCD(0); | |
282 | + | |
283 | + req->reset = AD7877_WRITEADD(AD7877_REG_CTRL1) | AD7877_MODE_NOC; | |
284 | + | |
285 | + req->command = (u16) command; | |
286 | + | |
287 | + req->xfer[0].tx_buf = &req->reset; | |
288 | + req->xfer[0].len = 2; | |
289 | + | |
290 | + req->xfer[1].tx_buf = &req->ref_on; | |
291 | + req->xfer[1].len = 2; | |
292 | + req->xfer[1].delay_usecs = ts->vref_delay_usecs; | |
293 | + | |
294 | + req->xfer[2].tx_buf = &req->command; | |
295 | + req->xfer[2].len = 2; | |
296 | + req->xfer[2].delay_usecs = ts->vref_delay_usecs; | |
297 | + | |
298 | + req->xfer[3].rx_buf = &req->sample; | |
299 | + req->xfer[3].len = 2; | |
300 | + | |
301 | + req->xfer[4].tx_buf = &ts->cmd_crtl2; /*REF OFF*/ | |
302 | + req->xfer[4].len = 2; | |
303 | + | |
304 | + req->xfer[5].tx_buf = &ts->cmd_crtl1; /*DEFAULT*/ | |
305 | + req->xfer[5].len = 2; | |
306 | + | |
307 | + /* group all the transfers together, so we can't interfere with | |
308 | + * reading touchscreen state; disable penirq while sampling | |
309 | + */ | |
310 | + for (i = 0; i < 6; i++) | |
311 | + spi_message_add_tail(&req->xfer[i], &req->msg); | |
312 | + | |
313 | + status = spi_sync(spi, &req->msg); | |
314 | + sample = req->sample; | |
315 | + | |
316 | + kfree(req); | |
317 | + | |
318 | + return status ? : sample; | |
319 | +} | |
320 | + | |
321 | +static void ad7877_rx(struct ad7877 *ts) | |
322 | +{ | |
323 | + struct input_dev *input_dev = ts->input; | |
324 | + unsigned Rt; | |
325 | + u16 x, y, z1, z2; | |
326 | + | |
327 | + x = ts->conversion_data[AD7877_SEQ_XPOS] & MAX_12BIT; | |
328 | + y = ts->conversion_data[AD7877_SEQ_YPOS] & MAX_12BIT; | |
329 | + z1 = ts->conversion_data[AD7877_SEQ_Z1] & MAX_12BIT; | |
330 | + z2 = ts->conversion_data[AD7877_SEQ_Z2] & MAX_12BIT; | |
331 | + | |
332 | + /* | |
333 | + * The samples processed here are already preprocessed by the AD7877. | |
334 | + * The preprocessing function consists of an averaging filter. | |
335 | + * The combination of 'first conversion delay' and averaging provides a robust solution, | |
336 | + * discarding the spurious noise in the signal and keeping only the data of interest. | |
337 | + * The size of the averaging filter is programmable. (dev.platform_data, see linux/spi/ad7877.h) | |
338 | + * Other user-programmable conversion controls include variable acquisition time, | |
339 | + * and first conversion delay. Up to 16 averages can be taken per conversion. | |
340 | + */ | |
341 | + | |
342 | + if (likely(x && z1)) { | |
343 | + /* compute touch pressure resistance using equation #1 */ | |
344 | + Rt = (z2 - z1) * x * ts->x_plate_ohms; | |
345 | + Rt /= z1; | |
346 | + Rt = (Rt + 2047) >> 12; | |
347 | + | |
348 | + input_report_abs(input_dev, ABS_X, x); | |
349 | + input_report_abs(input_dev, ABS_Y, y); | |
350 | + input_report_abs(input_dev, ABS_PRESSURE, Rt); | |
351 | + input_sync(input_dev); | |
352 | + } | |
353 | +} | |
354 | + | |
355 | +static inline void ad7877_ts_event_release(struct ad7877 *ts) | |
356 | +{ | |
357 | + struct input_dev *input_dev = ts->input; | |
358 | + | |
359 | + input_report_abs(input_dev, ABS_PRESSURE, 0); | |
360 | + input_sync(input_dev); | |
361 | +} | |
362 | + | |
363 | +static void ad7877_timer(unsigned long handle) | |
364 | +{ | |
365 | + struct ad7877 *ts = (void *)handle; | |
366 | + | |
367 | + ad7877_ts_event_release(ts); | |
368 | +} | |
369 | + | |
370 | +static irqreturn_t ad7877_irq(int irq, void *handle) | |
371 | +{ | |
372 | + struct ad7877 *ts = handle; | |
373 | + unsigned long flags; | |
374 | + int status; | |
375 | + | |
376 | + /* | |
377 | + * The repeated conversion sequencer controlled by TMR kicked off | |
378 | + * too fast. We ignore the last and process the sample sequence | |
379 | + * currently in the queue. It can't be older than 9.4ms, and we | |
380 | + * need to avoid that ts->msg doesn't get issued twice while in work. | |
381 | + */ | |
382 | + | |
383 | + spin_lock_irqsave(&ts->lock, flags); | |
384 | + if (!ts->pending) { | |
385 | + ts->pending = 1; | |
386 | + | |
387 | + status = spi_async(ts->spi, &ts->msg); | |
388 | + if (status) | |
389 | + dev_err(&ts->spi->dev, "spi_sync --> %d\n", status); | |
390 | + } | |
391 | + spin_unlock_irqrestore(&ts->lock, flags); | |
392 | + | |
393 | + return IRQ_HANDLED; | |
394 | +} | |
395 | + | |
396 | +static void ad7877_callback(void *_ts) | |
397 | +{ | |
398 | + struct ad7877 *ts = _ts; | |
399 | + | |
400 | + spin_lock_irq(&ts->lock); | |
401 | + | |
402 | + ad7877_rx(ts); | |
403 | + ts->pending = 0; | |
404 | + mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT); | |
405 | + | |
406 | + spin_unlock_irq(&ts->lock); | |
407 | +} | |
408 | + | |
409 | +static void ad7877_disable(struct ad7877 *ts) | |
410 | +{ | |
411 | + mutex_lock(&ts->mutex); | |
412 | + | |
413 | + if (!ts->disabled) { | |
414 | + ts->disabled = 1; | |
415 | + disable_irq(ts->spi->irq); | |
416 | + | |
417 | + /* Wait for spi_async callback */ | |
418 | + while (ts->pending) | |
419 | + msleep(1); | |
420 | + | |
421 | + if (del_timer_sync(&ts->timer)) | |
422 | + ad7877_ts_event_release(ts); | |
423 | + } | |
424 | + | |
425 | + /* we know the chip's in lowpower mode since we always | |
426 | + * leave it that way after every request | |
427 | + */ | |
428 | + | |
429 | + mutex_unlock(&ts->mutex); | |
430 | +} | |
431 | + | |
432 | +static void ad7877_enable(struct ad7877 *ts) | |
433 | +{ | |
434 | + mutex_lock(&ts->mutex); | |
435 | + | |
436 | + if (ts->disabled) { | |
437 | + ts->disabled = 0; | |
438 | + enable_irq(ts->spi->irq); | |
439 | + } | |
440 | + | |
441 | + mutex_unlock(&ts->mutex); | |
442 | +} | |
443 | + | |
444 | +#define SHOW(name) static ssize_t \ | |
445 | +name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \ | |
446 | +{ \ | |
447 | + struct ad7877 *ts = dev_get_drvdata(dev); \ | |
448 | + ssize_t v = ad7877_read_adc(ts->spi, \ | |
449 | + AD7877_READ_CHAN(name)); \ | |
450 | + if (v < 0) \ | |
451 | + return v; \ | |
452 | + return sprintf(buf, "%u\n", (unsigned) v); \ | |
453 | +} \ | |
454 | +static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL); | |
455 | + | |
456 | +SHOW(aux1) | |
457 | +SHOW(aux2) | |
458 | +SHOW(aux3) | |
459 | +SHOW(bat1) | |
460 | +SHOW(bat2) | |
461 | +SHOW(temp1) | |
462 | +SHOW(temp2) | |
463 | + | |
464 | +static ssize_t ad7877_disable_show(struct device *dev, | |
465 | + struct device_attribute *attr, char *buf) | |
466 | +{ | |
467 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
468 | + | |
469 | + return sprintf(buf, "%u\n", ts->disabled); | |
470 | +} | |
471 | + | |
472 | +static ssize_t ad7877_disable_store(struct device *dev, | |
473 | + struct device_attribute *attr, | |
474 | + const char *buf, size_t count) | |
475 | +{ | |
476 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
477 | + unsigned long val; | |
478 | + int error; | |
479 | + | |
480 | + error = strict_strtoul(buf, 10, &val); | |
481 | + if (error) | |
482 | + return error; | |
483 | + | |
484 | + if (val) | |
485 | + ad7877_disable(ts); | |
486 | + else | |
487 | + ad7877_enable(ts); | |
488 | + | |
489 | + return count; | |
490 | +} | |
491 | + | |
492 | +static DEVICE_ATTR(disable, 0664, ad7877_disable_show, ad7877_disable_store); | |
493 | + | |
494 | +static ssize_t ad7877_dac_show(struct device *dev, | |
495 | + struct device_attribute *attr, char *buf) | |
496 | +{ | |
497 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
498 | + | |
499 | + return sprintf(buf, "%u\n", ts->dac); | |
500 | +} | |
501 | + | |
502 | +static ssize_t ad7877_dac_store(struct device *dev, | |
503 | + struct device_attribute *attr, | |
504 | + const char *buf, size_t count) | |
505 | +{ | |
506 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
507 | + unsigned long val; | |
508 | + int error; | |
509 | + | |
510 | + error = strict_strtoul(buf, 10, &val); | |
511 | + if (error) | |
512 | + return error; | |
513 | + | |
514 | + mutex_lock(&ts->mutex); | |
515 | + ts->dac = val & 0xFF; | |
516 | + ad7877_write(ts->spi, AD7877_REG_DAC, (ts->dac << 4) | AD7877_DAC_CONF); | |
517 | + mutex_unlock(&ts->mutex); | |
518 | + | |
519 | + return count; | |
520 | +} | |
521 | + | |
522 | +static DEVICE_ATTR(dac, 0664, ad7877_dac_show, ad7877_dac_store); | |
523 | + | |
524 | +static ssize_t ad7877_gpio3_show(struct device *dev, | |
525 | + struct device_attribute *attr, char *buf) | |
526 | +{ | |
527 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
528 | + | |
529 | + return sprintf(buf, "%u\n", ts->gpio3); | |
530 | +} | |
531 | + | |
532 | +static ssize_t ad7877_gpio3_store(struct device *dev, | |
533 | + struct device_attribute *attr, | |
534 | + const char *buf, size_t count) | |
535 | +{ | |
536 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
537 | + unsigned long val; | |
538 | + int error; | |
539 | + | |
540 | + error = strict_strtoul(buf, 10, &val); | |
541 | + if (error) | |
542 | + return error; | |
543 | + | |
544 | + mutex_lock(&ts->mutex); | |
545 | + ts->gpio3 = !!val; | |
546 | + ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA | | |
547 | + (ts->gpio4 << 4) | (ts->gpio3 << 5)); | |
548 | + mutex_unlock(&ts->mutex); | |
549 | + | |
550 | + return count; | |
551 | +} | |
552 | + | |
553 | +static DEVICE_ATTR(gpio3, 0664, ad7877_gpio3_show, ad7877_gpio3_store); | |
554 | + | |
555 | +static ssize_t ad7877_gpio4_show(struct device *dev, | |
556 | + struct device_attribute *attr, char *buf) | |
557 | +{ | |
558 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
559 | + | |
560 | + return sprintf(buf, "%u\n", ts->gpio4); | |
561 | +} | |
562 | + | |
563 | +static ssize_t ad7877_gpio4_store(struct device *dev, | |
564 | + struct device_attribute *attr, | |
565 | + const char *buf, size_t count) | |
566 | +{ | |
567 | + struct ad7877 *ts = dev_get_drvdata(dev); | |
568 | + unsigned long val; | |
569 | + int error; | |
570 | + | |
571 | + error = strict_strtoul(buf, 10, &val); | |
572 | + if (error) | |
573 | + return error; | |
574 | + | |
575 | + mutex_lock(&ts->mutex); | |
576 | + ts->gpio4 = !!val; | |
577 | + ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA | | |
578 | + (ts->gpio4 << 4) | (ts->gpio3 << 5)); | |
579 | + mutex_unlock(&ts->mutex); | |
580 | + | |
581 | + return count; | |
582 | +} | |
583 | + | |
584 | +static DEVICE_ATTR(gpio4, 0664, ad7877_gpio4_show, ad7877_gpio4_store); | |
585 | + | |
586 | +static struct attribute *ad7877_attributes[] = { | |
587 | + &dev_attr_temp1.attr, | |
588 | + &dev_attr_temp2.attr, | |
589 | + &dev_attr_aux1.attr, | |
590 | + &dev_attr_aux2.attr, | |
591 | + &dev_attr_bat1.attr, | |
592 | + &dev_attr_bat2.attr, | |
593 | + &dev_attr_disable.attr, | |
594 | + &dev_attr_dac.attr, | |
595 | + &dev_attr_gpio4.attr, | |
596 | + NULL | |
597 | +}; | |
598 | + | |
599 | +static const struct attribute_group ad7877_attr_group = { | |
600 | + .attrs = ad7877_attributes, | |
601 | +}; | |
602 | + | |
603 | +static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts) | |
604 | +{ | |
605 | + struct spi_message *m; | |
606 | + int i; | |
607 | + | |
608 | + ts->cmd_crtl2 = AD7877_WRITEADD(AD7877_REG_CTRL2) | | |
609 | + AD7877_POL(ts->stopacq_polarity) | | |
610 | + AD7877_AVG(ts->averaging) | AD7877_PM(1) | | |
611 | + AD7877_TMR(ts->pen_down_acc_interval) | | |
612 | + AD7877_ACQ(ts->acquisition_time) | | |
613 | + AD7877_FCD(ts->first_conversion_delay); | |
614 | + | |
615 | + ad7877_write(spi, AD7877_REG_CTRL2, ts->cmd_crtl2); | |
616 | + | |
617 | + ts->cmd_crtl1 = AD7877_WRITEADD(AD7877_REG_CTRL1) | | |
618 | + AD7877_READADD(AD7877_REG_XPLUS-1) | | |
619 | + AD7877_MODE_SEQ1 | AD7877_DFR; | |
620 | + | |
621 | + ad7877_write(spi, AD7877_REG_CTRL1, ts->cmd_crtl1); | |
622 | + | |
623 | + ts->cmd_dummy = 0; | |
624 | + | |
625 | + m = &ts->msg; | |
626 | + | |
627 | + spi_message_init(m); | |
628 | + | |
629 | + m->complete = ad7877_callback; | |
630 | + m->context = ts; | |
631 | + | |
632 | + ts->xfer[0].tx_buf = &ts->cmd_crtl1; | |
633 | + ts->xfer[0].len = 2; | |
634 | + | |
635 | + spi_message_add_tail(&ts->xfer[0], m); | |
636 | + | |
637 | + ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */ | |
638 | + ts->xfer[1].len = 2; | |
639 | + | |
640 | + spi_message_add_tail(&ts->xfer[1], m); | |
641 | + | |
642 | + for (i = 0; i < 11; i++) { | |
643 | + ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i]; | |
644 | + ts->xfer[i + 2].len = 2; | |
645 | + spi_message_add_tail(&ts->xfer[i + 2], m); | |
646 | + } | |
647 | +} | |
648 | + | |
649 | +static int __devinit ad7877_probe(struct spi_device *spi) | |
650 | +{ | |
651 | + struct ad7877 *ts; | |
652 | + struct input_dev *input_dev; | |
653 | + struct ad7877_platform_data *pdata = spi->dev.platform_data; | |
654 | + int err; | |
655 | + u16 verify; | |
656 | + | |
657 | + if (!spi->irq) { | |
658 | + dev_dbg(&spi->dev, "no IRQ?\n"); | |
659 | + return -ENODEV; | |
660 | + } | |
661 | + | |
662 | + if (!pdata) { | |
663 | + dev_dbg(&spi->dev, "no platform data?\n"); | |
664 | + return -ENODEV; | |
665 | + } | |
666 | + | |
667 | + /* don't exceed max specified SPI CLK frequency */ | |
668 | + if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) { | |
669 | + dev_dbg(&spi->dev, "SPI CLK %d Hz?\n",spi->max_speed_hz); | |
670 | + return -EINVAL; | |
671 | + } | |
672 | + | |
673 | + ts = kzalloc(sizeof(struct ad7877), GFP_KERNEL); | |
674 | + input_dev = input_allocate_device(); | |
675 | + if (!ts || !input_dev) { | |
676 | + err = -ENOMEM; | |
677 | + goto err_free_mem; | |
678 | + } | |
679 | + | |
680 | + dev_set_drvdata(&spi->dev, ts); | |
681 | + ts->spi = spi; | |
682 | + ts->input = input_dev; | |
683 | + | |
684 | + setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts); | |
685 | + mutex_init(&ts->mutex); | |
686 | + spin_lock_init(&ts->lock); | |
687 | + | |
688 | + ts->model = pdata->model ? : 7877; | |
689 | + ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; | |
690 | + ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; | |
691 | + ts->pressure_max = pdata->pressure_max ? : ~0; | |
692 | + | |
693 | + ts->stopacq_polarity = pdata->stopacq_polarity; | |
694 | + ts->first_conversion_delay = pdata->first_conversion_delay; | |
695 | + ts->acquisition_time = pdata->acquisition_time; | |
696 | + ts->averaging = pdata->averaging; | |
697 | + ts->pen_down_acc_interval = pdata->pen_down_acc_interval; | |
698 | + | |
699 | + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); | |
700 | + | |
701 | + input_dev->name = "AD7877 Touchscreen"; | |
702 | + input_dev->phys = ts->phys; | |
703 | + input_dev->dev.parent = &spi->dev; | |
704 | + | |
705 | + __set_bit(EV_ABS, input_dev->evbit); | |
706 | + __set_bit(ABS_X, input_dev->absbit); | |
707 | + __set_bit(ABS_Y, input_dev->absbit); | |
708 | + __set_bit(ABS_PRESSURE, input_dev->absbit); | |
709 | + | |
710 | + input_set_abs_params(input_dev, ABS_X, | |
711 | + pdata->x_min ? : 0, | |
712 | + pdata->x_max ? : MAX_12BIT, | |
713 | + 0, 0); | |
714 | + input_set_abs_params(input_dev, ABS_Y, | |
715 | + pdata->y_min ? : 0, | |
716 | + pdata->y_max ? : MAX_12BIT, | |
717 | + 0, 0); | |
718 | + input_set_abs_params(input_dev, ABS_PRESSURE, | |
719 | + pdata->pressure_min, pdata->pressure_max, 0, 0); | |
720 | + | |
721 | + ad7877_write(spi, AD7877_REG_SEQ1, AD7877_MM_SEQUENCE); | |
722 | + | |
723 | + verify = ad7877_read(spi, AD7877_REG_SEQ1); | |
724 | + | |
725 | + if (verify != AD7877_MM_SEQUENCE){ | |
726 | + dev_err(&spi->dev, "%s: Failed to probe %s\n", | |
727 | + dev_name(&spi->dev), input_dev->name); | |
728 | + err = -ENODEV; | |
729 | + goto err_free_mem; | |
730 | + } | |
731 | + | |
732 | + if (gpio3) | |
733 | + ad7877_write(spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_3_CONF); | |
734 | + | |
735 | + ad7877_setup_ts_def_msg(spi, ts); | |
736 | + | |
737 | + /* Request AD7877 /DAV GPIO interrupt */ | |
738 | + | |
739 | + err = request_irq(spi->irq, ad7877_irq, IRQF_TRIGGER_FALLING | | |
740 | + IRQF_SAMPLE_RANDOM, spi->dev.driver->name, ts); | |
741 | + if (err) { | |
742 | + dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); | |
743 | + goto err_free_mem; | |
744 | + } | |
745 | + | |
746 | + err = sysfs_create_group(&spi->dev.kobj, &ad7877_attr_group); | |
747 | + if (err) | |
748 | + goto err_free_irq; | |
749 | + | |
750 | + err = device_create_file(&spi->dev, | |
751 | + gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3); | |
752 | + if (err) | |
753 | + goto err_remove_attr_group; | |
754 | + | |
755 | + err = input_register_device(input_dev); | |
756 | + if (err) | |
757 | + goto err_remove_attr; | |
758 | + | |
759 | + return 0; | |
760 | + | |
761 | +err_remove_attr: | |
762 | + device_remove_file(&spi->dev, | |
763 | + gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3); | |
764 | +err_remove_attr_group: | |
765 | + sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group); | |
766 | +err_free_irq: | |
767 | + free_irq(spi->irq, ts); | |
768 | +err_free_mem: | |
769 | + input_free_device(input_dev); | |
770 | + kfree(ts); | |
771 | + dev_set_drvdata(&spi->dev, NULL); | |
772 | + return err; | |
773 | +} | |
774 | + | |
775 | +static int __devexit ad7877_remove(struct spi_device *spi) | |
776 | +{ | |
777 | + struct ad7877 *ts = dev_get_drvdata(&spi->dev); | |
778 | + | |
779 | + sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group); | |
780 | + device_remove_file(&spi->dev, | |
781 | + gpio3 ? &dev_attr_gpio3 : &dev_attr_aux3); | |
782 | + | |
783 | + ad7877_disable(ts); | |
784 | + free_irq(ts->spi->irq, ts); | |
785 | + | |
786 | + input_unregister_device(ts->input); | |
787 | + kfree(ts); | |
788 | + | |
789 | + dev_dbg(&spi->dev, "unregistered touchscreen\n"); | |
790 | + dev_set_drvdata(&spi->dev, NULL); | |
791 | + | |
792 | + return 0; | |
793 | +} | |
794 | + | |
795 | +#ifdef CONFIG_PM | |
796 | +static int ad7877_suspend(struct spi_device *spi, pm_message_t message) | |
797 | +{ | |
798 | + struct ad7877 *ts = dev_get_drvdata(&spi->dev); | |
799 | + | |
800 | + ad7877_disable(ts); | |
801 | + | |
802 | + return 0; | |
803 | +} | |
804 | + | |
805 | +static int ad7877_resume(struct spi_device *spi) | |
806 | +{ | |
807 | + struct ad7877 *ts = dev_get_drvdata(&spi->dev); | |
808 | + | |
809 | + ad7877_enable(ts); | |
810 | + | |
811 | + return 0; | |
812 | +} | |
813 | +#else | |
814 | +#define ad7877_suspend NULL | |
815 | +#define ad7877_resume NULL | |
816 | +#endif | |
817 | + | |
818 | +static struct spi_driver ad7877_driver = { | |
819 | + .driver = { | |
820 | + .name = "ad7877", | |
821 | + .bus = &spi_bus_type, | |
822 | + .owner = THIS_MODULE, | |
823 | + }, | |
824 | + .probe = ad7877_probe, | |
825 | + .remove = __devexit_p(ad7877_remove), | |
826 | + .suspend = ad7877_suspend, | |
827 | + .resume = ad7877_resume, | |
828 | +}; | |
829 | + | |
830 | +static int __init ad7877_init(void) | |
831 | +{ | |
832 | + return spi_register_driver(&ad7877_driver); | |
833 | +} | |
834 | +module_init(ad7877_init); | |
835 | + | |
836 | +static void __exit ad7877_exit(void) | |
837 | +{ | |
838 | + spi_unregister_driver(&ad7877_driver); | |
839 | +} | |
840 | +module_exit(ad7877_exit); | |
841 | + | |
842 | +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | |
843 | +MODULE_DESCRIPTION("AD7877 touchscreen Driver"); | |
844 | +MODULE_LICENSE("GPL"); |
drivers/input/touchscreen/ad7879.c
1 | +/* | |
2 | + * Copyright (C) 2008 Michael Hennerich, Analog Devices Inc. | |
3 | + * | |
4 | + * Description: AD7879 based touchscreen, and GPIO driver (I2C/SPI Interface) | |
5 | + * | |
6 | + * Bugs: Enter bugs at http://blackfin.uclinux.org/ | |
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 as published by | |
10 | + * the Free Software Foundation; either version 2 of the License, or | |
11 | + * (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, see the file COPYING, or write | |
20 | + * to the Free Software Foundation, Inc., | |
21 | + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | + * | |
23 | + * History: | |
24 | + * Copyright (c) 2005 David Brownell | |
25 | + * Copyright (c) 2006 Nokia Corporation | |
26 | + * Various changes: Imre Deak <imre.deak@nokia.com> | |
27 | + * | |
28 | + * Using code from: | |
29 | + * - corgi_ts.c | |
30 | + * Copyright (C) 2004-2005 Richard Purdie | |
31 | + * - omap_ts.[hc], ads7846.h, ts_osk.c | |
32 | + * Copyright (C) 2002 MontaVista Software | |
33 | + * Copyright (C) 2004 Texas Instruments | |
34 | + * Copyright (C) 2005 Dirk Behme | |
35 | + * - ad7877.c | |
36 | + * Copyright (C) 2006-2008 Analog Devices Inc. | |
37 | + */ | |
38 | + | |
39 | +#include <linux/device.h> | |
40 | +#include <linux/init.h> | |
41 | +#include <linux/delay.h> | |
42 | +#include <linux/input.h> | |
43 | +#include <linux/interrupt.h> | |
44 | +#include <linux/irq.h> | |
45 | +#include <linux/slab.h> | |
46 | +#include <linux/workqueue.h> | |
47 | +#include <linux/spi/spi.h> | |
48 | +#include <linux/i2c.h> | |
49 | + | |
50 | +#include <linux/spi/ad7879.h> | |
51 | + | |
52 | +#define AD7879_REG_ZEROS 0 | |
53 | +#define AD7879_REG_CTRL1 1 | |
54 | +#define AD7879_REG_CTRL2 2 | |
55 | +#define AD7879_REG_CTRL3 3 | |
56 | +#define AD7879_REG_AUX1HIGH 4 | |
57 | +#define AD7879_REG_AUX1LOW 5 | |
58 | +#define AD7879_REG_TEMP1HIGH 6 | |
59 | +#define AD7879_REG_TEMP1LOW 7 | |
60 | +#define AD7879_REG_XPLUS 8 | |
61 | +#define AD7879_REG_YPLUS 9 | |
62 | +#define AD7879_REG_Z1 10 | |
63 | +#define AD7879_REG_Z2 11 | |
64 | +#define AD7879_REG_AUXVBAT 12 | |
65 | +#define AD7879_REG_TEMP 13 | |
66 | +#define AD7879_REG_REVID 14 | |
67 | + | |
68 | +/* Control REG 1 */ | |
69 | +#define AD7879_TMR(x) ((x & 0xFF) << 0) | |
70 | +#define AD7879_ACQ(x) ((x & 0x3) << 8) | |
71 | +#define AD7879_MODE_NOC (0 << 10) /* Do not convert */ | |
72 | +#define AD7879_MODE_SCC (1 << 10) /* Single channel conversion */ | |
73 | +#define AD7879_MODE_SEQ0 (2 << 10) /* Sequence 0 in Slave Mode */ | |
74 | +#define AD7879_MODE_SEQ1 (3 << 10) /* Sequence 1 in Master Mode */ | |
75 | +#define AD7879_MODE_INT (1 << 15) /* PENIRQ disabled INT enabled */ | |
76 | + | |
77 | +/* Control REG 2 */ | |
78 | +#define AD7879_FCD(x) ((x & 0x3) << 0) | |
79 | +#define AD7879_RESET (1 << 4) | |
80 | +#define AD7879_MFS(x) ((x & 0x3) << 5) | |
81 | +#define AD7879_AVG(x) ((x & 0x3) << 7) | |
82 | +#define AD7879_SER (1 << 9) /* non-differential */ | |
83 | +#define AD7879_DFR (0 << 9) /* differential */ | |
84 | +#define AD7879_GPIOPOL (1 << 10) | |
85 | +#define AD7879_GPIODIR (1 << 11) | |
86 | +#define AD7879_GPIO_DATA (1 << 12) | |
87 | +#define AD7879_GPIO_EN (1 << 13) | |
88 | +#define AD7879_PM(x) ((x & 0x3) << 14) | |
89 | +#define AD7879_PM_SHUTDOWN (0) | |
90 | +#define AD7879_PM_DYN (1) | |
91 | +#define AD7879_PM_FULLON (2) | |
92 | + | |
93 | +/* Control REG 3 */ | |
94 | +#define AD7879_TEMPMASK_BIT (1<<15) | |
95 | +#define AD7879_AUXVBATMASK_BIT (1<<14) | |
96 | +#define AD7879_INTMODE_BIT (1<<13) | |
97 | +#define AD7879_GPIOALERTMASK_BIT (1<<12) | |
98 | +#define AD7879_AUXLOW_BIT (1<<11) | |
99 | +#define AD7879_AUXHIGH_BIT (1<<10) | |
100 | +#define AD7879_TEMPLOW_BIT (1<<9) | |
101 | +#define AD7879_TEMPHIGH_BIT (1<<8) | |
102 | +#define AD7879_YPLUS_BIT (1<<7) | |
103 | +#define AD7879_XPLUS_BIT (1<<6) | |
104 | +#define AD7879_Z1_BIT (1<<5) | |
105 | +#define AD7879_Z2_BIT (1<<4) | |
106 | +#define AD7879_AUX_BIT (1<<3) | |
107 | +#define AD7879_VBAT_BIT (1<<2) | |
108 | +#define AD7879_TEMP_BIT (1<<1) | |
109 | + | |
110 | +enum { | |
111 | + AD7879_SEQ_XPOS = 0, | |
112 | + AD7879_SEQ_YPOS = 1, | |
113 | + AD7879_SEQ_Z1 = 2, | |
114 | + AD7879_SEQ_Z2 = 3, | |
115 | + AD7879_NR_SENSE = 4, | |
116 | +}; | |
117 | + | |
118 | +#define MAX_12BIT ((1<<12)-1) | |
119 | +#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50) | |
120 | + | |
121 | +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) | |
122 | +#define AD7879_DEVID 0x7A | |
123 | +typedef struct spi_device bus_device; | |
124 | +#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE) | |
125 | +#define AD7879_DEVID 0x79 | |
126 | +typedef struct i2c_client bus_device; | |
127 | +#endif | |
128 | + | |
129 | +struct ad7879 { | |
130 | + bus_device *bus; | |
131 | + struct input_dev *input; | |
132 | + struct work_struct work; | |
133 | + struct timer_list timer; | |
134 | + | |
135 | + struct mutex mutex; | |
136 | + unsigned disabled:1; /* P: mutex */ | |
137 | + | |
138 | +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) | |
139 | + struct spi_message msg; | |
140 | + struct spi_transfer xfer[AD7879_NR_SENSE + 1]; | |
141 | + u16 cmd; | |
142 | +#endif | |
143 | + u16 conversion_data[AD7879_NR_SENSE]; | |
144 | + char phys[32]; | |
145 | + u8 first_conversion_delay; | |
146 | + u8 acquisition_time; | |
147 | + u8 averaging; | |
148 | + u8 pen_down_acc_interval; | |
149 | + u8 median; | |
150 | + u16 x_plate_ohms; | |
151 | + u16 pressure_max; | |
152 | + u16 gpio_init; | |
153 | + u16 cmd_crtl1; | |
154 | + u16 cmd_crtl2; | |
155 | + u16 cmd_crtl3; | |
156 | + unsigned gpio:1; | |
157 | +}; | |
158 | + | |
159 | +static int ad7879_read(bus_device *, u8); | |
160 | +static int ad7879_write(bus_device *, u8, u16); | |
161 | +static void ad7879_collect(struct ad7879 *); | |
162 | + | |
163 | +static void ad7879_report(struct ad7879 *ts) | |
164 | +{ | |
165 | + struct input_dev *input_dev = ts->input; | |
166 | + unsigned Rt; | |
167 | + u16 x, y, z1, z2; | |
168 | + | |
169 | + x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT; | |
170 | + y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT; | |
171 | + z1 = ts->conversion_data[AD7879_SEQ_Z1] & MAX_12BIT; | |
172 | + z2 = ts->conversion_data[AD7879_SEQ_Z2] & MAX_12BIT; | |
173 | + | |
174 | + /* | |
175 | + * The samples processed here are already preprocessed by the AD7879. | |
176 | + * The preprocessing function consists of a median and an averaging filter. | |
177 | + * The combination of these two techniques provides a robust solution, | |
178 | + * discarding the spurious noise in the signal and keeping only the data of interest. | |
179 | + * The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h) | |
180 | + * Other user-programmable conversion controls include variable acquisition time, | |
181 | + * and first conversion delay. Up to 16 averages can be taken per conversion. | |
182 | + */ | |
183 | + | |
184 | + if (likely(x && z1)) { | |
185 | + /* compute touch pressure resistance using equation #1 */ | |
186 | + Rt = (z2 - z1) * x * ts->x_plate_ohms; | |
187 | + Rt /= z1; | |
188 | + Rt = (Rt + 2047) >> 12; | |
189 | + | |
190 | + input_report_abs(input_dev, ABS_X, x); | |
191 | + input_report_abs(input_dev, ABS_Y, y); | |
192 | + input_report_abs(input_dev, ABS_PRESSURE, Rt); | |
193 | + input_sync(input_dev); | |
194 | + } | |
195 | +} | |
196 | + | |
197 | +static void ad7879_work(struct work_struct *work) | |
198 | +{ | |
199 | + struct ad7879 *ts = container_of(work, struct ad7879, work); | |
200 | + | |
201 | + /* use keventd context to read the result registers */ | |
202 | + ad7879_collect(ts); | |
203 | + ad7879_report(ts); | |
204 | + mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT); | |
205 | +} | |
206 | + | |
207 | +static void ad7879_ts_event_release(struct ad7879 *ts) | |
208 | +{ | |
209 | + struct input_dev *input_dev = ts->input; | |
210 | + | |
211 | + input_report_abs(input_dev, ABS_PRESSURE, 0); | |
212 | + input_sync(input_dev); | |
213 | +} | |
214 | + | |
215 | +static void ad7879_timer(unsigned long handle) | |
216 | +{ | |
217 | + struct ad7879 *ts = (void *)handle; | |
218 | + | |
219 | + ad7879_ts_event_release(ts); | |
220 | +} | |
221 | + | |
222 | +static irqreturn_t ad7879_irq(int irq, void *handle) | |
223 | +{ | |
224 | + struct ad7879 *ts = handle; | |
225 | + | |
226 | + /* The repeated conversion sequencer controlled by TMR kicked off too fast. | |
227 | + * We ignore the last and process the sample sequence currently in the queue. | |
228 | + * It can't be older than 9.4ms | |
229 | + */ | |
230 | + | |
231 | + if (!work_pending(&ts->work)) | |
232 | + schedule_work(&ts->work); | |
233 | + | |
234 | + return IRQ_HANDLED; | |
235 | +} | |
236 | + | |
237 | +static void ad7879_setup(struct ad7879 *ts) | |
238 | +{ | |
239 | + ts->cmd_crtl3 = AD7879_YPLUS_BIT | | |
240 | + AD7879_XPLUS_BIT | | |
241 | + AD7879_Z2_BIT | | |
242 | + AD7879_Z1_BIT | | |
243 | + AD7879_TEMPMASK_BIT | | |
244 | + AD7879_AUXVBATMASK_BIT | | |
245 | + AD7879_GPIOALERTMASK_BIT; | |
246 | + | |
247 | + ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR | | |
248 | + AD7879_AVG(ts->averaging) | | |
249 | + AD7879_MFS(ts->median) | | |
250 | + AD7879_FCD(ts->first_conversion_delay) | | |
251 | + ts->gpio_init; | |
252 | + | |
253 | + ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 | | |
254 | + AD7879_ACQ(ts->acquisition_time) | | |
255 | + AD7879_TMR(ts->pen_down_acc_interval); | |
256 | + | |
257 | + ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2); | |
258 | + ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3); | |
259 | + ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1); | |
260 | +} | |
261 | + | |
262 | +static void ad7879_disable(struct ad7879 *ts) | |
263 | +{ | |
264 | + mutex_lock(&ts->mutex); | |
265 | + | |
266 | + if (!ts->disabled) { | |
267 | + | |
268 | + ts->disabled = 1; | |
269 | + disable_irq(ts->bus->irq); | |
270 | + | |
271 | + cancel_work_sync(&ts->work); | |
272 | + | |
273 | + if (del_timer_sync(&ts->timer)) | |
274 | + ad7879_ts_event_release(ts); | |
275 | + | |
276 | + ad7879_write(ts->bus, AD7879_REG_CTRL2, | |
277 | + AD7879_PM(AD7879_PM_SHUTDOWN)); | |
278 | + } | |
279 | + | |
280 | + mutex_unlock(&ts->mutex); | |
281 | +} | |
282 | + | |
283 | +static void ad7879_enable(struct ad7879 *ts) | |
284 | +{ | |
285 | + mutex_lock(&ts->mutex); | |
286 | + | |
287 | + if (ts->disabled) { | |
288 | + ad7879_setup(ts); | |
289 | + ts->disabled = 0; | |
290 | + enable_irq(ts->bus->irq); | |
291 | + } | |
292 | + | |
293 | + mutex_unlock(&ts->mutex); | |
294 | +} | |
295 | + | |
296 | +static ssize_t ad7879_disable_show(struct device *dev, | |
297 | + struct device_attribute *attr, char *buf) | |
298 | +{ | |
299 | + struct ad7879 *ts = dev_get_drvdata(dev); | |
300 | + | |
301 | + return sprintf(buf, "%u\n", ts->disabled); | |
302 | +} | |
303 | + | |
304 | +static ssize_t ad7879_disable_store(struct device *dev, | |
305 | + struct device_attribute *attr, | |
306 | + const char *buf, size_t count) | |
307 | +{ | |
308 | + struct ad7879 *ts = dev_get_drvdata(dev); | |
309 | + unsigned long val; | |
310 | + int error; | |
311 | + | |
312 | + error = strict_strtoul(buf, 10, &val); | |
313 | + if (error) | |
314 | + return error; | |
315 | + | |
316 | + if (val) | |
317 | + ad7879_disable(ts); | |
318 | + else | |
319 | + ad7879_enable(ts); | |
320 | + | |
321 | + return count; | |
322 | +} | |
323 | + | |
324 | +static DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store); | |
325 | + | |
326 | +static ssize_t ad7879_gpio_show(struct device *dev, | |
327 | + struct device_attribute *attr, char *buf) | |
328 | +{ | |
329 | + struct ad7879 *ts = dev_get_drvdata(dev); | |
330 | + | |
331 | + return sprintf(buf, "%u\n", ts->gpio); | |
332 | +} | |
333 | + | |
334 | +static ssize_t ad7879_gpio_store(struct device *dev, | |
335 | + struct device_attribute *attr, | |
336 | + const char *buf, size_t count) | |
337 | +{ | |
338 | + struct ad7879 *ts = dev_get_drvdata(dev); | |
339 | + unsigned long val; | |
340 | + int error; | |
341 | + | |
342 | + error = strict_strtoul(buf, 10, &val); | |
343 | + if (error) | |
344 | + return error; | |
345 | + | |
346 | + mutex_lock(&ts->mutex); | |
347 | + ts->gpio = !!val; | |
348 | + error = ad7879_write(ts->bus, AD7879_REG_CTRL2, | |
349 | + ts->gpio ? | |
350 | + ts->cmd_crtl2 & ~AD7879_GPIO_DATA : | |
351 | + ts->cmd_crtl2 | AD7879_GPIO_DATA); | |
352 | + mutex_unlock(&ts->mutex); | |
353 | + | |
354 | + return error ? : count; | |
355 | +} | |
356 | + | |
357 | +static DEVICE_ATTR(gpio, 0664, ad7879_gpio_show, ad7879_gpio_store); | |
358 | + | |
359 | +static struct attribute *ad7879_attributes[] = { | |
360 | + &dev_attr_disable.attr, | |
361 | + &dev_attr_gpio.attr, | |
362 | + NULL | |
363 | +}; | |
364 | + | |
365 | +static const struct attribute_group ad7879_attr_group = { | |
366 | + .attrs = ad7879_attributes, | |
367 | +}; | |
368 | + | |
369 | +static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts) | |
370 | +{ | |
371 | + struct input_dev *input_dev; | |
372 | + struct ad7879_platform_data *pdata = bus->dev.platform_data; | |
373 | + int err; | |
374 | + u16 revid; | |
375 | + | |
376 | + if (!bus->irq) { | |
377 | + dev_err(&bus->dev, "no IRQ?\n"); | |
378 | + return -ENODEV; | |
379 | + } | |
380 | + | |
381 | + if (!pdata) { | |
382 | + dev_err(&bus->dev, "no platform data?\n"); | |
383 | + return -ENODEV; | |
384 | + } | |
385 | + | |
386 | + input_dev = input_allocate_device(); | |
387 | + if (!input_dev) | |
388 | + return -ENOMEM; | |
389 | + | |
390 | + ts->input = input_dev; | |
391 | + | |
392 | + setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts); | |
393 | + INIT_WORK(&ts->work, ad7879_work); | |
394 | + mutex_init(&ts->mutex); | |
395 | + | |
396 | + ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; | |
397 | + ts->pressure_max = pdata->pressure_max ? : ~0; | |
398 | + | |
399 | + ts->first_conversion_delay = pdata->first_conversion_delay; | |
400 | + ts->acquisition_time = pdata->acquisition_time; | |
401 | + ts->averaging = pdata->averaging; | |
402 | + ts->pen_down_acc_interval = pdata->pen_down_acc_interval; | |
403 | + ts->median = pdata->median; | |
404 | + | |
405 | + if (pdata->gpio_output) | |
406 | + ts->gpio_init = AD7879_GPIO_EN | | |
407 | + (pdata->gpio_default ? 0 : AD7879_GPIO_DATA); | |
408 | + else | |
409 | + ts->gpio_init = AD7879_GPIO_EN | AD7879_GPIODIR; | |
410 | + | |
411 | + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev)); | |
412 | + | |
413 | + input_dev->name = "AD7879 Touchscreen"; | |
414 | + input_dev->phys = ts->phys; | |
415 | + input_dev->dev.parent = &bus->dev; | |
416 | + | |
417 | + __set_bit(EV_ABS, input_dev->evbit); | |
418 | + __set_bit(ABS_X, input_dev->absbit); | |
419 | + __set_bit(ABS_Y, input_dev->absbit); | |
420 | + __set_bit(ABS_PRESSURE, input_dev->absbit); | |
421 | + | |
422 | + input_set_abs_params(input_dev, ABS_X, | |
423 | + pdata->x_min ? : 0, | |
424 | + pdata->x_max ? : MAX_12BIT, | |
425 | + 0, 0); | |
426 | + input_set_abs_params(input_dev, ABS_Y, | |
427 | + pdata->y_min ? : 0, | |
428 | + pdata->y_max ? : MAX_12BIT, | |
429 | + 0, 0); | |
430 | + input_set_abs_params(input_dev, ABS_PRESSURE, | |
431 | + pdata->pressure_min, pdata->pressure_max, 0, 0); | |
432 | + | |
433 | + err = ad7879_write(bus, AD7879_REG_CTRL2, AD7879_RESET); | |
434 | + | |
435 | + if (err < 0) { | |
436 | + dev_err(&bus->dev, "Failed to write %s\n", input_dev->name); | |
437 | + goto err_free_mem; | |
438 | + } | |
439 | + | |
440 | + revid = ad7879_read(bus, AD7879_REG_REVID); | |
441 | + | |
442 | + if ((revid & 0xFF) != AD7879_DEVID) { | |
443 | + dev_err(&bus->dev, "Failed to probe %s\n", input_dev->name); | |
444 | + err = -ENODEV; | |
445 | + goto err_free_mem; | |
446 | + } | |
447 | + | |
448 | + ad7879_setup(ts); | |
449 | + | |
450 | + err = request_irq(bus->irq, ad7879_irq, | |
451 | + IRQF_TRIGGER_FALLING | IRQF_SAMPLE_RANDOM, | |
452 | + bus->dev.driver->name, ts); | |
453 | + | |
454 | + if (err) { | |
455 | + dev_err(&bus->dev, "irq %d busy?\n", bus->irq); | |
456 | + goto err_free_mem; | |
457 | + } | |
458 | + | |
459 | + err = sysfs_create_group(&bus->dev.kobj, &ad7879_attr_group); | |
460 | + if (err) | |
461 | + goto err_free_irq; | |
462 | + | |
463 | + err = input_register_device(input_dev); | |
464 | + if (err) | |
465 | + goto err_remove_attr; | |
466 | + | |
467 | + dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n", | |
468 | + revid >> 8, bus->irq); | |
469 | + | |
470 | + return 0; | |
471 | + | |
472 | +err_remove_attr: | |
473 | + sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group); | |
474 | +err_free_irq: | |
475 | + free_irq(bus->irq, ts); | |
476 | +err_free_mem: | |
477 | + input_free_device(input_dev); | |
478 | + | |
479 | + return err; | |
480 | +} | |
481 | + | |
482 | +static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts) | |
483 | +{ | |
484 | + ad7879_disable(ts); | |
485 | + sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group); | |
486 | + free_irq(ts->bus->irq, ts); | |
487 | + input_unregister_device(ts->input); | |
488 | + dev_dbg(&bus->dev, "unregistered touchscreen\n"); | |
489 | + | |
490 | + return 0; | |
491 | +} | |
492 | + | |
493 | +#ifdef CONFIG_PM | |
494 | +static int ad7879_suspend(bus_device *bus, pm_message_t message) | |
495 | +{ | |
496 | + struct ad7879 *ts = dev_get_drvdata(&bus->dev); | |
497 | + | |
498 | + ad7879_disable(ts); | |
499 | + | |
500 | + return 0; | |
501 | +} | |
502 | + | |
503 | +static int ad7879_resume(bus_device *bus) | |
504 | +{ | |
505 | + struct ad7879 *ts = dev_get_drvdata(&bus->dev); | |
506 | + | |
507 | + ad7879_enable(ts); | |
508 | + | |
509 | + return 0; | |
510 | +} | |
511 | +#else | |
512 | +#define ad7879_suspend NULL | |
513 | +#define ad7879_resume NULL | |
514 | +#endif | |
515 | + | |
516 | +#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE) | |
517 | +#define MAX_SPI_FREQ_HZ 5000000 | |
518 | +#define AD7879_CMD_MAGIC 0xE000 | |
519 | +#define AD7879_CMD_READ (1 << 10) | |
520 | +#define AD7879_WRITECMD(reg) (AD7879_CMD_MAGIC | (reg & 0xF)) | |
521 | +#define AD7879_READCMD(reg) (AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF)) | |
522 | + | |
523 | +struct ser_req { | |
524 | + u16 command; | |
525 | + u16 data; | |
526 | + struct spi_message msg; | |
527 | + struct spi_transfer xfer[2]; | |
528 | +}; | |
529 | + | |
530 | +/* | |
531 | + * ad7879_read/write are only used for initial setup and for sysfs controls. | |
532 | + * The main traffic is done in ad7879_collect(). | |
533 | + */ | |
534 | + | |
535 | +static int ad7879_read(struct spi_device *spi, u8 reg) | |
536 | +{ | |
537 | + struct ser_req *req; | |
538 | + int status, ret; | |
539 | + | |
540 | + req = kzalloc(sizeof *req, GFP_KERNEL); | |
541 | + if (!req) | |
542 | + return -ENOMEM; | |
543 | + | |
544 | + spi_message_init(&req->msg); | |
545 | + | |
546 | + req->command = (u16) AD7879_READCMD(reg); | |
547 | + req->xfer[0].tx_buf = &req->command; | |
548 | + req->xfer[0].len = 2; | |
549 | + | |
550 | + req->xfer[1].rx_buf = &req->data; | |
551 | + req->xfer[1].len = 2; | |
552 | + | |
553 | + spi_message_add_tail(&req->xfer[0], &req->msg); | |
554 | + spi_message_add_tail(&req->xfer[1], &req->msg); | |
555 | + | |
556 | + status = spi_sync(spi, &req->msg); | |
557 | + ret = status ? : req->data; | |
558 | + | |
559 | + kfree(req); | |
560 | + | |
561 | + return ret; | |
562 | +} | |
563 | + | |
564 | +static int ad7879_write(struct spi_device *spi, u8 reg, u16 val) | |
565 | +{ | |
566 | + struct ser_req *req; | |
567 | + int status; | |
568 | + | |
569 | + req = kzalloc(sizeof *req, GFP_KERNEL); | |
570 | + if (!req) | |
571 | + return -ENOMEM; | |
572 | + | |
573 | + spi_message_init(&req->msg); | |
574 | + | |
575 | + req->command = (u16) AD7879_WRITECMD(reg); | |
576 | + req->xfer[0].tx_buf = &req->command; | |
577 | + req->xfer[0].len = 2; | |
578 | + | |
579 | + req->data = val; | |
580 | + req->xfer[1].tx_buf = &req->data; | |
581 | + req->xfer[1].len = 2; | |
582 | + | |
583 | + spi_message_add_tail(&req->xfer[0], &req->msg); | |
584 | + spi_message_add_tail(&req->xfer[1], &req->msg); | |
585 | + | |
586 | + status = spi_sync(spi, &req->msg); | |
587 | + | |
588 | + kfree(req); | |
589 | + | |
590 | + return status; | |
591 | +} | |
592 | + | |
593 | +static void ad7879_collect(struct ad7879 *ts) | |
594 | +{ | |
595 | + int status = spi_sync(ts->bus, &ts->msg); | |
596 | + | |
597 | + if (status) | |
598 | + dev_err(&ts->bus->dev, "spi_sync --> %d\n", status); | |
599 | +} | |
600 | + | |
601 | +static void ad7879_setup_ts_def_msg(struct ad7879 *ts) | |
602 | +{ | |
603 | + struct spi_message *m; | |
604 | + int i; | |
605 | + | |
606 | + ts->cmd = (u16) AD7879_READCMD(AD7879_REG_XPLUS); | |
607 | + | |
608 | + m = &ts->msg; | |
609 | + spi_message_init(m); | |
610 | + ts->xfer[0].tx_buf = &ts->cmd; | |
611 | + ts->xfer[0].len = 2; | |
612 | + | |
613 | + spi_message_add_tail(&ts->xfer[0], m); | |
614 | + | |
615 | + for (i = 0; i < AD7879_NR_SENSE; i++) { | |
616 | + ts->xfer[i + 1].rx_buf = &ts->conversion_data[i]; | |
617 | + ts->xfer[i + 1].len = 2; | |
618 | + spi_message_add_tail(&ts->xfer[i + 1], m); | |
619 | + } | |
620 | +} | |
621 | + | |
622 | +static int __devinit ad7879_probe(struct spi_device *spi) | |
623 | +{ | |
624 | + struct ad7879 *ts; | |
625 | + int error; | |
626 | + | |
627 | + /* don't exceed max specified SPI CLK frequency */ | |
628 | + if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) { | |
629 | + dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz); | |
630 | + return -EINVAL; | |
631 | + } | |
632 | + | |
633 | + ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL); | |
634 | + if (!ts) | |
635 | + return -ENOMEM; | |
636 | + | |
637 | + dev_set_drvdata(&spi->dev, ts); | |
638 | + ts->bus = spi; | |
639 | + | |
640 | + ad7879_setup_ts_def_msg(ts); | |
641 | + | |
642 | + error = ad7879_construct(spi, ts); | |
643 | + if (error) { | |
644 | + dev_set_drvdata(&spi->dev, NULL); | |
645 | + kfree(ts); | |
646 | + } | |
647 | + | |
648 | + return 0; | |
649 | +} | |
650 | + | |
651 | +static int __devexit ad7879_remove(struct spi_device *spi) | |
652 | +{ | |
653 | + struct ad7879 *ts = dev_get_drvdata(&spi->dev); | |
654 | + | |
655 | + ad7879_destroy(spi, ts); | |
656 | + dev_set_drvdata(&spi->dev, NULL); | |
657 | + kfree(ts); | |
658 | + | |
659 | + return 0; | |
660 | +} | |
661 | + | |
662 | +static struct spi_driver ad7879_driver = { | |
663 | + .driver = { | |
664 | + .name = "ad7879", | |
665 | + .bus = &spi_bus_type, | |
666 | + .owner = THIS_MODULE, | |
667 | + }, | |
668 | + .probe = ad7879_probe, | |
669 | + .remove = __devexit_p(ad7879_remove), | |
670 | + .suspend = ad7879_suspend, | |
671 | + .resume = ad7879_resume, | |
672 | +}; | |
673 | + | |
674 | +static int __init ad7879_init(void) | |
675 | +{ | |
676 | + return spi_register_driver(&ad7879_driver); | |
677 | +} | |
678 | +module_init(ad7879_init); | |
679 | + | |
680 | +static void __exit ad7879_exit(void) | |
681 | +{ | |
682 | + spi_unregister_driver(&ad7879_driver); | |
683 | +} | |
684 | +module_exit(ad7879_exit); | |
685 | + | |
686 | +#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE) | |
687 | + | |
688 | +/* All registers are word-sized. | |
689 | + * AD7879 uses a high-byte first convention. | |
690 | + */ | |
691 | +static int ad7879_read(struct i2c_client *client, u8 reg) | |
692 | +{ | |
693 | + return swab16(i2c_smbus_read_word_data(client, reg)); | |
694 | +} | |
695 | + | |
696 | +static int ad7879_write(struct i2c_client *client, u8 reg, u16 val) | |
697 | +{ | |
698 | + return i2c_smbus_write_word_data(client, reg, swab16(val)); | |
699 | +} | |
700 | + | |
701 | +static void ad7879_collect(struct ad7879 *ts) | |
702 | +{ | |
703 | + int i; | |
704 | + | |
705 | + for (i = 0; i < AD7879_NR_SENSE; i++) | |
706 | + ts->conversion_data[i] = ad7879_read(ts->bus, | |
707 | + AD7879_REG_XPLUS + i); | |
708 | +} | |
709 | + | |
710 | +static int __devinit ad7879_probe(struct i2c_client *client, | |
711 | + const struct i2c_device_id *id) | |
712 | +{ | |
713 | + struct ad7879 *ts; | |
714 | + int error; | |
715 | + | |
716 | + if (!i2c_check_functionality(client->adapter, | |
717 | + I2C_FUNC_SMBUS_WORD_DATA)) { | |
718 | + dev_err(&client->dev, "SMBUS Word Data not Supported\n"); | |
719 | + return -EIO; | |
720 | + } | |
721 | + | |
722 | + ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL); | |
723 | + if (!ts) | |
724 | + return -ENOMEM; | |
725 | + | |
726 | + i2c_set_clientdata(client, ts); | |
727 | + ts->bus = client; | |
728 | + | |
729 | + error = ad7879_construct(client, ts); | |
730 | + if (error) { | |
731 | + i2c_set_clientdata(client, NULL); | |
732 | + kfree(ts); | |
733 | + } | |
734 | + | |
735 | + return 0; | |
736 | +} | |
737 | + | |
738 | +static int __devexit ad7879_remove(struct i2c_client *client) | |
739 | +{ | |
740 | + struct ad7879 *ts = dev_get_drvdata(&client->dev); | |
741 | + | |
742 | + ad7879_destroy(client, ts); | |
743 | + i2c_set_clientdata(client, NULL); | |
744 | + kfree(ts); | |
745 | + | |
746 | + return 0; | |
747 | +} | |
748 | + | |
749 | +static const struct i2c_device_id ad7879_id[] = { | |
750 | + { "ad7879", 0 }, | |
751 | + { } | |
752 | +}; | |
753 | +MODULE_DEVICE_TABLE(i2c, ad7879_id); | |
754 | + | |
755 | +static struct i2c_driver ad7879_driver = { | |
756 | + .driver = { | |
757 | + .name = "ad7879", | |
758 | + .owner = THIS_MODULE, | |
759 | + }, | |
760 | + .probe = ad7879_probe, | |
761 | + .remove = __devexit_p(ad7879_remove), | |
762 | + .suspend = ad7879_suspend, | |
763 | + .resume = ad7879_resume, | |
764 | + .id_table = ad7879_id, | |
765 | +}; | |
766 | + | |
767 | +static int __init ad7879_init(void) | |
768 | +{ | |
769 | + return i2c_add_driver(&ad7879_driver); | |
770 | +} | |
771 | +module_init(ad7879_init); | |
772 | + | |
773 | +static void __exit ad7879_exit(void) | |
774 | +{ | |
775 | + i2c_del_driver(&ad7879_driver); | |
776 | +} | |
777 | +module_exit(ad7879_exit); | |
778 | +#endif | |
779 | + | |
780 | +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | |
781 | +MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver"); | |
782 | +MODULE_LICENSE("GPL"); |
drivers/input/touchscreen/mainstone-wm97xx.c
... | ... | @@ -162,6 +162,7 @@ |
162 | 162 | input_report_abs(wm->input_dev, ABS_X, x & 0xfff); |
163 | 163 | input_report_abs(wm->input_dev, ABS_Y, y & 0xfff); |
164 | 164 | input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff); |
165 | + input_report_key(wm->input_dev, BTN_TOUCH, (p != 0)); | |
165 | 166 | input_sync(wm->input_dev); |
166 | 167 | reads++; |
167 | 168 | } while (reads < cinfo[sp_idx].reads); |
... | ... | @@ -245,7 +246,7 @@ |
245 | 246 | if (enable) |
246 | 247 | enable_irq(wm->pen_irq); |
247 | 248 | else |
248 | - disable_irq(wm->pen_irq); | |
249 | + disable_irq_nosync(wm->pen_irq); | |
249 | 250 | } |
250 | 251 | |
251 | 252 | static struct wm97xx_mach_ops mainstone_mach_ops = { |
drivers/input/touchscreen/ucb1400_ts.c
... | ... | @@ -151,12 +151,14 @@ |
151 | 151 | input_report_abs(idev, ABS_X, x); |
152 | 152 | input_report_abs(idev, ABS_Y, y); |
153 | 153 | input_report_abs(idev, ABS_PRESSURE, pressure); |
154 | + input_report_key(idev, BTN_TOUCH, 1); | |
154 | 155 | input_sync(idev); |
155 | 156 | } |
156 | 157 | |
157 | 158 | static void ucb1400_ts_event_release(struct input_dev *idev) |
158 | 159 | { |
159 | 160 | input_report_abs(idev, ABS_PRESSURE, 0); |
161 | + input_report_key(idev, BTN_TOUCH, 0); | |
160 | 162 | input_sync(idev); |
161 | 163 | } |
162 | 164 | |
... | ... | @@ -377,7 +379,8 @@ |
377 | 379 | ucb->ts_idev->id.product = ucb->id; |
378 | 380 | ucb->ts_idev->open = ucb1400_ts_open; |
379 | 381 | ucb->ts_idev->close = ucb1400_ts_close; |
380 | - ucb->ts_idev->evbit[0] = BIT_MASK(EV_ABS); | |
382 | + ucb->ts_idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); | |
383 | + ucb->ts_idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | |
381 | 384 | |
382 | 385 | ucb1400_adc_enable(ucb->ac97); |
383 | 386 | x_res = ucb1400_ts_read_xres(ucb); |
drivers/input/touchscreen/wm97xx-core.c
... | ... | @@ -409,6 +409,7 @@ |
409 | 409 | wm->pen_is_down = 0; |
410 | 410 | dev_dbg(wm->dev, "pen up\n"); |
411 | 411 | input_report_abs(wm->input_dev, ABS_PRESSURE, 0); |
412 | + input_report_key(wm->input_dev, BTN_TOUCH, 0); | |
412 | 413 | input_sync(wm->input_dev); |
413 | 414 | } else if (!(rc & RC_AGAIN)) { |
414 | 415 | /* We need high frequency updates only while |
... | ... | @@ -433,6 +434,7 @@ |
433 | 434 | input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff); |
434 | 435 | input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff); |
435 | 436 | input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff); |
437 | + input_report_key(wm->input_dev, BTN_TOUCH, 1); | |
436 | 438 | input_sync(wm->input_dev); |
437 | 439 | wm->pen_is_down = 1; |
438 | 440 | wm->ts_reader_interval = wm->ts_reader_min_interval; |
439 | 441 | |
440 | 442 | |
... | ... | @@ -628,18 +630,21 @@ |
628 | 630 | wm->input_dev->phys = "wm97xx"; |
629 | 631 | wm->input_dev->open = wm97xx_ts_input_open; |
630 | 632 | wm->input_dev->close = wm97xx_ts_input_close; |
631 | - set_bit(EV_ABS, wm->input_dev->evbit); | |
632 | - set_bit(ABS_X, wm->input_dev->absbit); | |
633 | - set_bit(ABS_Y, wm->input_dev->absbit); | |
634 | - set_bit(ABS_PRESSURE, wm->input_dev->absbit); | |
633 | + | |
634 | + __set_bit(EV_ABS, wm->input_dev->evbit); | |
635 | + __set_bit(EV_KEY, wm->input_dev->evbit); | |
636 | + __set_bit(BTN_TOUCH, wm->input_dev->keybit); | |
637 | + | |
635 | 638 | input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1], |
636 | 639 | abs_x[2], 0); |
637 | 640 | input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1], |
638 | 641 | abs_y[2], 0); |
639 | 642 | input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1], |
640 | 643 | abs_p[2], 0); |
644 | + | |
641 | 645 | input_set_drvdata(wm->input_dev, wm); |
642 | 646 | wm->input_dev->dev.parent = dev; |
647 | + | |
643 | 648 | ret = input_register_device(wm->input_dev); |
644 | 649 | if (ret < 0) |
645 | 650 | goto dev_alloc_err; |
drivers/input/touchscreen/zylonite-wm97xx.c
1 | +/* | |
2 | + * zylonite-wm97xx.c -- Zylonite Continuous Touch screen driver | |
3 | + * | |
4 | + * Copyright 2004, 2007, 2008 Wolfson Microelectronics PLC. | |
5 | + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | |
6 | + * Parts Copyright : Ian Molton <spyro@f2s.com> | |
7 | + * Andrew Zabolotny <zap@homelink.ru> | |
8 | + * | |
9 | + * This program is free software; you can redistribute it and/or modify it | |
10 | + * under the terms of the GNU General Public License as published by the | |
11 | + * Free Software Foundation; either version 2 of the License, or (at your | |
12 | + * option) any later version. | |
13 | + * | |
14 | + * Notes: | |
15 | + * This is a wm97xx extended touch driver supporting interrupt driven | |
16 | + * and continuous operation on Marvell Zylonite development systems | |
17 | + * (which have a WM9713 on board). | |
18 | + */ | |
19 | + | |
20 | +#include <linux/module.h> | |
21 | +#include <linux/moduleparam.h> | |
22 | +#include <linux/kernel.h> | |
23 | +#include <linux/init.h> | |
24 | +#include <linux/delay.h> | |
25 | +#include <linux/irq.h> | |
26 | +#include <linux/interrupt.h> | |
27 | +#include <linux/io.h> | |
28 | +#include <linux/wm97xx.h> | |
29 | + | |
30 | +#include <mach/hardware.h> | |
31 | +#include <mach/mfp.h> | |
32 | +#include <mach/regs-ac97.h> | |
33 | + | |
34 | +struct continuous { | |
35 | + u16 id; /* codec id */ | |
36 | + u8 code; /* continuous code */ | |
37 | + u8 reads; /* number of coord reads per read cycle */ | |
38 | + u32 speed; /* number of coords per second */ | |
39 | +}; | |
40 | + | |
41 | +#define WM_READS(sp) ((sp / HZ) + 1) | |
42 | + | |
43 | +static const struct continuous cinfo[] = { | |
44 | + { WM9713_ID2, 0, WM_READS(94), 94 }, | |
45 | + { WM9713_ID2, 1, WM_READS(120), 120 }, | |
46 | + { WM9713_ID2, 2, WM_READS(154), 154 }, | |
47 | + { WM9713_ID2, 3, WM_READS(188), 188 }, | |
48 | +}; | |
49 | + | |
50 | +/* continuous speed index */ | |
51 | +static int sp_idx; | |
52 | + | |
53 | +/* | |
54 | + * Pen sampling frequency (Hz) in continuous mode. | |
55 | + */ | |
56 | +static int cont_rate = 200; | |
57 | +module_param(cont_rate, int, 0); | |
58 | +MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)"); | |
59 | + | |
60 | +/* | |
61 | + * Pressure readback. | |
62 | + * | |
63 | + * Set to 1 to read back pen down pressure | |
64 | + */ | |
65 | +static int pressure; | |
66 | +module_param(pressure, int, 0); | |
67 | +MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)"); | |
68 | + | |
69 | +/* | |
70 | + * AC97 touch data slot. | |
71 | + * | |
72 | + * Touch screen readback data ac97 slot | |
73 | + */ | |
74 | +static int ac97_touch_slot = 5; | |
75 | +module_param(ac97_touch_slot, int, 0); | |
76 | +MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number"); | |
77 | + | |
78 | + | |
79 | +/* flush AC97 slot 5 FIFO machines */ | |
80 | +static void wm97xx_acc_pen_up(struct wm97xx *wm) | |
81 | +{ | |
82 | + int i; | |
83 | + | |
84 | + msleep(1); | |
85 | + | |
86 | + for (i = 0; i < 16; i++) | |
87 | + MODR; | |
88 | +} | |
89 | + | |
90 | +static int wm97xx_acc_pen_down(struct wm97xx *wm) | |
91 | +{ | |
92 | + u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES; | |
93 | + int reads = 0; | |
94 | + static u16 last, tries; | |
95 | + | |
96 | + /* When the AC97 queue has been drained we need to allow time | |
97 | + * to buffer up samples otherwise we end up spinning polling | |
98 | + * for samples. The controller can't have a suitably low | |
99 | + * threashold set to use the notifications it gives. | |
100 | + */ | |
101 | + msleep(1); | |
102 | + | |
103 | + if (tries > 5) { | |
104 | + tries = 0; | |
105 | + return RC_PENUP; | |
106 | + } | |
107 | + | |
108 | + x = MODR; | |
109 | + if (x == last) { | |
110 | + tries++; | |
111 | + return RC_AGAIN; | |
112 | + } | |
113 | + last = x; | |
114 | + do { | |
115 | + if (reads) | |
116 | + x = MODR; | |
117 | + y = MODR; | |
118 | + if (pressure) | |
119 | + p = MODR; | |
120 | + | |
121 | + /* are samples valid */ | |
122 | + if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X || | |
123 | + (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y || | |
124 | + (p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES) | |
125 | + goto up; | |
126 | + | |
127 | + /* coordinate is good */ | |
128 | + tries = 0; | |
129 | + input_report_abs(wm->input_dev, ABS_X, x & 0xfff); | |
130 | + input_report_abs(wm->input_dev, ABS_Y, y & 0xfff); | |
131 | + input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff); | |
132 | + input_report_key(wm->input_dev, BTN_TOUCH, (p != 0)); | |
133 | + input_sync(wm->input_dev); | |
134 | + reads++; | |
135 | + } while (reads < cinfo[sp_idx].reads); | |
136 | +up: | |
137 | + return RC_PENDOWN | RC_AGAIN; | |
138 | +} | |
139 | + | |
140 | +static int wm97xx_acc_startup(struct wm97xx *wm) | |
141 | +{ | |
142 | + int idx; | |
143 | + | |
144 | + /* check we have a codec */ | |
145 | + if (wm->ac97 == NULL) | |
146 | + return -ENODEV; | |
147 | + | |
148 | + /* Go you big red fire engine */ | |
149 | + for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) { | |
150 | + if (wm->id != cinfo[idx].id) | |
151 | + continue; | |
152 | + sp_idx = idx; | |
153 | + if (cont_rate <= cinfo[idx].speed) | |
154 | + break; | |
155 | + } | |
156 | + wm->acc_rate = cinfo[sp_idx].code; | |
157 | + wm->acc_slot = ac97_touch_slot; | |
158 | + dev_info(wm->dev, | |
159 | + "zylonite accelerated touchscreen driver, %d samples/sec\n", | |
160 | + cinfo[sp_idx].speed); | |
161 | + | |
162 | + return 0; | |
163 | +} | |
164 | + | |
165 | +static void wm97xx_irq_enable(struct wm97xx *wm, int enable) | |
166 | +{ | |
167 | + if (enable) | |
168 | + enable_irq(wm->pen_irq); | |
169 | + else | |
170 | + disable_irq_nosync(wm->pen_irq); | |
171 | +} | |
172 | + | |
173 | +static struct wm97xx_mach_ops zylonite_mach_ops = { | |
174 | + .acc_enabled = 1, | |
175 | + .acc_pen_up = wm97xx_acc_pen_up, | |
176 | + .acc_pen_down = wm97xx_acc_pen_down, | |
177 | + .acc_startup = wm97xx_acc_startup, | |
178 | + .irq_enable = wm97xx_irq_enable, | |
179 | + .irq_gpio = WM97XX_GPIO_2, | |
180 | +}; | |
181 | + | |
182 | +static int zylonite_wm97xx_probe(struct platform_device *pdev) | |
183 | +{ | |
184 | + struct wm97xx *wm = platform_get_drvdata(pdev); | |
185 | + int gpio_touch_irq; | |
186 | + | |
187 | + if (cpu_is_pxa320()) | |
188 | + gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO15); | |
189 | + else | |
190 | + gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26); | |
191 | + | |
192 | + wm->pen_irq = IRQ_GPIO(gpio_touch_irq); | |
193 | + set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); | |
194 | + | |
195 | + wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, | |
196 | + WM97XX_GPIO_POL_HIGH, | |
197 | + WM97XX_GPIO_STICKY, | |
198 | + WM97XX_GPIO_WAKE); | |
199 | + wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT, | |
200 | + WM97XX_GPIO_POL_HIGH, | |
201 | + WM97XX_GPIO_NOTSTICKY, | |
202 | + WM97XX_GPIO_NOWAKE); | |
203 | + | |
204 | + return wm97xx_register_mach_ops(wm, &zylonite_mach_ops); | |
205 | +} | |
206 | + | |
207 | +static int zylonite_wm97xx_remove(struct platform_device *pdev) | |
208 | +{ | |
209 | + struct wm97xx *wm = platform_get_drvdata(pdev); | |
210 | + | |
211 | + wm97xx_unregister_mach_ops(wm); | |
212 | + | |
213 | + return 0; | |
214 | +} | |
215 | + | |
216 | +static struct platform_driver zylonite_wm97xx_driver = { | |
217 | + .probe = zylonite_wm97xx_probe, | |
218 | + .remove = zylonite_wm97xx_remove, | |
219 | + .driver = { | |
220 | + .name = "wm97xx-touch", | |
221 | + }, | |
222 | +}; | |
223 | + | |
224 | +static int __init zylonite_wm97xx_init(void) | |
225 | +{ | |
226 | + return platform_driver_register(&zylonite_wm97xx_driver); | |
227 | +} | |
228 | + | |
229 | +static void __exit zylonite_wm97xx_exit(void) | |
230 | +{ | |
231 | + platform_driver_unregister(&zylonite_wm97xx_driver); | |
232 | +} | |
233 | + | |
234 | +module_init(zylonite_wm97xx_init); | |
235 | +module_exit(zylonite_wm97xx_exit); | |
236 | + | |
237 | +/* Module information */ | |
238 | +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | |
239 | +MODULE_DESCRIPTION("wm97xx continuous touch driver for Zylonite"); | |
240 | +MODULE_LICENSE("GPL"); |
include/linux/rotary_encoder.h
1 | +#ifndef __ROTARY_ENCODER_H__ | |
2 | +#define __ROTARY_ENCODER_H__ | |
3 | + | |
4 | +struct rotary_encoder_platform_data { | |
5 | + unsigned int steps; | |
6 | + unsigned int axis; | |
7 | + unsigned int gpio_a; | |
8 | + unsigned int gpio_b; | |
9 | + unsigned int inverted_a; | |
10 | + unsigned int inverted_b; | |
11 | +}; | |
12 | + | |
13 | +#endif /* __ROTARY_ENCODER_H__ */ |
include/linux/spi/ad7879.h
1 | +/* linux/spi/ad7879.h */ | |
2 | + | |
3 | +/* Touchscreen characteristics vary between boards and models. The | |
4 | + * platform_data for the device's "struct device" holds this information. | |
5 | + * | |
6 | + * It's OK if the min/max values are zero. | |
7 | + */ | |
8 | +struct ad7879_platform_data { | |
9 | + u16 model; /* 7879 */ | |
10 | + u16 x_plate_ohms; | |
11 | + u16 x_min, x_max; | |
12 | + u16 y_min, y_max; | |
13 | + u16 pressure_min, pressure_max; | |
14 | + | |
15 | + /* [0..255] 0=OFF Starts at 1=550us and goes | |
16 | + * all the way to 9.440ms in steps of 35us. | |
17 | + */ | |
18 | + u8 pen_down_acc_interval; | |
19 | + /* [0..15] Starts at 0=128us and goes all the | |
20 | + * way to 4.096ms in steps of 128us. | |
21 | + */ | |
22 | + u8 first_conversion_delay; | |
23 | + /* [0..3] 0 = 2us, 1 = 4us, 2 = 8us, 3 = 16us */ | |
24 | + u8 acquisition_time; | |
25 | + /* [0..3] Average X middle samples 0 = 2, 1 = 4, 2 = 8, 3 = 16 */ | |
26 | + u8 averaging; | |
27 | + /* [0..3] Perform X measurements 0 = OFF, | |
28 | + * 1 = 4, 2 = 8, 3 = 16 (median > averaging) | |
29 | + */ | |
30 | + u8 median; | |
31 | + /* 1 = AUX/VBAT/GPIO set to GPIO Output */ | |
32 | + u8 gpio_output; | |
33 | + /* Initial GPIO pin state (valid if gpio_output = 1) */ | |
34 | + u8 gpio_default; | |
35 | +}; |