drivers/input/keyboard/pmic8xxx-keypad.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/pmic8xxx-keypad.c
Extension
.c
Size
16932 bytes
Lines
684
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 pmic8xxx_kp {
	unsigned int num_rows;
	unsigned int num_cols;
	struct input_dev *input;
	struct regmap *regmap;
	int key_sense_irq;
	int key_stuck_irq;

	unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE];

	struct device *dev;
	u16 keystate[PM8XXX_MAX_ROWS];
	u16 stuckstate[PM8XXX_MAX_ROWS];

	u8 ctrl_reg;
};

static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
{
	/* all keys pressed on that particular row? */
	if (col == 0x00)
		return 1 << kp->num_cols;
	else
		return col & ((1 << kp->num_cols) - 1);
}

/*
 * Synchronous read protocol for RevB0 onwards:
 *
 * 1. Write '1' to ReadState bit in KEYP_SCAN register
 * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
 *    synchronously
 * 3. Read rows in old array first if events are more than one
 * 4. Read rows in recent array
 * 5. Wait 4*32KHz clocks
 * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
 *    synchronously exit read mode.
 */
static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
{
	int rc;
	unsigned int scan_val;

	rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val);
	if (rc < 0) {
		dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
		return rc;
	}

	scan_val |= 0x1;

	rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val);
	if (rc < 0) {
		dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
		return rc;
	}

	/* 2 * 32KHz clocks */
	udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);

	return rc;
}

static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
					u16 data_reg, int read_rows)
{
	int rc, row;
	unsigned int val;

	for (row = 0; row < read_rows; row++) {
		rc = regmap_read(kp->regmap, data_reg, &val);
		if (rc)
			return rc;
		dev_dbg(kp->dev, "%d = %d\n", row, val);
		state[row] = pmic8xxx_col_state(kp, val);
	}

	return 0;
}

static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
					 u16 *old_state)
{
	int rc, read_rows;
	unsigned int scan_val;

	if (kp->num_rows < PM8XXX_MIN_ROWS)
		read_rows = PM8XXX_MIN_ROWS;
	else
		read_rows = kp->num_rows;

Annotation

Implementation Notes