diff mbox series

[5/5] Input: zinitix - Support calibration

Message ID 20220410120059.2583849-5-linus.walleij@linaro.org (mailing list archive)
State Under Review
Headers show
Series [1/5] Input: zinitix - Helper dev variable in probe() | expand

Commit Message

Linus Walleij April 10, 2022, noon UTC
Support both hardware and software calibration on the Zinitix
touchscreens. This is lifted from the vendor driver but rewritten
to use the chip revision number in the hardware instead of
compile-time defines.

Use defines for the new "calibration mode" and add a new define
for the default touchpoint mode.

The registers for reading the EEPROM status actually differs
between BT5x2 and BT4x3+ so create very unique defines for
those registers and use a register variable in the state to
keep track of the right one to use.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/input/touchscreen/zinitix.c | 138 ++++++++++++++++++++++++++--
 1 file changed, 132 insertions(+), 6 deletions(-)

Comments

Dmitry Torokhov May 27, 2022, 5:48 a.m. UTC | #1
On Sun, Apr 10, 2022 at 02:00:59PM +0200, Linus Walleij wrote:
>  
> +	val = zinitix_get_u16_reg(bt541, bt541->eeprom_info_reg);
> +	if (val & ZINITIX_EEPROM_HW_CALIB) {
> +		error = zinitix_calibrate(bt541);
> +		if (error)
> +			return error;
> +	}
> +

My understanding that calibration might take pretty long time. Are you
sure you want it to happen automatically when opening the device? Or
maybe userspace needs to control this?

Thanks.
diff mbox series

Patch

diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index ea807b972f26..440ffc7c9b32 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -34,6 +34,8 @@ 
 #define ZINITIX_DEBUG_REG			0x0115 /* 0~7 */
 
 #define ZINITIX_TOUCH_MODE			0x0010
+#define ZINITIX_MODE_TOUCH_POINT		0x02
+#define ZINITIX_MODE_CALIBRATION		0x07
 #define ZINITIX_CHIP_REVISION			0x0011
 #define ZINITIX_CHIP_BT404			0x4040
 #define ZINITIX_CHIP_BT532			0x5320
@@ -49,7 +51,11 @@ 
 
 #define ZINITIX_DATA_VERSION_REG		0x0013
 #define ZINITIX_SUPPORTED_FINGER_NUM		0x0015
-#define ZINITIX_EEPROM_INFO			0x0018
+
+#define BT4X2_EEPROM_INFO			0x0014
+#define BT4X3_EEPROM_INFO			0x0018
+#define ZINITIX_EEPROM_HW_CALIB			BIT(0)
+
 #define ZINITIX_INITIAL_TOUCH_MODE		0x0019
 
 #define ZINITIX_TOTAL_NUMBER_OF_X		0x0060
@@ -57,6 +63,8 @@ 
 
 #define ZINITIX_DELAY_RAW_FOR_HOST		0x007f
 
+#define BT4X2_EEPROM_INFO_REG			0x00aa
+
 #define ZINITIX_BUTTON_SUPPORTED_NUM		0x00B0
 #define ZINITIX_BUTTON_SENSITIVITY		0x00B2
 #define ZINITIX_DUMMY_BUTTON_SENSITIVITY	0X00C8
@@ -75,8 +83,6 @@ 
 
 #define ZINITIX_RAWDATA_REG			0x0200
 
-#define ZINITIX_EEPROM_INFO_REG			0x0018
-
 #define ZINITIX_INT_ENABLE_FLAG			0x00f0
 #define ZINITIX_PERIODICAL_INTERRUPT_INTERVAL	0x00f1
 
@@ -120,7 +126,6 @@ 
 #define SUB_BIT_UPDATE				BIT(4)
 #define SUB_BIT_WAIT				BIT(5)
 
-#define DEFAULT_TOUCH_POINT_MODE		2
 #define MAX_SUPPORTED_FINGER_NUM		5
 
 #define CHIP_ON_DELAY				15 // ms
@@ -153,8 +158,33 @@  struct bt541_ts_data {
 	u16 chip_revision;
 	u16 firmware_version;
 	u16 regdata_version;
+	u16 eeprom_info_reg;
 };
 
+static bool zinitix_is_4x2(struct bt541_ts_data *bt541)
+{
+	u16 ver;
+
+	/* The revision is the high nybbles so shift down */
+	ver = bt541->chip_revision >> 4;
+	/* Skip middle digit */
+	ver &= 0xf0f;
+
+	return (ver == 0x402);
+}
+
+static bool zinitix_is_4x3_and_above(struct bt541_ts_data *bt541)
+{
+	u16 ver;
+
+	/* The revision is the high nybbles so shift down */
+	ver = bt541->chip_revision >> 4;
+	/* Skip middle digit */
+	ver &= 0xf0f;
+
+	return (ver >= 0x403);
+}
+
 static int zinitix_read_data(struct i2c_client *client,
 			     u16 reg, void *values, size_t length)
 {
@@ -209,12 +239,92 @@  static u16 zinitix_get_u16_reg(struct bt541_ts_data *bt541, u16 vreg)
         return le16_to_cpu(val);
 }
 
