drivers/input/keyboard/mpr121_touchkey.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/mpr121_touchkey.c
Extension
.c
Size
9357 bytes
Lines
353
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 mpr121_touchkey {
	struct i2c_client	*client;
	struct input_dev	*input_dev;
	unsigned int		statusbits;
	unsigned int		keycount;
	u32			keycodes[MPR121_MAX_KEY_COUNT];
};

struct mpr121_init_register {
	int addr;
	u8 val;
};

static const struct mpr121_init_register init_reg_table[] = {
	{ MHD_RISING_ADDR,	0x1 },
	{ NHD_RISING_ADDR,	0x1 },
	{ MHD_FALLING_ADDR,	0x1 },
	{ NHD_FALLING_ADDR,	0x1 },
	{ NCL_FALLING_ADDR,	0xff },
	{ FDL_FALLING_ADDR,	0x02 },
	{ FILTER_CONF_ADDR,	0x04 },
	{ AFE_CONF_ADDR,	0x0b },
	{ AUTO_CONFIG_CTRL_ADDR, 0x0b },
};

static void mpr_touchkey_report(struct input_dev *dev)
{
	struct mpr121_touchkey *mpr121 = input_get_drvdata(dev);
	struct input_dev *input = mpr121->input_dev;
	struct i2c_client *client = mpr121->client;
	unsigned long bit_changed;
	unsigned int key_num;
	int reg;

	reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
	if (reg < 0) {
		dev_err(&client->dev, "i2c read error [%d]\n", reg);
		return;
	}

	reg <<= 8;
	reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
	if (reg < 0) {
		dev_err(&client->dev, "i2c read error [%d]\n", reg);
		return;
	}

	reg &= TOUCH_STATUS_MASK;
	/* use old press bit to figure out which bit changed */
	bit_changed = reg ^ mpr121->statusbits;
	mpr121->statusbits = reg;
	for_each_set_bit(key_num, &bit_changed, mpr121->keycount) {
		unsigned int key_val, pressed;

		pressed = reg & BIT(key_num);
		key_val = mpr121->keycodes[key_num];

		input_event(input, EV_MSC, MSC_SCAN, key_num);
		input_report_key(input, key_val, pressed);

		dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
			pressed ? "pressed" : "released");

	}
	input_sync(input);
}

static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
{
	struct mpr121_touchkey *mpr121 = dev_id;

	mpr_touchkey_report(mpr121->input_dev);

	return IRQ_HANDLED;
}

static int mpr121_phys_init(struct mpr121_touchkey *mpr121,
			    struct i2c_client *client, int vdd_uv)
{
	const struct mpr121_init_register *reg;
	unsigned char usl, lsl, tl, eleconf;
	int i, t, vdd, ret;

	/* Set up touch/release threshold for ele0-ele11 */
	for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) {
		t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2);
		ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD);
		if (ret < 0)
			goto err_i2c_write;
		ret = i2c_smbus_write_byte_data(client, t + 1,

Annotation

Implementation Notes