drivers/input/keyboard/pinephone-keyboard.c

Source file repositories/reference/linux-study-clean/drivers/input/keyboard/pinephone-keyboard.c

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/pinephone-keyboard.c
Extension
.c
Size
11094 bytes
Lines
451
Domain
Driver Families
Bucket
drivers/input
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct pinephone_keyboard {
	struct i2c_adapter adapter;
	struct input_dev *input;
	u8 buf[2][PPKB_BUF_LEN];
	u8 crc_table[CRC8_TABLE_SIZE];
	u8 fn_state[PPKB_COLS];
	bool buf_swap;
	bool fn_pressed;
};

static int 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)
{
	struct i2c_client *client = adap->algo_data;
	u8 buf[3];
	int ret;

	buf[0] = command;
	buf[1] = data->byte;
	buf[2] = read_write == I2C_SMBUS_READ ? PPKB_SYS_COMMAND_SMBUS_READ
					      : PPKB_SYS_COMMAND_SMBUS_WRITE;

	ret = i2c_smbus_write_i2c_block_data(client, PPKB_SYS_SMBUS_COMMAND,
					     sizeof(buf), buf);
	if (ret)
		return ret;

	/* Read back the command status until it passes or fails. */
	do {
		usleep_range(300, 500);
		ret = i2c_smbus_read_byte_data(client, PPKB_SYS_COMMAND);
	} while (ret == buf[2]);
	if (ret < 0)
		return ret;
	/* Commands return 0x00 on success and 0xff on failure. */
	if (ret)
		return -EIO;

	if (read_write == I2C_SMBUS_READ) {
		ret = i2c_smbus_read_byte_data(client, PPKB_SYS_SMBUS_DATA);
		if (ret < 0)
			return ret;

		data->byte = ret;
	}

	return 0;
}

static u32 ppkg_adap_functionality(struct i2c_adapter *adap)
{
	return I2C_FUNC_SMBUS_BYTE_DATA;
}

static const struct i2c_algorithm ppkb_adap_algo = {
	.smbus_xfer		= ppkb_adap_smbus_xfer,
	.functionality		= ppkg_adap_functionality,
};

static void ppkb_update(struct i2c_client *client)
{
	struct pinephone_keyboard *ppkb = i2c_get_clientdata(client);
	unsigned short *keymap = ppkb->input->keycode;
	int row_shift = get_count_order(PPKB_COLS);
	u8 *old_buf = ppkb->buf[!ppkb->buf_swap];
	u8 *new_buf = ppkb->buf[ppkb->buf_swap];
	int col, crc, ret, row;
	struct device *dev = &client->dev;

	ret = i2c_smbus_read_i2c_block_data(client, PPKB_SCAN_CRC,
					    PPKB_BUF_LEN, new_buf);
	if (ret != PPKB_BUF_LEN) {
		dev_err(dev, "Failed to read scan data: %d\n", ret);
		return;
	}

	crc = crc8(ppkb->crc_table, &new_buf[1], PPKB_COLS, CRC8_INIT_VALUE);
	if (crc != new_buf[0]) {
		dev_err(dev, "Bad scan data (%02x != %02x)\n", crc, new_buf[0]);
		return;
	}

	ppkb->buf_swap = !ppkb->buf_swap;

	for (col = 0; col < PPKB_COLS; ++col) {
		u8 old = old_buf[1 + col];
		u8 new = new_buf[1 + col];
		u8 changed = old ^ new;

Annotation

Implementation Notes