diff options
Diffstat (limited to 'drivers/input/touchscreen/goodix.c')
-rw-r--r-- | drivers/input/touchscreen/goodix.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index e03ecaf7b822..7e318938b723 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -72,6 +72,7 @@ struct goodix_chip_data { u16 config_addr; int config_len; int (*check_config)(struct goodix_ts_data *, const struct firmware *); + void (*calc_config_checksum)(struct goodix_ts_data *ts); }; struct goodix_ts_data { @@ -96,35 +97,42 @@ struct goodix_ts_data { unsigned long irq_flags; enum goodix_irq_pin_access_method irq_pin_access_method; unsigned int contact_size; + u8 config[GOODIX_CONFIG_MAX_LENGTH]; }; static int goodix_check_cfg_8(struct goodix_ts_data *ts, const struct firmware *cfg); static int goodix_check_cfg_16(struct goodix_ts_data *ts, const struct firmware *cfg); +static void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts); +static void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts); static const struct goodix_chip_data gt1x_chip_data = { .config_addr = GOODIX_GT1X_REG_CONFIG_DATA, .config_len = GOODIX_CONFIG_MAX_LENGTH, .check_config = goodix_check_cfg_16, + .calc_config_checksum = goodix_calc_cfg_checksum_16, }; static const struct goodix_chip_data gt911_chip_data = { .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, .config_len = GOODIX_CONFIG_911_LENGTH, .check_config = goodix_check_cfg_8, + .calc_config_checksum = goodix_calc_cfg_checksum_8, }; static const struct goodix_chip_data gt967_chip_data = { .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, .config_len = GOODIX_CONFIG_967_LENGTH, .check_config = goodix_check_cfg_8, + .calc_config_checksum = goodix_calc_cfg_checksum_8, }; static const struct goodix_chip_data gt9x_chip_data = { .config_addr = GOODIX_GT9X_REG_CONFIG_DATA, .config_len = GOODIX_CONFIG_MAX_LENGTH, .check_config = goodix_check_cfg_8, + .calc_config_checksum = goodix_calc_cfg_checksum_8, }; static const unsigned long goodix_irq_flags[] = { @@ -458,6 +466,19 @@ static int goodix_check_cfg_8(struct goodix_ts_data *ts, return 0; } +static void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts) +{ + int i, raw_cfg_len = ts->chip->config_len - 2; + u8 check_sum = 0; + + for (i = 0; i < raw_cfg_len; i++) + check_sum += ts->config[i]; + check_sum = (~check_sum) + 1; + + ts->config[raw_cfg_len] = check_sum; + ts->config[raw_cfg_len + 1] = 1; /* Set "config_fresh" bit */ +} + static int goodix_check_cfg_16(struct goodix_ts_data *ts, const struct firmware *cfg) { @@ -482,6 +503,19 @@ static int goodix_check_cfg_16(struct goodix_ts_data *ts, return 0; } +static void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts) +{ + int i, raw_cfg_len = ts->chip->config_len - 3; + u16 check_sum = 0; + + for (i = 0; i < raw_cfg_len; i += 2) + check_sum += get_unaligned_be16(&ts->config[i]); + check_sum = (~check_sum) + 1; + + put_unaligned_be16(check_sum, &ts->config[raw_cfg_len]); + ts->config[raw_cfg_len + 2] = 1; /* Set "config_fresh" bit */ +} + /** * goodix_check_cfg - Checks if config fw is valid * @@ -859,12 +893,11 @@ retry_get_irq_gpio: */ static void goodix_read_config(struct goodix_ts_data *ts) { - u8 config[GOODIX_CONFIG_MAX_LENGTH]; int x_max, y_max; int error; error = goodix_i2c_read(ts->client, ts->chip->config_addr, - config, ts->chip->config_len); + ts->config, ts->chip->config_len); if (error) { dev_warn(&ts->client->dev, "Error reading config: %d\n", error); @@ -873,15 +906,17 @@ static void goodix_read_config(struct goodix_ts_data *ts) return; } - ts->int_trigger_type = config[TRIGGER_LOC] & 0x03; - ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f; + ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03; + ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f; - x_max = get_unaligned_le16(&config[RESOLUTION_LOC]); - y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]); + x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]); + y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]); if (x_max && y_max) { input_abs_set_max(ts->input_dev, ABS_MT_POSITION_X, x_max - 1); input_abs_set_max(ts->input_dev, ABS_MT_POSITION_Y, y_max - 1); } + + ts->chip->calc_config_checksum(ts); } /** |