18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010
48c2ecf20Sopenharmony_ci * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/bitops.h>
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/input.h>
128c2ecf20Sopenharmony_ci#include <linux/input/mt.h>
138c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/property.h>
188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/types.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define MAX_FINGERS	2
238c2ecf20Sopenharmony_ci#define RESET_DELAY	30
248c2ecf20Sopenharmony_ci#define PENUP_TIMEOUT	(10)
258c2ecf20Sopenharmony_ci#define DELTA_MIN	16
268c2ecf20Sopenharmony_ci#define MASK_BITS	0x03
278c2ecf20Sopenharmony_ci#define SHIFT_8		8
288c2ecf20Sopenharmony_ci#define SHIFT_2		2
298c2ecf20Sopenharmony_ci#define LENGTH_OF_BUFFER	11
308c2ecf20Sopenharmony_ci#define I2C_RETRY_COUNT	5
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define BU21013_SENSORS_BTN_0_7_REG	0x70
338c2ecf20Sopenharmony_ci#define BU21013_SENSORS_BTN_8_15_REG	0x71
348c2ecf20Sopenharmony_ci#define BU21013_SENSORS_BTN_16_23_REG	0x72
358c2ecf20Sopenharmony_ci#define BU21013_X1_POS_MSB_REG		0x73
368c2ecf20Sopenharmony_ci#define BU21013_X1_POS_LSB_REG		0x74
378c2ecf20Sopenharmony_ci#define BU21013_Y1_POS_MSB_REG		0x75
388c2ecf20Sopenharmony_ci#define BU21013_Y1_POS_LSB_REG		0x76
398c2ecf20Sopenharmony_ci#define BU21013_X2_POS_MSB_REG		0x77
408c2ecf20Sopenharmony_ci#define BU21013_X2_POS_LSB_REG		0x78
418c2ecf20Sopenharmony_ci#define BU21013_Y2_POS_MSB_REG		0x79
428c2ecf20Sopenharmony_ci#define BU21013_Y2_POS_LSB_REG		0x7A
438c2ecf20Sopenharmony_ci#define BU21013_INT_CLR_REG		0xE8
448c2ecf20Sopenharmony_ci#define BU21013_INT_MODE_REG		0xE9
458c2ecf20Sopenharmony_ci#define BU21013_GAIN_REG		0xEA
468c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_REG		0xEB
478c2ecf20Sopenharmony_ci#define BU21013_XY_EDGE_REG		0xEC
488c2ecf20Sopenharmony_ci#define BU21013_RESET_REG		0xED
498c2ecf20Sopenharmony_ci#define BU21013_CALIB_REG		0xEE
508c2ecf20Sopenharmony_ci#define BU21013_DONE_REG		0xEF
518c2ecf20Sopenharmony_ci#define BU21013_SENSOR_0_7_REG		0xF0
528c2ecf20Sopenharmony_ci#define BU21013_SENSOR_8_15_REG		0xF1
538c2ecf20Sopenharmony_ci#define BU21013_SENSOR_16_23_REG	0xF2
548c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_REG		0xF3
558c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_REG		0xF4
568c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_REG		0xF5
578c2ecf20Sopenharmony_ci#define BU21013_IDLE_REG		0xFA
588c2ecf20Sopenharmony_ci#define BU21013_FILTER_REG		0xFB
598c2ecf20Sopenharmony_ci#define BU21013_TH_ON_REG		0xFC
608c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_REG		0xFD
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define BU21013_RESET_ENABLE		0x01
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define BU21013_SENSORS_EN_0_7		0x3F
668c2ecf20Sopenharmony_ci#define BU21013_SENSORS_EN_8_15		0xFC
678c2ecf20Sopenharmony_ci#define BU21013_SENSORS_EN_16_23	0x1F
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_0		0x02
708c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_1		0x04
718c2ecf20Sopenharmony_ci#define BU21013_POS_MODE1_2		0x08
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_ZERO		0x01
748c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_AVG1		0x02
758c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_AVG2		0x04
768c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_EN_XY		0x08
778c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_EN_RAW	0x10
788c2ecf20Sopenharmony_ci#define BU21013_POS_MODE2_MULTI		0x80
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_DIV		0x01
818c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_EXT		0x02
828c2ecf20Sopenharmony_ci#define BU21013_CLK_MODE_CALIB		0x80
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define BU21013_IDLET_0			0x01
858c2ecf20Sopenharmony_ci#define BU21013_IDLET_1			0x02
868c2ecf20Sopenharmony_ci#define BU21013_IDLET_2			0x04
878c2ecf20Sopenharmony_ci#define BU21013_IDLET_3			0x08
888c2ecf20Sopenharmony_ci#define BU21013_IDLE_INTERMIT_EN	0x10
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define BU21013_DELTA_0_6	0x7F
918c2ecf20Sopenharmony_ci#define BU21013_FILTER_EN	0x80
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define BU21013_INT_MODE_LEVEL	0x00
948c2ecf20Sopenharmony_ci#define BU21013_INT_MODE_EDGE	0x01
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define BU21013_GAIN_0		0x01
978c2ecf20Sopenharmony_ci#define BU21013_GAIN_1		0x02
988c2ecf20Sopenharmony_ci#define BU21013_GAIN_2		0x04
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_DEFAULT	0x00
1018c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_MOVE	0x01
1028c2ecf20Sopenharmony_ci#define BU21013_OFFSET_MODE_DISABLE	0x02
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define BU21013_TH_ON_0		0x01
1058c2ecf20Sopenharmony_ci#define BU21013_TH_ON_1		0x02
1068c2ecf20Sopenharmony_ci#define BU21013_TH_ON_2		0x04
1078c2ecf20Sopenharmony_ci#define BU21013_TH_ON_3		0x08
1088c2ecf20Sopenharmony_ci#define BU21013_TH_ON_4		0x10
1098c2ecf20Sopenharmony_ci#define BU21013_TH_ON_5		0x20
1108c2ecf20Sopenharmony_ci#define BU21013_TH_ON_6		0x40
1118c2ecf20Sopenharmony_ci#define BU21013_TH_ON_7		0x80
1128c2ecf20Sopenharmony_ci#define BU21013_TH_ON_MAX	0xFF
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_0	0x01
1158c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_1	0x02
1168c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_2	0x04
1178c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_3	0x08
1188c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_4	0x10
1198c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_5	0x20
1208c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_6	0x40
1218c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_7	0x80
1228c2ecf20Sopenharmony_ci#define BU21013_TH_OFF_MAX	0xFF
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_0	0x01
1258c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_1	0x02
1268c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_2	0x04
1278c2ecf20Sopenharmony_ci#define BU21013_X_EDGE_3	0x08
1288c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_0	0x10
1298c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_1	0x20
1308c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_2	0x40
1318c2ecf20Sopenharmony_ci#define BU21013_Y_EDGE_3	0x80
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#define BU21013_DONE	0x01
1348c2ecf20Sopenharmony_ci#define BU21013_NUMBER_OF_X_SENSORS	(6)
1358c2ecf20Sopenharmony_ci#define BU21013_NUMBER_OF_Y_SENSORS	(11)
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define DRIVER_TP	"bu21013_tp"
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/**
1408c2ecf20Sopenharmony_ci * struct bu21013_ts - touch panel data structure
1418c2ecf20Sopenharmony_ci * @client: pointer to the i2c client
1428c2ecf20Sopenharmony_ci * @in_dev: pointer to the input device structure
1438c2ecf20Sopenharmony_ci * @props: the device coordinate transformation properties
1448c2ecf20Sopenharmony_ci * @regulator: pointer to the Regulator used for touch screen
1458c2ecf20Sopenharmony_ci * @cs_gpiod: chip select GPIO line
1468c2ecf20Sopenharmony_ci * @int_gpiod: touch interrupt GPIO line
1478c2ecf20Sopenharmony_ci * @touch_x_max: maximum X coordinate reported by the device
1488c2ecf20Sopenharmony_ci * @touch_y_max: maximum Y coordinate reported by the device
1498c2ecf20Sopenharmony_ci * @x_flip: indicates that the driver should invert X coordinate before
1508c2ecf20Sopenharmony_ci *	reporting
1518c2ecf20Sopenharmony_ci * @y_flip: indicates that the driver should invert Y coordinate before
1528c2ecf20Sopenharmony_ci *	reporting
1538c2ecf20Sopenharmony_ci * @touch_stopped: touch stop flag
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * Touch panel device data structure
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cistruct bu21013_ts {
1588c2ecf20Sopenharmony_ci	struct i2c_client *client;
1598c2ecf20Sopenharmony_ci	struct input_dev *in_dev;
1608c2ecf20Sopenharmony_ci	struct touchscreen_properties props;
1618c2ecf20Sopenharmony_ci	struct regulator *regulator;
1628c2ecf20Sopenharmony_ci	struct gpio_desc *cs_gpiod;
1638c2ecf20Sopenharmony_ci	struct gpio_desc *int_gpiod;
1648c2ecf20Sopenharmony_ci	u32 touch_x_max;
1658c2ecf20Sopenharmony_ci	u32 touch_y_max;
1668c2ecf20Sopenharmony_ci	bool x_flip;
1678c2ecf20Sopenharmony_ci	bool y_flip;
1688c2ecf20Sopenharmony_ci	bool touch_stopped;
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic int bu21013_read_block_data(struct bu21013_ts *ts, u8 *buf)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	int ret, i;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	for (i = 0; i < I2C_RETRY_COUNT; i++) {
1768c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_i2c_block_data(ts->client,
1778c2ecf20Sopenharmony_ci						    BU21013_SENSORS_BTN_0_7_REG,
1788c2ecf20Sopenharmony_ci						    LENGTH_OF_BUFFER, buf);
1798c2ecf20Sopenharmony_ci		if (ret == LENGTH_OF_BUFFER)
1808c2ecf20Sopenharmony_ci			return 0;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	return -EINVAL;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int bu21013_do_touch_report(struct bu21013_ts *ts)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct input_dev *input = ts->in_dev;
1898c2ecf20Sopenharmony_ci	struct input_mt_pos pos[MAX_FINGERS];
1908c2ecf20Sopenharmony_ci	int slots[MAX_FINGERS];
1918c2ecf20Sopenharmony_ci	u8 buf[LENGTH_OF_BUFFER];
1928c2ecf20Sopenharmony_ci	bool has_x_sensors, has_y_sensors;
1938c2ecf20Sopenharmony_ci	int finger_down_count = 0;
1948c2ecf20Sopenharmony_ci	int i;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (bu21013_read_block_data(ts, buf) < 0)
1978c2ecf20Sopenharmony_ci		return -EINVAL;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
2008c2ecf20Sopenharmony_ci	has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
2018c2ecf20Sopenharmony_ci		((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
2028c2ecf20Sopenharmony_ci	if (!has_x_sensors || !has_y_sensors)
2038c2ecf20Sopenharmony_ci		return 0;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_FINGERS; i++) {
2068c2ecf20Sopenharmony_ci		const u8 *data = &buf[4 * i + 3];
2078c2ecf20Sopenharmony_ci		unsigned int x, y;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		x = data[0] << SHIFT_2 | (data[1] & MASK_BITS);
2108c2ecf20Sopenharmony_ci		y = data[2] << SHIFT_2 | (data[3] & MASK_BITS);
2118c2ecf20Sopenharmony_ci		if (x != 0 && y != 0)
2128c2ecf20Sopenharmony_ci			touchscreen_set_mt_pos(&pos[finger_down_count++],
2138c2ecf20Sopenharmony_ci					       &ts->props, x, y);
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (finger_down_count == 2 &&
2178c2ecf20Sopenharmony_ci	    (abs(pos[0].x - pos[1].x) < DELTA_MIN ||
2188c2ecf20Sopenharmony_ci	     abs(pos[0].y - pos[1].y) < DELTA_MIN)) {
2198c2ecf20Sopenharmony_ci		return 0;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	input_mt_assign_slots(input, slots, pos, finger_down_count, DELTA_MIN);
2238c2ecf20Sopenharmony_ci	for (i = 0; i < finger_down_count; i++) {
2248c2ecf20Sopenharmony_ci		input_mt_slot(input, slots[i]);
2258c2ecf20Sopenharmony_ci		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
2268c2ecf20Sopenharmony_ci		input_report_abs(input, ABS_MT_POSITION_X, pos[i].x);
2278c2ecf20Sopenharmony_ci		input_report_abs(input, ABS_MT_POSITION_Y, pos[i].y);
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	input_mt_sync_frame(input);
2318c2ecf20Sopenharmony_ci	input_sync(input);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return 0;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct bu21013_ts *ts = device_data;
2398c2ecf20Sopenharmony_ci	int keep_polling;
2408c2ecf20Sopenharmony_ci	int error;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	do {
2438c2ecf20Sopenharmony_ci		error = bu21013_do_touch_report(ts);
2448c2ecf20Sopenharmony_ci		if (error) {
2458c2ecf20Sopenharmony_ci			dev_err(&ts->client->dev, "%s failed\n", __func__);
2468c2ecf20Sopenharmony_ci			break;
2478c2ecf20Sopenharmony_ci		}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		if (unlikely(ts->touch_stopped))
2508c2ecf20Sopenharmony_ci			break;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		keep_polling = ts->int_gpiod ?
2538c2ecf20Sopenharmony_ci			gpiod_get_value(ts->int_gpiod) : false;
2548c2ecf20Sopenharmony_ci		if (keep_polling)
2558c2ecf20Sopenharmony_ci			usleep_range(2000, 2500);
2568c2ecf20Sopenharmony_ci	} while (keep_polling);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic int bu21013_init_chip(struct bu21013_ts *ts)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct i2c_client *client = ts->client;
2648c2ecf20Sopenharmony_ci	int error;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_RESET_REG,
2678c2ecf20Sopenharmony_ci					  BU21013_RESET_ENABLE);
2688c2ecf20Sopenharmony_ci	if (error) {
2698c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_RESET reg write failed\n");
2708c2ecf20Sopenharmony_ci		return error;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci	msleep(RESET_DELAY);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_0_7_REG,
2758c2ecf20Sopenharmony_ci					  BU21013_SENSORS_EN_0_7);
2768c2ecf20Sopenharmony_ci	if (error) {
2778c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_SENSOR_0_7 reg write failed\n");
2788c2ecf20Sopenharmony_ci		return error;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_8_15_REG,
2828c2ecf20Sopenharmony_ci					  BU21013_SENSORS_EN_8_15);
2838c2ecf20Sopenharmony_ci	if (error) {
2848c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_SENSOR_8_15 reg write failed\n");
2858c2ecf20Sopenharmony_ci		return error;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_SENSOR_16_23_REG,
2898c2ecf20Sopenharmony_ci					  BU21013_SENSORS_EN_16_23);
2908c2ecf20Sopenharmony_ci	if (error) {
2918c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_SENSOR_16_23 reg write failed\n");
2928c2ecf20Sopenharmony_ci		return error;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE1_REG,
2968c2ecf20Sopenharmony_ci					  BU21013_POS_MODE1_0 |
2978c2ecf20Sopenharmony_ci						BU21013_POS_MODE1_1);
2988c2ecf20Sopenharmony_ci	if (error) {
2998c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_POS_MODE1 reg write failed\n");
3008c2ecf20Sopenharmony_ci		return error;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_POS_MODE2_REG,
3048c2ecf20Sopenharmony_ci					  BU21013_POS_MODE2_ZERO |
3058c2ecf20Sopenharmony_ci						BU21013_POS_MODE2_AVG1 |
3068c2ecf20Sopenharmony_ci						BU21013_POS_MODE2_AVG2 |
3078c2ecf20Sopenharmony_ci						BU21013_POS_MODE2_EN_RAW |
3088c2ecf20Sopenharmony_ci						BU21013_POS_MODE2_MULTI);
3098c2ecf20Sopenharmony_ci	if (error) {
3108c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_POS_MODE2 reg write failed\n");
3118c2ecf20Sopenharmony_ci		return error;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_CLK_MODE_REG,
3158c2ecf20Sopenharmony_ci					  BU21013_CLK_MODE_DIV |
3168c2ecf20Sopenharmony_ci						BU21013_CLK_MODE_CALIB);
3178c2ecf20Sopenharmony_ci	if (error) {
3188c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_CLK_MODE reg write failed\n");
3198c2ecf20Sopenharmony_ci		return error;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_IDLE_REG,
3238c2ecf20Sopenharmony_ci					  BU21013_IDLET_0 |
3248c2ecf20Sopenharmony_ci						BU21013_IDLE_INTERMIT_EN);
3258c2ecf20Sopenharmony_ci	if (error) {
3268c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_IDLE reg write failed\n");
3278c2ecf20Sopenharmony_ci		return error;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_INT_MODE_REG,
3318c2ecf20Sopenharmony_ci					  BU21013_INT_MODE_LEVEL);
3328c2ecf20Sopenharmony_ci	if (error) {
3338c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_INT_MODE reg write failed\n");
3348c2ecf20Sopenharmony_ci		return error;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_FILTER_REG,
3388c2ecf20Sopenharmony_ci					  BU21013_DELTA_0_6 |
3398c2ecf20Sopenharmony_ci						BU21013_FILTER_EN);
3408c2ecf20Sopenharmony_ci	if (error) {
3418c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_FILTER reg write failed\n");
3428c2ecf20Sopenharmony_ci		return error;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_TH_ON_REG,
3468c2ecf20Sopenharmony_ci					  BU21013_TH_ON_5);
3478c2ecf20Sopenharmony_ci	if (error) {
3488c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_TH_ON reg write failed\n");
3498c2ecf20Sopenharmony_ci		return error;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_TH_OFF_REG,
3538c2ecf20Sopenharmony_ci					  BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
3548c2ecf20Sopenharmony_ci	if (error) {
3558c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_TH_OFF reg write failed\n");
3568c2ecf20Sopenharmony_ci		return error;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_GAIN_REG,
3608c2ecf20Sopenharmony_ci					  BU21013_GAIN_0 | BU21013_GAIN_1);
3618c2ecf20Sopenharmony_ci	if (error) {
3628c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_GAIN reg write failed\n");
3638c2ecf20Sopenharmony_ci		return error;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_OFFSET_MODE_REG,
3678c2ecf20Sopenharmony_ci					  BU21013_OFFSET_MODE_DEFAULT);
3688c2ecf20Sopenharmony_ci	if (error) {
3698c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_OFFSET_MODE reg write failed\n");
3708c2ecf20Sopenharmony_ci		return error;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_XY_EDGE_REG,
3748c2ecf20Sopenharmony_ci					  BU21013_X_EDGE_0 |
3758c2ecf20Sopenharmony_ci						BU21013_X_EDGE_2 |
3768c2ecf20Sopenharmony_ci						BU21013_Y_EDGE_1 |
3778c2ecf20Sopenharmony_ci						BU21013_Y_EDGE_3);
3788c2ecf20Sopenharmony_ci	if (error) {
3798c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_XY_EDGE reg write failed\n");
3808c2ecf20Sopenharmony_ci		return error;
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	error = i2c_smbus_write_byte_data(client, BU21013_DONE_REG,
3848c2ecf20Sopenharmony_ci					  BU21013_DONE);
3858c2ecf20Sopenharmony_ci	if (error) {
3868c2ecf20Sopenharmony_ci		dev_err(&client->dev, "BU21013_REG_DONE reg write failed\n");
3878c2ecf20Sopenharmony_ci		return error;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return 0;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic void bu21013_power_off(void *_ts)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	struct bu21013_ts *ts = _ts;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	regulator_disable(ts->regulator);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic void bu21013_disable_chip(void *_ts)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct bu21013_ts *ts = _ts;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	gpiod_set_value(ts->cs_gpiod, 0);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic int bu21013_probe(struct i2c_client *client,
4088c2ecf20Sopenharmony_ci			 const struct i2c_device_id *id)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct bu21013_ts *ts;
4118c2ecf20Sopenharmony_ci	struct input_dev *in_dev;
4128c2ecf20Sopenharmony_ci	struct input_absinfo *info;
4138c2ecf20Sopenharmony_ci	u32 max_x = 0, max_y = 0;
4148c2ecf20Sopenharmony_ci	int error;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
4178c2ecf20Sopenharmony_ci				     I2C_FUNC_SMBUS_BYTE_DATA)) {
4188c2ecf20Sopenharmony_ci		dev_err(&client->dev, "i2c smbus byte data not supported\n");
4198c2ecf20Sopenharmony_ci		return -EIO;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (!client->irq) {
4238c2ecf20Sopenharmony_ci		dev_err(&client->dev, "No IRQ set up\n");
4248c2ecf20Sopenharmony_ci		return -EINVAL;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
4288c2ecf20Sopenharmony_ci	if (!ts)
4298c2ecf20Sopenharmony_ci		return -ENOMEM;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	ts->client = client;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x");
4348c2ecf20Sopenharmony_ci	ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y");
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	in_dev = devm_input_allocate_device(&client->dev);
4378c2ecf20Sopenharmony_ci	if (!in_dev) {
4388c2ecf20Sopenharmony_ci		dev_err(&client->dev, "device memory alloc failed\n");
4398c2ecf20Sopenharmony_ci		return -ENOMEM;
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci	ts->in_dev = in_dev;
4428c2ecf20Sopenharmony_ci	input_set_drvdata(in_dev, ts);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* register the device to input subsystem */
4458c2ecf20Sopenharmony_ci	in_dev->name = DRIVER_TP;
4468c2ecf20Sopenharmony_ci	in_dev->id.bustype = BUS_I2C;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x);
4498c2ecf20Sopenharmony_ci	device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0);
4528c2ecf20Sopenharmony_ci	input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	touchscreen_parse_properties(in_dev, true, &ts->props);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* Adjust for the legacy "flip" properties, if present */
4578c2ecf20Sopenharmony_ci	if (!ts->props.invert_x &&
4588c2ecf20Sopenharmony_ci	    device_property_read_bool(&client->dev, "rohm,flip-x")) {
4598c2ecf20Sopenharmony_ci		info = &in_dev->absinfo[ABS_MT_POSITION_X];
4608c2ecf20Sopenharmony_ci		info->maximum -= info->minimum;
4618c2ecf20Sopenharmony_ci		info->minimum = 0;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (!ts->props.invert_y &&
4658c2ecf20Sopenharmony_ci	    device_property_read_bool(&client->dev, "rohm,flip-y")) {
4668c2ecf20Sopenharmony_ci		info = &in_dev->absinfo[ABS_MT_POSITION_Y];
4678c2ecf20Sopenharmony_ci		info->maximum -= info->minimum;
4688c2ecf20Sopenharmony_ci		info->minimum = 0;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	error = input_mt_init_slots(in_dev, MAX_FINGERS,
4728c2ecf20Sopenharmony_ci				    INPUT_MT_DIRECT | INPUT_MT_TRACK |
4738c2ecf20Sopenharmony_ci					INPUT_MT_DROP_UNUSED);
4748c2ecf20Sopenharmony_ci	if (error) {
4758c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed to initialize MT slots");
4768c2ecf20Sopenharmony_ci		return error;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	ts->regulator = devm_regulator_get(&client->dev, "avdd");
4808c2ecf20Sopenharmony_ci	if (IS_ERR(ts->regulator)) {
4818c2ecf20Sopenharmony_ci		dev_err(&client->dev, "regulator_get failed\n");
4828c2ecf20Sopenharmony_ci		return PTR_ERR(ts->regulator);
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	error = regulator_enable(ts->regulator);
4868c2ecf20Sopenharmony_ci	if (error) {
4878c2ecf20Sopenharmony_ci		dev_err(&client->dev, "regulator enable failed\n");
4888c2ecf20Sopenharmony_ci		return error;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts);
4928c2ecf20Sopenharmony_ci	if (error) {
4938c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed to install power off handler\n");
4948c2ecf20Sopenharmony_ci		return error;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/* Named "CS" on the chip, DT binding is "reset" */
4988c2ecf20Sopenharmony_ci	ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
4998c2ecf20Sopenharmony_ci	error = PTR_ERR_OR_ZERO(ts->cs_gpiod);
5008c2ecf20Sopenharmony_ci	if (error) {
5018c2ecf20Sopenharmony_ci		if (error != -EPROBE_DEFER)
5028c2ecf20Sopenharmony_ci			dev_err(&client->dev, "failed to get CS GPIO\n");
5038c2ecf20Sopenharmony_ci		return error;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci	gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS");
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	error = devm_add_action_or_reset(&client->dev,
5088c2ecf20Sopenharmony_ci					 bu21013_disable_chip, ts);
5098c2ecf20Sopenharmony_ci	if (error) {
5108c2ecf20Sopenharmony_ci		dev_err(&client->dev,
5118c2ecf20Sopenharmony_ci			"failed to install chip disable handler\n");
5128c2ecf20Sopenharmony_ci		return error;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* Named "INT" on the chip, DT binding is "touch" */
5168c2ecf20Sopenharmony_ci	ts->int_gpiod = devm_gpiod_get_optional(&client->dev,
5178c2ecf20Sopenharmony_ci						"touch", GPIOD_IN);
5188c2ecf20Sopenharmony_ci	error = PTR_ERR_OR_ZERO(ts->int_gpiod);
5198c2ecf20Sopenharmony_ci	if (error) {
5208c2ecf20Sopenharmony_ci		if (error != -EPROBE_DEFER)
5218c2ecf20Sopenharmony_ci			dev_err(&client->dev, "failed to get INT GPIO\n");
5228c2ecf20Sopenharmony_ci		return error;
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (ts->int_gpiod)
5268c2ecf20Sopenharmony_ci		gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT");
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/* configure the touch panel controller */
5298c2ecf20Sopenharmony_ci	error = bu21013_init_chip(ts);
5308c2ecf20Sopenharmony_ci	if (error) {
5318c2ecf20Sopenharmony_ci		dev_err(&client->dev, "error in bu21013 config\n");
5328c2ecf20Sopenharmony_ci		return error;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	error = devm_request_threaded_irq(&client->dev, client->irq,
5368c2ecf20Sopenharmony_ci					  NULL, bu21013_gpio_irq,
5378c2ecf20Sopenharmony_ci					  IRQF_ONESHOT, DRIVER_TP, ts);
5388c2ecf20Sopenharmony_ci	if (error) {
5398c2ecf20Sopenharmony_ci		dev_err(&client->dev, "request irq %d failed\n",
5408c2ecf20Sopenharmony_ci			client->irq);
5418c2ecf20Sopenharmony_ci		return error;
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	error = input_register_device(in_dev);
5458c2ecf20Sopenharmony_ci	if (error) {
5468c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed to register input device\n");
5478c2ecf20Sopenharmony_ci		return error;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, ts);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return 0;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cistatic int bu21013_remove(struct i2c_client *client)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	struct bu21013_ts *ts = i2c_get_clientdata(client);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* Make sure IRQ will exit quickly even if there is contact */
5608c2ecf20Sopenharmony_ci	ts->touch_stopped = true;
5618c2ecf20Sopenharmony_ci	/* The resources will be freed by devm */
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	return 0;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic int __maybe_unused bu21013_suspend(struct device *dev)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
5698c2ecf20Sopenharmony_ci	struct bu21013_ts *ts = i2c_get_clientdata(client);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	ts->touch_stopped = true;
5728c2ecf20Sopenharmony_ci	mb();
5738c2ecf20Sopenharmony_ci	disable_irq(client->irq);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	if (!device_may_wakeup(&client->dev))
5768c2ecf20Sopenharmony_ci		regulator_disable(ts->regulator);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	return 0;
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic int __maybe_unused bu21013_resume(struct device *dev)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
5848c2ecf20Sopenharmony_ci	struct bu21013_ts *ts = i2c_get_clientdata(client);
5858c2ecf20Sopenharmony_ci	int error;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	if (!device_may_wakeup(&client->dev)) {
5888c2ecf20Sopenharmony_ci		error = regulator_enable(ts->regulator);
5898c2ecf20Sopenharmony_ci		if (error) {
5908c2ecf20Sopenharmony_ci			dev_err(&client->dev,
5918c2ecf20Sopenharmony_ci				"failed to re-enable regulator when resuming\n");
5928c2ecf20Sopenharmony_ci			return error;
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		error = bu21013_init_chip(ts);
5968c2ecf20Sopenharmony_ci		if (error) {
5978c2ecf20Sopenharmony_ci			dev_err(&client->dev,
5988c2ecf20Sopenharmony_ci				"failed to reinitialize chip when resuming\n");
5998c2ecf20Sopenharmony_ci			return error;
6008c2ecf20Sopenharmony_ci		}
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	ts->touch_stopped = false;
6048c2ecf20Sopenharmony_ci	mb();
6058c2ecf20Sopenharmony_ci	enable_irq(client->irq);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	return 0;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic const struct i2c_device_id bu21013_id[] = {
6138c2ecf20Sopenharmony_ci	{ DRIVER_TP, 0 },
6148c2ecf20Sopenharmony_ci	{ }
6158c2ecf20Sopenharmony_ci};
6168c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bu21013_id);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic struct i2c_driver bu21013_driver = {
6198c2ecf20Sopenharmony_ci	.driver	= {
6208c2ecf20Sopenharmony_ci		.name	=	DRIVER_TP,
6218c2ecf20Sopenharmony_ci		.pm	=	&bu21013_dev_pm_ops,
6228c2ecf20Sopenharmony_ci	},
6238c2ecf20Sopenharmony_ci	.probe		=	bu21013_probe,
6248c2ecf20Sopenharmony_ci	.remove		=	bu21013_remove,
6258c2ecf20Sopenharmony_ci	.id_table	=	bu21013_id,
6268c2ecf20Sopenharmony_ci};
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cimodule_i2c_driver(bu21013_driver);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
6318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
6328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("bu21013 touch screen controller driver");
633