+static int zinitix_calibrate(struct bt541_ts_data *bt541)
+{
+	struct i2c_client *client = bt541->client;
+	int maxsec = 10;
+	int error;
+	u16 val;
+
+	dev_info(bt541->dev, "HW calibration - calibrating\n");
+
+	error = zinitix_write_u16(client, ZINITIX_TOUCH_MODE,
+				  ZINITIX_MODE_CALIBRATION);
+	if (error)
+		return error;
+	error = zinitix_write_cmd(client, ZINITIX_CALIBRATE_CMD);
+	if (error)
+		return error;
+	error = zinitix_write_cmd(client, ZINITIX_SWRESET_CMD);
+	if (error)
+		return error;
+	msleep(1);
+	error = zinitix_write_cmd(client, ZINITIX_CLEAR_INT_STATUS_CMD);
+	if (error)
+		return error;
+
+	/* Wait for hardware calibration to commence */
+	do {
+		msleep(1000);
+		val = zinitix_get_u16_reg(bt541, bt541->eeprom_info_reg);
+		maxsec --;
+	} while ((val & ZINITIX_EEPROM_HW_CALIB) && maxsec);
+
+	if (!maxsec) {
+		dev_err(bt541->dev, "timeout waiting for HW calibration\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Get out of calibration mode */
+	error = zinitix_write_u16(client, ZINITIX_TOUCH_MODE,
+				  bt541->zinitix_mode);
+	if (error)
+		return error;
+
+	error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, 0x0);
+	if (error)
+		return error;
+
+	msleep(10);
+
+	error = zinitix_write_cmd(client, ZINITIX_SWRESET_CMD);
+	if (error)
+		return error;
+
+	if (zinitix_is_4x3_and_above(bt541)) {
+		error = zinitix_write_cmd(client, ZINITIX_SAVE_CALIBRATION_CMD);
+		if (error)
+			return error;
+		msleep(500);
+	}
+
+	if (zinitix_is_4x2(bt541)) {
+		error = zinitix_write_cmd(client, ZINITIX_SAVE_STATUS_CMD);
+		if (error)
+			return error;
+		/* Wait for fusing EEPROM */
+		msleep(1000);
+		error = zinitix_write_cmd(client, ZINITIX_SWRESET_CMD);
+		if (error)
+			return error;
+	}
+
+	error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, 0x0);
+	if (error)
+		return error;
+
+	dev_info(bt541->dev, "HW calibration complete\n");
+
+	return 0;
+}
+
 static int zinitix_init_touch(struct bt541_ts_data *bt541)
 {
 	struct i2c_client *client = bt541->client;
 	int i;
 	int error;
 	static bool read_static = false;
+	u16 val;
 
 	error = zinitix_write_cmd(client, ZINITIX_SWRESET_CMD);
 	if (error) {
@@ -237,9 +347,20 @@  static int zinitix_init_touch(struct bt541_ts_data *bt541)
 			 "chip revision %04x firmware version %04x regdata version %04x\n",
 			 bt541->chip_revision, bt541->firmware_version,
 			 bt541->regdata_version);
+		if (zinitix_is_4x2(bt541))
+			bt541->eeprom_info_reg = BT4X2_EEPROM_INFO_REG;
+		else
+			bt541->eeprom_info_reg = BT4X3_EEPROM_INFO;
 		read_static = true;
 	}
 
+	val = zinitix_get_u16_reg(bt541, bt541->eeprom_info_reg);
+	if (val & ZINITIX_EEPROM_HW_CALIB) {
+		error = zinitix_calibrate(bt541);
+		if (error)
+			return error;
+	}
+
 	error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, 0x0);
 	if (error) {
 		dev_err(bt541->dev,
@@ -273,6 +394,11 @@  static int zinitix_init_touch(struct bt541_ts_data *bt541)
 	if (error)
 		return error;
 
+	/* Software calibration */
+	error = zinitix_write_cmd(client, ZINITIX_CALIBRATE_CMD);
+	if (error)
+		return error;
+
 	error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG,
 				  BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE |
 					BIT_UP);
@@ -584,10 +710,10 @@  static int zinitix_ts_probe(struct i2c_client *client)
 					 &bt541->zinitix_mode);
 	if (error < 0) {
 		/* fall back to mode 2 */
-		bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
+		bt541->zinitix_mode = ZINITIX_MODE_TOUCH_POINT;
 	}
 
-	if (bt541->zinitix_mode != 2) {
+	if (bt541->zinitix_mode != ZINITIX_MODE_TOUCH_POINT) {
 		/*
 		 * If there are devices that don't support mode 2, support
 		 * for other modes (0, 1) will be needed.