drivers/input/keyboard/max7360-keypad.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/max7360-keypad.c
Extension
.c
Size
8890 bytes
Lines
309
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 max7360_keypad {
	struct input_dev *input;
	unsigned int rows;
	unsigned int cols;
	unsigned int debounce_ms;
	int irq;
	struct regmap *regmap;
	unsigned short keycodes[MAX7360_MAX_KEY_ROWS * MAX7360_MAX_KEY_COLS];
};

static irqreturn_t max7360_keypad_irq(int irq, void *data)
{
	struct max7360_keypad *max7360_keypad = data;
	struct device *dev = max7360_keypad->input->dev.parent;
	unsigned int val;
	unsigned int row, col;
	unsigned int release;
	unsigned int code;
	int error;

	error = regmap_read(max7360_keypad->regmap, MAX7360_REG_KEYFIFO, &val);
	if (error) {
		dev_err(dev, "Failed to read MAX7360 FIFO");
		return IRQ_NONE;
	}

	/* FIFO overflow: ignore it and get next event. */
	if (val == MAX7360_FIFO_OVERFLOW) {
		dev_warn(dev, "max7360 FIFO overflow");
		error = regmap_read_poll_timeout(max7360_keypad->regmap, MAX7360_REG_KEYFIFO,
						 val, val != MAX7360_FIFO_OVERFLOW, 0, 1000);
		if (error) {
			dev_err(dev, "Failed to empty MAX7360 FIFO");
			return IRQ_NONE;
		}
	}

	if (val == MAX7360_FIFO_EMPTY) {
		dev_dbg(dev, "Got a spurious interrupt");

		return IRQ_NONE;
	}

	row = FIELD_GET(MAX7360_FIFO_ROW, val);
	col = FIELD_GET(MAX7360_FIFO_COL, val);
	release = val & MAX7360_FIFO_RELEASE;

	code = MATRIX_SCAN_CODE(row, col, get_count_order(max7360_keypad->cols));

	dev_dbg(dev, "key[%d:%d] %s\n", row, col, release ? "release" : "press");

	input_event(max7360_keypad->input, EV_MSC, MSC_SCAN, code);
	input_report_key(max7360_keypad->input, max7360_keypad->keycodes[code], !release);
	input_sync(max7360_keypad->input);

	return IRQ_HANDLED;
}

static int max7360_keypad_open(struct input_dev *pdev)
{
	struct max7360_keypad *max7360_keypad = input_get_drvdata(pdev);
	struct device *dev = max7360_keypad->input->dev.parent;
	int error;

	/* Somebody is using the device: get out of sleep. */
	error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_CONFIG,
				  MAX7360_CFG_SLEEP, MAX7360_CFG_SLEEP);
	if (error)
		dev_err(dev, "Failed to write max7360 configuration: %d\n", error);

	return error;
}

static void max7360_keypad_close(struct input_dev *pdev)
{
	struct max7360_keypad *max7360_keypad = input_get_drvdata(pdev);
	struct device *dev = max7360_keypad->input->dev.parent;
	int error;

	/* Nobody is using the device anymore: go to sleep. */
	error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_CONFIG, MAX7360_CFG_SLEEP, 0);
	if (error)
		dev_err(dev, "Failed to write max7360 configuration: %d\n", error);
}

static int max7360_keypad_hw_init(struct max7360_keypad *max7360_keypad)
{
	struct device *dev = max7360_keypad->input->dev.parent;
	unsigned int val;
	int error;

Annotation

Implementation Notes