// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Hynitron cstxxx Touchscreen * * Copyright (c) 2022 Chris Morgan <macromorgan@hotmail.com> * * This code is based on hynitron_core.c authored by Hynitron. * Note that no datasheet was available, so much of these registers * are undocumented. This is essentially a cleaned-up version of the * vendor driver with support removed for hardware I cannot test and * device-specific functions replated with generic functions wherever * possible.
*/
/* Per chip data */ struct hynitron_ts_chip_data { unsignedint max_touch_num;
u32 ic_chkcode; int (*firmware_info)(struct i2c_client *client); int (*bootloader_enter)(struct i2c_client *client); int (*init_input)(struct i2c_client *client); void (*report_touch)(struct i2c_client *client);
};
/* Data generic to all (supported and non-supported) controllers. */ struct hynitron_ts_data { conststruct hynitron_ts_chip_data *chip; struct i2c_client *client; struct input_dev *input_dev; struct touchscreen_properties prop; struct gpio_desc *reset_gpio;
};
/* * Since I have no datasheet, these values are guessed and/or assumed * based on observation and testing.
*/ #define CST3XX_FIRMWARE_INFO_START_CMD 0x01d1 #define CST3XX_FIRMWARE_INFO_END_CMD 0x09d1 #define CST3XX_FIRMWARE_CHK_CODE_REG 0xfcd1 #define CST3XX_FIRMWARE_VERSION_REG 0x08d2 #define CST3XX_FIRMWARE_VER_INVALID_VAL 0xa5a5a5a5
/* * Hard coded reset delay value of 20ms not IC dependent in * vendor driver.
*/ staticvoid hyn_reset_proc(struct i2c_client *client, int delay)
{ struct hynitron_ts_data *ts_data = i2c_get_clientdata(client);
/* * Tests suggest this command needed to read firmware regs.
*/
put_unaligned_le16(CST3XX_FIRMWARE_INFO_START_CMD, buf);
err = cst3xx_i2c_write(client, buf, 2); if (err) return err;
usleep_range(10000, 11000);
/* * Read register for check-code to determine if device detected * correctly.
*/
err = cst3xx_i2c_read_register(client, CST3XX_FIRMWARE_CHK_CODE_REG,
buf, 4); if (err) return err;
tmp = get_unaligned_le32(buf); if ((tmp & 0xffff0000) != ts_data->chip->ic_chkcode) {
dev_err(&client->dev, "%s ic mismatch, chkcode is %u\n",
__func__, tmp); return -ENODEV;
}
usleep_range(10000, 11000);
/* Read firmware version and test if firmware missing. */
err = cst3xx_i2c_read_register(client, CST3XX_FIRMWARE_VERSION_REG,
buf, 4); if (err) return err;
/* * Handle events from IRQ. Note that for cst3xx it appears that IRQ * fires continuously while touched, otherwise once every 1500ms * when not touched (assume touchscreen waking up periodically). * Note buffer is sized for 5 fingers, if more needed buffer must * be increased. The buffer contains 5 bytes for each touch point, * a touch count byte, a check byte, and then a second check byte after * all other touch points. * * For example 1 touch would look like this: * touch1[5]:touch_count[1]:chk_byte[1] * * 3 touches would look like this: * touch1[5]:touch_count[1]:chk_byte[1]:touch2[5]:touch3[5]:chk_byte[1]
*/ staticvoid cst3xx_touch_report(struct i2c_client *client)
{ struct hynitron_ts_data *ts_data = i2c_get_clientdata(client);
u8 buf[28];
u8 finger_id, sw, w; unsignedint x, y; unsignedint touch_cnt, end_byte; unsignedint idx = 0; unsignedint i; int err;
/* Read and validate the first bits of input data. */
err = cst3xx_i2c_read_register(client, CST3XX_TOUCH_DATA_PART_REG,
buf, 28); if (err ||
buf[6] != CST3XX_TOUCH_DATA_CHK_VAL ||
buf[0] == CST3XX_TOUCH_DATA_CHK_VAL) {
dev_err(&client->dev, "cst3xx touch read failure\n"); return;
}
/* Report to the device we're done reading the touch data. */
err = cst3xx_finish_touch_read(client); if (err) return;
touch_cnt = buf[5] & CST3XX_TOUCH_COUNT_MASK; /* * Check the check bit of the last touch slot. The check bit is * always present after touch point 1 for valid data, and then * appears as the last byte after all other touch data.
*/ if (touch_cnt > 1) {
end_byte = touch_cnt * 5 + 2; if (buf[end_byte] != CST3XX_TOUCH_DATA_CHK_VAL) {
dev_err(&client->dev, "cst3xx touch read failure\n"); return;
}
}
/* Parse through the buffer to capture touch data. */ for (i = 0; i < touch_cnt; i++) {
x = ((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0f));
y = ((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0f));
w = (buf[idx + 4] >> 3);
sw = (buf[idx] & 0x0f) >> 1;
finger_id = (buf[idx] >> 4) & 0x0f;
/* Sanity check we don't have more fingers than we expect */ if (ts_data->chip->max_touch_num < finger_id) {
dev_err(&client->dev, "cst3xx touch read failure\n"); break;
}
/* sw value of 0 means no touch, 0x03 means touch */ if (sw == CST3XX_TOUCH_DATA_TOUCH_VAL)
cst3xx_report_contact(ts_data, finger_id, x, y, w);
idx += 5;
/* Skip the 2 bytes between point 1 and point 2 */ if (i == 0)
idx += 2;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.