diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2017-06-05 17:48:44 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-06-05 18:35:32 -0400 |
commit | 131b3de7016b73fca1aba8ffb528217ac95b2505 (patch) | |
tree | c9c6135e399c76c577c2d548443aa639330da398 | |
parent | 086cebfa72fa22e1e49f251d33fe1ceaab4af2d4 (diff) |
Input: add D-Link DIR-685 touchkeys driver
This adds support for the D-Link DIR-685 touchkeys found in the
router with this name.
The vendor code calles this a "touchpad" but we are registering
it here under its real name.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt | 21 | ||||
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | drivers/input/keyboard/Kconfig | 11 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/dlink-dir685-touchkeys.c | 155 |
5 files changed, 194 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt b/Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt new file mode 100644 index 000000000000..10dec1c57abf --- /dev/null +++ b/Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt | |||
@@ -0,0 +1,21 @@ | |||
1 | * D-Link DIR-685 Touchkeys | ||
2 | |||
3 | This is a I2C one-off touchkey controller based on the Cypress Semiconductor | ||
4 | CY8C214 MCU with some firmware in its internal 8KB flash. The circuit | ||
5 | board inside the router is named E119921. | ||
6 | |||
7 | The touchkey device node should be placed inside an I2C bus node. | ||
8 | |||
9 | Required properties: | ||
10 | - compatible: must be "dlink,dir685-touchkeys" | ||
11 | - reg: the I2C address of the touchkeys | ||
12 | - interrupts: reference to the interrupt number | ||
13 | |||
14 | Example: | ||
15 | |||
16 | touchkeys@26 { | ||
17 | compatible = "dlink,dir685-touchkeys"; | ||
18 | reg = <0x26>; | ||
19 | interrupt-parent = <&gpio0>; | ||
20 | interrupts = <17 IRQ_TYPE_EDGE_FALLING>; | ||
21 | }; | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 053c3bdd1fe5..98861181fb2a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3786,6 +3786,12 @@ S: Supported | |||
3786 | F: drivers/input/touchscreen/cyttsp* | 3786 | F: drivers/input/touchscreen/cyttsp* |
3787 | F: include/linux/input/cyttsp.h | 3787 | F: include/linux/input/cyttsp.h |
3788 | 3788 | ||
3789 | D-LINK DIR-685 TOUCHKEYS DRIVER | ||
3790 | M: Linus Walleij <linus.walleij@linaro.org> | ||
3791 | L: linux-input@vger.kernel.org | ||
3792 | S: Supported | ||
3793 | F: drivers/input/dlink-dir685-touchkeys.c | ||
3794 | |||
3789 | DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK | 3795 | DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK |
3790 | M: Joshua Kinard <kumba@gentoo.org> | 3796 | M: Joshua Kinard <kumba@gentoo.org> |
3791 | S: Maintained | 3797 | S: Maintained |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 97acd6524ad7..4c4ab1ced235 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -178,6 +178,17 @@ config KEYBOARD_CLPS711X | |||
178 | To compile this driver as a module, choose M here: the | 178 | To compile this driver as a module, choose M here: the |
179 | module will be called clps711x-keypad. | 179 | module will be called clps711x-keypad. |
180 | 180 | ||
181 | config KEYBOARD_DLINK_DIR685 | ||
182 | tristate "D-Link DIR-685 touchkeys support" | ||
183 | depends on I2C | ||
184 | default ARCH_GEMINI | ||
185 | help | ||
186 | If you say yes here you get support for the D-Link DIR-685 | ||
187 | touchkeys. | ||
188 | |||
189 | To compile this driver as a module, choose M here: the | ||
190 | module will be called dlink-dir685-touchkeys. | ||
191 | |||
181 | config KEYBOARD_LKKBD | 192 | config KEYBOARD_LKKBD |
182 | tristate "DECstation/VAXstation LK201/LK401 keyboard" | 193 | tristate "DECstation/VAXstation LK201/LK401 keyboard" |
183 | select SERIO | 194 | select SERIO |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 7d9acff819a7..d2338bacdad1 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o | |||
17 | obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o | 17 | obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o |
18 | obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o | 18 | obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o |
19 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o | 19 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o |
20 | obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o | ||
20 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o | 21 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o |
21 | obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o | 22 | obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o |
22 | obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o | 23 | obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o |
diff --git a/drivers/input/keyboard/dlink-dir685-touchkeys.c b/drivers/input/keyboard/dlink-dir685-touchkeys.c new file mode 100644 index 000000000000..88e321b76397 --- /dev/null +++ b/drivers/input/keyboard/dlink-dir685-touchkeys.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * D-Link DIR-685 router I2C-based Touchkeys input driver | ||
3 | * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> | ||
4 | * | ||
5 | * This is a one-off touchkey controller based on the Cypress Semiconductor | ||
6 | * CY8C214 MCU with some firmware in its internal 8KB flash. The circuit | ||
7 | * board inside the router is named E119921 | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/i2c.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/input.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/bitops.h> | ||
17 | |||
18 | struct dir685_touchkeys { | ||
19 | struct device *dev; | ||
20 | struct i2c_client *client; | ||
21 | struct input_dev *input; | ||
22 | unsigned long cur_key; | ||
23 | u16 codes[7]; | ||
24 | }; | ||
25 | |||
26 | static irqreturn_t dir685_tk_irq_thread(int irq, void *data) | ||
27 | { | ||
28 | struct dir685_touchkeys *tk = data; | ||
29 | const int num_bits = min_t(int, ARRAY_SIZE(tk->codes), 16); | ||
30 | unsigned long changed; | ||
31 | u8 buf[6]; | ||
32 | unsigned long key; | ||
33 | int i; | ||
34 | int err; | ||
35 | |||
36 | memset(buf, 0, sizeof(buf)); | ||
37 | err = i2c_master_recv(tk->client, buf, sizeof(buf)); | ||
38 | if (err != sizeof(buf)) { | ||
39 | dev_err(tk->dev, "short read %d\n", err); | ||
40 | return IRQ_HANDLED; | ||
41 | } | ||
42 | |||
43 | dev_dbg(tk->dev, "IN: %*ph\n", (int)sizeof(buf), buf); | ||
44 | key = be16_to_cpup((__be16 *) &buf[4]); | ||
45 | |||
46 | /* Figure out if any bits went high or low since last message */ | ||
47 | changed = tk->cur_key ^ key; | ||
48 | for_each_set_bit(i, &changed, num_bits) { | ||
49 | dev_dbg(tk->dev, "key %d is %s\n", i, | ||
50 | test_bit(i, &key) ? "down" : "up"); | ||
51 | input_report_key(tk->input, tk->codes[i], test_bit(i, &key)); | ||
52 | } | ||
53 | |||
54 | /* Store currently down keys */ | ||
55 | tk->cur_key = key; | ||
56 | input_sync(tk->input); | ||
57 | |||
58 | return IRQ_HANDLED; | ||
59 | } | ||
60 | |||
61 | static int dir685_tk_probe(struct i2c_client *client, | ||
62 | const struct i2c_device_id *id) | ||
63 | { | ||
64 | struct dir685_touchkeys *tk; | ||
65 | struct device *dev = &client->dev; | ||
66 | u8 bl_data[] = { 0xa7, 0x40 }; | ||
67 | int err; | ||
68 | int i; | ||
69 | |||
70 | tk = devm_kzalloc(&client->dev, sizeof(*tk), GFP_KERNEL); | ||
71 | if (!tk) | ||
72 | return -ENOMEM; | ||
73 | |||
74 | tk->input = devm_input_allocate_device(dev); | ||
75 | if (!tk->input) | ||
76 | return -ENOMEM; | ||
77 | |||
78 | tk->client = client; | ||
79 | tk->dev = dev; | ||
80 | |||
81 | tk->input->keycodesize = sizeof(u16); | ||
82 | tk->input->keycodemax = ARRAY_SIZE(tk->codes); | ||
83 | tk->input->keycode = tk->codes; | ||
84 | tk->codes[0] = KEY_UP; | ||
85 | tk->codes[1] = KEY_DOWN; | ||
86 | tk->codes[2] = KEY_LEFT; | ||
87 | tk->codes[3] = KEY_RIGHT; | ||
88 | tk->codes[4] = KEY_ENTER; | ||
89 | tk->codes[5] = KEY_WPS_BUTTON; | ||
90 | /* | ||
91 | * This key appears in the vendor driver, but I have | ||
92 | * not been able to activate it. | ||
93 | */ | ||
94 | tk->codes[6] = KEY_RESERVED; | ||
95 | |||
96 | __set_bit(EV_KEY, tk->input->evbit); | ||
97 | for (i = 0; i < ARRAY_SIZE(tk->codes); i++) | ||
98 | __set_bit(tk->codes[i], tk->input->keybit); | ||
99 | __clear_bit(KEY_RESERVED, tk->input->keybit); | ||
100 | |||
101 | tk->input->name = "D-Link DIR-685 touchkeys"; | ||
102 | tk->input->id.bustype = BUS_I2C; | ||
103 | |||
104 | err = input_register_device(tk->input); | ||
105 | if (err) | ||
106 | return err; | ||
107 | |||
108 | /* Set the brightness to max level */ | ||
109 | err = i2c_master_send(client, bl_data, sizeof(bl_data)); | ||
110 | if (err != sizeof(bl_data)) | ||
111 | dev_warn(tk->dev, "error setting brightness level\n"); | ||
112 | |||
113 | if (!client->irq) { | ||
114 | dev_err(dev, "no IRQ on the I2C device\n"); | ||
115 | return -ENODEV; | ||
116 | } | ||
117 | err = devm_request_threaded_irq(dev, client->irq, | ||
118 | NULL, dir685_tk_irq_thread, | ||
119 | IRQF_ONESHOT, | ||
120 | "dir685-tk", tk); | ||
121 | if (err) { | ||
122 | dev_err(dev, "can't request IRQ\n"); | ||
123 | return err; | ||
124 | } | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static const struct i2c_device_id dir685_tk_id[] = { | ||
130 | { "dir685tk", 0 }, | ||
131 | { } | ||
132 | }; | ||
133 | MODULE_DEVICE_TABLE(i2c, dir685_tk_id); | ||
134 | |||
135 | #ifdef CONFIG_OF | ||
136 | static const struct of_device_id dir685_tk_of_match[] = { | ||
137 | { .compatible = "dlink,dir685-touchkeys" }, | ||
138 | {}, | ||
139 | }; | ||
140 | MODULE_DEVICE_TABLE(of, dir685_tk_of_match); | ||
141 | #endif | ||
142 | |||
143 | static struct i2c_driver dir685_tk_i2c_driver = { | ||
144 | .driver = { | ||
145 | .name = "dlin-dir685-touchkeys", | ||
146 | .of_match_table = of_match_ptr(dir685_tk_of_match), | ||
147 | }, | ||
148 | .probe = dir685_tk_probe, | ||
149 | .id_table = dir685_tk_id, | ||
150 | }; | ||
151 | module_i2c_driver(dir685_tk_i2c_driver); | ||
152 | |||
153 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); | ||
154 | MODULE_DESCRIPTION("D-Link DIR-685 touchkeys driver"); | ||
155 | MODULE_LICENSE("GPL"); | ||