drivers/input/keyboard/sun4i-lradc-keys.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/sun4i-lradc-keys.c
Extension
.c
Size
9490 bytes
Lines
361
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 lradc_variant {
	u8 divisor_numerator;
	u8 divisor_denominator;
	bool has_clock_reset;
};

static const struct lradc_variant lradc_variant_a10 = {
	.divisor_numerator = 2,
	.divisor_denominator = 3
};

static const struct lradc_variant r_lradc_variant_a83t = {
	.divisor_numerator = 3,
	.divisor_denominator = 4
};

static const struct lradc_variant lradc_variant_r329 = {
	.divisor_numerator = 3,
	.divisor_denominator = 4,
	.has_clock_reset = true,
};

struct sun4i_lradc_keymap {
	u32 voltage;
	u32 keycode;
};

struct sun4i_lradc_data {
	struct device *dev;
	struct input_dev *input;
	void __iomem *base;
	struct clk *clk;
	struct reset_control *reset;
	struct regulator *vref_supply;
	struct sun4i_lradc_keymap *chan0_map;
	const struct lradc_variant *variant;
	u32 chan0_map_count;
	u32 chan0_keycode;
	u32 vref;
};

static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id)
{
	struct sun4i_lradc_data *lradc = dev_id;
	u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff;

	ints  = readl(lradc->base + LRADC_INTS);

	/*
	 * lradc supports only one keypress at a time, release does not give
	 * any info as to which key was released, so we cache the keycode.
	 */

	if (ints & CHAN0_KEYUP_IRQ) {
		input_report_key(lradc->input, lradc->chan0_keycode, 0);
		lradc->chan0_keycode = 0;
	}

	if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) {
		val = readl(lradc->base + LRADC_DATA0) & 0x3f;
		voltage = val * lradc->vref / 63;

		for (i = 0; i < lradc->chan0_map_count; i++) {
			diff = abs(lradc->chan0_map[i].voltage - voltage);
			if (diff < closest) {
				closest = diff;
				keycode = lradc->chan0_map[i].keycode;
			}
		}

		lradc->chan0_keycode = keycode;
		input_report_key(lradc->input, lradc->chan0_keycode, 1);
	}

	input_sync(lradc->input);

	writel(ints, lradc->base + LRADC_INTS);

	return IRQ_HANDLED;
}

static int sun4i_lradc_open(struct input_dev *dev)
{
	struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
	int error;

	error = regulator_enable(lradc->vref_supply);
	if (error)
		return error;

Annotation

Implementation Notes