drivers/input/keyboard/lpc32xx-keys.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/lpc32xx-keys.c
Extension
.c
Size
8396 bytes
Lines
321
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 lpc32xx_kscan_drv {
	struct input_dev *input;
	struct clk *clk;
	void __iomem *kscan_base;

	u32 matrix_sz;		/* Size of matrix in XxY, ie. 3 = 3x3 */
	u32 deb_clks;		/* Debounce clocks (based on 32KHz clock) */
	u32 scan_delay;		/* Scan delay (based on 32KHz clock) */

	unsigned int row_shift;
	unsigned short *keymap;	/* Pointer to key map for the scan matrix */

	u8 lastkeystates[8];
};

static void lpc32xx_mod_states(struct lpc32xx_kscan_drv *kscandat, int col)
{
	struct input_dev *input = kscandat->input;
	unsigned row, changed, scancode, keycode;
	u8 key;

	key = readl(LPC32XX_KS_DATA(kscandat->kscan_base, col));
	changed = key ^ kscandat->lastkeystates[col];
	kscandat->lastkeystates[col] = key;

	for (row = 0; changed; row++, changed >>= 1) {
		if (changed & 1) {
			/* Key state changed, signal an event */
			scancode = MATRIX_SCAN_CODE(row, col,
						    kscandat->row_shift);
			keycode = kscandat->keymap[scancode];
			input_event(input, EV_MSC, MSC_SCAN, scancode);
			input_report_key(input, keycode, key & (1 << row));
		}
	}
}

static irqreturn_t lpc32xx_kscan_irq(int irq, void *dev_id)
{
	struct lpc32xx_kscan_drv *kscandat = dev_id;
	int i;

	for (i = 0; i < kscandat->matrix_sz; i++)
		lpc32xx_mod_states(kscandat, i);

	writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base));

	input_sync(kscandat->input);

	return IRQ_HANDLED;
}

static int lpc32xx_kscan_open(struct input_dev *dev)
{
	struct lpc32xx_kscan_drv *kscandat = input_get_drvdata(dev);
	int error;

	error = clk_prepare_enable(kscandat->clk);
	if (error)
		return error;

	writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base));

	return 0;
}

static void lpc32xx_kscan_close(struct input_dev *dev)
{
	struct lpc32xx_kscan_drv *kscandat = input_get_drvdata(dev);

	writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base));
	clk_disable_unprepare(kscandat->clk);
}

static int lpc32xx_parse_dt(struct device *dev,
				      struct lpc32xx_kscan_drv *kscandat)
{
	struct device_node *np = dev->of_node;
	u32 rows = 0, columns = 0;
	int err;

	err = matrix_keypad_parse_properties(dev, &rows, &columns);
	if (err)
		return err;
	if (rows != columns) {
		dev_err(dev, "rows and columns must be equal!\n");
		return -EINVAL;
	}

	kscandat->matrix_sz = rows;

Annotation

Implementation Notes