/* Himax Android Driver Sample Code for HX83192 chipset * * Copyright (C) 2021 Himax Corporation. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define hx83192_data_adc_num 120 #include "himax.h" #include "himax_ic_core.h" static void hx83192_chip_init(struct himax_ts_data *ts) { ts->chip_cell_type = CHIP_IS_IN_CELL; I("%s:IC cell type = %d\n", __func__, ts->chip_cell_type); ts->ic_checksum = HX_TP_BIN_CHECKSUM_CRC; /*Himax: Set FW and CFG Flash Address*/ ts->fw_ver_maj_flash_addr = 49157; /*0x00C005*/ ts->fw_ver_min_flash_addr = 49158; /*0x00C006*/ ts->cfg_ver_maj_flash_addr = 49408; /*0x00C100*/ ts->cfg_ver_min_flash_addr = 49409; /*0x00C101*/ ts->cid_ver_maj_flash_addr = 49154; /*0x00C002*/ ts->cid_ver_min_flash_addr = 49155; /*0x00C003*/ ts->cfg_table_flash_addr = 0x10000; } static bool himax_get_ic_Amount(struct himax_ts_data *ts) { bool result = false; uint8_t tmp_addr[DATA_LEN_4] = { 0 }; uint8_t tmp_data[DATA_LEN_4] = { 0 }; int cascadeenb; tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0xEC; himax_mcu_register_read(ts, tmp_addr, DATA_LEN_4, tmp_data, false); if (result) { cascadeenb = (tmp_data[1] >> 2); switch (cascadeenb) { case 0: ts->hx_ic_amount = 3; break; case 2: ts->hx_ic_amount = 2; break; case 3: ts->hx_ic_amount = 1; break; default: result = false; break; } } I("hx_ic_Amount : %d\n", ts->hx_ic_amount); return result; } static void hx83192_sense_on(struct himax_ts_data *ts, uint8_t FlashMode) { uint8_t tmp_addr[DATA_LEN_4]; uint8_t tmp_data[DATA_LEN_4]; int retry = 0; int ret = 0; I("Enter %s\n", __func__); ts->core_fp.fp_interface_on(ts); if (!FlashMode) { #if defined(HX_RST_PIN_FUNC) if (HX_SYSTEM_RESET == 0) ts->core_fp.fp_ic_reset(ts, false, false); else ts->core_fp.fp_system_reset(ts); #endif } else { do { himax_parse_assign_cmd(addr_ctrl_fw, tmp_addr, sizeof(tmp_addr)); himax_parse_assign_cmd(data_clear, tmp_data, sizeof(tmp_data)); himax_mcu_register_write(ts, tmp_addr, DATA_LEN_4, tmp_data, 0); msleep(20); himax_mcu_register_read(ts, tmp_addr, DATA_LEN_4, tmp_data, 0); I("%s:Read status from IC = %X,%X\n", __func__, tmp_data[0], tmp_data[1]); } while (tmp_data[0] != 0x00 && retry++ < 5); if (retry >= 5) { E("%s: Fail:\n", __func__); #if defined(HX_RST_PIN_FUNC) if (HX_SYSTEM_RESET == 0) ts->core_fp.fp_ic_reset(ts, false, false); else ts->core_fp.fp_system_reset(ts); #endif } else { I("%s:OK and Read status from IC = %X,%X\n", __func__, tmp_data[0], tmp_data[1]); /* reset code*/ tmp_data[0] = 0x00; tmp_data[1] = 0x00; ret = himax_bus_write(ts, addr_sense_on_off_0, tmp_data, 2, HIMAX_I2C_RETRY_TIMES); if (ret < 0) E("%s: i2c access fail!\n", __func__); /*ret = himax_bus_write(ts, ts->ic_incell.pfw_op ->adr_i2c_psw_ub[0], tmp_data, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) E("%s: i2c access fail!\n", __func__);*/ } msleep(280); #if defined(HIMAX_I2C_PLATFORM) ret = himax_bus_read(ts, addr_AHB_rdata_byte_0, tmp_data, DATA_LEN_4, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { E("%s: i2c access fail!\n", __func__); } #endif } } static bool hx83192_sense_off(struct himax_ts_data *ts, bool check_en) { bool result = true; uint8_t cnt = 0; uint8_t tmp_addr[DATA_LEN_4] = { 0 }; uint8_t tmp_data[DATA_LEN_4] = { 0 }; uint8_t cMax = 7; uint8_t check = 0x87; int ret = 0; msleep(280); himax_parse_assign_cmd(addr_cs_central_state, tmp_addr, sizeof(tmp_addr)); himax_mcu_register_read(ts, tmp_addr, DATA_LEN_4, tmp_data, false); if (tmp_data[0] != 0x0C) { tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x5C; cnt = 0; do { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xA5; himax_mcu_register_write(ts, tmp_addr, DATA_LEN_4, tmp_data, 0); msleep(20); himax_mcu_register_read(ts, tmp_addr, DATA_LEN_4, tmp_data, 0); I("%s: Check 9000005C data[0]=%X\n", __func__, tmp_data[0]); if (cnt++ >= cMax) break; } while (tmp_data[0] != check); } do { tmp_data[0] = para_sense_off_0; ret = himax_bus_write(ts, addr_sense_on_off_0, tmp_data, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { E("%s: i2c access fail!\n", __func__); return false; } tmp_data[0] = para_sense_off_1; ret = himax_bus_write(ts, addr_sense_on_off_1, tmp_data, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { E("%s: i2c access fail!\n", __func__); return false; } himax_parse_assign_cmd(addr_cs_central_state, tmp_addr, sizeof(tmp_addr)); himax_mcu_register_read(ts, tmp_addr, DATA_LEN_4, tmp_data, false); I("%s: Check enter_save_mode data[0]=%X\n", __func__, tmp_data[0]); if (tmp_data[0] == 0x0C) { return true; } else if (cnt == 6) { usleep_range(10000, 11000); #if defined(HX_RST_PIN_FUNC) if (HX_SYSTEM_RESET == 0) ts->core_fp.fp_ic_reset(ts, false, false); else ts->core_fp.fp_system_reset(ts); #endif } } while (cnt++ < 15); return result; } static int hx83192_mcu_register_read(struct himax_ts_data *ts, uint8_t *read_addr, uint32_t read_length, uint8_t *read_data, uint8_t cfg_flag) { uint8_t tmp_data[DATA_LEN_4]; int i = 0; int address = 0; int ret = 0; if (cfg_flag == false) { if (read_length > FLASH_RW_MAX_LEN) { E("%s: read len over %d!\n", __func__, FLASH_RW_MAX_LEN); return LENGTH_FAIL; } address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0]; i = address; tmp_data[0] = (uint8_t)i; tmp_data[1] = (uint8_t)(i >> 8); tmp_data[2] = (uint8_t)(i >> 16); tmp_data[3] = (uint8_t)(i >> 24); ret = himax_bus_write(ts, addr_AHB_address_byte_0, tmp_data, DATA_LEN_4, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { E("%s: i2c access fail!\n", __func__); return I2C_FAIL; } tmp_data[0] = para_AHB_access_direction_read; ret = himax_bus_write(ts, addr_AHB_access_direction, tmp_data, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { E("%s: i2c access fail!\n", __func__); return I2C_FAIL; } ret = himax_bus_read(ts, addr_AHB_rdata_byte_0, read_data, read_length, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { E("%s: i2c access fail!\n", __func__); return I2C_FAIL; } } else { ret = himax_bus_read(ts, read_addr[0], read_data, read_length, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { E("%s: i2c access fail!\n", __func__); return I2C_FAIL; } } return NO_ERR; } static void hx83192_mcu_flash_dump_func(struct himax_ts_data *ts, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) { uint8_t tmp_addr[DATA_LEN_4]; uint8_t tmp_data[DATA_LEN_4]; int page_prog_start = 0, retry_cnt = 0; I("%s,Entering\n", __func__); ts->core_fp.fp_sense_off(ts, true); ts->core_fp.fp_burst_enable(ts, 0); /* ===SPI RX-FIFO Reset===*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_fifo_rst, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_rxfifo_rst, 0); do { himax_mcu_register_read(ts, ts->ic_incell.pflash_op->addr_spi200_fifo_rst, DATA_LEN_4, tmp_data, 0); if (retry_cnt > 50) { E("%s: Polling SPI Status FAIL", __func__); return; } retry_cnt++; } while ((tmp_data[0] & 0x02) != 0); /* ===SPI Transfer Control===*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_trans_ctrl, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_trans_ctrl_7, 0); for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start += 16) { tmp_addr[0] = page_prog_start % 0x100; tmp_addr[1] = (page_prog_start >> 8) % 0x100; tmp_addr[2] = (page_prog_start >> 16) % 0x100; tmp_addr[3] = page_prog_start / 0x1000000; /* ===Set SPI Address ===*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_addr, DATA_LEN_4, tmp_addr, 0); /* ===SPI Transfer Control===*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_cmd, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_cmd_7, 0); retry_cnt = 0; do { himax_mcu_register_read(ts, ts->ic_incell.pflash_op->addr_spi200_rst_status, DATA_LEN_4, tmp_data, 0); if (retry_cnt > 50) { E("%s: Polling SPI Status FAIL", __func__); return; } retry_cnt++; } while ((tmp_data[1] & 0x80) == 0); hx83192_mcu_register_read(ts, ts->ic_incell.pflash_op->addr_spi200_data, 16, &flash_buffer[page_prog_start], false); } ts->core_fp.fp_sense_on(ts, 0x01); } static void hx83192_mcu_flash_programming(struct himax_ts_data *ts, uint8_t *FW_content, int start_addr, int length) { int page_prog_start = 0, i = 0, j = 0, k = 0, retry_cnt = 0; uint8_t tmp_data[DATA_LEN_4]; uint8_t buring_data[FLASH_RW_MAX_LEN]; /* Read for flash data, 128K*/ I("%s", __func__); /* 4 bytes for padding*/ ts->core_fp.fp_interface_on(ts); himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_flash_speed, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_cmd_8, 0); /* ===SPI TX-FIFO Reset===*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_fifo_rst, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_txfifo_rst, 0); /* ===Polling Reset Status ===*/ retry_cnt = 0; do { himax_mcu_register_read(ts, ts->ic_incell.pflash_op->addr_spi200_fifo_rst, DATA_LEN_4, tmp_data, 0); if (retry_cnt > 50) { E("%s: Polling SPI Status Active FAIL", __func__); return; } retry_cnt++; } while (((tmp_data[0] & 0x04) >> 2) == 1); /* ===SPI Transfer Format===*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_trans_fmt, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_trans_fmt, 0); for (page_prog_start = start_addr; page_prog_start < start_addr + length; page_prog_start += FLASH_RW_MAX_LEN) { himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_trans_ctrl, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_trans_ctrl_2, 0); himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_cmd, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_cmd_2, 0); /* ===Polling SPI Status Active ===*/ retry_cnt = 0; do { himax_mcu_register_read(ts, ts->ic_incell.pflash_op->addr_spi200_rst_status, 4, tmp_data, 0); if (retry_cnt > 50) { E("%s: Polling FAIL", __func__); return; } retry_cnt++; } while ((tmp_data[0] & 0x01) == 1); /* ===WEL Write Enable ===*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_trans_ctrl, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_trans_ctrl_6, 0); himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_cmd, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_cmd_1, 0); /* ===Polling SPI Status Active ===*/ retry_cnt = 0; do { himax_mcu_register_read(ts, ts->ic_incell.pflash_op->addr_spi200_rst_status, DATA_LEN_4, tmp_data, 0); if (retry_cnt > 50) { E("%s: Polling FAIL", __func__); return; } retry_cnt++; } while ((tmp_data[0] & 0x01) == 1); himax_mcu_register_read(ts, ts->ic_incell.pflash_op->addr_spi200_data, DATA_LEN_4, tmp_data, 0); //WEL Fail if (((tmp_data[0] & 0x02) >> 1) == 0) { I("%s:SPI 0x8000002c = %d\n", __func__, tmp_data[0]); break; } /*Programmable size = 256 bytes, word_number = 256/4 = 64*/ himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_trans_ctrl, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_trans_ctrl_4, 0); /* Flash start address 1st : 0x0000_0000*/ if (page_prog_start < 0x100) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; } else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; } else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) { tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; } himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_addr, DATA_LEN_4, tmp_data, 0); for (i = 0; i < ADDR_LEN_4; i++) buring_data[i] = ts->ic_incell.pflash_op->addr_spi200_data[i]; himax_mcu_register_write(ts, ts->ic_incell.pflash_op->addr_spi200_cmd, DATA_LEN_4, ts->ic_incell.pflash_op->data_spi200_cmd_6, 0); for (j = 0; j < 16; j++) { for (i = (page_prog_start + (j * 16)), k = 0; i < (page_prog_start + (j * 16)) + 16; i++, k++) buring_data[k + ADDR_LEN_4] = FW_content[i - start_addr]; /*I("FW_content[%d] = 0x%02X", i - start_addr, FW_content[i - start_addr]);*/ if (himax_bus_write(ts, addr_AHB_address_byte_0, buring_data, ADDR_LEN_4 + 16, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } /* ===Polling SPI Status Active ===*/ retry_cnt = 0; do { himax_mcu_register_read( ts, ts->ic_incell.pflash_op->addr_spi200_rst_status, DATA_LEN_4, tmp_data, 0); if (retry_cnt > 50) { E("%s: Polling FAIL", __func__); return; } retry_cnt++; } while ((tmp_data[2] & 0x40) == 0); } if (!ts->core_fp.fp_wait_wip(ts, 1)) E("%s:Flash_Programming Fail\n", __func__); } } static bool hx83192_mcu_ic_id_read(struct himax_ts_data *ts) { I("%s: [HX83192-A]", __func__); return true; } static bool hx83192_mcu_dd_clk_set(struct himax_ts_data *ts, bool enable) { uint8_t data[4] = { 0 }; data[0] = (enable) ? 0xDD : 0x00; return (himax_mcu_register_write(ts, ts->ic_incell.pfw_op->addr_osc_en, sizeof(ts->ic_incell.pfw_op->addr_osc_en), data, 0) == NO_ERR); } static void hx83192_mcu_dd_reg_en(struct himax_ts_data *ts, bool enable) { uint8_t data[4] = { 0 }; data[0] = 0xA5; data[1] = 0x00; data[2] = 0x00; data[3] = 0x00; himax_mcu_register_write(ts, ts->ic_incell.pfw_op->addr_osc_pw, sizeof(ts->ic_incell.pfw_op->addr_osc_pw), data, 0); data[0] = 0x00; data[1] = 0x55; data[2] = 0x66; data[3] = 0xCC; ts->core_fp.fp_dd_reg_write(ts, 0xEB, 0, 4, data, 0); data[0] = 0x00; data[1] = 0x83; data[2] = 0x19; data[3] = 0x2A; ts->core_fp.fp_dd_reg_write(ts, 0xB9, 0, 4, data, 0); } static void hx83192_func_re_init(struct himax_ts_data *ts) { ts->core_fp.fp_sense_on = hx83192_sense_on; ts->core_fp.fp_sense_off = hx83192_sense_off; ts->core_fp.fp_chip_init = hx83192_chip_init; ts->core_fp.fp_ic_id_read = hx83192_mcu_ic_id_read; ts->core_fp.fp_dd_clk_set = hx83192_mcu_dd_clk_set; ts->core_fp.fp_dd_reg_en = hx83192_mcu_dd_reg_en; ts->core_fp.fp_flash_dump_func = hx83192_mcu_flash_dump_func; ts->core_fp.fp_flash_programming = hx83192_mcu_flash_programming; } bool hx83192_chip_detect(struct himax_ts_data *ts) { uint8_t tmp_data[DATA_LEN_4] = { 0 }; uint8_t tmp_addr[DATA_LEN_4] = { 0 }; bool ret_data = false; int ret = 0; int i = 0; ret = himax_mcu_in_cmd_struct_init(ts); if (ret < 0) { ret_data = false; E("%s:cmd_struct_init Fail:\n", __func__); return ret_data; } himax_mcu_in_cmd_init(ts); hx83192_func_re_init(ts); ts->core_fp.fp_sense_off(ts, true); for (i = 0; i < 5; i++) { himax_parse_assign_cmd(addr_icid_addr, tmp_addr, sizeof(tmp_addr)); himax_mcu_register_read(ts, tmp_addr, DATA_LEN_4, tmp_data, false); I("%s:Read driver IC ID = %X,%X,%X\n", __func__, tmp_data[3], tmp_data[2], tmp_data[1]); if ((tmp_data[3] == 0x83) && (tmp_data[2] == 0x19) && (tmp_data[1] == 0x2a)) { strlcpy(ts->chip_name, HX_83192A_SERIES_PWON, 30); I("%s:IC name = %s\n", __func__, ts->chip_name); I("Himax IC package %x%x%x in\n", tmp_data[3], tmp_data[2], tmp_data[1]); ret_data = true; ts->ic_data->ic_adc_num = hx83192_data_adc_num; himax_get_ic_Amount(ts); return ret_data; } } ret_data = false; E("%s:Read driver ID register Fail:\n", __func__); E("Could NOT find Himax Chipset\n"); E("Please check 1.VCCD,VCCA,VSP,VSN\n"); E("2.LCM_RST,TP_RST\n"); E("3.Power On Sequence\n"); return ret_data; } EXPORT_SYMBOL(hx83192_chip_detect); MODULE_LICENSE("GPL");