1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Atmel Atmegaxx Capacitive Touch Button Driver |
4 | * |
5 | * Copyright (C) 2016 Google, inc. |
6 | */ |
7 | |
8 | /* |
9 | * It's irrelevant that the HW used to develop captouch driver is based |
10 | * on Atmega88PA part and uses QtouchADC parts for sensing touch. |
11 | * Calling this driver "captouch" is an arbitrary way to distinguish |
12 | * the protocol this driver supported by other atmel/qtouch drivers. |
13 | * |
14 | * Captouch driver supports a newer/different version of the I2C |
15 | * registers/commands than the qt1070.c driver. |
16 | * Don't let the similarity of the general driver structure fool you. |
17 | * |
18 | * For raw i2c access from userspace, use i2cset/i2cget |
19 | * to poke at /dev/i2c-N devices. |
20 | */ |
21 | |
22 | #include <linux/device.h> |
23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> |
25 | #include <linux/init.h> |
26 | #include <linux/i2c.h> |
27 | #include <linux/input.h> |
28 | #include <linux/interrupt.h> |
29 | #include <linux/slab.h> |
30 | |
31 | /* Maximum number of buttons supported */ |
32 | #define MAX_NUM_OF_BUTTONS 8 |
33 | |
34 | /* Registers */ |
35 | #define REG_KEY1_THRESHOLD 0x02 |
36 | #define REG_KEY2_THRESHOLD 0x03 |
37 | #define REG_KEY3_THRESHOLD 0x04 |
38 | #define REG_KEY4_THRESHOLD 0x05 |
39 | |
40 | #define REG_KEY1_REF_H 0x20 |
41 | #define REG_KEY1_REF_L 0x21 |
42 | #define REG_KEY2_REF_H 0x22 |
43 | #define REG_KEY2_REF_L 0x23 |
44 | #define REG_KEY3_REF_H 0x24 |
45 | #define REG_KEY3_REF_L 0x25 |
46 | #define REG_KEY4_REF_H 0x26 |
47 | #define REG_KEY4_REF_L 0x27 |
48 | |
49 | #define REG_KEY1_DLT_H 0x30 |
50 | #define REG_KEY1_DLT_L 0x31 |
51 | #define REG_KEY2_DLT_H 0x32 |
52 | #define REG_KEY2_DLT_L 0x33 |
53 | #define REG_KEY3_DLT_H 0x34 |
54 | #define REG_KEY3_DLT_L 0x35 |
55 | #define REG_KEY4_DLT_H 0x36 |
56 | #define REG_KEY4_DLT_L 0x37 |
57 | |
58 | #define REG_KEY_STATE 0x3C |
59 | |
60 | /* |
61 | * @i2c_client: I2C slave device client pointer |
62 | * @input: Input device pointer |
63 | * @num_btn: Number of buttons |
64 | * @keycodes: map of button# to KeyCode |
65 | * @prev_btn: Previous key state to detect button "press" or "release" |
66 | * @xfer_buf: I2C transfer buffer |
67 | */ |
68 | struct atmel_captouch_device { |
69 | struct i2c_client *client; |
70 | struct input_dev *input; |
71 | u32 num_btn; |
72 | u32 keycodes[MAX_NUM_OF_BUTTONS]; |
73 | u8 prev_btn; |
74 | u8 xfer_buf[8] ____cacheline_aligned; |
75 | }; |
76 | |
77 | /* |
78 | * Read from I2C slave device |
79 | * The protocol is that the client has to provide both the register address |
80 | * and the length, and while reading back the device would prepend the data |
81 | * with address and length for verification. |
82 | */ |
83 | static int atmel_read(struct atmel_captouch_device *capdev, |
84 | u8 reg, u8 *data, size_t len) |
85 | { |
86 | struct i2c_client *client = capdev->client; |
87 | struct device *dev = &client->dev; |
88 | struct i2c_msg msg[2]; |
89 | int err; |
90 | |
91 | if (len > sizeof(capdev->xfer_buf) - 2) |
92 | return -EINVAL; |
93 | |
94 | capdev->xfer_buf[0] = reg; |
95 | capdev->xfer_buf[1] = len; |
96 | |
97 | msg[0].addr = client->addr; |
98 | msg[0].flags = 0; |
99 | msg[0].buf = capdev->xfer_buf; |
100 | msg[0].len = 2; |
101 | |
102 | msg[1].addr = client->addr; |
103 | msg[1].flags = I2C_M_RD; |
104 | msg[1].buf = capdev->xfer_buf; |
105 | msg[1].len = len + 2; |
106 | |
107 | err = i2c_transfer(adap: client->adapter, msgs: msg, ARRAY_SIZE(msg)); |
108 | if (err != ARRAY_SIZE(msg)) |
109 | return err < 0 ? err : -EIO; |
110 | |
111 | if (capdev->xfer_buf[0] != reg) { |
112 | dev_err(dev, |
113 | "I2C read error: register address does not match (%#02x vs %02x)\n" , |
114 | capdev->xfer_buf[0], reg); |
115 | return -ECOMM; |
116 | } |
117 | |
118 | memcpy(data, &capdev->xfer_buf[2], len); |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | /* |
124 | * Handle interrupt and report the key changes to the input system. |
125 | * Multi-touch can be supported; however, it really depends on whether |
126 | * the device can multi-touch. |
127 | */ |
128 | static irqreturn_t atmel_captouch_isr(int irq, void *data) |
129 | { |
130 | struct atmel_captouch_device *capdev = data; |
131 | struct device *dev = &capdev->client->dev; |
132 | int error; |
133 | int i; |
134 | u8 new_btn; |
135 | u8 changed_btn; |
136 | |
137 | error = atmel_read(capdev, REG_KEY_STATE, data: &new_btn, len: 1); |
138 | if (error) { |
139 | dev_err(dev, "failed to read button state: %d\n" , error); |
140 | goto out; |
141 | } |
142 | |
143 | dev_dbg(dev, "%s: button state %#02x\n" , __func__, new_btn); |
144 | |
145 | changed_btn = new_btn ^ capdev->prev_btn; |
146 | capdev->prev_btn = new_btn; |
147 | |
148 | for (i = 0; i < capdev->num_btn; i++) { |
149 | if (changed_btn & BIT(i)) |
150 | input_report_key(dev: capdev->input, |
151 | code: capdev->keycodes[i], |
152 | value: new_btn & BIT(i)); |
153 | } |
154 | |
155 | input_sync(dev: capdev->input); |
156 | |
157 | out: |
158 | return IRQ_HANDLED; |
159 | } |
160 | |
161 | /* |
162 | * Probe function to setup the device, input system and interrupt |
163 | */ |
164 | static int atmel_captouch_probe(struct i2c_client *client) |
165 | { |
166 | struct atmel_captouch_device *capdev; |
167 | struct device *dev = &client->dev; |
168 | struct device_node *node; |
169 | int i; |
170 | int err; |
171 | |
172 | if (!i2c_check_functionality(adap: client->adapter, |
173 | I2C_FUNC_SMBUS_BYTE_DATA | |
174 | I2C_FUNC_SMBUS_WORD_DATA | |
175 | I2C_FUNC_SMBUS_I2C_BLOCK)) { |
176 | dev_err(dev, "needed i2c functionality is not supported\n" ); |
177 | return -EINVAL; |
178 | } |
179 | |
180 | capdev = devm_kzalloc(dev, size: sizeof(*capdev), GFP_KERNEL); |
181 | if (!capdev) |
182 | return -ENOMEM; |
183 | |
184 | capdev->client = client; |
185 | |
186 | err = atmel_read(capdev, REG_KEY_STATE, |
187 | data: &capdev->prev_btn, len: sizeof(capdev->prev_btn)); |
188 | if (err) { |
189 | dev_err(dev, "failed to read initial button state: %d\n" , err); |
190 | return err; |
191 | } |
192 | |
193 | capdev->input = devm_input_allocate_device(dev); |
194 | if (!capdev->input) { |
195 | dev_err(dev, "failed to allocate input device\n" ); |
196 | return -ENOMEM; |
197 | } |
198 | |
199 | capdev->input->id.bustype = BUS_I2C; |
200 | capdev->input->id.product = 0x880A; |
201 | capdev->input->id.version = 0; |
202 | capdev->input->name = "ATMegaXX Capacitive Button Controller" ; |
203 | __set_bit(EV_KEY, capdev->input->evbit); |
204 | |
205 | node = dev->of_node; |
206 | if (!node) { |
207 | dev_err(dev, "failed to find matching node in device tree\n" ); |
208 | return -EINVAL; |
209 | } |
210 | |
211 | if (of_property_read_bool(np: node, propname: "autorepeat" )) |
212 | __set_bit(EV_REP, capdev->input->evbit); |
213 | |
214 | capdev->num_btn = of_property_count_u32_elems(np: node, propname: "linux,keymap" ); |
215 | if (capdev->num_btn > MAX_NUM_OF_BUTTONS) |
216 | capdev->num_btn = MAX_NUM_OF_BUTTONS; |
217 | |
218 | err = of_property_read_u32_array(np: node, propname: "linux,keycodes" , |
219 | out_values: capdev->keycodes, |
220 | sz: capdev->num_btn); |
221 | if (err) { |
222 | dev_err(dev, |
223 | "failed to read linux,keycode property: %d\n" , err); |
224 | return err; |
225 | } |
226 | |
227 | for (i = 0; i < capdev->num_btn; i++) |
228 | __set_bit(capdev->keycodes[i], capdev->input->keybit); |
229 | |
230 | capdev->input->keycode = capdev->keycodes; |
231 | capdev->input->keycodesize = sizeof(capdev->keycodes[0]); |
232 | capdev->input->keycodemax = capdev->num_btn; |
233 | |
234 | err = input_register_device(capdev->input); |
235 | if (err) |
236 | return err; |
237 | |
238 | err = devm_request_threaded_irq(dev, irq: client->irq, |
239 | NULL, thread_fn: atmel_captouch_isr, |
240 | IRQF_ONESHOT, |
241 | devname: "atmel_captouch" , dev_id: capdev); |
242 | if (err) { |
243 | dev_err(dev, "failed to request irq %d: %d\n" , |
244 | client->irq, err); |
245 | return err; |
246 | } |
247 | |
248 | return 0; |
249 | } |
250 | |
251 | static const struct of_device_id atmel_captouch_of_id[] = { |
252 | { |
253 | .compatible = "atmel,captouch" , |
254 | }, |
255 | { /* sentinel */ } |
256 | }; |
257 | MODULE_DEVICE_TABLE(of, atmel_captouch_of_id); |
258 | |
259 | static const struct i2c_device_id atmel_captouch_id[] = { |
260 | { "atmel_captouch" , 0 }, |
261 | { } |
262 | }; |
263 | MODULE_DEVICE_TABLE(i2c, atmel_captouch_id); |
264 | |
265 | static struct i2c_driver atmel_captouch_driver = { |
266 | .probe = atmel_captouch_probe, |
267 | .id_table = atmel_captouch_id, |
268 | .driver = { |
269 | .name = "atmel_captouch" , |
270 | .of_match_table = atmel_captouch_of_id, |
271 | }, |
272 | }; |
273 | module_i2c_driver(atmel_captouch_driver); |
274 | |
275 | /* Module information */ |
276 | MODULE_AUTHOR("Hung-yu Wu <hywu@google.com>" ); |
277 | MODULE_DESCRIPTION("Atmel ATmegaXX Capacitance Touch Sensor I2C Driver" ); |
278 | MODULE_LICENSE("GPL v2" ); |
279 | |