drivers/input/touchscreen/lpc32xx_ts.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/touchscreen/lpc32xx_ts.c
Extension
.c
Size
8826 bytes
Lines
342
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_tsc {
	struct input_dev *dev;
	void __iomem *tsc_base;
	int irq;
	struct clk *clk;
};

static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
{
	while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
			LPC32XX_TSC_STAT_FIFO_EMPTY))
		tsc_readl(tsc, LPC32XX_TSC_FIFO);
}

static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
{
	u32 tmp, rv[4], xs[4], ys[4];
	int idx;
	struct lpc32xx_tsc *tsc = dev_id;
	struct input_dev *input = tsc->dev;

	tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);

	if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
		/* FIFO overflow - throw away samples */
		lpc32xx_fifo_clear(tsc);
		return IRQ_HANDLED;
	}

	/*
	 * Gather and normalize 4 samples. Pen-up events may have less
	 * than 4 samples, but its ok to pop 4 and let the last sample
	 * pen status check drop the samples.
	 */
	idx = 0;
	while (idx < 4 &&
	       !(tsc_readl(tsc, LPC32XX_TSC_STAT) &
			LPC32XX_TSC_STAT_FIFO_EMPTY)) {
		tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
		xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
			LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
		ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
			LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
		rv[idx] = tmp;
		idx++;
	}

	/* Data is only valid if pen is still down in last sample */
	if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
		/* Use average of 2nd and 3rd sample for position */
		input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
		input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
		input_report_key(input, BTN_TOUCH, 1);
	} else {
		input_report_key(input, BTN_TOUCH, 0);
	}

	input_sync(input);

	return IRQ_HANDLED;
}

static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
{
	/* Disable auto mode */
	tsc_writel(tsc, LPC32XX_TSC_CON,
		   tsc_readl(tsc, LPC32XX_TSC_CON) &
			     ~LPC32XX_TSC_ADCCON_AUTO_EN);

	clk_disable_unprepare(tsc->clk);
}

static int lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
{
	u32 tmp;
	int err;

	err = clk_prepare_enable(tsc->clk);
	if (err)
		return err;

	tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;

	/* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
	tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
	      LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
	      LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
	tsc_writel(tsc, LPC32XX_TSC_CON, tmp);

	/* These values are all preset */

Annotation

Implementation Notes