drivers/input/keyboard/adp5520-keys.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/adp5520-keys.c
Extension
.c
Size
4907 bytes
Lines
192
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 adp5520_keys {
	struct input_dev *input;
	struct notifier_block notifier;
	struct device *master;
	unsigned short keycode[ADP5520_KEYMAPSIZE];
};

static void adp5520_keys_report_event(struct adp5520_keys *dev,
					unsigned short keymask, int value)
{
	int i;

	for (i = 0; i < ADP5520_MAXKEYS; i++)
		if (keymask & (1 << i))
			input_report_key(dev->input, dev->keycode[i], value);

	input_sync(dev->input);
}

static int adp5520_keys_notifier(struct notifier_block *nb,
				 unsigned long event, void *data)
{
	struct adp5520_keys *dev;
	uint8_t reg_val_lo, reg_val_hi;
	unsigned short keymask;

	dev = container_of(nb, struct adp5520_keys, notifier);

	if (event & ADP5520_KP_INT) {
		adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
		adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);

		keymask = (reg_val_hi << 8) | reg_val_lo;
		/* Read twice to clear */
		adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
		adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);
		keymask |= (reg_val_hi << 8) | reg_val_lo;
		adp5520_keys_report_event(dev, keymask, 1);
	}

	if (event & ADP5520_KR_INT) {
		adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
		adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);

		keymask = (reg_val_hi << 8) | reg_val_lo;
		/* Read twice to clear */
		adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
		adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);
		keymask |= (reg_val_hi << 8) | reg_val_lo;
		adp5520_keys_report_event(dev, keymask, 0);
	}

	return 0;
}

static int adp5520_keys_probe(struct platform_device *pdev)
{
	struct adp5520_keys_platform_data *pdata = dev_get_platdata(&pdev->dev);
	struct input_dev *input;
	struct adp5520_keys *dev;
	int ret, i;
	unsigned char en_mask, ctl_mask = 0;

	if (pdev->id != ID_ADP5520) {
		dev_err(&pdev->dev, "only ADP5520 supports Keypad\n");
		return -EINVAL;
	}

	if (!pdata) {
		dev_err(&pdev->dev, "missing platform data\n");
		return -EINVAL;
	}

	if (!(pdata->rows_en_mask && pdata->cols_en_mask))
		return -EINVAL;

	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
	if (!dev) {
		dev_err(&pdev->dev, "failed to alloc memory\n");
		return -ENOMEM;
	}

	input = devm_input_allocate_device(&pdev->dev);
	if (!input)
		return -ENOMEM;

	dev->master = pdev->dev.parent;
	dev->input = input;

	input->name = pdev->name;

Annotation

Implementation Notes