xref: /openbmc/linux/drivers/input/keyboard/pinephone-keyboard.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
117406967SSamuel Holland // SPDX-License-Identifier: GPL-2.0-only
217406967SSamuel Holland //
317406967SSamuel Holland // Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org>
417406967SSamuel Holland 
517406967SSamuel Holland #include <linux/crc8.h>
663c5eb15SSamuel Holland #include <linux/delay.h>
717406967SSamuel Holland #include <linux/err.h>
817406967SSamuel Holland #include <linux/i2c.h>
917406967SSamuel Holland #include <linux/input.h>
1017406967SSamuel Holland #include <linux/input/matrix_keypad.h>
1117406967SSamuel Holland #include <linux/interrupt.h>
1217406967SSamuel Holland #include <linux/module.h>
1317406967SSamuel Holland #include <linux/mod_devicetable.h>
1463c5eb15SSamuel Holland #include <linux/of.h>
1517406967SSamuel Holland #include <linux/regulator/consumer.h>
1617406967SSamuel Holland #include <linux/types.h>
1717406967SSamuel Holland 
1817406967SSamuel Holland #define DRV_NAME			"pinephone-keyboard"
1917406967SSamuel Holland 
2017406967SSamuel Holland #define PPKB_CRC8_POLYNOMIAL		0x07
2117406967SSamuel Holland 
2217406967SSamuel Holland #define PPKB_DEVICE_ID_HI		0x00
2317406967SSamuel Holland #define PPKB_DEVICE_ID_HI_VALUE			'K'
2417406967SSamuel Holland #define PPKB_DEVICE_ID_LO		0x01
2517406967SSamuel Holland #define PPKB_DEVICE_ID_LO_VALUE			'B'
2617406967SSamuel Holland #define PPKB_FW_REVISION		0x02
2717406967SSamuel Holland #define PPKB_FW_FEATURES		0x03
2817406967SSamuel Holland #define PPKB_MATRIX_SIZE		0x06
2917406967SSamuel Holland #define PPKB_SCAN_CRC			0x07
3017406967SSamuel Holland #define PPKB_SCAN_DATA			0x08
3117406967SSamuel Holland #define PPKB_SYS_CONFIG			0x20
3217406967SSamuel Holland #define PPKB_SYS_CONFIG_DISABLE_SCAN		BIT(0)
3363c5eb15SSamuel Holland #define PPKB_SYS_SMBUS_COMMAND		0x21
3463c5eb15SSamuel Holland #define PPKB_SYS_SMBUS_DATA		0x22
3563c5eb15SSamuel Holland #define PPKB_SYS_COMMAND		0x23
3663c5eb15SSamuel Holland #define PPKB_SYS_COMMAND_SMBUS_READ		0x91
3763c5eb15SSamuel Holland #define PPKB_SYS_COMMAND_SMBUS_WRITE		0xa1
3817406967SSamuel Holland 
3917406967SSamuel Holland #define PPKB_ROWS			6
4017406967SSamuel Holland #define PPKB_COLS			12
4117406967SSamuel Holland 
4217406967SSamuel Holland /* Size of the scan buffer, including the CRC byte at the beginning. */
4317406967SSamuel Holland #define PPKB_BUF_LEN			(1 + PPKB_COLS)
4417406967SSamuel Holland 
4517406967SSamuel Holland static const uint32_t ppkb_keymap[] = {
4617406967SSamuel Holland 	KEY(0,  0, KEY_ESC),
4717406967SSamuel Holland 	KEY(0,  1, KEY_1),
4817406967SSamuel Holland 	KEY(0,  2, KEY_2),
4917406967SSamuel Holland 	KEY(0,  3, KEY_3),
5017406967SSamuel Holland 	KEY(0,  4, KEY_4),
5117406967SSamuel Holland 	KEY(0,  5, KEY_5),
5217406967SSamuel Holland 	KEY(0,  6, KEY_6),
5317406967SSamuel Holland 	KEY(0,  7, KEY_7),
5417406967SSamuel Holland 	KEY(0,  8, KEY_8),
5517406967SSamuel Holland 	KEY(0,  9, KEY_9),
5617406967SSamuel Holland 	KEY(0, 10, KEY_0),
5717406967SSamuel Holland 	KEY(0, 11, KEY_BACKSPACE),
5817406967SSamuel Holland 
5917406967SSamuel Holland 	KEY(1,  0, KEY_TAB),
6017406967SSamuel Holland 	KEY(1,  1, KEY_Q),
6117406967SSamuel Holland 	KEY(1,  2, KEY_W),
6217406967SSamuel Holland 	KEY(1,  3, KEY_E),
6317406967SSamuel Holland 	KEY(1,  4, KEY_R),
6417406967SSamuel Holland 	KEY(1,  5, KEY_T),
6517406967SSamuel Holland 	KEY(1,  6, KEY_Y),
6617406967SSamuel Holland 	KEY(1,  7, KEY_U),
6717406967SSamuel Holland 	KEY(1,  8, KEY_I),
6817406967SSamuel Holland 	KEY(1,  9, KEY_O),
6917406967SSamuel Holland 	KEY(1, 10, KEY_P),
7017406967SSamuel Holland 	KEY(1, 11, KEY_ENTER),
7117406967SSamuel Holland 
7217406967SSamuel Holland 	KEY(2,  0, KEY_LEFTMETA),
7317406967SSamuel Holland 	KEY(2,  1, KEY_A),
7417406967SSamuel Holland 	KEY(2,  2, KEY_S),
7517406967SSamuel Holland 	KEY(2,  3, KEY_D),
7617406967SSamuel Holland 	KEY(2,  4, KEY_F),
7717406967SSamuel Holland 	KEY(2,  5, KEY_G),
7817406967SSamuel Holland 	KEY(2,  6, KEY_H),
7917406967SSamuel Holland 	KEY(2,  7, KEY_J),
8017406967SSamuel Holland 	KEY(2,  8, KEY_K),
8117406967SSamuel Holland 	KEY(2,  9, KEY_L),
8217406967SSamuel Holland 	KEY(2, 10, KEY_SEMICOLON),
8317406967SSamuel Holland 
8417406967SSamuel Holland 	KEY(3,  0, KEY_LEFTSHIFT),
8517406967SSamuel Holland 	KEY(3,  1, KEY_Z),
8617406967SSamuel Holland 	KEY(3,  2, KEY_X),
8717406967SSamuel Holland 	KEY(3,  3, KEY_C),
8817406967SSamuel Holland 	KEY(3,  4, KEY_V),
8917406967SSamuel Holland 	KEY(3,  5, KEY_B),
9017406967SSamuel Holland 	KEY(3,  6, KEY_N),
9117406967SSamuel Holland 	KEY(3,  7, KEY_M),
9217406967SSamuel Holland 	KEY(3,  8, KEY_COMMA),
9317406967SSamuel Holland 	KEY(3,  9, KEY_DOT),
9417406967SSamuel Holland 	KEY(3, 10, KEY_SLASH),
9517406967SSamuel Holland 
9617406967SSamuel Holland 	KEY(4,  1, KEY_LEFTCTRL),
9717406967SSamuel Holland 	KEY(4,  4, KEY_SPACE),
9817406967SSamuel Holland 	KEY(4,  6, KEY_APOSTROPHE),
9917406967SSamuel Holland 	KEY(4,  8, KEY_RIGHTBRACE),
10017406967SSamuel Holland 	KEY(4,  9, KEY_LEFTBRACE),
10117406967SSamuel Holland 
10217406967SSamuel Holland 	KEY(5,  2, KEY_FN),
10317406967SSamuel Holland 	KEY(5,  3, KEY_LEFTALT),
10417406967SSamuel Holland 	KEY(5,  5, KEY_RIGHTALT),
10517406967SSamuel Holland 
10617406967SSamuel Holland 	/* FN layer */
10717406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  0, KEY_FN_ESC),
10817406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  1, KEY_F1),
10917406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  2, KEY_F2),
11017406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  3, KEY_F3),
11117406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  4, KEY_F4),
11217406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  5, KEY_F5),
11317406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  6, KEY_F6),
11417406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  7, KEY_F7),
11517406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  8, KEY_F8),
11617406967SSamuel Holland 	KEY(PPKB_ROWS + 0,  9, KEY_F9),
11717406967SSamuel Holland 	KEY(PPKB_ROWS + 0, 10, KEY_F10),
11817406967SSamuel Holland 	KEY(PPKB_ROWS + 0, 11, KEY_DELETE),
11917406967SSamuel Holland 
12017406967SSamuel Holland 	KEY(PPKB_ROWS + 1, 10, KEY_PAGEUP),
12117406967SSamuel Holland 
12217406967SSamuel Holland 	KEY(PPKB_ROWS + 2,  0, KEY_SYSRQ),
12317406967SSamuel Holland 	KEY(PPKB_ROWS + 2,  9, KEY_PAGEDOWN),
12417406967SSamuel Holland 	KEY(PPKB_ROWS + 2, 10, KEY_INSERT),
12517406967SSamuel Holland 
12617406967SSamuel Holland 	KEY(PPKB_ROWS + 3,  0, KEY_LEFTSHIFT),
12717406967SSamuel Holland 	KEY(PPKB_ROWS + 3,  8, KEY_HOME),
12817406967SSamuel Holland 	KEY(PPKB_ROWS + 3,  9, KEY_UP),
12917406967SSamuel Holland 	KEY(PPKB_ROWS + 3, 10, KEY_END),
13017406967SSamuel Holland 
13117406967SSamuel Holland 	KEY(PPKB_ROWS + 4, 1, KEY_LEFTCTRL),
13217406967SSamuel Holland 	KEY(PPKB_ROWS + 4, 6, KEY_LEFT),
13317406967SSamuel Holland 	KEY(PPKB_ROWS + 4, 8, KEY_RIGHT),
13417406967SSamuel Holland 	KEY(PPKB_ROWS + 4, 9, KEY_DOWN),
13517406967SSamuel Holland 
13617406967SSamuel Holland 	KEY(PPKB_ROWS + 5, 3, KEY_LEFTALT),
13717406967SSamuel Holland 	KEY(PPKB_ROWS + 5, 5, KEY_RIGHTALT),
13817406967SSamuel Holland };
13917406967SSamuel Holland 
14017406967SSamuel Holland static const struct matrix_keymap_data ppkb_keymap_data = {
14117406967SSamuel Holland 	.keymap		= ppkb_keymap,
14217406967SSamuel Holland 	.keymap_size	= ARRAY_SIZE(ppkb_keymap),
14317406967SSamuel Holland };
14417406967SSamuel Holland 
14517406967SSamuel Holland struct pinephone_keyboard {
14663c5eb15SSamuel Holland 	struct i2c_adapter adapter;
14717406967SSamuel Holland 	struct input_dev *input;
14817406967SSamuel Holland 	u8 buf[2][PPKB_BUF_LEN];
14917406967SSamuel Holland 	u8 crc_table[CRC8_TABLE_SIZE];
15017406967SSamuel Holland 	u8 fn_state[PPKB_COLS];
15117406967SSamuel Holland 	bool buf_swap;
15217406967SSamuel Holland 	bool fn_pressed;
15317406967SSamuel Holland };
15417406967SSamuel Holland 
ppkb_adap_smbus_xfer(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)15563c5eb15SSamuel Holland static int ppkb_adap_smbus_xfer(struct i2c_adapter *adap, u16 addr,
15663c5eb15SSamuel Holland 				unsigned short flags, char read_write,
15763c5eb15SSamuel Holland 				u8 command, int size,
15863c5eb15SSamuel Holland 				union i2c_smbus_data *data)
15963c5eb15SSamuel Holland {
16063c5eb15SSamuel Holland 	struct i2c_client *client = adap->algo_data;
16163c5eb15SSamuel Holland 	u8 buf[3];
16263c5eb15SSamuel Holland 	int ret;
16363c5eb15SSamuel Holland 
16463c5eb15SSamuel Holland 	buf[0] = command;
16563c5eb15SSamuel Holland 	buf[1] = data->byte;
16663c5eb15SSamuel Holland 	buf[2] = read_write == I2C_SMBUS_READ ? PPKB_SYS_COMMAND_SMBUS_READ
16763c5eb15SSamuel Holland 					      : PPKB_SYS_COMMAND_SMBUS_WRITE;
16863c5eb15SSamuel Holland 
16963c5eb15SSamuel Holland 	ret = i2c_smbus_write_i2c_block_data(client, PPKB_SYS_SMBUS_COMMAND,
17063c5eb15SSamuel Holland 					     sizeof(buf), buf);
17163c5eb15SSamuel Holland 	if (ret)
17263c5eb15SSamuel Holland 		return ret;
17363c5eb15SSamuel Holland 
17463c5eb15SSamuel Holland 	/* Read back the command status until it passes or fails. */
17563c5eb15SSamuel Holland 	do {
17663c5eb15SSamuel Holland 		usleep_range(300, 500);
17763c5eb15SSamuel Holland 		ret = i2c_smbus_read_byte_data(client, PPKB_SYS_COMMAND);
17863c5eb15SSamuel Holland 	} while (ret == buf[2]);
17963c5eb15SSamuel Holland 	if (ret < 0)
18063c5eb15SSamuel Holland 		return ret;
18163c5eb15SSamuel Holland 	/* Commands return 0x00 on success and 0xff on failure. */
18263c5eb15SSamuel Holland 	if (ret)
18363c5eb15SSamuel Holland 		return -EIO;
18463c5eb15SSamuel Holland 
18563c5eb15SSamuel Holland 	if (read_write == I2C_SMBUS_READ) {
18663c5eb15SSamuel Holland 		ret = i2c_smbus_read_byte_data(client, PPKB_SYS_SMBUS_DATA);
18763c5eb15SSamuel Holland 		if (ret < 0)
18863c5eb15SSamuel Holland 			return ret;
18963c5eb15SSamuel Holland 
19063c5eb15SSamuel Holland 		data->byte = ret;
19163c5eb15SSamuel Holland 	}
19263c5eb15SSamuel Holland 
19363c5eb15SSamuel Holland 	return 0;
19463c5eb15SSamuel Holland }
19563c5eb15SSamuel Holland 
ppkg_adap_functionality(struct i2c_adapter * adap)19663c5eb15SSamuel Holland static u32 ppkg_adap_functionality(struct i2c_adapter *adap)
19763c5eb15SSamuel Holland {
19863c5eb15SSamuel Holland 	return I2C_FUNC_SMBUS_BYTE_DATA;
19963c5eb15SSamuel Holland }
20063c5eb15SSamuel Holland 
20163c5eb15SSamuel Holland static const struct i2c_algorithm ppkb_adap_algo = {
20263c5eb15SSamuel Holland 	.smbus_xfer		= ppkb_adap_smbus_xfer,
20363c5eb15SSamuel Holland 	.functionality		= ppkg_adap_functionality,
20463c5eb15SSamuel Holland };
20563c5eb15SSamuel Holland 
ppkb_update(struct i2c_client * client)20617406967SSamuel Holland static void ppkb_update(struct i2c_client *client)
20717406967SSamuel Holland {
20817406967SSamuel Holland 	struct pinephone_keyboard *ppkb = i2c_get_clientdata(client);
20917406967SSamuel Holland 	unsigned short *keymap = ppkb->input->keycode;
21017406967SSamuel Holland 	int row_shift = get_count_order(PPKB_COLS);
21117406967SSamuel Holland 	u8 *old_buf = ppkb->buf[!ppkb->buf_swap];
21217406967SSamuel Holland 	u8 *new_buf = ppkb->buf[ppkb->buf_swap];
21317406967SSamuel Holland 	int col, crc, ret, row;
21417406967SSamuel Holland 	struct device *dev = &client->dev;
21517406967SSamuel Holland 
21617406967SSamuel Holland 	ret = i2c_smbus_read_i2c_block_data(client, PPKB_SCAN_CRC,
21717406967SSamuel Holland 					    PPKB_BUF_LEN, new_buf);
21817406967SSamuel Holland 	if (ret != PPKB_BUF_LEN) {
21917406967SSamuel Holland 		dev_err(dev, "Failed to read scan data: %d\n", ret);
22017406967SSamuel Holland 		return;
22117406967SSamuel Holland 	}
22217406967SSamuel Holland 
22317406967SSamuel Holland 	crc = crc8(ppkb->crc_table, &new_buf[1], PPKB_COLS, CRC8_INIT_VALUE);
22417406967SSamuel Holland 	if (crc != new_buf[0]) {
22517406967SSamuel Holland 		dev_err(dev, "Bad scan data (%02x != %02x)\n", crc, new_buf[0]);
22617406967SSamuel Holland 		return;
22717406967SSamuel Holland 	}
22817406967SSamuel Holland 
22917406967SSamuel Holland 	ppkb->buf_swap = !ppkb->buf_swap;
23017406967SSamuel Holland 
23117406967SSamuel Holland 	for (col = 0; col < PPKB_COLS; ++col) {
23217406967SSamuel Holland 		u8 old = old_buf[1 + col];
23317406967SSamuel Holland 		u8 new = new_buf[1 + col];
23417406967SSamuel Holland 		u8 changed = old ^ new;
23517406967SSamuel Holland 
23617406967SSamuel Holland 		if (!changed)
23717406967SSamuel Holland 			continue;
23817406967SSamuel Holland 
23917406967SSamuel Holland 		for (row = 0; row < PPKB_ROWS; ++row) {
24017406967SSamuel Holland 			u8 mask = BIT(row);
24117406967SSamuel Holland 			u8 value = new & mask;
24217406967SSamuel Holland 			unsigned short code;
24317406967SSamuel Holland 			bool fn_state;
24417406967SSamuel Holland 
24517406967SSamuel Holland 			if (!(changed & mask))
24617406967SSamuel Holland 				continue;
24717406967SSamuel Holland 
24817406967SSamuel Holland 			/*
24917406967SSamuel Holland 			 * Save off the FN key state when the key was pressed,
25017406967SSamuel Holland 			 * and use that to determine the code during a release.
25117406967SSamuel Holland 			 */
25217406967SSamuel Holland 			fn_state = value ? ppkb->fn_pressed : ppkb->fn_state[col] & mask;
25317406967SSamuel Holland 			if (fn_state)
25417406967SSamuel Holland 				ppkb->fn_state[col] ^= mask;
25517406967SSamuel Holland 
25617406967SSamuel Holland 			/* The FN layer is a second set of rows. */
25717406967SSamuel Holland 			code = MATRIX_SCAN_CODE(fn_state ? PPKB_ROWS + row : row,
25817406967SSamuel Holland 						col, row_shift);
25917406967SSamuel Holland 			input_event(ppkb->input, EV_MSC, MSC_SCAN, code);
26017406967SSamuel Holland 			input_report_key(ppkb->input, keymap[code], value);
26117406967SSamuel Holland 			if (keymap[code] == KEY_FN)
26217406967SSamuel Holland 				ppkb->fn_pressed = value;
26317406967SSamuel Holland 		}
26417406967SSamuel Holland 	}
26517406967SSamuel Holland 	input_sync(ppkb->input);
26617406967SSamuel Holland }
26717406967SSamuel Holland 
ppkb_irq_thread(int irq,void * data)26817406967SSamuel Holland static irqreturn_t ppkb_irq_thread(int irq, void *data)
26917406967SSamuel Holland {
27017406967SSamuel Holland 	struct i2c_client *client = data;
27117406967SSamuel Holland 
27217406967SSamuel Holland 	ppkb_update(client);
27317406967SSamuel Holland 
27417406967SSamuel Holland 	return IRQ_HANDLED;
27517406967SSamuel Holland }
27617406967SSamuel Holland 
ppkb_set_scan(struct i2c_client * client,bool enable)27717406967SSamuel Holland static int ppkb_set_scan(struct i2c_client *client, bool enable)
27817406967SSamuel Holland {
27917406967SSamuel Holland 	struct device *dev = &client->dev;
28017406967SSamuel Holland 	int ret, val;
28117406967SSamuel Holland 
28217406967SSamuel Holland 	ret = i2c_smbus_read_byte_data(client, PPKB_SYS_CONFIG);
28317406967SSamuel Holland 	if (ret < 0) {
28417406967SSamuel Holland 		dev_err(dev, "Failed to read config: %d\n", ret);
28517406967SSamuel Holland 		return ret;
28617406967SSamuel Holland 	}
28717406967SSamuel Holland 
28817406967SSamuel Holland 	if (enable)
28917406967SSamuel Holland 		val = ret & ~PPKB_SYS_CONFIG_DISABLE_SCAN;
29017406967SSamuel Holland 	else
29117406967SSamuel Holland 		val = ret | PPKB_SYS_CONFIG_DISABLE_SCAN;
29217406967SSamuel Holland 
29317406967SSamuel Holland 	ret = i2c_smbus_write_byte_data(client, PPKB_SYS_CONFIG, val);
29417406967SSamuel Holland 	if (ret) {
29517406967SSamuel Holland 		dev_err(dev, "Failed to write config: %d\n", ret);
29617406967SSamuel Holland 		return ret;
29717406967SSamuel Holland 	}
29817406967SSamuel Holland 
29917406967SSamuel Holland 	return 0;
30017406967SSamuel Holland }
30117406967SSamuel Holland 
ppkb_open(struct input_dev * input)30217406967SSamuel Holland static int ppkb_open(struct input_dev *input)
30317406967SSamuel Holland {
30417406967SSamuel Holland 	struct i2c_client *client = input_get_drvdata(input);
30517406967SSamuel Holland 	int error;
30617406967SSamuel Holland 
30717406967SSamuel Holland 	error = ppkb_set_scan(client, true);
30817406967SSamuel Holland 	if (error)
30917406967SSamuel Holland 		return error;
31017406967SSamuel Holland 
31117406967SSamuel Holland 	return 0;
31217406967SSamuel Holland }
31317406967SSamuel Holland 
ppkb_close(struct input_dev * input)31417406967SSamuel Holland static void ppkb_close(struct input_dev *input)
31517406967SSamuel Holland {
31617406967SSamuel Holland 	struct i2c_client *client = input_get_drvdata(input);
31717406967SSamuel Holland 
31817406967SSamuel Holland 	ppkb_set_scan(client, false);
31917406967SSamuel Holland }
32017406967SSamuel Holland 
ppkb_probe(struct i2c_client * client)32117406967SSamuel Holland static int ppkb_probe(struct i2c_client *client)
32217406967SSamuel Holland {
32317406967SSamuel Holland 	struct device *dev = &client->dev;
32417406967SSamuel Holland 	unsigned int phys_rows, phys_cols;
32517406967SSamuel Holland 	struct pinephone_keyboard *ppkb;
32617406967SSamuel Holland 	u8 info[PPKB_MATRIX_SIZE + 1];
32763c5eb15SSamuel Holland 	struct device_node *i2c_bus;
32817406967SSamuel Holland 	int ret;
32917406967SSamuel Holland 	int error;
33017406967SSamuel Holland 
331*3ce6e062SChristophe JAILLET 	error = devm_regulator_get_enable(dev, "vbat");
33217406967SSamuel Holland 	if (error) {
33317406967SSamuel Holland 		dev_err(dev, "Failed to get VBAT supply: %d\n", error);
33417406967SSamuel Holland 		return error;
33517406967SSamuel Holland 	}
33617406967SSamuel Holland 
33717406967SSamuel Holland 	ret = i2c_smbus_read_i2c_block_data(client, 0, sizeof(info), info);
33817406967SSamuel Holland 	if (ret != sizeof(info)) {
33917406967SSamuel Holland 		error = ret < 0 ? ret : -EIO;
34017406967SSamuel Holland 		dev_err(dev, "Failed to read device ID: %d\n", error);
34117406967SSamuel Holland 		return error;
34217406967SSamuel Holland 	}
34317406967SSamuel Holland 
34417406967SSamuel Holland 	if (info[PPKB_DEVICE_ID_HI] != PPKB_DEVICE_ID_HI_VALUE ||
34517406967SSamuel Holland 	    info[PPKB_DEVICE_ID_LO] != PPKB_DEVICE_ID_LO_VALUE) {
34617406967SSamuel Holland 		dev_warn(dev, "Unexpected device ID: %#02x %#02x\n",
34717406967SSamuel Holland 			 info[PPKB_DEVICE_ID_HI], info[PPKB_DEVICE_ID_LO]);
34817406967SSamuel Holland 		return -ENODEV;
34917406967SSamuel Holland 	}
35017406967SSamuel Holland 
35117406967SSamuel Holland 	dev_info(dev, "Found firmware version %d.%d features %#x\n",
35217406967SSamuel Holland 		 info[PPKB_FW_REVISION] >> 4,
35317406967SSamuel Holland 		 info[PPKB_FW_REVISION] & 0xf,
35417406967SSamuel Holland 		 info[PPKB_FW_FEATURES]);
35517406967SSamuel Holland 
35617406967SSamuel Holland 	phys_rows = info[PPKB_MATRIX_SIZE] & 0xf;
35717406967SSamuel Holland 	phys_cols = info[PPKB_MATRIX_SIZE] >> 4;
35817406967SSamuel Holland 	if (phys_rows != PPKB_ROWS || phys_cols != PPKB_COLS) {
35917406967SSamuel Holland 		dev_err(dev, "Unexpected keyboard size %ux%u\n",
36017406967SSamuel Holland 			phys_rows, phys_cols);
36117406967SSamuel Holland 		return -EINVAL;
36217406967SSamuel Holland 	}
36317406967SSamuel Holland 
36417406967SSamuel Holland 	/* Disable scan by default to save power. */
36517406967SSamuel Holland 	error = ppkb_set_scan(client, false);
36617406967SSamuel Holland 	if (error)
36717406967SSamuel Holland 		return error;
36817406967SSamuel Holland 
36917406967SSamuel Holland 	ppkb = devm_kzalloc(dev, sizeof(*ppkb), GFP_KERNEL);
37017406967SSamuel Holland 	if (!ppkb)
37117406967SSamuel Holland 		return -ENOMEM;
37217406967SSamuel Holland 
37317406967SSamuel Holland 	i2c_set_clientdata(client, ppkb);
37417406967SSamuel Holland 
37563c5eb15SSamuel Holland 	i2c_bus = of_get_child_by_name(dev->of_node, "i2c");
37663c5eb15SSamuel Holland 	if (i2c_bus) {
37763c5eb15SSamuel Holland 		ppkb->adapter.owner = THIS_MODULE;
37863c5eb15SSamuel Holland 		ppkb->adapter.algo = &ppkb_adap_algo;
37963c5eb15SSamuel Holland 		ppkb->adapter.algo_data = client;
38063c5eb15SSamuel Holland 		ppkb->adapter.dev.parent = dev;
38163c5eb15SSamuel Holland 		ppkb->adapter.dev.of_node = i2c_bus;
38263c5eb15SSamuel Holland 		strscpy(ppkb->adapter.name, DRV_NAME, sizeof(ppkb->adapter.name));
38363c5eb15SSamuel Holland 
38463c5eb15SSamuel Holland 		error = devm_i2c_add_adapter(dev, &ppkb->adapter);
38563c5eb15SSamuel Holland 		if (error) {
38663c5eb15SSamuel Holland 			dev_err(dev, "Failed to add I2C adapter: %d\n", error);
38763c5eb15SSamuel Holland 			return error;
38863c5eb15SSamuel Holland 		}
38963c5eb15SSamuel Holland 	}
39063c5eb15SSamuel Holland 
39117406967SSamuel Holland 	crc8_populate_msb(ppkb->crc_table, PPKB_CRC8_POLYNOMIAL);
39217406967SSamuel Holland 
39317406967SSamuel Holland 	ppkb->input = devm_input_allocate_device(dev);
39417406967SSamuel Holland 	if (!ppkb->input)
39517406967SSamuel Holland 		return -ENOMEM;
39617406967SSamuel Holland 
39717406967SSamuel Holland 	input_set_drvdata(ppkb->input, client);
39817406967SSamuel Holland 
39917406967SSamuel Holland 	ppkb->input->name = "PinePhone Keyboard";
40017406967SSamuel Holland 	ppkb->input->phys = DRV_NAME "/input0";
40117406967SSamuel Holland 	ppkb->input->id.bustype = BUS_I2C;
40217406967SSamuel Holland 	ppkb->input->open = ppkb_open;
40317406967SSamuel Holland 	ppkb->input->close = ppkb_close;
40417406967SSamuel Holland 
40517406967SSamuel Holland 	input_set_capability(ppkb->input, EV_MSC, MSC_SCAN);
40617406967SSamuel Holland 	__set_bit(EV_REP, ppkb->input->evbit);
40717406967SSamuel Holland 
40817406967SSamuel Holland 	error = matrix_keypad_build_keymap(&ppkb_keymap_data, NULL,
40917406967SSamuel Holland 					   2 * PPKB_ROWS, PPKB_COLS, NULL,
41017406967SSamuel Holland 					   ppkb->input);
41117406967SSamuel Holland 	if (error) {
41217406967SSamuel Holland 		dev_err(dev, "Failed to build keymap: %d\n", error);
41317406967SSamuel Holland 		return error;
41417406967SSamuel Holland 	}
41517406967SSamuel Holland 
41617406967SSamuel Holland 	error = input_register_device(ppkb->input);
41717406967SSamuel Holland 	if (error) {
41817406967SSamuel Holland 		dev_err(dev, "Failed to register input: %d\n", error);
41917406967SSamuel Holland 		return error;
42017406967SSamuel Holland 	}
42117406967SSamuel Holland 
42217406967SSamuel Holland 	error = devm_request_threaded_irq(dev, client->irq,
42317406967SSamuel Holland 					  NULL, ppkb_irq_thread,
42417406967SSamuel Holland 					  IRQF_ONESHOT, client->name, client);
42517406967SSamuel Holland 	if (error) {
42617406967SSamuel Holland 		dev_err(dev, "Failed to request IRQ: %d\n", error);
42717406967SSamuel Holland 		return error;
42817406967SSamuel Holland 	}
42917406967SSamuel Holland 
43017406967SSamuel Holland 	return 0;
43117406967SSamuel Holland }
43217406967SSamuel Holland 
43317406967SSamuel Holland static const struct of_device_id ppkb_of_match[] = {
43417406967SSamuel Holland 	{ .compatible = "pine64,pinephone-keyboard" },
43517406967SSamuel Holland 	{ }
43617406967SSamuel Holland };
43717406967SSamuel Holland MODULE_DEVICE_TABLE(of, ppkb_of_match);
43817406967SSamuel Holland 
43917406967SSamuel Holland static struct i2c_driver ppkb_driver = {
440d8bde56dSUwe Kleine-König 	.probe		= ppkb_probe,
44117406967SSamuel Holland 	.driver		= {
44217406967SSamuel Holland 		.name		= DRV_NAME,
44317406967SSamuel Holland 		.of_match_table = ppkb_of_match,
44417406967SSamuel Holland 	},
44517406967SSamuel Holland };
44617406967SSamuel Holland module_i2c_driver(ppkb_driver);
44717406967SSamuel Holland 
44817406967SSamuel Holland MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
44917406967SSamuel Holland MODULE_DESCRIPTION("Pine64 PinePhone keyboard driver");
45017406967SSamuel Holland MODULE_LICENSE("GPL");
451