1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org> |
4 | |
5 | #include <linux/crc8.h> |
6 | #include <linux/delay.h> |
7 | #include <linux/err.h> |
8 | #include <linux/i2c.h> |
9 | #include <linux/input.h> |
10 | #include <linux/input/matrix_keypad.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/module.h> |
13 | #include <linux/mod_devicetable.h> |
14 | #include <linux/of.h> |
15 | #include <linux/regulator/consumer.h> |
16 | #include <linux/types.h> |
17 | |
18 | #define DRV_NAME "pinephone-keyboard" |
19 | |
20 | #define PPKB_CRC8_POLYNOMIAL 0x07 |
21 | |
22 | #define PPKB_DEVICE_ID_HI 0x00 |
23 | #define PPKB_DEVICE_ID_HI_VALUE 'K' |
24 | #define PPKB_DEVICE_ID_LO 0x01 |
25 | #define PPKB_DEVICE_ID_LO_VALUE 'B' |
26 | #define PPKB_FW_REVISION 0x02 |
27 | #define PPKB_FW_FEATURES 0x03 |
28 | #define PPKB_MATRIX_SIZE 0x06 |
29 | #define PPKB_SCAN_CRC 0x07 |
30 | #define PPKB_SCAN_DATA 0x08 |
31 | #define PPKB_SYS_CONFIG 0x20 |
32 | #define PPKB_SYS_CONFIG_DISABLE_SCAN BIT(0) |
33 | #define PPKB_SYS_SMBUS_COMMAND 0x21 |
34 | #define PPKB_SYS_SMBUS_DATA 0x22 |
35 | #define PPKB_SYS_COMMAND 0x23 |
36 | #define PPKB_SYS_COMMAND_SMBUS_READ 0x91 |
37 | #define PPKB_SYS_COMMAND_SMBUS_WRITE 0xa1 |
38 | |
39 | #define PPKB_ROWS 6 |
40 | #define PPKB_COLS 12 |
41 | |
42 | /* Size of the scan buffer, including the CRC byte at the beginning. */ |
43 | #define PPKB_BUF_LEN (1 + PPKB_COLS) |
44 | |
45 | static const uint32_t ppkb_keymap[] = { |
46 | KEY(0, 0, KEY_ESC), |
47 | KEY(0, 1, KEY_1), |
48 | KEY(0, 2, KEY_2), |
49 | KEY(0, 3, KEY_3), |
50 | KEY(0, 4, KEY_4), |
51 | KEY(0, 5, KEY_5), |
52 | KEY(0, 6, KEY_6), |
53 | KEY(0, 7, KEY_7), |
54 | KEY(0, 8, KEY_8), |
55 | KEY(0, 9, KEY_9), |
56 | KEY(0, 10, KEY_0), |
57 | KEY(0, 11, KEY_BACKSPACE), |
58 | |
59 | KEY(1, 0, KEY_TAB), |
60 | KEY(1, 1, KEY_Q), |
61 | KEY(1, 2, KEY_W), |
62 | KEY(1, 3, KEY_E), |
63 | KEY(1, 4, KEY_R), |
64 | KEY(1, 5, KEY_T), |
65 | KEY(1, 6, KEY_Y), |
66 | KEY(1, 7, KEY_U), |
67 | KEY(1, 8, KEY_I), |
68 | KEY(1, 9, KEY_O), |
69 | KEY(1, 10, KEY_P), |
70 | KEY(1, 11, KEY_ENTER), |
71 | |
72 | KEY(2, 0, KEY_LEFTMETA), |
73 | KEY(2, 1, KEY_A), |
74 | KEY(2, 2, KEY_S), |
75 | KEY(2, 3, KEY_D), |
76 | KEY(2, 4, KEY_F), |
77 | KEY(2, 5, KEY_G), |
78 | KEY(2, 6, KEY_H), |
79 | KEY(2, 7, KEY_J), |
80 | KEY(2, 8, KEY_K), |
81 | KEY(2, 9, KEY_L), |
82 | KEY(2, 10, KEY_SEMICOLON), |
83 | |
84 | KEY(3, 0, KEY_LEFTSHIFT), |
85 | KEY(3, 1, KEY_Z), |
86 | KEY(3, 2, KEY_X), |
87 | KEY(3, 3, KEY_C), |
88 | KEY(3, 4, KEY_V), |
89 | KEY(3, 5, KEY_B), |
90 | KEY(3, 6, KEY_N), |
91 | KEY(3, 7, KEY_M), |
92 | KEY(3, 8, KEY_COMMA), |
93 | KEY(3, 9, KEY_DOT), |
94 | KEY(3, 10, KEY_SLASH), |
95 | |
96 | KEY(4, 1, KEY_LEFTCTRL), |
97 | KEY(4, 4, KEY_SPACE), |
98 | KEY(4, 6, KEY_APOSTROPHE), |
99 | KEY(4, 8, KEY_RIGHTBRACE), |
100 | KEY(4, 9, KEY_LEFTBRACE), |
101 | |
102 | KEY(5, 2, KEY_FN), |
103 | KEY(5, 3, KEY_LEFTALT), |
104 | KEY(5, 5, KEY_RIGHTALT), |
105 | |
106 | /* FN layer */ |
107 | KEY(PPKB_ROWS + 0, 0, KEY_FN_ESC), |
108 | KEY(PPKB_ROWS + 0, 1, KEY_F1), |
109 | KEY(PPKB_ROWS + 0, 2, KEY_F2), |
110 | KEY(PPKB_ROWS + 0, 3, KEY_F3), |
111 | KEY(PPKB_ROWS + 0, 4, KEY_F4), |
112 | KEY(PPKB_ROWS + 0, 5, KEY_F5), |
113 | KEY(PPKB_ROWS + 0, 6, KEY_F6), |
114 | KEY(PPKB_ROWS + 0, 7, KEY_F7), |
115 | KEY(PPKB_ROWS + 0, 8, KEY_F8), |
116 | KEY(PPKB_ROWS + 0, 9, KEY_F9), |
117 | KEY(PPKB_ROWS + 0, 10, KEY_F10), |
118 | KEY(PPKB_ROWS + 0, 11, KEY_DELETE), |
119 | |
120 | KEY(PPKB_ROWS + 1, 10, KEY_PAGEUP), |
121 | |
122 | KEY(PPKB_ROWS + 2, 0, KEY_SYSRQ), |
123 | KEY(PPKB_ROWS + 2, 9, KEY_PAGEDOWN), |
124 | KEY(PPKB_ROWS + 2, 10, KEY_INSERT), |
125 | |
126 | KEY(PPKB_ROWS + 3, 0, KEY_LEFTSHIFT), |
127 | KEY(PPKB_ROWS + 3, 8, KEY_HOME), |
128 | KEY(PPKB_ROWS + 3, 9, KEY_UP), |
129 | KEY(PPKB_ROWS + 3, 10, KEY_END), |
130 | |
131 | KEY(PPKB_ROWS + 4, 1, KEY_LEFTCTRL), |
132 | KEY(PPKB_ROWS + 4, 6, KEY_LEFT), |
133 | KEY(PPKB_ROWS + 4, 8, KEY_RIGHT), |
134 | KEY(PPKB_ROWS + 4, 9, KEY_DOWN), |
135 | |
136 | KEY(PPKB_ROWS + 5, 3, KEY_LEFTALT), |
137 | KEY(PPKB_ROWS + 5, 5, KEY_RIGHTALT), |
138 | }; |
139 | |
140 | static const struct matrix_keymap_data ppkb_keymap_data = { |
141 | .keymap = ppkb_keymap, |
142 | .keymap_size = ARRAY_SIZE(ppkb_keymap), |
143 | }; |
144 | |
145 | struct pinephone_keyboard { |
146 | struct i2c_adapter adapter; |
147 | struct input_dev *input; |
148 | u8 buf[2][PPKB_BUF_LEN]; |
149 | u8 crc_table[CRC8_TABLE_SIZE]; |
150 | u8 fn_state[PPKB_COLS]; |
151 | bool buf_swap; |
152 | bool fn_pressed; |
153 | }; |
154 | |
155 | static int ppkb_adap_smbus_xfer(struct i2c_adapter *adap, u16 addr, |
156 | unsigned short flags, char read_write, |
157 | u8 command, int size, |
158 | union i2c_smbus_data *data) |
159 | { |
160 | struct i2c_client *client = adap->algo_data; |
161 | u8 buf[3]; |
162 | int ret; |
163 | |
164 | buf[0] = command; |
165 | buf[1] = data->byte; |
166 | buf[2] = read_write == I2C_SMBUS_READ ? PPKB_SYS_COMMAND_SMBUS_READ |
167 | : PPKB_SYS_COMMAND_SMBUS_WRITE; |
168 | |
169 | ret = i2c_smbus_write_i2c_block_data(client, PPKB_SYS_SMBUS_COMMAND, |
170 | length: sizeof(buf), values: buf); |
171 | if (ret) |
172 | return ret; |
173 | |
174 | /* Read back the command status until it passes or fails. */ |
175 | do { |
176 | usleep_range(min: 300, max: 500); |
177 | ret = i2c_smbus_read_byte_data(client, PPKB_SYS_COMMAND); |
178 | } while (ret == buf[2]); |
179 | if (ret < 0) |
180 | return ret; |
181 | /* Commands return 0x00 on success and 0xff on failure. */ |
182 | if (ret) |
183 | return -EIO; |
184 | |
185 | if (read_write == I2C_SMBUS_READ) { |
186 | ret = i2c_smbus_read_byte_data(client, PPKB_SYS_SMBUS_DATA); |
187 | if (ret < 0) |
188 | return ret; |
189 | |
190 | data->byte = ret; |
191 | } |
192 | |
193 | return 0; |
194 | } |
195 | |
196 | static u32 ppkg_adap_functionality(struct i2c_adapter *adap) |
197 | { |
198 | return I2C_FUNC_SMBUS_BYTE_DATA; |
199 | } |
200 | |
201 | static const struct i2c_algorithm ppkb_adap_algo = { |
202 | .smbus_xfer = ppkb_adap_smbus_xfer, |
203 | .functionality = ppkg_adap_functionality, |
204 | }; |
205 | |
206 | static void ppkb_update(struct i2c_client *client) |
207 | { |
208 | struct pinephone_keyboard *ppkb = i2c_get_clientdata(client); |
209 | unsigned short *keymap = ppkb->input->keycode; |
210 | int row_shift = get_count_order(PPKB_COLS); |
211 | u8 *old_buf = ppkb->buf[!ppkb->buf_swap]; |
212 | u8 *new_buf = ppkb->buf[ppkb->buf_swap]; |
213 | int col, crc, ret, row; |
214 | struct device *dev = &client->dev; |
215 | |
216 | ret = i2c_smbus_read_i2c_block_data(client, PPKB_SCAN_CRC, |
217 | PPKB_BUF_LEN, values: new_buf); |
218 | if (ret != PPKB_BUF_LEN) { |
219 | dev_err(dev, "Failed to read scan data: %d\n" , ret); |
220 | return; |
221 | } |
222 | |
223 | crc = crc8(table: ppkb->crc_table, pdata: &new_buf[1], PPKB_COLS, CRC8_INIT_VALUE); |
224 | if (crc != new_buf[0]) { |
225 | dev_err(dev, "Bad scan data (%02x != %02x)\n" , crc, new_buf[0]); |
226 | return; |
227 | } |
228 | |
229 | ppkb->buf_swap = !ppkb->buf_swap; |
230 | |
231 | for (col = 0; col < PPKB_COLS; ++col) { |
232 | u8 old = old_buf[1 + col]; |
233 | u8 new = new_buf[1 + col]; |
234 | u8 changed = old ^ new; |
235 | |
236 | if (!changed) |
237 | continue; |
238 | |
239 | for (row = 0; row < PPKB_ROWS; ++row) { |
240 | u8 mask = BIT(row); |
241 | u8 value = new & mask; |
242 | unsigned short code; |
243 | bool fn_state; |
244 | |
245 | if (!(changed & mask)) |
246 | continue; |
247 | |
248 | /* |
249 | * Save off the FN key state when the key was pressed, |
250 | * and use that to determine the code during a release. |
251 | */ |
252 | fn_state = value ? ppkb->fn_pressed : ppkb->fn_state[col] & mask; |
253 | if (fn_state) |
254 | ppkb->fn_state[col] ^= mask; |
255 | |
256 | /* The FN layer is a second set of rows. */ |
257 | code = MATRIX_SCAN_CODE(fn_state ? PPKB_ROWS + row : row, |
258 | col, row_shift); |
259 | input_event(dev: ppkb->input, EV_MSC, MSC_SCAN, value: code); |
260 | input_report_key(dev: ppkb->input, code: keymap[code], value); |
261 | if (keymap[code] == KEY_FN) |
262 | ppkb->fn_pressed = value; |
263 | } |
264 | } |
265 | input_sync(dev: ppkb->input); |
266 | } |
267 | |
268 | static irqreturn_t ppkb_irq_thread(int irq, void *data) |
269 | { |
270 | struct i2c_client *client = data; |
271 | |
272 | ppkb_update(client); |
273 | |
274 | return IRQ_HANDLED; |
275 | } |
276 | |
277 | static int ppkb_set_scan(struct i2c_client *client, bool enable) |
278 | { |
279 | struct device *dev = &client->dev; |
280 | int ret, val; |
281 | |
282 | ret = i2c_smbus_read_byte_data(client, PPKB_SYS_CONFIG); |
283 | if (ret < 0) { |
284 | dev_err(dev, "Failed to read config: %d\n" , ret); |
285 | return ret; |
286 | } |
287 | |
288 | if (enable) |
289 | val = ret & ~PPKB_SYS_CONFIG_DISABLE_SCAN; |
290 | else |
291 | val = ret | PPKB_SYS_CONFIG_DISABLE_SCAN; |
292 | |
293 | ret = i2c_smbus_write_byte_data(client, PPKB_SYS_CONFIG, value: val); |
294 | if (ret) { |
295 | dev_err(dev, "Failed to write config: %d\n" , ret); |
296 | return ret; |
297 | } |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | static int ppkb_open(struct input_dev *input) |
303 | { |
304 | struct i2c_client *client = input_get_drvdata(dev: input); |
305 | int error; |
306 | |
307 | error = ppkb_set_scan(client, enable: true); |
308 | if (error) |
309 | return error; |
310 | |
311 | return 0; |
312 | } |
313 | |
314 | static void ppkb_close(struct input_dev *input) |
315 | { |
316 | struct i2c_client *client = input_get_drvdata(dev: input); |
317 | |
318 | ppkb_set_scan(client, enable: false); |
319 | } |
320 | |
321 | static int ppkb_probe(struct i2c_client *client) |
322 | { |
323 | struct device *dev = &client->dev; |
324 | unsigned int phys_rows, phys_cols; |
325 | struct pinephone_keyboard *ppkb; |
326 | u8 info[PPKB_MATRIX_SIZE + 1]; |
327 | struct device_node *i2c_bus; |
328 | int ret; |
329 | int error; |
330 | |
331 | error = devm_regulator_get_enable(dev, id: "vbat" ); |
332 | if (error) { |
333 | dev_err(dev, "Failed to get VBAT supply: %d\n" , error); |
334 | return error; |
335 | } |
336 | |
337 | ret = i2c_smbus_read_i2c_block_data(client, command: 0, length: sizeof(info), values: info); |
338 | if (ret != sizeof(info)) { |
339 | error = ret < 0 ? ret : -EIO; |
340 | dev_err(dev, "Failed to read device ID: %d\n" , error); |
341 | return error; |
342 | } |
343 | |
344 | if (info[PPKB_DEVICE_ID_HI] != PPKB_DEVICE_ID_HI_VALUE || |
345 | info[PPKB_DEVICE_ID_LO] != PPKB_DEVICE_ID_LO_VALUE) { |
346 | dev_warn(dev, "Unexpected device ID: %#02x %#02x\n" , |
347 | info[PPKB_DEVICE_ID_HI], info[PPKB_DEVICE_ID_LO]); |
348 | return -ENODEV; |
349 | } |
350 | |
351 | dev_info(dev, "Found firmware version %d.%d features %#x\n" , |
352 | info[PPKB_FW_REVISION] >> 4, |
353 | info[PPKB_FW_REVISION] & 0xf, |
354 | info[PPKB_FW_FEATURES]); |
355 | |
356 | phys_rows = info[PPKB_MATRIX_SIZE] & 0xf; |
357 | phys_cols = info[PPKB_MATRIX_SIZE] >> 4; |
358 | if (phys_rows != PPKB_ROWS || phys_cols != PPKB_COLS) { |
359 | dev_err(dev, "Unexpected keyboard size %ux%u\n" , |
360 | phys_rows, phys_cols); |
361 | return -EINVAL; |
362 | } |
363 | |
364 | /* Disable scan by default to save power. */ |
365 | error = ppkb_set_scan(client, enable: false); |
366 | if (error) |
367 | return error; |
368 | |
369 | ppkb = devm_kzalloc(dev, size: sizeof(*ppkb), GFP_KERNEL); |
370 | if (!ppkb) |
371 | return -ENOMEM; |
372 | |
373 | i2c_set_clientdata(client, data: ppkb); |
374 | |
375 | i2c_bus = of_get_child_by_name(node: dev->of_node, name: "i2c" ); |
376 | if (i2c_bus) { |
377 | ppkb->adapter.owner = THIS_MODULE; |
378 | ppkb->adapter.algo = &ppkb_adap_algo; |
379 | ppkb->adapter.algo_data = client; |
380 | ppkb->adapter.dev.parent = dev; |
381 | ppkb->adapter.dev.of_node = i2c_bus; |
382 | strscpy(ppkb->adapter.name, DRV_NAME, sizeof(ppkb->adapter.name)); |
383 | |
384 | error = devm_i2c_add_adapter(dev, adapter: &ppkb->adapter); |
385 | if (error) { |
386 | dev_err(dev, "Failed to add I2C adapter: %d\n" , error); |
387 | return error; |
388 | } |
389 | } |
390 | |
391 | crc8_populate_msb(table: ppkb->crc_table, PPKB_CRC8_POLYNOMIAL); |
392 | |
393 | ppkb->input = devm_input_allocate_device(dev); |
394 | if (!ppkb->input) |
395 | return -ENOMEM; |
396 | |
397 | input_set_drvdata(dev: ppkb->input, data: client); |
398 | |
399 | ppkb->input->name = "PinePhone Keyboard" ; |
400 | ppkb->input->phys = DRV_NAME "/input0" ; |
401 | ppkb->input->id.bustype = BUS_I2C; |
402 | ppkb->input->open = ppkb_open; |
403 | ppkb->input->close = ppkb_close; |
404 | |
405 | input_set_capability(dev: ppkb->input, EV_MSC, MSC_SCAN); |
406 | __set_bit(EV_REP, ppkb->input->evbit); |
407 | |
408 | error = matrix_keypad_build_keymap(keymap_data: &ppkb_keymap_data, NULL, |
409 | rows: 2 * PPKB_ROWS, PPKB_COLS, NULL, |
410 | input_dev: ppkb->input); |
411 | if (error) { |
412 | dev_err(dev, "Failed to build keymap: %d\n" , error); |
413 | return error; |
414 | } |
415 | |
416 | error = input_register_device(ppkb->input); |
417 | if (error) { |
418 | dev_err(dev, "Failed to register input: %d\n" , error); |
419 | return error; |
420 | } |
421 | |
422 | error = devm_request_threaded_irq(dev, irq: client->irq, |
423 | NULL, thread_fn: ppkb_irq_thread, |
424 | IRQF_ONESHOT, devname: client->name, dev_id: client); |
425 | if (error) { |
426 | dev_err(dev, "Failed to request IRQ: %d\n" , error); |
427 | return error; |
428 | } |
429 | |
430 | return 0; |
431 | } |
432 | |
433 | static const struct of_device_id ppkb_of_match[] = { |
434 | { .compatible = "pine64,pinephone-keyboard" }, |
435 | { } |
436 | }; |
437 | MODULE_DEVICE_TABLE(of, ppkb_of_match); |
438 | |
439 | static struct i2c_driver ppkb_driver = { |
440 | .probe = ppkb_probe, |
441 | .driver = { |
442 | .name = DRV_NAME, |
443 | .of_match_table = ppkb_of_match, |
444 | }, |
445 | }; |
446 | module_i2c_driver(ppkb_driver); |
447 | |
448 | MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>" ); |
449 | MODULE_DESCRIPTION("Pine64 PinePhone keyboard driver" ); |
450 | MODULE_LICENSE("GPL" ); |
451 | |