#define LOG_TAG "Core" #include "cts_config.h" #include "cts_platform.h" #include "cts_core.h" #include "cts_sfctrl.h" #include "cts_spi_flash.h" #include "cts_sysfs.h" #include "cts_firmware.h" #include "cts_charger_detect.h" #include "cts_earjack_detect.h" #include "cts_tcs.h" //drv added by chenjiaxi, hardware_info, begin #if IS_ENABLED(CONFIG_PRIZE_HARDWARE_INFO) #include "../../../misc/mediatek/prize/hardware_info/hardware_info.h" #endif //drv added by chenjiaxi, hardware_info, end #ifdef CONFIG_CTS_I2C_HOST static int cts_i2c_writeb(const struct cts_device *cts_dev, u32 addr, u8 b, int retry, int delay) { u8 buff[8]; cts_dbg("Write to slave_addr: 0x%02x reg: 0x%0*x val: 0x%02x", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr, b); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, buff); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, buff); else { cts_err("Writeb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } buff[cts_dev->rtdata.addr_width] = b; return cts_plat_i2c_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, buff, cts_dev->rtdata.addr_width + 1, retry, delay); } static int cts_i2c_writew(const struct cts_device *cts_dev, u32 addr, u16 w, int retry, int delay) { u8 buff[8]; cts_dbg("Write to slave_addr: 0x%02x reg: 0x%0*x val: 0x%04x", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr, w); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, buff); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, buff); else { cts_err("Writew invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } put_unaligned_le16(w, buff + cts_dev->rtdata.addr_width); return cts_plat_i2c_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, buff, cts_dev->rtdata.addr_width + 2, retry, delay); } static int cts_i2c_writel(const struct cts_device *cts_dev, u32 addr, u32 l, int retry, int delay) { u8 buff[8]; cts_dbg("Write to slave_addr: 0x%02x reg: 0x%0*x val: 0x%08x", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr, l); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, buff); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, buff); else { cts_err("Writel invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } put_unaligned_le32(l, buff + cts_dev->rtdata.addr_width); return cts_plat_i2c_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, buff, cts_dev->rtdata.addr_width + 4, retry, delay); } static int cts_i2c_writesb(const struct cts_device *cts_dev, u32 addr, const u8 *src, size_t len, int retry, int delay) { int ret; u8 *data; size_t max_xfer_size; size_t payload_len; size_t xfer_len; cts_dbg("Write to slave_addr: 0x%02x reg: 0x%0*x len: %zu", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr, len); max_xfer_size = cts_plat_get_max_i2c_xfer_size(cts_dev->pdata); data = cts_plat_get_i2c_xfer_buf(cts_dev->pdata, len); while (len) { payload_len = min((size_t)(max_xfer_size - cts_dev->rtdata.addr_width), len); xfer_len = payload_len + cts_dev->rtdata.addr_width; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, data); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, data); else { cts_err("Writesb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } memcpy(data + cts_dev->rtdata.addr_width, src, payload_len); ret = cts_plat_i2c_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, data, xfer_len, retry, delay); if (ret) { cts_err("Platform i2c write failed %d", ret); return ret; } src += payload_len; len -= payload_len; addr += payload_len; } return 0; } static int cts_i2c_readb(const struct cts_device *cts_dev, u32 addr, u8 *b, int retry, int delay) { u8 addr_buf[4]; cts_dbg("Readb from slave_addr: 0x%02x reg: 0x%0*x", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } return cts_plat_i2c_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, b, 1, retry, delay); } static int cts_i2c_readw(const struct cts_device *cts_dev, u32 addr, u16 *w, int retry, int delay) { int ret; u8 addr_buf[4]; u8 buff[2]; cts_dbg("Readw from slave_addr: 0x%02x reg: 0x%0*x", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readw invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } ret = cts_plat_i2c_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, buff, 2, retry, delay); if (ret == 0) *w = get_unaligned_le16(buff); return ret; } static int cts_i2c_readl(const struct cts_device *cts_dev, u32 addr, u32 *l, int retry, int delay) { int ret; u8 addr_buf[4]; u8 buff[4]; cts_dbg("Readl from slave_addr: 0x%02x reg: 0x%0*x", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readl invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } ret = cts_plat_i2c_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, buff, 4, retry, delay); if (ret == 0) *l = get_unaligned_le32(buff); return ret; } static int cts_i2c_readsb(const struct cts_device *cts_dev, u32 addr, void *dst, size_t len, int retry, int delay) { int ret; u8 addr_buf[4]; size_t max_xfer_size, xfer_len; cts_dbg("Readsb from slave_addr: 0x%02x reg: 0x%0*x len: %zu", cts_dev->rtdata.slave_addr, cts_dev->rtdata.addr_width * 2, addr, len); max_xfer_size = cts_plat_get_max_i2c_xfer_size(cts_dev->pdata); while (len) { xfer_len = min(max_xfer_size, len); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readsb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } ret = cts_plat_i2c_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, dst, xfer_len, retry, delay); if (ret) { cts_err("Platform i2c read failed %d", ret); return ret; } dst += xfer_len; len -= xfer_len; addr += xfer_len; } return 0; } #else static int cts_spi_writeb(const struct cts_device *cts_dev, u32 addr, u8 b, int retry, int delay) { u8 buff[8]; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, buff); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, buff); else { cts_err("Writeb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } buff[cts_dev->rtdata.addr_width] = b; return cts_plat_spi_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, buff, cts_dev->rtdata.addr_width + 1, retry, delay); return 0; } static int cts_spi_writew(const struct cts_device *cts_dev, u32 addr, u16 w, int retry, int delay) { u8 buff[8]; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, buff); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, buff); else { cts_err("Writew invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } put_unaligned_le16(w, buff + cts_dev->rtdata.addr_width); return cts_plat_spi_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, buff, cts_dev->rtdata.addr_width + 2, retry, delay); return 0; } static int cts_spi_writel(const struct cts_device *cts_dev, u32 addr, u32 l, int retry, int delay) { u8 buff[8]; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, buff); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, buff); else { cts_err("Writel invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } put_unaligned_le32(l, buff + cts_dev->rtdata.addr_width); return cts_plat_spi_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, buff, cts_dev->rtdata.addr_width + 4, retry, delay); return 0; } static int cts_spi_writesb(const struct cts_device *cts_dev, u32 addr, const u8 *src, size_t len, int retry, int delay) { int ret; u8 *data; size_t max_xfer_size; size_t payload_len; size_t xfer_len; max_xfer_size = cts_plat_get_max_spi_xfer_size(cts_dev->pdata); data = cts_plat_get_spi_xfer_buf(cts_dev->pdata, len); while (len) { payload_len = min((size_t)(max_xfer_size - cts_dev->rtdata.addr_width), len); xfer_len = payload_len + cts_dev->rtdata.addr_width; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, data); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, data); else { cts_err("Writesb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } memcpy(data + cts_dev->rtdata.addr_width, src, payload_len); ret = cts_plat_spi_write(cts_dev->pdata, cts_dev->rtdata.slave_addr, data, xfer_len, retry, delay); if (ret) { cts_err("Platform i2c write failed %d", ret); return ret; } src += payload_len; len -= payload_len; addr += payload_len; } return 0; } static int cts_spi_readb(const struct cts_device *cts_dev, u32 addr, u8 *b, int retry, int delay) { u8 addr_buf[4]; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } return cts_plat_spi_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, b, 1, retry, delay); } static int cts_spi_readw(const struct cts_device *cts_dev, u32 addr, u16 *w, int retry, int delay) { int ret; u8 addr_buf[4]; u8 buff[2]; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readw invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } ret = cts_plat_spi_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, buff, 2, retry, delay); if (ret == 0) *w = get_unaligned_le16(buff); return ret; } static int cts_spi_readl(const struct cts_device *cts_dev, u32 addr, u32 *l, int retry, int delay) { int ret; u8 addr_buf[4]; u8 buff[4]; if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readl invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } ret = cts_plat_spi_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, buff, 4, retry, delay); if (ret == 0) *l = get_unaligned_le32(buff); return ret; } static int cts_spi_readsb(const struct cts_device *cts_dev, u32 addr, void *dst, size_t len, int retry, int delay) { int ret; u8 addr_buf[4]; size_t max_xfer_size, xfer_len; max_xfer_size = cts_plat_get_max_spi_xfer_size(cts_dev->pdata); while (len) { xfer_len = min(max_xfer_size, len); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readsb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } ret = cts_plat_spi_read(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, dst, xfer_len, retry, delay); if (ret) { cts_err("Platform i2c read failed %d", ret); return ret; } dst += xfer_len; len -= xfer_len; addr += xfer_len; } return 0; } static int cts_spi_readsb_delay_idle(const struct cts_device *cts_dev, u32 addr, void *dst, size_t len, int retry, int delay, int idle) { int ret; u8 addr_buf[4]; size_t max_xfer_size, xfer_len; max_xfer_size = cts_plat_get_max_spi_xfer_size(cts_dev->pdata); while (len) { xfer_len = min(max_xfer_size, len); if (cts_dev->rtdata.addr_width == 2) put_unaligned_be16(addr, addr_buf); else if (cts_dev->rtdata.addr_width == 3) put_unaligned_be24(addr, addr_buf); else { cts_err("Readsb invalid address width %u", cts_dev->rtdata.addr_width); return -EINVAL; } ret = cts_plat_spi_read_delay_idle(cts_dev->pdata, cts_dev->rtdata.slave_addr, addr_buf, cts_dev->rtdata.addr_width, dst, xfer_len, retry, delay, idle); if (ret) { cts_err("Platform i2c read failed %d", ret); return ret; } dst += xfer_len; len -= xfer_len; addr += xfer_len; } return 0; } #endif /* CONFIG_CTS_I2C_HOST */ int cts_dev_writeb(const struct cts_device *cts_dev, u32 addr, u8 b, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_writeb(cts_dev, addr, b, retry, delay); #else return cts_spi_writeb(cts_dev, addr, b, retry, delay); #endif } static inline int cts_dev_writew(const struct cts_device *cts_dev, u32 addr, u16 w, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_writew(cts_dev, addr, w, retry, delay); #else return cts_spi_writew(cts_dev, addr, w, retry, delay); #endif } static inline int cts_dev_writel(const struct cts_device *cts_dev, u32 addr, u32 l, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_writel(cts_dev, addr, l, retry, delay); #else return cts_spi_writel(cts_dev, addr, l, retry, delay); #endif } static inline int cts_dev_writesb(const struct cts_device *cts_dev, u32 addr, const u8 *src, size_t len, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_writesb(cts_dev, addr, src, len, retry, delay); #else return cts_spi_writesb(cts_dev, addr, src, len, retry, delay); #endif } int cts_dev_readb(const struct cts_device *cts_dev, u32 addr, u8 *b, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_readb(cts_dev, addr, b, retry, delay); #else return cts_spi_readb(cts_dev, addr, b, retry, delay); #endif } static inline int cts_dev_readw(const struct cts_device *cts_dev, u32 addr, u16 *w, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_readw(cts_dev, addr, w, retry, delay); #else return cts_spi_readw(cts_dev, addr, w, retry, delay); #endif } static inline int cts_dev_readl(const struct cts_device *cts_dev, u32 addr, u32 *l, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_readl(cts_dev, addr, l, retry, delay); #else return cts_spi_readl(cts_dev, addr, l, retry, delay); #endif } static inline int cts_dev_readsb(const struct cts_device *cts_dev, u32 addr, void *dst, size_t len, int retry, int delay) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_readsb(cts_dev, addr, dst, len, retry, delay); #else return cts_spi_readsb(cts_dev, addr, dst, len, retry, delay); #endif } static inline int cts_dev_readsb_delay_idle(const struct cts_device *cts_dev, u32 addr, void *dst, size_t len, int retry, int delay, int idle) { #ifdef CONFIG_CTS_I2C_HOST return cts_i2c_readsb(cts_dev, addr, dst, len, retry, delay); #else return cts_spi_readsb_delay_idle(cts_dev, addr, dst, len, retry, delay, idle); #endif } #ifdef CFG_CTS_UPDATE_CRCCHECK int cts_sram_writesb_boot_crc_retry(const struct cts_device *cts_dev, size_t len, u32 crc, int retry) { int ret = 0, retries; u32 addr[3]; if (cts_dev->hwdata->hwid == CTS_DEV_HWID_ICNL9922C) { addr[0] = 0x02bff0; addr[1] = 0x02bff8; addr[2] = 0x02bffc; } else { addr[0] = 0x01fff0; addr[1] = 0x01fff8; addr[2] = 0x01fffc; } retries = 0; do { ret = cts_dev_writel(cts_dev, addr[0], 0xCC33555A, 3, 1); if (ret != 0) { cts_err("SRAM writesb failed %d", ret); continue; } ret = cts_dev_writel(cts_dev, addr[1], crc, 3, 1); if (ret != 0) { cts_err("SRAM writesb failed %d", ret); continue; } ret = cts_dev_writel(cts_dev, addr[2], len, 3, 1); if (ret != 0) { cts_err("SRAM writesb failed %d", ret); continue; } break; } while (retries++ < retry); return ret; } #endif static int cts_write_sram_normal_mode(const struct cts_device *cts_dev, u32 addr, const void *src, size_t len, int retry, int delay) { int i, ret; u8 buff[5]; for (i = 0; i < len; i++) { put_unaligned_le32(addr, buff); buff[4] = *(u8 *) src; addr++; src++; ret = cts_dev_writesb(cts_dev, CTS_DEVICE_FW_REG_DEBUG_INTF, buff, 5, retry, delay); if (ret) { cts_err("Write rDEBUG_INTF len=5B failed %d", ret); return ret; } } return 0; } int cts_sram_writeb_retry(const struct cts_device *cts_dev, u32 addr, u8 b, int retry, int delay) { if (cts_dev->rtdata.program_mode) return cts_dev_writeb(cts_dev, addr, b, retry, delay); else return cts_write_sram_normal_mode(cts_dev, addr, &b, 1, retry, delay); } int cts_sram_writew_retry(const struct cts_device *cts_dev, u32 addr, u16 w, int retry, int delay) { u8 buff[2]; if (cts_dev->rtdata.program_mode) return cts_dev_writew(cts_dev, addr, w, retry, delay); else { put_unaligned_le16(w, buff); return cts_write_sram_normal_mode(cts_dev, addr, buff, 2, retry, delay); } } int cts_sram_writel_retry(const struct cts_device *cts_dev, u32 addr, u32 l, int retry, int delay) { u8 buff[4]; if (cts_dev->rtdata.program_mode) return cts_dev_writel(cts_dev, addr, l, retry, delay); else { put_unaligned_le32(l, buff); return cts_write_sram_normal_mode(cts_dev, addr, buff, 4, retry, delay); } } int cts_sram_writesb_retry(const struct cts_device *cts_dev, u32 addr, const void *src, size_t len, int retry, int delay) { if (cts_dev->rtdata.program_mode) return cts_dev_writesb(cts_dev, addr, src, len, retry, delay); else return cts_write_sram_normal_mode(cts_dev, addr, src, len, retry, delay); } static int cts_calc_sram_crc(const struct cts_device *cts_dev, u32 sram_addr, size_t size, u32 *crc) { cts_info("Calc crc from sram 0x%06x size %zu", sram_addr, size); return cts_dev->hwdata->sfctrl->ops->calc_sram_crc(cts_dev, sram_addr, size, crc); } int cts_sram_writesb_check_crc_retry(const struct cts_device *cts_dev, u32 addr, const void *src, size_t len, u32 crc, int retry) { int ret, retries; u32 fw_crc; u8 tdata[16]; u8 magic_num[] = { 0x5A, 0x55, 0x33, 0xCC, 0x00, 0x00, 0x00, 0x00 }; retries = 0; do { u32 crc_sram; retries++; ret = cts_sram_writesb(cts_dev, 0, src, len); if (ret != 0) { cts_err("SRAM writesb failed %d", ret); continue; } fw_crc = cts_crc32(src, len); cts_info("fw crc: 0x%04x", fw_crc); memcpy(tdata, magic_num, 8); memcpy(tdata + 8, &fw_crc, 4); memcpy(tdata + 12, &len, 4); ret = cts_sram_writesb_boot_crc_retry(cts_dev, len, fw_crc, 3); if (ret != 0) { cts_err("cts_hw_reg_writesb_retry %d", ret); continue; } ret = cts_calc_sram_crc(cts_dev, 0, len, &crc_sram); if (ret != 0) { cts_err("Get CRC for sram writesb failed %d retries %d", ret, retries); continue; } if (crc == crc_sram) return 0; cts_err("Check CRC for sram writesb mismatch %x != %x retries %d", crc, crc_sram, retries); ret = -EFAULT; } while (retries < retry); return ret; } int cts_read_sram_normal_mode(const struct cts_device *cts_dev, u32 addr, void *dst, size_t len, int retry, int delay) { int i, ret; for (i = 0; i < len; i++) { ret = cts_dev_writel(cts_dev, CTS_DEVICE_FW_REG_DEBUG_INTF, addr, retry, delay); if (ret) { cts_err("Write addr to rDEBUG_INTF failed %d", ret); return ret; } ret = cts_dev_readb(cts_dev, CTS_DEVICE_FW_REG_DEBUG_INTF + 4, (u8 *) dst, retry, delay); if (ret) { cts_err("Read value from rDEBUG_INTF + 4 failed %d", ret); return ret; } addr++; dst++; } return 0; } int cts_sram_readb_retry(const struct cts_device *cts_dev, u32 addr, u8 *b, int retry, int delay) { if (cts_dev->rtdata.program_mode) return cts_dev_readb(cts_dev, addr, b, retry, delay); else return cts_read_sram_normal_mode(cts_dev, addr, b, 1, retry, delay); } int cts_sram_readw_retry(const struct cts_device *cts_dev, u32 addr, u16 *w, int retry, int delay) { int ret; u8 buff[2]; if (cts_dev->rtdata.program_mode) return cts_dev_readw(cts_dev, addr, w, retry, delay); else { ret = cts_read_sram_normal_mode(cts_dev, addr, buff, 2, retry, delay); if (ret) { cts_err("SRAM readw in normal mode failed %d", ret); return ret; } *w = get_unaligned_le16(buff); return 0; } } int cts_sram_readl_retry(const struct cts_device *cts_dev, u32 addr, u32 *l, int retry, int delay) { int ret; u8 buff[4]; if (cts_dev->rtdata.program_mode) return cts_dev_readl(cts_dev, addr, l, retry, delay); else { ret = cts_read_sram_normal_mode(cts_dev, addr, buff, 4, retry, delay); if (ret) { cts_err("SRAM readl in normal mode failed %d", ret); return ret; } *l = get_unaligned_le32(buff); return 0; } } int cts_sram_readsb_retry(const struct cts_device *cts_dev, u32 addr, void *dst, size_t len, int retry, int delay) { if (cts_dev->rtdata.program_mode) return cts_dev_readsb(cts_dev, addr, dst, len, retry, delay); else return cts_read_sram_normal_mode(cts_dev, addr, dst, len, retry, delay); } int cts_fw_reg_writeb_retry(const struct cts_device *cts_dev, u32 reg_addr, u8 b, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Writeb to fw reg 0x%04x under program mode", reg_addr); return -ENODEV; } return cts_dev_writeb(cts_dev, reg_addr, b, retry, delay); } int cts_fw_reg_writew_retry(const struct cts_device *cts_dev, u32 reg_addr, u16 w, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Writew to fw reg 0x%04x under program mode", reg_addr); return -ENODEV; } return cts_dev_writew(cts_dev, reg_addr, w, retry, delay); } int cts_fw_reg_writel_retry(const struct cts_device *cts_dev, u32 reg_addr, u32 l, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Writel to fw reg 0x%04x under program mode", reg_addr); return -ENODEV; } return cts_dev_writel(cts_dev, reg_addr, l, retry, delay); } int cts_fw_reg_writesb_retry(const struct cts_device *cts_dev, u32 reg_addr, const void *src, size_t len, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Writesb to fw reg 0x%04x under program mode", reg_addr); return -ENODEV; } return cts_dev_writesb(cts_dev, reg_addr, src, len, retry, delay); } int cts_fw_reg_readb_retry(const struct cts_device *cts_dev, u32 reg_addr, u8 *b, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Readb from fw reg under program mode"); return -ENODEV; } return cts_dev_readb(cts_dev, reg_addr, b, retry, delay); } int cts_fw_reg_readw_retry(const struct cts_device *cts_dev, u32 reg_addr, u16 *w, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Readw from fw reg under program mode"); return -ENODEV; } return cts_dev_readw(cts_dev, reg_addr, w, retry, delay); } int cts_fw_reg_readl_retry(const struct cts_device *cts_dev, u32 reg_addr, u32 *l, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Readl from fw reg under program mode"); return -ENODEV; } return cts_dev_readl(cts_dev, reg_addr, l, retry, delay); } int cts_fw_reg_readsb_retry(const struct cts_device *cts_dev, u32 reg_addr, void *dst, size_t len, int retry, int delay) { if (cts_dev->rtdata.program_mode) { cts_err("Readsb from fw reg under program mode"); return -ENODEV; } return cts_dev_readsb(cts_dev, reg_addr, dst, len, retry, delay); } int cts_fw_reg_readsb_retry_delay_idle(const struct cts_device *cts_dev, u32 reg_addr, void *dst, size_t len, int retry, int delay, int idle) { if (cts_dev->rtdata.program_mode) { cts_err("Readsb from fw reg under program mode"); return -ENODEV; } return cts_dev_readsb_delay_idle(cts_dev, reg_addr, dst, len, retry, delay, idle); } int cts_hw_reg_writeb_retry(const struct cts_device *cts_dev, u32 reg_addr, u8 b, int retry, int delay) { return cts_sram_writeb_retry(cts_dev, reg_addr, b, retry, delay); } int cts_hw_reg_writew_retry(const struct cts_device *cts_dev, u32 reg_addr, u16 w, int retry, int delay) { return cts_sram_writew_retry(cts_dev, reg_addr, w, retry, delay); } int cts_hw_reg_writel_retry(const struct cts_device *cts_dev, u32 reg_addr, u32 l, int retry, int delay) { return cts_sram_writel_retry(cts_dev, reg_addr, l, retry, delay); } int cts_hw_reg_writesb_retry(const struct cts_device *cts_dev, u32 reg_addr, const void *src, size_t len, int retry, int delay) { return cts_sram_writesb_retry(cts_dev, reg_addr, src, len, retry, delay); } int cts_hw_reg_readb_retry(const struct cts_device *cts_dev, u32 reg_addr, u8 *b, int retry, int delay) { return cts_sram_readb_retry(cts_dev, reg_addr, b, retry, delay); } int cts_hw_reg_readw_retry(const struct cts_device *cts_dev, u32 reg_addr, u16 *w, int retry, int delay) { return cts_sram_readw_retry(cts_dev, reg_addr, w, retry, delay); } int cts_hw_reg_readl_retry(const struct cts_device *cts_dev, u32 reg_addr, u32 *l, int retry, int delay) { return cts_sram_readl_retry(cts_dev, reg_addr, l, retry, delay); } int cts_hw_reg_readsb_retry(const struct cts_device *cts_dev, u32 reg_addr, void *dst, size_t len, int retry, int delay) { return cts_sram_readsb_retry(cts_dev, reg_addr, dst, len, retry, delay); } static int icnl9916_set_access_ddi_reg(struct cts_device *cts_dev, bool enable) { int ret; u8 access_flag; cts_info("ICNL9916 %s access ddi reg", enable ? "enable" : "disable"); ret = cts_hw_reg_readb(cts_dev, CTS_DEV_HW_REG_DDI_REG_CTRL, &access_flag); if (ret) { cts_err("Read HW_REG_DDI_REG_CTRL failed %d", ret); return ret; } access_flag = enable ? (access_flag | 0x01) : (access_flag & (~0x01)); ret = cts_hw_reg_writeb(cts_dev, CTS_DEV_HW_REG_DDI_REG_CTRL, access_flag); if (ret) { cts_err("Write HW_REG_DDI_REG_CTRL %02x failed %d", access_flag, ret); return ret; } ret = cts_hw_reg_writeb(cts_dev, CTS_DEV_HW_REG_HPPROG, enable ? 1 : 0); if (ret) { cts_err("Write CTS_DEV_HW_REG_HPPROG failed %d", ret); return ret; } ret = cts_hw_reg_writew(cts_dev, 0x3DFF0, enable ? 0x595A : 0x5A5A); if (ret) { cts_err("Write password to F0 failed %d", ret); return ret; } ret = cts_hw_reg_writew(cts_dev, 0x3DFF4, enable ? 0xA6A5 : 0x5A5A); if (ret) { cts_err("Write password to F1 failed %d", ret); return ret; } return 0; } const static struct cts_sfctrl icnl9916_sfctrl = { .reg_base = 0x34000, .xchg_sram_base = 96 * 1024, .xchg_sram_size = 32 * 1024, /* For non firmware programming */ .ops = &cts_sfctrlv2_ops }; const static struct cts_sfctrl icnl9916c_sfctrl = { .reg_base = 0x34000, .xchg_sram_base = 96 * 1024, .xchg_sram_size = 32 * 1024, /* For non firmware programming */ .ops = &cts_sfctrlv2_ops }; const static struct cts_sfctrl icnl9922_sfctrl = { .reg_base = 0x34000, .xchg_sram_base = 96 * 1024, .xchg_sram_size = 32 * 1024, /* For non firmware programming */ .ops = &cts_sfctrlv2_ops }; const static struct cts_sfctrl icnl9922c_sfctrl = { .reg_base = 0x74000, .xchg_sram_base = 0x24000, .xchg_sram_size = 16 * 1024, /* For non firmware programming */ .ops = &cts_sfctrlv2_ops }; const static struct cts_sfctrl icnl9951_sfctrl = { .reg_base = 0x74000, .xchg_sram_base = 160 * 1024, .xchg_sram_size = 64 * 1024, /* For non firmware programming */ .ops = &cts_sfctrlv2_ops }; const static struct cts_device_hwdata cts_device_hwdatas[] = { { .name = "ICNL9916", .hwid = CTS_DEV_HWID_ICNL9916, .fwid = CTS_DEV_FWID_ICNL9916, .num_row = 32, .num_col = 18, .sram_size = 96 * 1024, .program_addr_width = 3, .sfctrl = &icnl9916_sfctrl, .enable_access_ddi_reg = icnl9916_set_access_ddi_reg, }, { .name = "ICNL9916C", .hwid = CTS_DEV_HWID_ICNL9916C, .fwid = CTS_DEV_FWID_ICNL9916C, .num_row = 32, .num_col = 18, .sram_size = 96 * 1024, .program_addr_width = 3, .sfctrl = &icnl9916c_sfctrl, .enable_access_ddi_reg = icnl9916_set_access_ddi_reg, }, { .name = "ICNL9922", .hwid = CTS_DEV_HWID_ICNL9922, .fwid = CTS_DEV_FWID_ICNL9922, .num_row = 36, .num_col = 18, .sram_size = 96 * 1024, .program_addr_width = 3, .sfctrl = &icnl9922_sfctrl, .enable_access_ddi_reg = icnl9916_set_access_ddi_reg, }, { .name = "ICNL9922C", .hwid = CTS_DEV_HWID_ICNL9922C, .fwid = CTS_DEV_FWID_ICNL9922C, .num_row = 36, .num_col = 18, .sram_size = 96 * 1024, .program_addr_width = 3, .sfctrl = &icnl9922c_sfctrl, .enable_access_ddi_reg = icnl9916_set_access_ddi_reg, }, { .name = "ICNL9951", .hwid = CTS_DEV_HWID_ICNL9951, .fwid = CTS_DEV_FWID_ICNL9951, .num_row = 36, .num_col = 22, .sram_size = 128 * 1024, .program_addr_width = 3, .sfctrl = &icnl9951_sfctrl, .enable_access_ddi_reg = icnl9916_set_access_ddi_reg, } }; static int cts_init_device_hwdata(struct cts_device *cts_dev, u32 hwid, u16 fwid) { int i; cts_info("Init hardware data hwid: %06x fwid: %04x", hwid, fwid); for (i = 0; i < ARRAY_SIZE(cts_device_hwdatas); i++) { if (hwid == cts_device_hwdatas[i].hwid || fwid == cts_device_hwdatas[i].fwid) { cts_dev->hwdata = &cts_device_hwdatas[i]; return 0; } } return -EINVAL; } void cts_lock_device(const struct cts_device *cts_dev) { cts_dbg("*** Lock ***"); mutex_lock(&cts_dev->pdata->dev_lock); } void cts_unlock_device(const struct cts_device *cts_dev) { cts_dbg("### Un-Lock ###"); mutex_unlock(&cts_dev->pdata->dev_lock); } int cts_send_command(const struct cts_device *cts_dev, u8 cmd) { cts_info("Send command 0x%02x", cmd); if (cts_dev->rtdata.program_mode) { cts_warn("Send command %u while chip in program mode", cmd); return -ENODEV; } return cts_fw_reg_writeb_retry(cts_dev, CTS_DEVICE_FW_REG_CMD, cmd, 3, 0); } static int cts_get_touchinfo(struct cts_device *cts_dev, struct cts_device_touch_info *touch_info) { cts_dbg("Get touch info"); if (cts_dev->rtdata.program_mode) { cts_warn("Get touch info in program mode"); return -ENODEV; } return cts_tcs_get_touchinfo(cts_dev, touch_info); } static int cts_get_dev_boot_mode(const struct cts_device *cts_dev, u8 *boot_mode) { int ret; if (cts_dev->rtdata.program_mode) ret = cts_hw_reg_readb_retry(cts_dev, CTS_DEV_HW_REG_CURRENT_MODE, boot_mode, 5, 10); else ret = cts_tcs_read_hw_reg(cts_dev, CTS_DEV_HW_REG_CURRENT_MODE, boot_mode, 1); if (ret) { cts_err("Read boot mode failed %d", ret); return ret; } *boot_mode &= CTS_DEV_BOOT_MODE_MASK; cts_info("Curr dev boot mode: %u(%s)", *boot_mode, cts_dev_boot_mode2str(*boot_mode)); return 0; } static int cts_set_dev_boot_mode(const struct cts_device *cts_dev, u8 boot_mode) { int ret; cts_info("Set dev boot mode to %u(%s)", boot_mode, cts_dev_boot_mode2str(boot_mode)); ret = cts_hw_reg_writeb_retry(cts_dev, CTS_DEV_HW_REG_BOOT_MODE, boot_mode, 5, 5); if (ret) { cts_err("Write hw register BOOT_MODE failed %d", ret); return ret; } return 0; } static int cts_init_fwdata(struct cts_device *cts_dev) { struct cts_device_fwdata *fwdata = &cts_dev->fwdata; int ret; cts_info("Init firmware data"); if (cts_dev->rtdata.program_mode) { cts_err("Init firmware data while in program mode"); return -EINVAL; } memset(fwdata, 0, sizeof(*fwdata)); ret = cts_tcs_get_fw_ver(cts_dev, &fwdata->version); if (ret < 0) { cts_err("get_fw_ver failed"); return -EINVAL; } ret = cts_tcs_get_lib_ver(cts_dev, &fwdata->lib_version); if (ret < 0) { cts_err("get_lib_ver failed"); return -EINVAL; } ret = cts_tcs_get_ddi_ver(cts_dev, &fwdata->ddi_version); if (ret < 0) { cts_err("get_ddi_ver failed"); return -EINVAL; } ret = cts_tcs_get_res_x(cts_dev, &fwdata->res_x); if (ret < 0) { cts_err("get_res_x failed"); return -EINVAL; } ret = cts_tcs_get_res_y(cts_dev, &fwdata->res_y); if (ret < 0) { cts_err("get_res_y failed"); return -EINVAL; } ret = cts_tcs_get_rows(cts_dev, &fwdata->rows); if (ret < 0) { cts_err("get_rows failed"); return -EINVAL; } ret = cts_tcs_get_cols(cts_dev, &fwdata->cols); if (ret < 0) { cts_err("get_cols failed"); return -EINVAL; } ret = cts_tcs_get_flip_x(cts_dev, &fwdata->flip_x); if (ret < 0) { cts_err("get_flip_x failed"); return -EINVAL; } ret = cts_tcs_get_flip_y(cts_dev, &fwdata->flip_y); if (ret < 0) { cts_err("get_flip_y failed"); return -EINVAL; } ret = cts_tcs_get_swap_axes(cts_dev, &fwdata->swap_axes); if (ret < 0) { cts_err("get_swap_axes failed"); return -EINVAL; } ret = cts_tcs_get_int_mode(cts_dev, &fwdata->int_mode); if (ret < 0) { cts_err("get_int_mode failed"); return -EINVAL; } ret = cts_tcs_get_int_keep_time(cts_dev, &fwdata->int_keep_time); if (ret < 0) { cts_err("get_int_keep_time failed"); return -EINVAL; } ret = cts_tcs_get_rawdata_target(cts_dev, &fwdata->rawdata_target); if (ret < 0) { cts_err("get_rawdata_target failed"); return -EINVAL; } ret = cts_tcs_get_esd_method(cts_dev, &fwdata->esd_method); if (ret < 0) { cts_err("get_esd_method failed"); return -EINVAL; } ret = cts_tcs_get_has_int_data(cts_dev, &fwdata->has_int_data); if (ret < 0) { cts_err("get_has_int_data failed: %d", ret); return -EINVAL; } if (fwdata->has_int_data) { ret = cts_tcs_get_int_data_method(cts_dev, &fwdata->int_data_method); if (ret < 0) { cts_err("get_int_data_method failed: %d", ret); return -EINVAL; } if (fwdata->int_data_method >= INT_DATA_METHOD_CNT) { cts_err("Invalid int data method: %d", fwdata->int_data_method); return -EINVAL; } ret = cts_tcs_get_int_data_types(cts_dev, &fwdata->int_data_types); if (ret < 0) { cts_err("get_int_data_types failed: %d", ret); return -EINVAL; } fwdata->int_data_types &= INT_DATA_TYPE_MASK; ret = cts_tcs_calc_int_data_size(cts_dev); if (ret < 0) { cts_err("calc_int_data_size failed: %d", ret); return -EINVAL; } } //drv added by chenjiaxi, hardware_info, begin #if IS_ENABLED(CONFIG_PRIZE_HARDWARE_INFO) snprintf(current_tp_info.chip, sizeof(current_tp_info.chip), "%s, Fwver:%04x", cts_dev->hwdata->name, cts_dev->fwdata.version); sprintf(current_tp_info.id, "hwid: %08x fwid: %04x", cts_dev->hwdata->hwid, cts_dev->hwdata->fwid); strcpy(current_tp_info.vendor, "chipone"); snprintf(current_tp_info.more, sizeof(current_tp_info.more), "%d*%d\n ddi_version:%02x", cts_dev->fwdata.res_x+1, cts_dev->fwdata.res_y+1, cts_dev->fwdata.ddi_version); #endif //drv added by chenjiaxi, hardware_info, end cts_err("fwver: %04x", fwdata->version); cts_err("libver: %04x", fwdata->lib_version); cts_err("ddi_version: %02x", fwdata->ddi_version); cts_err("res_x: %d", fwdata->res_x); cts_err("res_y: %d", fwdata->res_y); cts_err("rows: %d", fwdata->rows); cts_err("cols: %d", fwdata->cols); cts_err("flip_x: %d", fwdata->flip_x); cts_err("flip_y: %d", fwdata->flip_y); cts_err("swap_axes: %d", fwdata->swap_axes); cts_err("int_mode: %d", fwdata->int_mode); cts_err("int_keep_time: %d", fwdata->int_keep_time); cts_err("rawdata_target: %d", fwdata->rawdata_target); cts_err("esd_method: %d", fwdata->esd_method); cts_err("has_int_data: %d", fwdata->has_int_data); cts_err("int_data_method: %d", fwdata->int_data_method); cts_err("int_data_types: %d", fwdata->int_data_types); cts_err("int_data_size: %ld", fwdata->int_data_size); return 0; } #ifdef CFG_CTS_FW_LOG_REDIRECT void cts_show_fw_log(struct cts_device *cts_dev) { u8 len, max_len; int ret; u8 *data; max_len = cts_plat_get_max_fw_log_size(cts_dev->pdata); data = cts_plat_get_fw_log_buf(cts_dev->pdata, max_len); ret = cts_fw_reg_readsb(cts_dev, CTS_DEVICE_FW_REG_TOUCH_INFO + 1, &len, 1); if (ret) { cts_err("Get i2c print buf len error"); return; } if (len >= max_len) len = max_len - 1; ret = cts_fw_reg_readsb(cts_dev, CTS_DEVICE_FW_REG_TOUCH_INFO + 2, data, len); if (ret) { cts_err("Get i2c print buf error"); return; } data[len] = '\0'; printk("CTS-FW_LOG %s", data); cts_fw_log_show_finish(cts_dev); } #endif #ifdef CONFIG_CTS_TP_PROXIMITY static bool cts_is_proximity_enable(struct cts_device *cts_dev) { struct cts_firmware_status *status = (struct cts_firmware_status *) &cts_dev->rtdata.firmware_status; return !!status->proximity; } static int cts_enable_proximity_mode(struct cts_device *cts_dev) { return cts_tcs_set_proximity_mode(cts_dev, 1); } static int cts_exit_proximity_mode(struct cts_device *cts_dev) { return cts_tcs_set_proximity_mode(cts_dev, 0); } static void cts_handle_proximity_event(bool status) { cts_info("Handler proximity '%s' event", status ? "Near" : "Far"); } #endif int cts_irq_handler(struct cts_device *cts_dev) { struct cts_device_touch_info *touch_info; #ifdef CFG_CTS_GESTURE u8 pwrmode = 3; #endif int ret; cts_dbg("Enter IRQ handler"); if (cts_dev->rtdata.program_mode) { cts_err("IRQ triggered in program mode"); return -EINVAL; } touch_info = &cts_dev->rtdata.touch_info; ret = cts_get_touchinfo(cts_dev, touch_info); if (ret) { cts_err("Get touch info failed %d", ret); return ret; } if (unlikely(cts_dev->rtdata.suspended)) { #ifdef CFG_CTS_GESTURE if (cts_dev->rtdata.gesture_wakeup_enabled) { struct cts_device_gesture_info *gesture_info; gesture_info = &cts_dev->rtdata.gesture_info; memcpy(gesture_info, touch_info, sizeof(struct cts_device_gesture_info)); ret = cts_plat_process_gesture_info(cts_dev->pdata, gesture_info); if (cts_dev->fwdata.int_data_method != INT_DATA_METHOD_HOST) { if (ret) cts_err("Process gesture info failed %d", ret); ret = cts_tcs_set_pwr_mode(cts_dev, pwrmode); if (ret) cts_warn("Reenter suspend with gesture wakeup failed %d", ret); if (cts_tcs_clr_gstr_ready_flag(cts_dev)) cts_err("Clear gesture ready flag failed"); } } else { cts_warn("IRQ triggered while device suspended " "without gesture wakeup enable"); } #endif /* CFG_CTS_GESTURE */ } else { cts_dbg("Touch info: vkey_state %x, num_msg %u", touch_info->vkey_state, touch_info->num_msg); #ifdef CFG_CTS_PALM_DETECT if (CFG_CTS_PALM_ID == touch_info->vkey_state) { cts_report_palm_event(cts_dev->pdata); cts_plat_release_all_touch(cts_dev->pdata); return 0; } #endif #ifdef CONFIG_CTS_TP_PROXIMITY if (cts_is_proximity_enable(cts_dev)) { cts_dbg("proximity status:%d", cts_dev->rtdata.proximity_status); if (!cts_dev->rtdata.proximity_status && touch_info->vkey_state == CTS_CMD_PROXIMITY_STATUS) { cts_dev->rtdata.proximity_num++; if (cts_dev->rtdata.proximity_num == 4) { cts_dev->rtdata.proximity_num = 0; cts_dev->rtdata.proximity_status = true; cts_handle_proximity_event(true); return 0; } } else if (cts_dev->rtdata.proximity_status && (touch_info->vkey_state == 0)) { cts_dev->rtdata.proximity_num = 0; cts_dev->rtdata.proximity_status = false; cts_handle_proximity_event(false); cts_plat_release_all_touch(cts_dev->pdata); return 0; } } #endif ret = cts_plat_process_touch_msg(cts_dev->pdata, touch_info->msgs, touch_info->num_msg); if (ret) { cts_err("Process touch msg failed %d", ret); return ret; } #ifdef CONFIG_CTS_VIRTUALKEY ret = cts_plat_process_vkey(cts_dev->pdata, touch_info->vkey_state); if (ret) { cts_err("Process vkey failed %d", ret); return ret; } #endif } return 0; } bool cts_is_device_suspended(const struct cts_device *cts_dev) { return cts_dev->rtdata.suspended; } int cts_suspend_device(struct cts_device *cts_dev) { int ret; u8 buf; cts_info("Suspend device"); /* Disable this check for sleep/gesture switch */ /* if (cts_dev->rtdata.suspended) { cts_warn("Suspend device while already suspended"); return 0; } */ if (cts_dev->rtdata.program_mode) { cts_info("Quit programming mode before suspend"); ret = cts_enter_normal_mode(cts_dev); if (ret) { cts_err("Failed to exit program mode before suspend:%d", ret); return ret; } } cts_info("Set suspend mode:%s", cts_dev->rtdata.gesture_wakeup_enabled ? "gesture" : "sleep"); buf = cts_dev->rtdata.gesture_wakeup_enabled ? 3 : 2; ret = cts_tcs_set_pwr_mode(cts_dev, buf); if (ret) { cts_err("Suspend device failed %d", ret); return ret; } cts_info("Device suspended ..."); cts_dev->rtdata.suspended = true; return 0; } int cts_resume_device(struct cts_device *cts_dev) { u8 data[4] = {'R', 'S', 'T', '!'}; int retries = 3; int ret = 0; cts_info("Resume device"); /* Check whether device is in normal mode */ while (--retries >= 0) { #ifdef CFG_CTS_HAS_RESET_PIN ret = cts_tcs_write_hw_reg(cts_dev, CTS_DEV_HW_REG_SET_RESET, data, sizeof(data)); if (ret) { cts_err("write RST failed"); } cts_reset_device(cts_dev); #endif cts_set_normal_addr(cts_dev); if (cts_plat_is_normal_mode(cts_dev->pdata)) { break; } } if (retries < 0) { const struct cts_firmware *firmware = NULL; cts_info("Need update firmware when resume"); #ifdef CFG_CTS_FW_UPDATE_FILE_LOAD if (cts_dev->config_fw_name[0] != '\0') { firmware = cts_request_firmware_from_fs(cts_dev, cts_dev->config_fw_name); } #else firmware = cts_request_firmware(cts_dev, cts_dev->hwdata->hwid, cts_dev->hwdata->fwid, 0); #endif if (firmware) { ret = cts_update_firmware(cts_dev, firmware, false); cts_release_firmware(firmware); if (ret) { cts_err("Update default firmware failed %d", ret); goto err_set_program_mode; } } else { cts_err("Request default firmware failed %d, " "please update manually!!", ret); goto err_set_program_mode; } } #ifdef CONFIG_CTS_CHARGER_DETECT if (cts_is_charger_exist(cts_dev)) { int r = cts_set_dev_charger_attached(cts_dev, true); if (r) cts_err("Set dev charger attached failed %d", r); } #endif #ifdef CONFIG_CTS_EARJACK_DETECT if (cts_is_earjack_exist(cts_dev)) { int r = cts_set_dev_earjack_attached(cts_dev, true); if (r) { cts_err("Set dev earjack attached failed %d", r); } } #endif #ifdef CONFIG_CTS_GLOVE if (cts_is_glove_enabled(cts_dev)) cts_enter_glove_mode(cts_dev); #endif #ifdef CFG_CTS_FW_LOG_REDIRECT if (cts_is_fw_log_redirect(cts_dev)) cts_enable_fw_log_redirect(cts_dev); #endif #ifdef CONFIG_CTS_TP_PROXIMITY if (cts_is_proximity_enable(cts_dev)) { cts_enable_proximity_mode(cts_dev); cts_info("after update firmware, enable proximity mode."); } #endif cts_dev->rtdata.suspended = false; return 0; err_set_program_mode: cts_dev->rtdata.program_mode = true; cts_dev->rtdata.slave_addr = CTS_DEV_PROGRAM_MODE_I2CADDR; cts_dev->rtdata.addr_width = CTS_DEV_PROGRAM_MODE_ADDR_WIDTH; return ret; } bool cts_is_device_program_mode(const struct cts_device *cts_dev) { return cts_dev->rtdata.program_mode; } static inline void cts_init_rtdata_with_normal_mode(struct cts_device *cts_dev) { memset(&cts_dev->rtdata, 0, sizeof(cts_dev->rtdata)); cts_set_normal_addr(cts_dev); cts_dev->rtdata.suspended = false; cts_dev->rtdata.updating = false; cts_dev->rtdata.testing = false; cts_dev->rtdata.fw_log_redirect_enabled = false; cts_dev->rtdata.glove_mode_enabled = false; cts_dev->rtdata.esd_count = 0; #ifdef CONFIG_CTS_TP_PROXIMITY cts_dev->rtdata.proximity_num = 0; cts_dev->rtdata.proximity_status = false; #endif } #ifdef FIX_DEFAULT_ENABLE_DRW extern int cts_spi_send_recv(struct cts_platform_data *pdata, size_t len, u8 *tx_buffer, u8 *rx_buffer); static int cts_disable_drw(struct cts_device *cts_dev) { int ret; u8 txbuf[] = { 0x60, 0x07, 0x80, 0x34, 0x00, 0x00, 0x04, 0xdd, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xdf, 0xfc, 0x00, 0x00, 0x00 }; u8 rxbuf[] = { 0x60, 0x07, 0x80, 0x34, 0x00, 0x00, 0x04, 0xdd, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xdf, 0xfc, 0x00, 0x00, 0x00 }; ret = cts_spi_send_recv(cts_dev->pdata, sizeof(txbuf), txbuf, rxbuf); if (ret) cts_err("disable drw ret=%d", ret); return ret; } #endif int cts_enter_program_mode(struct cts_device *cts_dev) { const static u8 magic_num[] = { 0xCC, 0x33, 0x55, 0x5A }; u8 boot_mode; int ret; cts_info("Enter program mode"); if (cts_dev->rtdata.program_mode) { cts_warn("Enter program mode while alredy in"); /* return 0; */ } #ifdef CONFIG_CTS_I2C_HOST ret = cts_plat_i2c_write(cts_dev->pdata, CTS_DEV_PROGRAM_MODE_I2CADDR, magic_num, 4, 5, 10); if (ret) { cts_err("Write magic number to i2c_dev: 0x%02x failed %d", CTS_DEV_PROGRAM_MODE_I2CADDR, ret); return ret; } cts_set_program_addr(cts_dev); /* Write i2c deglitch register */ ret = cts_hw_reg_writeb_retry(cts_dev, CTS_DEV_HW_REG_I2C_CFG, 0x0F, 5, 1); if (ret) cts_err("Write i2c deglitch register failed\n"); #else cts_set_program_addr(cts_dev); ret = cts_spi_send_recv(cts_dev->pdata, sizeof(magic_num), (u8 *)magic_num, NULL); if (ret) { cts_err("Write magic number to i2c_dev: 0x%02x failed %d", CTS_DEV_PROGRAM_MODE_SPIADDR, ret); return ret; } #endif /* CONFIG_CTS_I2C_HOST */ cts_dev->rtdata.program_mode = true; mdelay(5); #ifdef FIX_DEFAULT_ENABLE_DRW cts_disable_drw(cts_dev); #endif ret = cts_get_dev_boot_mode(cts_dev, &boot_mode); if (ret) { cts_err("Read BOOT_MODE failed %d", ret); return ret; } /* Note: the following CTS_DEV_BOOT_MODE_TCH_PRG_9916 is used by both ICNL9916 and ICNL9916C */ #ifdef CONFIG_CTS_I2C_HOST if ((boot_mode == CTS_DEV_BOOT_MODE_TCH_PRG_9916) || (boot_mode == CTS_DEV_BOOT_MODE_I2C_PRG_9911C)) #else if ((boot_mode == CTS_DEV_BOOT_MODE_TCH_PRG_9916) || (boot_mode == CTS_DEV_BOOT_MODE_SPI_PRG_9911C)) #endif { return 0; } cts_err("BOOT_MODE readback %u != I2C/SPI PROMGRAM mode", boot_mode); return -EFAULT; } const char *cts_dev_boot_mode2str(u8 boot_mode) { switch (boot_mode) { case CTS_DEV_BOOT_MODE_IDLE: return "IDLE-BOOT"; case CTS_DEV_BOOT_MODE_FLASH: return "FLASH-BOOT"; case CTS_DEV_BOOT_MODE_SRAM: return "SRAM-BOOT"; /* case CTS_DEV_BOOT_MODE_I2C_PRG_9911C: */ case CTS_DEV_BOOT_MODE_TCH_PRG_9916: return "I2C-PRG-BOOT/TCH-PRG-BOOT"; case CTS_DEV_BOOT_MODE_DDI_PRG: return "DDI-PRG-BOOT"; case CTS_DEV_BOOT_MODE_SPI_PRG_9911C: return "SPI-PROG-BOOT/INVALID-BOOT"; default: return "INVALID"; } } int cts_enter_normal_mode(struct cts_device *cts_dev) { int ret = 0; u8 boot_mode; int retries; u16 fwid = CTS_DEV_FWID_INVALID; u8 auto_boot = 0; u8 first_boot = 1; cts_info("Enter normal mode"); if (!cts_dev->rtdata.program_mode) { cts_warn("Enter normal mode while already in"); return 0; } if (cts_dev->rtdata.has_flash) auto_boot = 1; #ifdef CFG_CTS_UPDATE_CRCCHECK auto_boot = 1; #endif for (retries = 5; retries >= 0; retries--) { if (first_boot == 1 || auto_boot == 0) { cts_set_program_addr(cts_dev); ret = cts_set_dev_boot_mode(cts_dev, CTS_DEV_BOOT_MODE_SRAM); if (ret) { cts_err("Set BOOT_MODE to SRAM failed %d," "try to reset device", ret); } mdelay(30); } first_boot = 0; cts_set_normal_addr(cts_dev); ret = cts_get_dev_boot_mode(cts_dev, &boot_mode); if (ret) cts_err("Get BOOT_MODE failed %d", ret); if (boot_mode != CTS_DEV_BOOT_MODE_SRAM) cts_err("Curr boot mode %u(%s) != SRAM_BOOT", boot_mode, cts_dev_boot_mode2str(boot_mode)); else break; ret = cts_tcs_get_fw_id(cts_dev, &fwid); if (ret) cts_err("Get firmware id failed %d, retries %d", ret, retries); else { cts_info("Get firmware id: 0x%02x", fwid); break; } cts_reset_device(cts_dev); } if (retries >= 0) { ret = cts_init_fwdata(cts_dev); if (ret) { cts_err("Device init firmware data failed %d", ret); return ret; } return 0; } cts_set_program_addr(cts_dev); return ret; } bool cts_is_device_enabled(const struct cts_device *cts_dev) { return cts_dev->enabled; } int cts_start_device(struct cts_device *cts_dev) { #if defined(CONFIG_CTS_ESD_PROTECTION) || \ defined(CONFIG_CTS_CHARGER_DETECT) || \ defined(CONFIG_CTS_EARJACK_DETECT) struct chipone_ts_data *cts_data = container_of(cts_dev, struct chipone_ts_data, cts_dev); #endif int ret; cts_info("Start device..."); if (cts_is_device_enabled(cts_dev)) { cts_warn("Start device while already started"); return 0; } #ifdef CFG_CTS_HEARTBEAT_MECHANISM cts_enable_heartbeat_mechanism(cts_data); #endif #ifdef CONFIG_CTS_ESD_PROTECTION cts_enable_esd_protection(cts_data); #endif #ifdef CONFIG_CTS_CHARGER_DETECT cts_start_charger_detect(cts_data); #endif #ifdef CONFIG_CTS_EARJACK_DETECT cts_start_earjack_detect(cts_data); #endif ret = cts_plat_enable_irq(cts_dev->pdata); if (ret < 0) { cts_err("Enable IRQ failed %d", ret); return ret; } cts_dev->enabled = true; cts_info("Start device successfully"); return 0; } int cts_stop_device(struct cts_device *cts_dev) { struct chipone_ts_data *cts_data = container_of(cts_dev, struct chipone_ts_data, cts_dev); int ret; cts_info("Stop device..."); if (!cts_is_device_enabled(cts_dev)) { cts_warn("Stop device while halted"); return 0; } if (cts_is_firmware_updating(cts_dev)) { cts_warn("Stop device while firmware updating, please try again"); return -EAGAIN; } ret = cts_plat_disable_irq(cts_dev->pdata); if (ret < 0) { cts_err("Disable IRQ failed %d", ret); return ret; } cts_dev->enabled = false; #ifdef CFG_CTS_HEARTBEAT_MECHANISM cts_disable_heartbeat_mechanism(cts_data); #endif #ifdef CONFIG_CTS_ESD_PROTECTION cts_disable_esd_protection(cts_data); #endif #ifdef CONFIG_CTS_CHARGER_DETECT cts_stop_charger_detect(cts_data); #endif #ifdef CONFIG_CTS_EARJACK_DETECT cts_stop_earjack_detect(cts_data); #endif #ifndef CONFIG_GENERIC_HARDIRQS if (work_pending(&cts_data->pdata->ts_irq_work)) { cts_warn("IRQ work is pending .... flush it"); flush_work(&cts_data->pdata->ts_irq_work); } else cts_info("None IRQ work is pending"); #endif cts_info("Flush workqueue..."); if (!cts_dev->rtdata.update_work_run) flush_workqueue(cts_data->workqueue); ret = cts_plat_release_all_touch(cts_dev->pdata); if (ret) { cts_err("Release all touch failed %d", ret); return ret; } #ifdef CONFIG_CTS_VIRTUALKEY ret = cts_plat_release_all_vkey(cts_dev->pdata); if (ret) { cts_err("Release all vkey failed %d", ret); return ret; } #endif return 0; } #ifdef CONFIG_CTS_ESD_PROTECTION int cts_start_device_esdrecover(struct cts_device *cts_dev) { int ret; cts_info("Start device..."); if (cts_is_device_enabled(cts_dev)) { cts_warn("Start device while already started"); return 0; } ret = cts_plat_enable_irq(cts_dev->pdata); if (ret < 0) { cts_err("Enable IRQ failed %d", ret); return ret; } cts_dev->enabled = true; cts_info("Start device successfully"); return 0; } int cts_stop_device_esdrecover(struct cts_device *cts_dev) { struct chipone_ts_data *cts_data = container_of(cts_dev, struct chipone_ts_data, cts_dev); int ret; cts_info("Stop device..."); if (!cts_is_device_enabled(cts_dev)) { cts_warn("Stop device while halted"); return 0; } if (cts_is_firmware_updating(cts_dev)) { cts_warn("Stop device while firmware updating, please try again"); return -EAGAIN; } ret = cts_plat_disable_irq(cts_dev->pdata); if (ret < 0) { cts_err("Disable IRQ failed %d", ret); return ret; } cts_dev->enabled = false; flush_workqueue(cts_data->workqueue); ret = cts_plat_release_all_touch(cts_dev->pdata); if (ret) { cts_err("Release all touch failed %d", ret); return ret; } #ifdef CONFIG_CTS_VIRTUALKEY ret = cts_plat_release_all_vkey(cts_dev->pdata); if (ret) { cts_err("Release all vkey failed %d", ret); return ret; } #endif /* CONFIG_CTS_VIRTUALKEY */ return 0; } #endif bool cts_is_fwid_valid(u16 fwid) { int i; for (i = 0; i < ARRAY_SIZE(cts_device_hwdatas); i++) { if (cts_device_hwdatas[i].fwid == fwid) return true; } return true; } static bool cts_is_hwid_valid(u32 hwid) { int i; for (i = 0; i < ARRAY_SIZE(cts_device_hwdatas); i++) { if (cts_device_hwdatas[i].hwid == hwid) return true; } return false; } int cts_get_hwid(struct cts_device *cts_dev, u32 *hwid) { int ret; cts_info("Get device hardware id"); if (cts_dev->hwdata) { *hwid = cts_dev->hwdata->hwid; return 0; } cts_info("Device hardware data not initialized, try to read from register"); if (!cts_dev->rtdata.program_mode) { ret = cts_enter_program_mode(cts_dev); if (ret) { cts_err("Enter program mode failed %d", ret); goto err_out; } } ret = cts_hw_reg_readl_retry(cts_dev, CTS_DEV_HW_REG_HARDWARE_ID, hwid, 5, 0); if (ret) goto err_out; *hwid = le32_to_cpu(*hwid); *hwid &= 0XFFFFFFF0; cts_info("Device hardware id: %04x", *hwid); if (!cts_is_hwid_valid(*hwid)) { cts_warn("Device hardware id %04x invalid", *hwid); ret = -EINVAL; goto err_out; } return 0; err_out: *hwid = CTS_DEV_HWID_INVALID; return ret; } int cts_probe_device(struct cts_device *cts_dev) { int ret, retries = 0; u16 fwid = CTS_DEV_FWID_INVALID; u32 hwid = CTS_DEV_HWID_INVALID; cts_dev->fwdata.version = 0; cts_info("Probe device"); cts_init_rtdata_with_normal_mode(cts_dev); if (!cts_plat_is_normal_mode(cts_dev->pdata)) { cts_warn("Normal mode spi addr is offline"); } /* else { ret = cts_tcs_get_fw_id(cts_dev, &fwid); if (ret) { cts_err("Get firmware id failed %d", ret); } else { cts_info("Firmware id: 0x%04x", fwid); ret = cts_tcs_get_fw_ver(cts_dev, &cts_dev->fwdata.version); if (ret) { cts_err("Read firmware version failed %d", ret); cts_dev->fwdata.version = 0; } else { cts_info("Firmware version: 0x%04x", cts_dev->fwdata.version); } goto init_hwdata; } } */ read_hwid: ret = cts_get_hwid(cts_dev, &hwid); if (ret || hwid == CTS_DEV_HWID_INVALID) { retries++; cts_err("Get hardware id failed %d retries %d", ret, retries); if (retries < 3) { cts_reset_device(cts_dev); goto read_hwid; } else return -ENODEV; } //init_hwdata: ret = cts_init_device_hwdata(cts_dev, hwid, fwid); if (ret) { cts_err("Device hwid: %06x fwid: %04x not found", hwid, fwid); return -ENODEV; } cts_info("Touch info size:%zu", sizeof(struct cts_device_touch_info)); return ret; } #ifdef CFG_CTS_GESTURE void cts_enable_gesture_wakeup(struct cts_device *cts_dev) { cts_info("Enable gesture wakeup"); cts_dev->rtdata.gesture_wakeup_enabled = true; } void cts_disable_gesture_wakeup(struct cts_device *cts_dev) { cts_info("Disable gesture wakeup"); cts_dev->rtdata.gesture_wakeup_enabled = false; } bool cts_is_gesture_wakeup_enabled(const struct cts_device *cts_dev) { return cts_dev->rtdata.gesture_wakeup_enabled; } int cts_get_gesture_info(struct cts_device *cts_dev, void *gesture_info) { int ret; cts_info("Get gesture info"); if (cts_dev->rtdata.program_mode) { cts_warn("Get gesture info in program mode"); return -ENODEV; } if (!cts_dev->rtdata.suspended) { cts_warn("Get gesture info while not suspended"); return -ENODEV; } if (!cts_dev->rtdata.gesture_wakeup_enabled) { cts_warn("Get gesture info while gesture wakeup not enabled"); return -ENODEV; } ret = cts_tcs_get_gestureinfo(cts_dev, gesture_info); if (ret) { cts_err("Read gesture info header failed %d", ret); return ret; } return 0; } #endif /* CFG_CTS_GESTURE */ int cts_set_int_data_types(struct cts_device *cts_dev, u16 types) { int ret; u16 realtypes = types & INT_DATA_TYPE_MASK; cts_info("Set int data types: %#06x, mask to %#06x", types, realtypes); ret = cts_tcs_set_int_data_types(cts_dev, realtypes); if (ret) { cts_err("Set int data type failed: %d", ret); return -EIO; } cts_dev->fwdata.int_data_types = realtypes; cts_tcs_calc_int_data_size(cts_dev); return ret; } int cts_set_int_data_method(struct cts_device *cts_dev, u8 method) { int ret = 0; cts_info("Set int data method: %d", method); if (method >= INT_DATA_METHOD_CNT) { cts_err("Invalid int data method"); return -EINVAL; } ret = cts_tcs_set_int_data_method(cts_dev, method); if (ret) { cts_err("Set int data method failed: %d", ret); return -EIO; } cts_dev->fwdata.int_data_method = method; cts_tcs_calc_int_data_size(cts_dev); return ret; } #ifdef CONFIG_CTS_ESD_PROTECTION static void cts_esd_protection_work(struct work_struct *work) { struct chipone_ts_data *cts_data; int ret = 0; cts_dbg("ESD protection work"); cts_data = container_of(work, struct chipone_ts_data, esd_work.work); cts_lock_device(&cts_data->cts_dev); if (!cts_plat_is_normal_mode(cts_data->pdata)) { cts_data->esd_check_fail_cnt++; /*reset chip next time */ if ((cts_data->esd_check_fail_cnt % 2) == 0) { cts_err("ESD protection read normal mode failed, reset chip!"); ret = cts_reset_device(&cts_data->cts_dev); if (ret) cts_err("ESD protection reset chip failed %d", ret); } } else { cts_data->esd_check_fail_cnt = 0; } if (cts_data->esd_check_fail_cnt >= CFG_CTS_ESD_FAILED_CONFIRM_CNT) { const struct cts_firmware *firmware; cts_warn("ESD protection check failed, update firmware!!!"); cts_stop_device_esdrecover(&cts_data->cts_dev); firmware = cts_request_firmware(&cts_data->cts_dev, cts_data->cts_dev.hwdata->hwid, cts_data->cts_dev.hwdata->fwid, 0); if (firmware) { ret = cts_update_firmware(&cts_data->cts_dev, firmware, false); cts_release_firmware(firmware); if (ret) cts_err("Update default firmware failed %d", ret); } else cts_err("Request default firmware failed %d, " "please update manually!!", ret); cts_start_device_esdrecover(&cts_data->cts_dev); cts_data->esd_check_fail_cnt = 0; } queue_delayed_work(cts_data->esd_workqueue, &cts_data->esd_work, CFG_CTS_ESD_PROTECTION_CHECK_PERIOD); cts_unlock_device(&cts_data->cts_dev); } void cts_enable_esd_protection(struct chipone_ts_data *cts_data) { if (cts_data->esd_workqueue && !cts_data->esd_enabled) { cts_info("ESD protection enable"); cts_data->esd_enabled = true; cts_data->esd_check_fail_cnt = 0; queue_delayed_work(cts_data->esd_workqueue, &cts_data->esd_work, CFG_CTS_ESD_PROTECTION_CHECK_PERIOD); } } void cts_disable_esd_protection(struct chipone_ts_data *cts_data) { if (cts_data->esd_workqueue && cts_data->esd_enabled) { cts_info("ESD protection disable"); cts_data->esd_enabled = false; cancel_delayed_work(&cts_data->esd_work); flush_workqueue(cts_data->esd_workqueue); } } void cts_init_esd_protection(struct chipone_ts_data *cts_data) { cts_info("Init ESD protection"); INIT_DELAYED_WORK(&cts_data->esd_work, cts_esd_protection_work); cts_data->esd_enabled = false; cts_data->esd_check_fail_cnt = 0; } void cts_deinit_esd_protection(struct chipone_ts_data *cts_data) { cts_info("De-Init ESD protection"); if (cts_data->esd_workqueue && cts_data->esd_enabled) { cts_data->esd_enabled = false; cancel_delayed_work(&cts_data->esd_work); } } #endif /* CONFIG_CTS_ESD_PROTECTION */ #ifdef CFG_CTS_HEARTBEAT_MECHANISM void cts_show_touch_debug_msg(void *debug) { struct cts_touch_debug_msg *msg = (struct cts_touch_debug_msg *)debug; struct cts_firmware_status *status = (struct cts_firmware_status *) &msg->firmware_status; cts_info("FW_Ver : 0x%02X", msg->fw_version); cts_info("Reset_Flag : 0x%08X", msg->reset_flag); cts_info("Charger : %d", status->charger); cts_info("Proxmty : %d", status->proximity); cts_info("Earjack : %d", status->earjack); cts_info("Knuckle : %d", status->knuckle); cts_info("Glove : %d", status->glove); cts_info("Pocket : %d", status->pocket); cts_info("Game : %d", status->game); cts_info("High_Temp : %d", status->high_temperature); cts_info("Low_Temp : %d", status->low_temperature); cts_info("Bend : %d", status->bend_mode); cts_info("Palm : %d", status->palm_status); cts_info("Noise : %d", status->noise_mode); cts_info("Base_Trace : %d", status->base_trace); cts_info("Water : %d", status->water_mode); cts_info("Ground : %d", status->ground); cts_info("Proxmity_Sts: 0x%02x", msg->proximity); cts_info("Work_Mode : %d", msg->work_mode); cts_info("Power_Mode : %d", msg->power_mode); cts_info("Freq : %d", msg->curr_freq); cts_info("Esd_0a : %d", msg->esd_0a_status); cts_info("Fw_Esd : %d", msg->fw_esd_status); cts_info("Landscape : %d", msg->landscape_mode); cts_info("Freq_Noise : %d", msg->curr_freq_noise); cts_info("Max_Diff : %d", msg->max_diff); cts_info("Row : %d", msg->max_diff_row); cts_info("Col : %d", msg->max_diff_col); cts_info("Max_Neg : -%d", msg->max_neg_diff); cts_info("Neg_Row : %d", msg->max_neg_diff_row); cts_info("Neg_Col : %d", msg->max_neg_diff_col); } void cts_heartbeat_mechanism_work(struct work_struct *work) { struct chipone_ts_data *cts_data; struct cts_device *cts_dev; struct cts_device_touch_info info; const struct cts_firmware *firmware; u8 curr_status; int ret = 0; cts_data = container_of(work, struct chipone_ts_data, heart_work.work); cts_dev = &cts_data->cts_dev; cts_dbg("heartbeat mechanism work"); cts_lock_device(cts_dev); ret = cts_tcs_get_touch_status(cts_dev); if (ret) { cts_err("get touch status failed"); cts_reset_device(cts_dev); if (++cts_dev->rtdata.esd_count < 3) goto end; firmware = cts_request_firmware(cts_dev, cts_dev->hwdata->hwid, cts_dev->hwdata->fwid, 0); if (firmware) { ret = cts_update_firmware(&cts_data->cts_dev, firmware, false); if (ret) cts_err("Update default firmware failed %d", ret); cts_release_firmware(firmware); } cts_tcs_reinit_fw_status(cts_dev); goto end; } memcpy(&info, cts_dev->int_data, sizeof(info)); curr_status = info.debug_msg.firmware_status; cts_dev->rtdata.esd_count = 0; /* 9922C reset_flag:0xFFFFFF; 9922 9916 9916C reset_flag:0xFFFF */ if ((info.debug_msg.reset_flag & 0xFFFFFF) != 0xFFFFFF || (info.debug_msg.reset_flag & 0xFFFF) != 0xFFFF) { cts_err("heartbeat reset flag:0x%08x error", info.debug_msg.reset_flag); cts_show_touch_debug_msg(&info.debug_msg); } if (curr_status != cts_dev->rtdata.firmware_status) { cts_err("firmware status error"); cts_show_touch_debug_msg(&info.debug_msg); cts_tcs_reinit_fw_status(cts_dev); } end: queue_delayed_work(cts_data->heart_workqueue, &cts_data->heart_work, msecs_to_jiffies(2000)); cts_unlock_device(cts_dev); } void cts_enable_heartbeat_mechanism(struct chipone_ts_data *cts_data) { queue_delayed_work(cts_data->heart_workqueue, &cts_data->heart_work, msecs_to_jiffies(2000)); } void cts_disable_heartbeat_mechanism(struct chipone_ts_data *cts_data) { cancel_delayed_work_sync(&cts_data->heart_work); } #endif #ifdef CONFIG_CTS_GLOVE int cts_enter_glove_mode(const struct cts_device *cts_dev) { int ret; cts_info("Enter glove mode"); ret = cts_tcs_set_glove_mode(cts_dev, 1); if (ret) cts_err("Enable Glove mode err"); else cts_dev->rtdata.glove_mode_enabled = true; return ret; } int cts_exit_glove_mode(const struct cts_device *cts_dev) { cts_info("Exit glove mode"); ret = cts_tcs_set_glove_mode(cts_dev, 0); if (ret) cts_err("Exit Glove mode err"); else cts_dev->rtdata.glove_mode_enabled = false; return ret; } int cts_is_glove_enabled(const struct cts_device *cts_dev) { return cts_dev->rtdata.glove_mode_enabled; } #endif /* CONFIG_CTS_GLOVE */ #ifdef CONFIG_CTS_CHARGER_DETECT bool cts_is_charger_exist(struct cts_device *cts_dev) { struct chipone_ts_data *cts_data; bool attached = false; int ret; cts_data = container_of(cts_dev, struct chipone_ts_data, cts_dev); ret = cts_is_charger_attached(cts_data, &attached); if (ret) cts_err("Get charger state failed %d", ret); cts_dev->rtdata.charger_exist = attached; return attached; } int cts_set_dev_charger_attached(struct cts_device *cts_dev, bool attached) { int ret; u8 buf; cts_info("Set dev charger %s", attached ? "ATTACHED" : "DETATCHED"); buf = attached ? 1 : 0; ret = cts_tcs_set_charger_plug(cts_dev, buf); if (ret) cts_err("Set failed %d", ret); return ret; } #endif /* CONFIG_CTS_CHARGER_DETECT */ #ifdef CONFIG_CTS_EARJACK_DETECT bool cts_is_earjack_exist(struct cts_device *cts_dev) { struct chipone_ts_data *cts_data; bool attached = false; int ret; cts_data = container_of(cts_dev, struct chipone_ts_data, cts_dev); ret = cts_is_earjack_attached(cts_data, &attached); if (ret) { cts_err("Get earjack state failed %d", ret); } return attached; } int cts_set_dev_earjack_attached(struct cts_device *cts_dev, bool attached) { int ret; u8 buf; cts_info("Set dev earjack %s", attached ? "ATTACHED" : "DETATCHED"); buf = attached ? 1 : 0; ret = cts_tcs_set_earjack_plug(cts_dev, buf); if (ret) cts_err("Set failed %d", ret); return ret; } #endif /* CONFIG_CTS_EARJACK_DETECT */ int cts_enable_fw_log_redirect(struct cts_device *cts_dev) { int ret; cts_info("Fw log redirect enable"); ret = cts_send_command(cts_dev, CTS_CMD_ENABLE_FW_LOG_REDIRECT); if (ret) cts_err("Send CTS_CMD_ENABLE_FW_LOG_REDIRECT failed %d", ret); else cts_dev->rtdata.fw_log_redirect_enabled = true; return 0; } int cts_disable_fw_log_redirect(struct cts_device *cts_dev) { int ret; cts_info("Fw log redirect disable"); ret = cts_send_command(cts_dev, CTS_CMD_DISABLE_FW_LOG_REDIRECT); if (ret) cts_err("Send CTS_CMD_DISABLE_FW_LOG_REDIRECT failed %d", ret); else cts_dev->rtdata.fw_log_redirect_enabled = false; return 0; } bool cts_is_fw_log_redirect(struct cts_device *cts_dev) { return cts_dev->rtdata.fw_log_redirect_enabled; } int cts_fw_log_show_finish(struct cts_device *cts_dev) { int ret; ret = cts_send_command(cts_dev, CTS_CMD_FW_LOG_SHOW_FINISH); if (ret) cts_err("Send CTS_CMD_FW_LOG_SHOW_FINISH failed %d", ret); return ret; } void cts_firmware_upgrade_work(struct work_struct *work) { struct chipone_ts_data *cts_data; struct cts_device *cts_dev; const struct cts_firmware *firmware; int retries; int ret = 0; cts_info("Firmware upgrade work"); cts_data = container_of(work, struct chipone_ts_data, fw_upgrade_work.work); cts_dev = &cts_data->cts_dev; cts_lock_device(cts_dev); cts_dev->rtdata.update_work_run = true; firmware = cts_request_firmware(cts_dev, cts_dev->hwdata->hwid, CTS_DEV_FWID_ANY, cts_dev->fwdata.version); if (firmware == NULL) { cts_warn("Request firmware failed"); /* With flash, do not update. */ cts_set_program_addr(cts_dev); cts_enter_normal_mode(cts_dev); goto end; } retries = 0; do { ret = cts_update_firmware(cts_dev, firmware, false); if (ret) { cts_err("Update firmware failed times: %d", retries); cts_reset_device(cts_dev); } else break; } while (++retries < 3); cts_release_firmware(firmware); end: if (ret == 0) cts_start_device(cts_dev); cts_dev->rtdata.update_work_run = false; cts_unlock_device(cts_dev); } int cts_reset_device(struct cts_device *cts_dev) { cts_info("Reset device"); return cts_tcs_reset_device(cts_dev); } static struct file *cts_log_filp; static int cts_log_to_file_level; extern int cts_write_file(struct file *filp, const void *data, size_t size); static char *cts_log_buffer; static int cts_log_buf_size; static int cts_log_buf_wr_size; static bool cts_log_redirect; extern int cts_mkdir_for_file(const char *filepath, umode_t mode); int cts_start_driver_log_redirect(const char *filepath, bool append_to_file, char *log_buffer, int log_buf_size, int log_level) { #define START_BANNER \ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" int ret = 0; cts_info("Start driver log redirect"); cts_log_to_file_level = log_level; if (log_buffer && log_buf_size) { cts_info(" - Start driver log to buffer: %p size: %d level: %d", log_buffer, log_buf_size, log_level); cts_log_buffer = log_buffer; cts_log_buf_size = log_buf_size; cts_log_buf_wr_size = 0; } if (filepath && filepath[0]) { cts_info(" - Start driver log to file : '%s' level: %d", filepath, log_level); #ifdef CFG_CTS_FOR_GKI cts_info("%s(): filp_open is forbiddon with GKI Version!", __func__); #else cts_log_filp = filp_open(filepath, O_WRONLY | O_CREAT | (append_to_file ? O_APPEND : O_TRUNC), S_IRUGO | S_IWUGO); if (IS_ERR(cts_log_filp)) { ret = PTR_ERR(cts_log_filp); cts_log_filp = NULL; cts_err("Open file '%s' for driver log failed %d", filepath, ret); } else { cts_write_file(cts_log_filp, START_BANNER, strlen(START_BANNER)); } #endif } cts_log_redirect = true; return ret; #undef START_BANNER } void cts_stop_driver_log_redirect(void) { #define END_BANNER \ "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" #ifndef CFG_CTS_FOR_GKI int ret; #endif cts_log_redirect = false; cts_info("Stop driver log redirect"); if (cts_log_filp) { cts_info(" - Stop driver log to file"); cts_write_file(cts_log_filp, END_BANNER, strlen(END_BANNER)); #ifndef CFG_CTS_FOR_GKI ret = filp_close(cts_log_filp, NULL); if (ret) { cts_err("Close driver log file failed %d", ret); } #endif cts_log_filp = NULL; } if (cts_log_buffer) { cts_info(" - Stop driver log to buffer"); cts_log_buffer = NULL; cts_log_buf_size = 0; cts_log_buf_wr_size = 0; } #undef END_BANNER } int cts_get_driver_log_redirect_size(void) { if (cts_log_redirect && cts_log_buffer && cts_log_buf_wr_size) { return cts_log_buf_wr_size; } else { return 0; } } void cts_log(int level, const char *fmt, ...) { va_list args; va_start(args, fmt); if (cts_log_redirect) { if (cts_log_buffer && cts_log_buf_wr_size < cts_log_buf_size && level <= cts_log_to_file_level) { cts_log_buf_wr_size += vscnprintf(cts_log_buffer + cts_log_buf_wr_size, cts_log_buf_size - cts_log_buf_wr_size, fmt, args); } if (cts_log_filp != NULL && level <= cts_log_to_file_level) { char buf[512]; int count = vscnprintf(buf, sizeof(buf), fmt, args); cts_write_file(cts_log_filp, buf, count); } } if (level < CTS_DRIVER_LOG_DEBUG || cts_show_debug_log) { vprintk(fmt, args); } va_end(args); } #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) /* From lib/kstrtox.c */ /** * kstrtobool - convert common user inputs into boolean values * @s: input string * @res: result * * This routine returns 0 iff the first character is one of 'Yy1Nn0', or * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value * pointed to by res is updated upon finding a match. */ int kstrtobool(const char *s, bool *res) { if (!s) return -EINVAL; switch (s[0]) { case 'y': case 'Y': case '1': *res = true; return 0; case 'n': case 'N': case '0': *res = false; return 0; case 'o': case 'O': switch (s[1]) { case 'n': case 'N': *res = true; return 0; case 'f': case 'F': *res = false; return 0; default: break; } default: break; } return -EINVAL; } #endif