drivers/input/touchscreen/sx8654.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/touchscreen/sx8654.c
Extension
.c
Size
11769 bytes
Lines
474
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 sx865x_data {
	u8 cmd_manual;
	u8 chan_mask;
	bool has_irq_penrelease;
	bool has_reg_irqmask;
	irq_handler_t irqh;
};

struct sx8654 {
	struct input_dev *input;
	struct i2c_client *client;
	struct gpio_desc *gpio_reset;

	spinlock_t lock;	/* for input reporting from irq/timer */
	struct timer_list timer;

	struct touchscreen_properties props;

	const struct sx865x_data *data;
};

static inline void sx865x_penrelease(struct sx8654 *ts)
{
	struct input_dev *input_dev = ts->input;

	input_report_key(input_dev, BTN_TOUCH, 0);
	input_sync(input_dev);
}

static void sx865x_penrelease_timer_handler(struct timer_list *t)
{
	struct sx8654 *ts = timer_container_of(ts, t, timer);

	dev_dbg(&ts->client->dev, "penrelease by timer\n");

	guard(spinlock_irqsave)(&ts->lock);
	sx865x_penrelease(ts);
}

static irqreturn_t sx8650_irq(int irq, void *handle)
{
	struct sx8654 *ts = handle;
	struct device *dev = &ts->client->dev;
	int len, i;
	u8 stat;
	u16 x, y;
	u16 ch;
	u16 chdata;
	__be16 data[MAX_I2C_READ_LEN / sizeof(__be16)];
	u8 nchan = hweight32(ts->data->chan_mask);
	u8 readlen = nchan * sizeof(*data);

	stat = i2c_smbus_read_byte_data(ts->client, CMD_READ_REGISTER
						    | I2C_REG_SX8650_STAT);

	if (!(stat & SX8650_STAT_CONVIRQ)) {
		dev_dbg(dev, "%s ignore stat [0x%02x]", __func__, stat);
		return IRQ_HANDLED;
	}

	len = i2c_master_recv(ts->client, (u8 *)data, readlen);
	if (len != readlen) {
		dev_dbg(dev, "ignore short recv (%d)\n", len);
		return IRQ_HANDLED;
	}

	guard(spinlock_irqsave)(&ts->lock);

	x = 0;
	y = 0;
	for (i = 0; i < nchan; i++) {
		chdata = be16_to_cpu(data[i]);

		if (unlikely(chdata == 0xFFFF)) {
			dev_dbg(dev, "invalid qualified data @ %d\n", i);
			continue;
		} else if (unlikely(chdata & 0x8000)) {
			dev_warn(dev, "hibit @ %d [0x%04x]\n", i, chdata);
			continue;
		}

		ch = chdata >> 12;
		if (ch == CH_X)
			x = chdata & MAX_12BIT;
		else if (ch == CH_Y)
			y = chdata & MAX_12BIT;
		else
			dev_warn(dev, "unknown channel %d [0x%04x]\n", ch,
				 chdata);
	}

Annotation

Implementation Notes