drivers/input/touchscreen/bu21013_ts.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/touchscreen/bu21013_ts.c
Extension
.c
Size
16188 bytes
Lines
620
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 bu21013_ts {
	struct i2c_client *client;
	struct input_dev *in_dev;
	struct touchscreen_properties props;
	struct regulator *regulator;
	struct gpio_desc *cs_gpiod;
	struct gpio_desc *int_gpiod;
	u32 touch_x_max;
	u32 touch_y_max;
	bool x_flip;
	bool y_flip;
	bool touch_stopped;
};

static int bu21013_read_block_data(struct bu21013_ts *ts, u8 *buf)
{
	int ret, i;

	for (i = 0; i < I2C_RETRY_COUNT; i++) {
		ret = i2c_smbus_read_i2c_block_data(ts->client,
						    BU21013_SENSORS_BTN_0_7_REG,
						    LENGTH_OF_BUFFER, buf);
		if (ret == LENGTH_OF_BUFFER)
			return 0;
	}

	return -EINVAL;
}

static int bu21013_do_touch_report(struct bu21013_ts *ts)
{
	struct input_dev *input = ts->in_dev;
	struct input_mt_pos pos[MAX_FINGERS];
	int slots[MAX_FINGERS];
	u8 buf[LENGTH_OF_BUFFER];
	bool has_x_sensors, has_y_sensors;
	int finger_down_count = 0;
	int i;

	if (bu21013_read_block_data(ts, buf) < 0)
		return -EINVAL;

	has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
	has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
		((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
	if (!has_x_sensors || !has_y_sensors)
		return 0;

	for (i = 0; i < MAX_FINGERS; i++) {
		const u8 *data = &buf[4 * i + 3];
		unsigned int x, y;

		x = data[0] << SHIFT_2 | (data[1] & MASK_BITS);
		y = data[2] << SHIFT_2 | (data[3] & MASK_BITS);
		if (x != 0 && y != 0)
			touchscreen_set_mt_pos(&pos[finger_down_count++],
					       &ts->props, x, y);
	}

	if (finger_down_count == 2 &&
	    (abs(pos[0].x - pos[1].x) < DELTA_MIN ||
	     abs(pos[0].y - pos[1].y) < DELTA_MIN)) {
		return 0;
	}

	input_mt_assign_slots(input, slots, pos, finger_down_count, DELTA_MIN);
	for (i = 0; i < finger_down_count; i++) {
		input_mt_slot(input, slots[i]);
		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
		input_report_abs(input, ABS_MT_POSITION_X, pos[i].x);
		input_report_abs(input, ABS_MT_POSITION_Y, pos[i].y);
	}

	input_mt_sync_frame(input);
	input_sync(input);

	return 0;
}

static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
{
	struct bu21013_ts *ts = device_data;
	int keep_polling;
	int error;

	do {
		error = bu21013_do_touch_report(ts);
		if (error) {
			dev_err(&ts->client->dev, "%s failed\n", __func__);
			break;

Annotation

Implementation Notes