0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/device.h>
0013 #include <linux/firmware.h>
0014 #include <linux/i2c.h>
0015 #include "goodix.h"
0016
0017 #define GOODIX_FW_HEADER_LENGTH sizeof(struct goodix_fw_header)
0018 #define GOODIX_FW_SECTION_LENGTH 0x2000
0019 #define GOODIX_FW_DSP_LENGTH 0x1000
0020 #define GOODIX_FW_UPLOAD_ADDRESS 0xc000
0021
0022 #define GOODIX_CFG_LOC_HAVE_KEY 7
0023 #define GOODIX_CFG_LOC_DRVA_NUM 27
0024 #define GOODIX_CFG_LOC_DRVB_NUM 28
0025 #define GOODIX_CFG_LOC_SENS_NUM 29
0026
0027 struct goodix_fw_header {
0028 u8 hw_info[4];
0029 u8 pid[8];
0030 u8 vid[2];
0031 } __packed;
0032
0033 static u16 goodix_firmware_checksum(const u8 *data, int size)
0034 {
0035 u16 checksum = 0;
0036 int i;
0037
0038 for (i = 0; i < size; i += 2)
0039 checksum += (data[i] << 8) + data[i + 1];
0040
0041 return checksum;
0042 }
0043
0044 static int goodix_firmware_verify(struct device *dev, const struct firmware *fw)
0045 {
0046 const struct goodix_fw_header *fw_header;
0047 size_t expected_size;
0048 const u8 *data;
0049 u16 checksum;
0050 char buf[9];
0051
0052 expected_size = GOODIX_FW_HEADER_LENGTH + 4 * GOODIX_FW_SECTION_LENGTH +
0053 GOODIX_FW_DSP_LENGTH;
0054 if (fw->size != expected_size) {
0055 dev_err(dev, "Firmware has wrong size, expected %zu got %zu\n",
0056 expected_size, fw->size);
0057 return -EINVAL;
0058 }
0059
0060 data = fw->data + GOODIX_FW_HEADER_LENGTH;
0061 checksum = goodix_firmware_checksum(data, 4 * GOODIX_FW_SECTION_LENGTH);
0062 if (checksum) {
0063 dev_err(dev, "Main firmware checksum error\n");
0064 return -EINVAL;
0065 }
0066
0067 data += 4 * GOODIX_FW_SECTION_LENGTH;
0068 checksum = goodix_firmware_checksum(data, GOODIX_FW_DSP_LENGTH);
0069 if (checksum) {
0070 dev_err(dev, "DSP firmware checksum error\n");
0071 return -EINVAL;
0072 }
0073
0074 fw_header = (const struct goodix_fw_header *)fw->data;
0075 dev_info(dev, "Firmware hardware info %02x%02x%02x%02x\n",
0076 fw_header->hw_info[0], fw_header->hw_info[1],
0077 fw_header->hw_info[2], fw_header->hw_info[3]);
0078
0079 memcpy(buf, fw_header->pid, 8);
0080 buf[8] = 0;
0081 dev_info(dev, "Firmware PID: %s VID: %02x%02x\n", buf,
0082 fw_header->vid[0], fw_header->vid[1]);
0083 return 0;
0084 }
0085
0086 static int goodix_enter_upload_mode(struct i2c_client *client)
0087 {
0088 int tries, error;
0089 u8 val;
0090
0091 tries = 200;
0092 do {
0093 error = goodix_i2c_write_u8(client,
0094 GOODIX_REG_MISCTL_SWRST, 0x0c);
0095 if (error)
0096 return error;
0097
0098 error = goodix_i2c_read(client,
0099 GOODIX_REG_MISCTL_SWRST, &val, 1);
0100 if (error)
0101 return error;
0102
0103 if (val == 0x0c)
0104 break;
0105 } while (--tries);
0106
0107 if (!tries) {
0108 dev_err(&client->dev, "Error could not hold ss51 & dsp\n");
0109 return -EIO;
0110 }
0111
0112
0113 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_DSP_CTL, 0x00);
0114 if (error)
0115 return error;
0116
0117
0118 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_TMR0_EN, 0x00);
0119 if (error)
0120 return error;
0121
0122
0123 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_CACHE_EN, 0x00);
0124 if (error)
0125 return error;
0126
0127
0128 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x02);
0129 if (error)
0130 return error;
0131
0132
0133 error = goodix_i2c_write_u8(client,
0134 GOODIX_REG_MISCTL_CPU_SWRST_PULSE, 0x01);
0135 if (error)
0136 return error;
0137
0138
0139 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x00);
0140 if (error)
0141 return error;
0142
0143
0144 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOT_OPT, 0x00);
0145 if (error)
0146 return error;
0147
0148
0149 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_MEM_CD_EN, 0x01);
0150 if (error)
0151 return error;
0152
0153 return 0;
0154 }
0155
0156 static int goodix_start_firmware(struct i2c_client *client)
0157 {
0158 int error;
0159 u8 val;
0160
0161
0162 error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa);
0163 if (error)
0164 return error;
0165
0166
0167 error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_SWRST, 0x00);
0168 if (error)
0169 return error;
0170
0171 error = goodix_i2c_read(client, GOODIX_REG_SW_WDT, &val, 1);
0172 if (error)
0173 return error;
0174
0175
0176 if (val == 0xaa) {
0177 dev_err(&client->dev, "Error SW_WDT reg not cleared on fw startup\n");
0178 return -EIO;
0179 }
0180
0181
0182 error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa);
0183 if (error)
0184 return error;
0185
0186 return 0;
0187 }
0188
0189 static int goodix_firmware_upload(struct goodix_ts_data *ts)
0190 {
0191 const struct firmware *fw;
0192 char fw_name[64];
0193 const u8 *data;
0194 int error;
0195
0196 snprintf(fw_name, sizeof(fw_name), "goodix/%s", ts->firmware_name);
0197
0198 error = request_firmware(&fw, fw_name, &ts->client->dev);
0199 if (error) {
0200 dev_err(&ts->client->dev, "Firmware request error %d\n", error);
0201 return error;
0202 }
0203
0204 error = goodix_firmware_verify(&ts->client->dev, fw);
0205 if (error)
0206 goto release;
0207
0208 error = goodix_reset_no_int_sync(ts);
0209 if (error)
0210 goto release;
0211
0212 error = goodix_enter_upload_mode(ts->client);
0213 if (error)
0214 goto release;
0215
0216
0217 error = goodix_i2c_write_u8(ts->client,
0218 GOODIX_REG_MISCTL_SRAM_BANK, 0x00);
0219 if (error)
0220 goto release;
0221
0222 data = fw->data + GOODIX_FW_HEADER_LENGTH;
0223 error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
0224 data, 2 * GOODIX_FW_SECTION_LENGTH);
0225 if (error)
0226 goto release;
0227
0228
0229 error = goodix_i2c_write_u8(ts->client,
0230 GOODIX_REG_MISCTL_SRAM_BANK, 0x01);
0231 if (error)
0232 goto release;
0233
0234 data += 2 * GOODIX_FW_SECTION_LENGTH;
0235 error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
0236 data, 2 * GOODIX_FW_SECTION_LENGTH);
0237 if (error)
0238 goto release;
0239
0240
0241 error = goodix_i2c_write_u8(ts->client,
0242 GOODIX_REG_MISCTL_SRAM_BANK, 0x02);
0243 if (error)
0244 goto release;
0245
0246 data += 2 * GOODIX_FW_SECTION_LENGTH;
0247 error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
0248 data, GOODIX_FW_DSP_LENGTH);
0249 if (error)
0250 goto release;
0251
0252 error = goodix_start_firmware(ts->client);
0253 if (error)
0254 goto release;
0255
0256 error = goodix_int_sync(ts);
0257 release:
0258 release_firmware(fw);
0259 return error;
0260 }
0261
0262 static int goodix_prepare_bak_ref(struct goodix_ts_data *ts)
0263 {
0264 u8 have_key, driver_num, sensor_num;
0265
0266 if (ts->bak_ref)
0267 return 0;
0268
0269 have_key = (ts->config[GOODIX_CFG_LOC_HAVE_KEY] & 0x01);
0270
0271 driver_num = (ts->config[GOODIX_CFG_LOC_DRVA_NUM] & 0x1f) +
0272 (ts->config[GOODIX_CFG_LOC_DRVB_NUM] & 0x1f);
0273 if (have_key)
0274 driver_num--;
0275
0276 sensor_num = (ts->config[GOODIX_CFG_LOC_SENS_NUM] & 0x0f) +
0277 ((ts->config[GOODIX_CFG_LOC_SENS_NUM] >> 4) & 0x0f);
0278
0279 dev_dbg(&ts->client->dev, "Drv %d Sen %d Key %d\n",
0280 driver_num, sensor_num, have_key);
0281
0282 ts->bak_ref_len = (driver_num * (sensor_num - 2) + 2) * 2;
0283
0284 ts->bak_ref = devm_kzalloc(&ts->client->dev,
0285 ts->bak_ref_len, GFP_KERNEL);
0286 if (!ts->bak_ref)
0287 return -ENOMEM;
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 ts->bak_ref[ts->bak_ref_len - 1] = 1;
0305
0306 return 0;
0307 }
0308
0309 static int goodix_send_main_clock(struct goodix_ts_data *ts)
0310 {
0311 u32 main_clk = 54;
0312 u8 checksum = 0;
0313 int i;
0314
0315 device_property_read_u32(&ts->client->dev,
0316 "goodix,main-clk", &main_clk);
0317
0318 for (i = 0; i < (GOODIX_MAIN_CLK_LEN - 1); i++) {
0319 ts->main_clk[i] = main_clk;
0320 checksum += main_clk;
0321 }
0322
0323
0324 ts->main_clk[GOODIX_MAIN_CLK_LEN - 1] = 256 - checksum;
0325
0326 return goodix_i2c_write(ts->client, GOODIX_REG_MAIN_CLK,
0327 ts->main_clk, GOODIX_MAIN_CLK_LEN);
0328 }
0329
0330 int goodix_firmware_check(struct goodix_ts_data *ts)
0331 {
0332 device_property_read_string(&ts->client->dev,
0333 "firmware-name", &ts->firmware_name);
0334 if (!ts->firmware_name)
0335 return 0;
0336
0337 if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
0338 dev_err(&ts->client->dev, "Error no IRQ-pin access method, cannot upload fw.\n");
0339 return -EINVAL;
0340 }
0341
0342 dev_info(&ts->client->dev, "Touchscreen controller needs fw-upload\n");
0343 ts->load_cfg_from_disk = true;
0344
0345 return goodix_firmware_upload(ts);
0346 }
0347
0348 bool goodix_handle_fw_request(struct goodix_ts_data *ts)
0349 {
0350 int error;
0351 u8 val;
0352
0353 error = goodix_i2c_read(ts->client, GOODIX_REG_REQUEST, &val, 1);
0354 if (error)
0355 return false;
0356
0357 switch (val) {
0358 case GOODIX_RQST_RESPONDED:
0359
0360
0361
0362
0363 return false;
0364 case GOODIX_RQST_CONFIG:
0365 error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
0366 if (error)
0367 return false;
0368
0369 break;
0370 case GOODIX_RQST_BAK_REF:
0371 error = goodix_prepare_bak_ref(ts);
0372 if (error)
0373 return false;
0374
0375 error = goodix_i2c_write(ts->client, GOODIX_REG_BAK_REF,
0376 ts->bak_ref, ts->bak_ref_len);
0377 if (error)
0378 return false;
0379
0380 break;
0381 case GOODIX_RQST_RESET:
0382 error = goodix_firmware_upload(ts);
0383 if (error)
0384 return false;
0385
0386 break;
0387 case GOODIX_RQST_MAIN_CLOCK:
0388 error = goodix_send_main_clock(ts);
0389 if (error)
0390 return false;
0391
0392 break;
0393 case GOODIX_RQST_UNKNOWN:
0394 case GOODIX_RQST_IDLE:
0395 break;
0396 default:
0397 dev_err_ratelimited(&ts->client->dev, "Unknown Request: 0x%02x\n", val);
0398 }
0399
0400
0401 goodix_i2c_write_u8(ts->client,
0402 GOODIX_REG_REQUEST, GOODIX_RQST_RESPONDED);
0403 return true;
0404 }
0405
0406 void goodix_save_bak_ref(struct goodix_ts_data *ts)
0407 {
0408 int error;
0409 u8 val;
0410
0411 if (!ts->firmware_name)
0412 return;
0413
0414 error = goodix_i2c_read(ts->client, GOODIX_REG_STATUS, &val, 1);
0415 if (error)
0416 return;
0417
0418 if (!(val & 0x80))
0419 return;
0420
0421 error = goodix_i2c_read(ts->client, GOODIX_REG_BAK_REF,
0422 ts->bak_ref, ts->bak_ref_len);
0423 if (error) {
0424 memset(ts->bak_ref, 0, ts->bak_ref_len);
0425 ts->bak_ref[ts->bak_ref_len - 1] = 1;
0426 }
0427 }