drivers/input/touchscreen/wm831x-ts.c

Source file repositories/reference/linux-study-clean/drivers/input/touchscreen/wm831x-ts.c

File Facts

System
Linux kernel
Corpus path
drivers/input/touchscreen/wm831x-ts.c
Extension
.c
Size
11380 bytes
Lines
399
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 wm831x_ts {
	struct input_dev *input_dev;
	struct wm831x *wm831x;
	unsigned int data_irq;
	unsigned int pd_irq;
	bool pressure;
	bool pen_down;
	struct work_struct pd_data_work;
};

static void wm831x_pd_data_work(struct work_struct *work)
{
	struct wm831x_ts *wm831x_ts =
		container_of(work, struct wm831x_ts, pd_data_work);

	if (wm831x_ts->pen_down) {
		enable_irq(wm831x_ts->data_irq);
		dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n");
	} else {
		enable_irq(wm831x_ts->pd_irq);
		dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n");
	}
}

static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
{
	struct wm831x_ts *wm831x_ts = irq_data;
	struct wm831x *wm831x = wm831x_ts->wm831x;
	static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE };
	u16 data[3];
	int count;
	int i, ret;

	if (wm831x_ts->pressure)
		count = 3;
	else
		count = 2;

	wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
			WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT);

	ret = wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count,
			       data);
	if (ret != 0) {
		dev_err(wm831x->dev, "Failed to read touch data: %d\n",
			ret);
		return IRQ_NONE;
	}

	/*
	 * We get a pen down reading on every reading, report pen up if any
	 * individual reading does so.
	 */
	wm831x_ts->pen_down = true;
	for (i = 0; i < count; i++) {
		if (!(data[i] & WM831X_TCH_PD)) {
			wm831x_ts->pen_down = false;
			continue;
		}
		input_report_abs(wm831x_ts->input_dev, data_types[i],
				 data[i] & WM831X_TCH_DATA_MASK);
	}

	if (!wm831x_ts->pen_down) {
		/* Switch from data to pen down */
		dev_dbg(wm831x->dev, "IRQ DATA->PD\n");

		disable_irq_nosync(wm831x_ts->data_irq);

		/* Don't need data any more */
		wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
				WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
				WM831X_TCH_Z_ENA, 0);

		/* Flush any final samples that arrived while reading */
		wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
				WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT);

		wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, data);

		if (wm831x_ts->pressure)
			input_report_abs(wm831x_ts->input_dev,
					 ABS_PRESSURE, 0);

		input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0);

		schedule_work(&wm831x_ts->pd_data_work);
	} else {
		input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
	}

Annotation

Implementation Notes