drivers/input/touchscreen/siw/siw_touch_hal.c (5,769 lines of code) (raw):

/* * siw_touch_hal.c - SiW touch hal driver * * Copyright (C) 2016 Silicon Works - http://www.siliconworks.co.kr * Author: Hyunho Kim <kimhh@siliconworks.co.kr> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/types.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/async.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/input.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/irqreturn.h> #include <linux/slab.h> #include <linux/pm.h> #include <linux/gpio.h> #include <linux/string.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_device.h> #include <linux/firmware.h> #include <asm/page.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/memory.h> #include "siw_touch.h" #include "siw_touch_hal.h" #include "siw_touch_bus.h" #include "siw_touch_event.h" #include "siw_touch_gpio.h" #include "siw_touch_irq.h" #include "siw_touch_sys.h" #ifndef __weak #define __weak __attribute__((weak)) #endif //#define __FW_VERIFY_TEST /* undefine __SIW_CONFIG_FB so that we can use primary suspend/resume */ #undef __SIW_CONFIG_FB enum { LPWG_SET_SKIP = -1, }; struct lpwg_mode_ctrl { int clk; int qcover; int lpwg; int lcd; }; extern int siw_hal_sysfs(struct device *dev, int on_off); /* * weak(dummy) function for ABT control * These are deactivated by enabling __SIW_SUPPORT_ABT * and the actual functions can be found in siw_touch_hal_abt.c */ int __weak siw_hal_abt_init(struct device *dev) { t_dev_warn(dev, "ABT disabled\n"); return 0; } int __weak siw_hal_abt_sysfs(struct device *dev, int on_off) { t_dev_warn(dev, "ABT disabled\n"); return 0; } /* * weak(dummy) function for PRD control * These are deactivated by enabling __SIW_SUPPORT_PRD * and the actual functions can be found in siw_touch_hal_prd.c */ int __weak siw_hal_prd_sysfs(struct device *dev, int on_off) { t_dev_warn(dev, "PRD disabled\n"); return 0; } #if defined(__SIW_SUPPORT_WATCH) #define t_warn_weak_watch(_dev, fmt, args...) \ t_dev_warn(_dev, "Watch disabled: "fmt, ##args) #else #define t_warn_weak_watch(_dev, fmt, args...) do { }while(0) #endif /* * weak(dummy) function for Watch control * These are deactivated by enabling __SIW_SUPPORT_WATCH * and the actual functions can be found in siw_touch_hal_watch.c */ int __weak siw_hal_watch_sysfs(struct device *dev, int on_off) { t_warn_weak_watch(dev, "%s\n", __func__); return 0; } int __weak siw_hal_watch_init(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); return 0; } int __weak siw_hal_watch_chk_font_status(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); return 0; } int __weak siw_hal_watch_get_curr_time(struct device *dev, char *buf, int *len) { t_warn_weak_watch(dev, "%s\n", __func__); return 0; } int __weak siw_hal_watch_display_off(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); return 0; } int __weak siw_hal_watch_is_disp_waton(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); return 0; } int __weak siw_hal_watch_is_rtc_run(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); return 0; } void __weak siw_hal_watch_set_rtc_run(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); } void __weak siw_hal_watch_set_rtc_clear(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); } void __weak siw_hal_watch_set_font_empty(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); } void __weak siw_hal_watch_set_cfg_blocked(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); } void __weak siw_hal_watch_rtc_on(struct device *dev) { t_warn_weak_watch(dev, "%s\n", __func__); } static int siw_hal_reset_ctrl(struct device *dev, int ctrl); static int siw_hal_tc_driving(struct device *dev, int mode); #define t_hal_bus_info(_dev, fmt, args...) \ __t_dev_info(_dev, "hal(bus) : " fmt, ##args) #define t_hal_bus_err(_dev, fmt, args...) \ __t_dev_err(_dev, "hal(bus) : " fmt, ##args) #define t_hal_bus_warn(_abt, fmt, args...) \ __t_dev_warn(_dev, "hal(bus) : " fmt, ##args) #if defined(__SIW_CONFIG_KNOCK) #define TCI_FAIL_NUM 11 static const char const *siw_hal_tci_debug_str[TCI_FAIL_NUM] = { "NONE", "DISTANCE_INTER_TAP", "DISTANCE_TOUCHSLOP", "TIMEOUT_INTER_TAP_LONG", "MULTI_FINGER", "DELAY_TIME",/* It means Over Tap */ "TIMEOUT_INTER_TAP_SHORT", "PALM_STATE", "TAP_TIMEOVER", "DEBUG9", "DEBUG10" }; #endif /* __SIW_CONFIG_KNOCK */ #if defined(__SIW_CONFIG_SWIPE) #define SWIPE_FAIL_NUM 7 static const char const *siw_hal_swipe_debug_str[SWIPE_FAIL_NUM] = { "ERROR", "1FINGER_FAST_RELEASE", "MULTI_FINGER", "FAST_SWIPE", "SLOW_SWIPE", "OUT_OF_AREA", "RATIO_FAIL", }; #endif /* __SIW_CONFIG_SWIPE */ static void siw_hal_deep_sleep(struct device *dev); static int siw_hal_lpwg_mode(struct device *dev); static void siw_hal_power_init(struct device *dev) { siw_touch_power_init(dev); } static void siw_hal_power_free(struct device *dev) { siw_touch_power_free(dev); } static void siw_hal_power_vdd(struct device *dev, int value) { siw_touch_power_vdd(dev, value); } static void siw_hal_power_vio(struct device *dev, int value) { siw_touch_power_vio(dev, value); } #define SIW_HAL_GPIO_RST "siw_hal_reset" #define SIW_HAL_GPIO_IRQ "siw_hal_irq" #define SIW_HAL_GPIO_MAKER "siw_hal_maker_id" static int __siw_hal_gpio_skip_reset(struct siw_ts *ts) { struct device *dev = ts->dev; int reset_pin = touch_reset_pin(ts); if (touch_flags(ts) & TOUCH_SKIP_RESET_PIN) { return 1; } if (!gpio_is_valid(reset_pin)) { t_dev_err(dev, "reset_pin invalid, %d\n", reset_pin); return 1; } return 0; } static void siw_hal_set_gpio_reset(struct device *dev, int val) { struct siw_ts *ts = to_touch_core(dev); int reset_pin = touch_reset_pin(ts); if (__siw_hal_gpio_skip_reset(ts)) { return; } siw_touch_gpio_direction_output(dev, reset_pin, !!(val)); t_dev_dbg_gpio(dev, "set %s(%d) : %d\n", SIW_HAL_GPIO_RST, reset_pin, !!(val)); } static void siw_hal_init_gpio_reset(struct device *dev) { struct siw_ts *ts = to_touch_core(dev); int reset_pin = touch_reset_pin(ts); int ret = 0; if (__siw_hal_gpio_skip_reset(ts)) { return; } ret = siw_touch_gpio_init(dev, reset_pin, SIW_HAL_GPIO_RST); if (ret) return; siw_touch_gpio_direction_output(dev, reset_pin, GPIO_OUT_ONE); t_dev_dbg_gpio(dev, "set %s(%d) as output\n", SIW_HAL_GPIO_RST, reset_pin); siw_touch_gpio_set_pull(dev, reset_pin, GPIO_PULL_UP); t_dev_dbg_gpio(dev, "set %s(%d) as pull-up(%d)\n", SIW_HAL_GPIO_RST, reset_pin, GPIO_NO_PULL); } static void siw_hal_trigger_gpio_reset(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; if (__siw_hal_gpio_skip_reset(ts)) { return; } siw_hal_set_gpio_reset(dev, GPIO_OUT_ZERO); touch_msleep(1 + hal_dbg_delay(chip, HAL_DBG_DLY_HW_RST_0)); siw_hal_set_gpio_reset(dev, GPIO_OUT_ONE); t_dev_info(dev, "trigger gpio reset\n"); } static void siw_hal_free_gpio_reset(struct device *dev) { struct siw_ts *ts = to_touch_core(dev); int reset_pin = touch_reset_pin(ts); if (__siw_hal_gpio_skip_reset(ts)) { return; } siw_touch_gpio_free(dev, reset_pin); } static int __siw_hal_gpio_skip_irq(struct siw_ts *ts) { struct device *dev = ts->dev; int irq_pin = touch_irq_pin(ts); if (!gpio_is_valid(irq_pin)) { t_dev_err(dev, "irq_pin inavlid, %d\n", irq_pin); return 1; } return 0; } static void siw_hal_init_gpio_irq(struct device *dev) { struct siw_ts *ts = to_touch_core(dev); int irq_pin = touch_irq_pin(ts); int ret = 0; if (__siw_hal_gpio_skip_irq(ts)) { return; } ret = siw_touch_gpio_init(dev, irq_pin, SIW_HAL_GPIO_IRQ); if (ret) return; siw_touch_gpio_direction_input(dev, irq_pin); t_dev_dbg_gpio(dev, "set %s(%d) as input\n", SIW_HAL_GPIO_IRQ, irq_pin); siw_touch_gpio_set_pull(dev, irq_pin, GPIO_PULL_UP); t_dev_dbg_gpio(dev, "set %s(%d) as pull-up(%d)\n", SIW_HAL_GPIO_IRQ, irq_pin, GPIO_PULL_UP); } static void siw_hal_free_gpio_irq(struct device *dev) { struct siw_ts *ts = to_touch_core(dev); int irq_pin = touch_irq_pin(ts); if (__siw_hal_gpio_skip_irq(ts)) { return; } siw_touch_gpio_free(dev, irq_pin); } static void siw_hal_init_gpio_maker_id(struct device *dev) { #if 0 struct siw_ts *ts = to_touch_core(dev); int maker_id_pin = touch_maker_id_pin(ts); int ret = 0; if (!gpio_is_valid(maker_id_pin)) { return; } ret = siw_touch_gpio_init(dev, maker_id_pin, SIW_HAL_GPIO_MAKER, ts->addr); if (ret) return; siw_touch_gpio_direction_input(dev, maker_id_pin); #endif } static void siw_hal_free_gpio_maker_id(struct device *dev) { #if 0 struct siw_ts *ts = to_touch_core(dev); int maker_id_pin = touch_maker_id_pin(ts); if (!gpio_is_valid(maker_id_pin)) { return; } siw_touch_gpio_free(dev, maker_id_pin); #endif } static void siw_hal_init_gpios(struct device *dev) { siw_hal_init_gpio_reset(dev); siw_hal_init_gpio_irq(dev); siw_hal_init_gpio_maker_id(dev); siw_hal_trigger_gpio_reset(dev); } static void siw_hal_free_gpios(struct device *dev) { siw_hal_free_gpio_reset(dev); siw_hal_free_gpio_irq(dev); siw_hal_free_gpio_maker_id(dev); } u32 t_bus_dbg_mask = 0; /* usage * (1) echo <value> > /sys/module/{Siw Touch Module Name}/parameters/bus_dbg_mask * (2) insmod {Siw Touch Module Name}.ko bus_dbg_mask=<value> */ module_param_named(bus_dbg_mask, t_bus_dbg_mask, uint, S_IRUGO|S_IWUSR|S_IWGRP); #if 1 #define t_bus_info(_dev, fmt, args...) __t_dev_info(_dev, "bus: " fmt, ##args) #define t_bus_warn(_dev, fmt, args...) __t_dev_warn(_dev, "bus: " fmt, ##args) #else #define t_bus_info(_dev, fmt, args...) __t_dev_none() #define t_bus_warn(_dev, fmt, args...) __t_dev_none() #endif #define t_bus_err(_dev, fmt, args...) __t_dev_err(_dev, "bus: " fmt, ##args) #define t_bus_dbg(condition, _dev, fmt, args...) \ do { \ if (unlikely(t_bus_dbg_mask & (condition))) \ __t_dev_info(_dev, "bus: " fmt, ##args); \ } while (0) #define t_bus_dbg_base(_dev, fmt, args...) \ t_bus_dbg(DBG_BASE, _dev, fmt, ##args) #define t_bus_dbg_trace(_dev, fmt, args...) \ t_bus_dbg(DBG_TRACE, _dev, fmt, ##args) static inline void __siw_hal_bus_dbg(struct device *dev, u32 addr, u8 *buf, int size, int wr, int xfer) { if (!wr && !xfer && (size == sizeof(struct siw_hal_touch_info))) { t_bus_dbg_trace(dev, "%s(%s) 0x%04X, 0x%04X: %02X %02X %02X %02X %02X %02X %02X %02X%s\n", (wr) ? "wr" : "rd", (xfer) ? "x" : "s", (u32)addr, (u32)size, buf[0], buf[1],buf[2], buf[3], buf[4], buf[5],buf[6], buf[7], (size > 8) ? " ..." : ""); return; } if (size > 4) { t_bus_dbg_base(dev, "%s(%s) 0x%04X, 0x%04X: %02X %02X %02X %02X %02X %02X %02X %02X%s\n", (wr) ? "wr" : "rd", (xfer) ? "x" : "s", (u32)addr, (u32)size, buf[0], buf[1],buf[2], buf[3], buf[4], buf[5],buf[6], buf[7], (size > 8) ? " ..." : ""); } else { t_bus_dbg_base(dev, "%s(%s) 0x%04X, 0x%04X: %02X %02X %02X %02X\n", (wr) ? "wr" : "rd", (xfer) ? "x" : "s", (u32)addr, (u32)size, buf[0], buf[1],buf[2], buf[3]); } } static void *__siw_hal_get_curr_buf(struct siw_ts *ts, dma_addr_t *dma, int tx) { struct siw_touch_buf *t_buf; int *idx; void *buf = NULL; idx = (tx) ? &ts->tx_buf_idx : &ts->rx_buf_idx; t_buf = (tx) ? &ts->tx_buf[(*idx)] : &ts->rx_buf[(*idx)]; buf = t_buf->buf; if (dma) *dma = t_buf->dma; (*idx)++; (*idx) %= SIW_TOUCH_MAX_BUF_IDX; return buf; } static int __used __siw_hal_do_reg_read(struct device *dev, u32 addr, void *data, int size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int bus_tx_hdr_size = touch_tx_hdr_size(ts); int bus_rx_hdr_size = touch_rx_hdr_size(ts); // int bus_tx_dummy_size = touch_tx_dummy_size(ts); int bus_rx_dummy_size = (touch_rx_dummy_size(ts) & 0xFFFF); int bus_rx_dummy_flag = (touch_rx_dummy_size(ts) >> 16); int bus_rd_hdr_flag = 0; struct touch_bus_msg _msg = {0, }; struct touch_bus_msg *msg = &_msg; int tx_size = bus_tx_hdr_size; u8 *tx_buf; u8 *rx_buf; dma_addr_t tx_dma; dma_addr_t rx_dma; int ret = 0; #if 0 if (!addr) { t_dev_err(dev, "NULL addr\n"); return -EFAULT; } #endif if (!data) { t_dev_err(dev, "NULL data(0x%04X, 0x%04X)\n", addr, size); return -EFAULT; } #if defined(__SIW_I2C_TYPE_1) if (touch_bus_type(ts) == BUS_IF_I2C) { struct siw_hal_reg *reg = chip->reg; /* * If 0x200 and burst, change to 0x201 * If 0x201, change to 0x202 */ if (addr == reg->tc_ic_status) { addr += !!(size > 4); } else { addr += !!(addr == reg->tc_status); } } #endif #if defined(__SIW_SPI_TYPE_1) /* * 0x10 : 128-bit dummy * size > 4 : burst */ if (bus_rx_dummy_flag & SPI_BUS_RX_DUMMY_FLAG_128BIT) { /* Burst restriction under 128-bit dummy */ if (size > 4) { switch (addr & 0xF00) { case 0xC00: case 0xD00: case 0xE00: break; default: bus_rx_dummy_flag &= ~SPI_BUS_RX_DUMMY_FLAG_128BIT; bus_rx_hdr_size = SPI_BUS_RX_HDR_SZ_32BIT; bus_rx_dummy_size = SPI_BUS_RX_DUMMY_SZ_32BIT; break; } } } if (bus_rx_dummy_flag & SPI_BUS_RX_DUMMY_FLAG_128BIT) { bus_rd_hdr_flag |= SPI_BUS_RX_DUMMY_FLAG_128BIT; } #else bus_rx_dummy_flag = 0; #endif // t_dev_info(dev, "addr %04Xh, size %d\n", addr, size); tx_buf = __siw_hal_get_curr_buf(ts, &tx_dma, 1); rx_buf = __siw_hal_get_curr_buf(ts, &rx_dma, 0); #if defined(__SIW_BUS_ADDR_16BIT) tx_buf[0] = ((addr >> 8) & 0xff); tx_buf[1] = (addr & 0xff); tx_buf[2] = bus_rd_hdr_flag; /* just prevent 'build warning' */ #else tx_buf[0] = bus_rd_hdr_flag | ((size > 4) ? 0x20 : 0x00); tx_buf[0] |= ((addr >> 8) & 0x0f); tx_buf[1] = (addr & 0xff); #endif // while (bus_tx_dummy_size--) { while (bus_rx_dummy_size--) { tx_buf[tx_size++] = 0; } msg->tx_buf = tx_buf; msg->tx_size = tx_size; msg->rx_buf = rx_buf; msg->rx_size = bus_rx_hdr_size + size; msg->tx_dma = tx_dma; msg->rx_dma = rx_dma; msg->bits_per_word = 8; msg->priv = 0; ret = siw_touch_bus_read(dev, msg); if (ret < 0) { t_dev_err(dev, "touch bus read error(0x%04X, 0x%04X), %d\n", (u32)addr, (u32)size, ret); return ret; } memcpy(data, &rx_buf[bus_rx_hdr_size], size); __siw_hal_bus_dbg(dev, addr, (u8 *)data, size, 0, 0); return size; } static int __used __siw_hal_reg_read(struct device *dev, u32 addr, void *data, int size) { struct siw_touch_chip *chip = to_touch_chip(dev); int ret = 0; mutex_lock(&chip->bus_lock); ret = __siw_hal_do_reg_read(dev, addr, data, size); mutex_unlock(&chip->bus_lock); return ret; } static int __used __siw_hal_do_reg_write(struct device *dev, u32 addr, void *data, int size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int bus_tx_hdr_size = touch_tx_hdr_size(ts); // int bus_rx_hdr_size = touch_rx_hdr_size(ts); struct touch_bus_msg _msg = {0, }; struct touch_bus_msg *msg = &_msg; u8 *tx_buf; dma_addr_t tx_dma; int ret = 0; #if 0 if (!addr) { t_dev_err(dev, "NULL addr\n"); return -EFAULT; } #endif if (!data) { t_dev_err(dev, "NULL data(0x%04X, 0x%04X)\n", addr, size); return -EFAULT; } tx_buf = __siw_hal_get_curr_buf(ts, &tx_dma, 1); #if defined(__SIW_BUS_ADDR_16BIT) tx_buf[0] = ((addr >> 8) & 0xff); tx_buf[1] = (addr & 0xff); #else tx_buf[0] = (touch_bus_type(ts) == BUS_IF_SPI) ? 0x60 : \ ((size > 4) ? 0x60 : 0x40); tx_buf[0] |= ((addr >> 8) & 0x0f); tx_buf[1] = (addr & 0xff); #endif msg->tx_buf = tx_buf; msg->tx_size = bus_tx_hdr_size + size; msg->rx_buf = NULL; msg->rx_size = 0; msg->tx_dma = tx_dma; msg->rx_dma = 0; msg->bits_per_word = 8; msg->priv = 0; memcpy(&tx_buf[bus_tx_hdr_size], data, size); ret = siw_touch_bus_write(dev, msg); if (ret < 0) { t_dev_err(dev, "touch bus write error(0x%04X, 0x%04X), %d\n", (u32)addr, (u32)size, ret); return ret; } __siw_hal_bus_dbg(dev, addr, (u8 *)data, size, 1, 0); return size; } static int __used __siw_hal_reg_write(struct device *dev, u32 addr, void *data, int size) { struct siw_touch_chip *chip = to_touch_chip(dev); int ret = 0; mutex_lock(&chip->bus_lock); ret = __siw_hal_do_reg_write(dev, addr, data, size); mutex_unlock(&chip->bus_lock); return ret; } static void __used __siw_hal_do_xfer_dbg(struct device *dev, struct touch_xfer_msg *xfer) { struct touch_xfer_data_t *tx = NULL; struct touch_xfer_data_t *rx = NULL; int i; for (i = 0; i < xfer->msg_count; i++) { tx = &xfer->data[i].tx; rx = &xfer->data[i].rx; t_dev_err(dev, "[%d] rx(0x%04X, 0x%04X) tx(0x%04X, 0x%04X)\n", i, (u32)rx->addr, (u32)rx->size, (u32)tx->addr, (u32)tx->size); } } static int __used __siw_hal_do_xfer_to_single(struct device *dev, struct touch_xfer_msg *xfer) { struct touch_xfer_data_t *tx = NULL; struct touch_xfer_data_t *rx = NULL; int i = 0; int ret = 0; for (i = 0; i < xfer->msg_count; i++) { tx = &xfer->data[i].tx; rx = &xfer->data[i].rx; if (rx->size) { ret = __siw_hal_do_reg_read(dev, rx->addr, rx->buf, rx->size); t_dev_dbg_trace(dev, "xfer single [%d/%d] - rd(%04Xh, %d), %d\n", i, xfer->msg_count, rx->addr, rx->size, ret); if (ret < 0) { return ret; } } else if (tx->size) { ret = __siw_hal_do_reg_write(dev, tx->addr, tx->buf, tx->size); t_dev_dbg_trace(dev, "xfer single [%d/%d] - wr(%04Xh, %d), %d\n", i, xfer->msg_count, rx->addr, rx->size, ret); if (ret < 0) { return ret; } } } return 0; } static int __used __siw_hal_do_xfer_msg(struct device *dev, struct touch_xfer_msg *xfer) { struct siw_ts *ts = to_touch_core(dev); struct touch_xfer_data_t *tx = NULL; struct touch_xfer_data_t *rx = NULL; int bus_tx_hdr_size = touch_tx_hdr_size(ts); int bus_rx_hdr_size = touch_rx_hdr_size(ts); // int bus_tx_dummy_size = touch_tx_dummy_size(ts); int bus_rx_dummy_size = (touch_rx_dummy_size(ts) & 0xFFFF); int bus_rx_dummy_flag = (touch_rx_dummy_size(ts) >> 16); int bus_dummy; int buf_size = touch_get_act_buf_size(ts); int tx_size; int i = 0; int ret = 0; if (!touch_xfer_allowed(ts)) { return __siw_hal_do_xfer_to_single(dev, xfer); } t_dev_dbg_base(dev, "xfer: start\n"); #if defined(__SIW_SPI_TYPE_1) /* * 0x10 : 128-bit dummy * size > 4 : burst */ if (bus_rx_dummy_flag & SPI_BUS_RX_DUMMY_FLAG_128BIT) { bus_rx_hdr_size = SPI_BUS_RX_HDR_SZ_32BIT; bus_rx_dummy_size = SPI_BUS_RX_DUMMY_SZ_32BIT; } #else bus_rx_dummy_flag = 0; #endif for (i = 0; i < xfer->msg_count; i++) { tx = &xfer->data[i].tx; rx = &xfer->data[i].rx; if (rx->size) { t_dev_dbg_base(dev, "xfer: rd set(%d)\n", i); #if 0 if (!rx->addr) { t_dev_err(dev, "NULL xfer rx->addr(%i)\n", i); __siw_hal_do_xfer_dbg(dev, xfer); return -EFAULT; } #endif tx_size = bus_tx_hdr_size; bus_dummy = bus_rx_dummy_size; tx->data[0] = (rx->size > 4) ? 0x20 : 0x00; tx->data[0] |= ((rx->addr >> 8) & 0x0f); tx->data[1] = (rx->addr & 0xff); while (bus_dummy--) { tx->data[tx_size++] = 0; } tx->size = tx_size; rx->size += bus_rx_hdr_size; continue; } t_dev_dbg_base(dev, "xfer: wr set(%d)\n", i); #if 0 if (!tx->addr) { t_dev_err(dev, "NULL xfer tx->addr(%i)\n", i); __siw_hal_do_xfer_dbg(dev, xfer); return -EFAULT; } #endif if (tx->size > (buf_size - bus_tx_hdr_size)) { t_dev_err(dev, "buffer overflow\n"); return -EOVERFLOW; } // tx->data[0] = ((tx->size == 1) ? 0x60 : 0x40); tx->data[0] = 0x60; tx->data[0] |= ((tx->addr >> 8) & 0x0f); tx->data[1] = (tx->addr & 0xff); memcpy(&tx->data[bus_tx_hdr_size], tx->buf, tx->size); tx->size += bus_tx_hdr_size; } t_dev_dbg_base(dev, "xfer: call bus xfer\n"); ret = siw_touch_bus_xfer(dev, xfer); if (ret < 0) { t_dev_err(dev, "touch bus xfer error, %d\n", ret); __siw_hal_do_xfer_dbg(dev, xfer); return ret; } ret = 0; for (i = 0; i < xfer->msg_count; i++) { tx = &xfer->data[i].tx; rx = &xfer->data[i].rx; if (rx->size) { if (!rx->buf) { t_dev_err(dev, "NULL xfer->data[%d].rx.buf\n", i); return -EFAULT; } memcpy(rx->buf, rx->data + bus_rx_hdr_size, (rx->size - bus_rx_hdr_size)); } ret += rx->size; { struct touch_xfer_data_t *dbg = (rx->size) ? rx : tx; int dbg_hdr_size = (rx->size) ? bus_rx_hdr_size : bus_tx_hdr_size; __siw_hal_bus_dbg(dev, dbg->addr, dbg->buf, dbg->size - dbg_hdr_size, !(rx->size), 1); } } return ret; } int siw_hal_read_value(struct device *dev, u32 addr, u32 *value) { int ret = __siw_hal_reg_read(dev, addr, value, sizeof(u32)); if (ret < 0) t_hal_bus_err(dev, "read val err[%03Xh, 0x%X], %d", addr, *value, ret); return ret; } int siw_hal_write_value(struct device *dev, u32 addr, u32 value) { int ret = __siw_hal_reg_write(dev, addr, &value, sizeof(u32)); if (ret < 0) t_hal_bus_err(dev, "write val err[%03Xh, 0x%X], %d", addr, value, ret); return ret; } int siw_hal_reg_read(struct device *dev, u32 addr, void *data, int size) { int ret = __siw_hal_reg_read(dev, addr, data, size); if (ret < 0) t_hal_bus_err(dev, "read reg err[%03Xh, 0x%X], %d", addr, ((u32 *)data)[0], ret); return ret; } int siw_hal_reg_write(struct device *dev, u32 addr, void *data, int size) { int ret = __siw_hal_reg_write(dev, addr, data, size); if (ret < 0) t_hal_bus_err(dev, "write reg err[%03Xh, 0x%X], %d", addr, ((u32 *)data)[0], ret); return ret; } void siw_hal_xfer_init(struct device *dev, void *xfer_data) { struct touch_xfer_msg *xfer = xfer_data; struct siw_touch_chip *chip = to_touch_chip(dev); mutex_lock(&chip->bus_lock); xfer->bits_per_word = 8; xfer->msg_count = 0; // mutex_unlock(&chip->bus_lock); } int siw_hal_xfer_msg(struct device *dev, struct touch_xfer_msg *xfer) { struct siw_touch_chip *chip = to_touch_chip(dev); int ret = 0; // mutex_lock(&chip->bus_lock); ret = __siw_hal_do_xfer_msg(dev, xfer); mutex_unlock(&chip->bus_lock); return ret; } void siw_hal_xfer_add_rx(void *xfer_data, u32 reg, void *buf, u32 size) { struct touch_xfer_msg *xfer = xfer_data; struct touch_xfer_data_t *rx = &xfer->data[xfer->msg_count].rx; struct touch_xfer_data_t *tx = &xfer->data[xfer->msg_count].tx; if (xfer->msg_count >= SIW_TOUCH_MAX_XFER_COUNT) { t_pr_err("touch xfer msg_count overflow (rx)\n"); return; } rx->addr = reg; rx->buf = buf; rx->size = size; tx->addr = 0; tx->buf = NULL; tx->size = 0; xfer->msg_count++; } void siw_hal_xfer_add_tx(void *xfer_data, u32 reg, void *buf, u32 size) { struct touch_xfer_msg *xfer = xfer_data; struct touch_xfer_data_t *rx = &xfer->data[xfer->msg_count].rx; struct touch_xfer_data_t *tx = &xfer->data[xfer->msg_count].tx; if (xfer->msg_count >= SIW_TOUCH_MAX_XFER_COUNT) { t_pr_err("touch xfer msg_count overflow (tx)\n"); return; } rx->addr = 0; rx->buf = NULL; rx->size = 0; tx->addr = reg; tx->buf = buf; tx->size = size; xfer->msg_count++; } static int siw_hal_cmd_write(struct device *dev, u8 cmd) { // struct siw_touch_chip *chip = to_touch_chip(dev); struct touch_bus_msg msg = {0, }; u8 input[2] = {0, }; int ret = 0; input[0] = cmd; input[1] = 0; msg.tx_buf = input; msg.tx_size = 2; msg.rx_buf = NULL; msg.rx_size = 0; msg.bits_per_word = 8; ret = siw_touch_bus_write(dev, &msg); if (ret < 0) { t_dev_err(dev, "touch cmd(0x%02X) write error, %d\n", cmd, ret); return ret; } return 0; } static int siw_hal_condition_wait(struct device *dev, u16 addr, u32 *value, u32 expect, u32 mask, u32 delay, u32 retry) { u32 data = 0; int ret = 0; do { touch_msleep(delay); ret = siw_hal_read_value(dev, addr, &data); switch (expect) { case FLASH_CODE_DNCHK_VALUE: case FLASH_CONF_DNCHK_VALUE: t_dev_dbg_base(dev, "wait read: addr[%04Xh] data[%08Xh], " "mask[%08Xh], expect[%08Xh], %d\n", addr, data, mask, expect, retry); break; } if ((ret >= 0) && ((data & mask) == expect)) { if (value) *value = data; #if 0 t_dev_info(dev, "wait done: addr[%04Xh] data[%08Xh], " "mask[%08Xh], expect[%08Xh], %d\n", addr, data, mask, expect, retry); #endif return 0; } } while (--retry); if (value) *value = data; t_dev_err(dev, "wait fail: addr[%04Xh] data[%08Xh], " "mask[%08Xh], expect[%08Xh]\n", addr, data, mask, expect); return -EPERM; } static void siw_hal_fb_notify_work_func(struct work_struct *fb_notify_work) { struct siw_touch_chip *chip = container_of(to_delayed_work(fb_notify_work), struct siw_touch_chip, fb_notify_work); int type = 0; type = (chip->lcd_mode == LCD_MODE_U3) ? FB_RESUME : FB_SUSPEND; siw_touch_notifier_call_chain(NOTIFY_FB, &type); } static void siw_hal_init_works(struct siw_touch_chip *chip) { INIT_DELAYED_WORK(&chip->fb_notify_work, siw_hal_fb_notify_work_func); } static void siw_hal_free_works(struct siw_touch_chip *chip) { cancel_delayed_work(&chip->fb_notify_work); } static void siw_hal_init_locks(struct siw_touch_chip *chip) { mutex_init(&chip->bus_lock); } static void siw_hal_free_locks(struct siw_touch_chip *chip) { mutex_destroy(&chip->bus_lock); } const struct tci_info siw_hal_tci_info_default[2] = { [TCI_1] = { .tap_count = 2, .min_intertap = 6, .max_intertap = 70, .touch_slop = 100, .tap_distance = 10, .intr_delay = 0, }, [TCI_2] = { .tap_count = 0, .min_intertap = 6, .max_intertap = 70, .touch_slop = 100, .tap_distance = 255, .intr_delay = 20, }, }; #if defined(__SIW_CONFIG_SHOW_TCI_INIT_VAL) #define t_dev_dbg_tci t_dev_info #else #define t_dev_dbg_tci t_dev_dbg_base #endif #define siw_prt_tci_info(_dev, _idx, _info) \ do { \ t_dev_dbg_tci(_dev, \ "tci info[%s] tap_count %d, min_intertap %d, max_intertap %d\n", \ _idx, _info->tap_count, _info->min_intertap, _info->max_intertap); \ t_dev_dbg_tci(_dev, \ "tci info[%s] touch_slop %d, tap_distance %d, intr_delay %d\n", \ _idx, _info->touch_slop, _info->tap_distance, _info->intr_delay); \ } while(0) static void siw_hal_prt_tci_info(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct tci_ctrl *tci = &ts->tci; struct tci_info *info; struct active_area *area; struct reset_area *rst_area; struct reset_area *tci_qcover; info = &tci->info[TCI_1]; siw_prt_tci_info(dev, "TCI_1", info); info = &tci->info[TCI_2]; siw_prt_tci_info(dev, "TCI_2", info); rst_area = &ts->tci.rst_area; t_dev_dbg_tci(dev, "tci rst area %Xh %Xh %Xh %Xh\n", rst_area->x1, rst_area->y1, rst_area->x2, rst_area->y2); area = &ts->tci.area; t_dev_dbg_tci(dev, "tci active area %Xh %Xh %Xh %Xh\n", area->x1, area->y1, area->x2, area->y2); tci_qcover = &ts->tci.qcover_open; t_dev_dbg_tci(dev, "tci qcover_open %Xh %Xh %Xh %Xh\n", tci_qcover->x1, tci_qcover->y1, tci_qcover->x2, tci_qcover->y2); tci_qcover = &ts->tci.qcover_close; t_dev_dbg_tci(dev, "tci qcover_close %Xh %Xh %Xh %Xh\n", tci_qcover->x1, tci_qcover->y1, tci_qcover->x2, tci_qcover->y2); } static void siw_hal_get_tci_info(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; void *tci_src; void *tci_reset_area; struct reset_area *tci_qcover; tci_src = pdata_tci_info(ts->pdata); if (tci_src == NULL) { tci_src = (void *)siw_hal_tci_info_default; } memcpy(ts->tci.info, tci_src, sizeof(siw_hal_tci_info_default)); tci_reset_area = pdata_tci_reset_area(ts->pdata); if (tci_reset_area == NULL) { ts->tci.rst_area.x1 = 0; ts->tci.rst_area.y1 = 0; ts->tci.rst_area.x2 = ts->caps.max_x | (ts->caps.max_x<<16); ts->tci.rst_area.y2 = ts->caps.max_y | (ts->caps.max_y<<16); } else { memcpy(&ts->tci.rst_area, tci_reset_area, sizeof(struct reset_area)); } //Set default ts->tci.area.x1 = 0; ts->tci.area.y1 = 0; ts->tci.area.x2 = ts->caps.max_x; ts->tci.area.y2 = ts->caps.max_y; tci_qcover = pdata_tci_qcover_open(ts->pdata); if (!tci_qcover) { memset(&ts->tci.qcover_open, ~0, sizeof(struct reset_area)); } else { memcpy(&ts->tci.qcover_open, tci_qcover, sizeof(struct reset_area)); } tci_qcover = pdata_tci_qcover_close(ts->pdata); if (!tci_qcover) { memset((void *)&ts->tci.qcover_close, ~0, sizeof(struct reset_area)); } else { memcpy(&ts->tci.qcover_close, tci_qcover, sizeof(struct reset_area)); } siw_hal_prt_tci_info(dev); } const struct siw_hal_swipe_ctrl siw_hal_swipe_info_default = { .mode = SWIPE_LEFT_BIT | SWIPE_RIGHT_BIT, .info = { [SWIPE_R] = { .distance = 5, .ratio_thres = 100, .ratio_distance = 2, .ratio_period = 5, .min_time = 0, .max_time = 150, .area.x1 = 401, .area.y1 = 0, .area.x2 = 1439, .area.y2 = 159, }, [SWIPE_L] = { .distance = 5, .ratio_thres = 100, .ratio_distance = 2, .ratio_period = 5, .min_time = 0, .max_time = 150, .area.x1 = 401, /* 0 */ .area.y1 = 0, /* 2060 */ .area.x2 = 1439, .area.y2 = 159, /* 2559 */ }, }, }; #if defined(__SIW_CONFIG_SHOW_SWIPE_INIT_VAL) #define t_dev_dbg_swipe t_dev_info #else #define t_dev_dbg_swipe t_dev_dbg_base #endif #define siw_prt_swipe_info(_dev, _idx, _info) \ do { \ t_dev_dbg_swipe(_dev, \ "swipe info[%s] distance %d, ratio_thres %d, ratio_distance %d\n", \ _idx, _info->distance, _info->ratio_thres, _info->ratio_distance); \ t_dev_dbg_swipe(_dev, \ "swipe info[%s] ratio_period %d, min_time %d, max_time %d\n", \ _idx, _info->ratio_period, _info->min_time, _info->max_time); \ t_dev_dbg_swipe(_dev, \ "swipe info[%s] area_x1 %d, area_y1 %d, area_x2 %d, area_y2 %d\n", \ _idx, _info->area.x1, _info->area.y1, _info->area.x2, _info->area.y2); \ } while(0) static void siw_hal_prt_swipe_info(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_swipe_ctrl *swipe = &chip->swipe; struct siw_hal_swipe_info *info; t_dev_dbg_swipe(dev, "swipe mode %08Xh\n", swipe->mode); info = &swipe->info[SWIPE_R]; siw_prt_swipe_info(dev, "SWIPE_R", info); info = &swipe->info[SWIPE_L]; siw_prt_swipe_info(dev, "SWIPE_L", info); } static void siw_hal_get_swipe_info(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; void *swipe_src; swipe_src = pdata_swipe_ctrl(ts->pdata); if (!swipe_src) swipe_src = (void *)&siw_hal_swipe_info_default; memcpy(&chip->swipe, swipe_src, sizeof(struct siw_hal_swipe_ctrl)); siw_hal_prt_swipe_info(dev); } static const char *siw_hal_pwr_name[] = { [POWER_OFF] = "Power off", [POWER_SLEEP] = "Power sleep", [POWER_WAKE] = "Power wake", [POWER_ON] = "Power on", }; static int siw_hal_power(struct device *dev, int ctrl) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; if ((ctrl < 0) || (ctrl > POWER_ON)) { t_dev_err(dev, "power ctrl: wrong ctrl value, %d\n", ctrl); return -EINVAL; } t_dev_dbg_pm(dev, "power ctrl: %s - %s\n", touch_chip_name(ts), siw_hal_pwr_name[ctrl]); switch (ctrl) { case POWER_OFF: t_dev_dbg_pm(dev, "power ctrl: power off\n"); atomic_set(&chip->init, IC_INIT_NEED); siw_hal_set_gpio_reset(dev, GPIO_OUT_ZERO); siw_hal_power_vio(dev, 0); siw_hal_power_vdd(dev, 0); touch_msleep(1 + hal_dbg_delay(chip, HAL_DBG_DLY_HW_RST_0)); break; case POWER_ON: t_dev_dbg_pm(dev, "power ctrl: power on\n"); siw_hal_power_vdd(dev, 1); siw_hal_power_vio(dev, 1); siw_hal_set_gpio_reset(dev, GPIO_OUT_ONE); break; case POWER_SLEEP: t_dev_dbg_pm(dev, "power ctrl: sleep\n"); break; case POWER_WAKE: t_dev_dbg_pm(dev, "power ctrl: wake\n"); break; case POWER_HW_RESET: t_dev_info(dev, "power ctrl: reset\n"); siw_hal_reset_ctrl(dev, HW_RESET_ASYNC); } return 0; } enum { BOOT_CHK_SKIP = (1<<16), }; static int siw_hal_chk_boot_mode(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 bootmode = 0; u32 boot_chk_offset_busy; u32 boot_chk_offset_err; int ret = 0; switch (chip->opt.t_boot_mode) { case 1: boot_chk_offset_busy = 0; boot_chk_offset_err = 2; break; default: boot_chk_offset_busy = 1; boot_chk_offset_err = 3; break; } ret = siw_hal_read_value(dev, reg->spr_boot_status, &bootmode); if (ret < 0) { return ret; } /* maybe nReset is low state */ if (!bootmode || (bootmode == ~0)) { return BOOT_CHK_SKIP; } /* booting... need to wait */ if ((bootmode >> boot_chk_offset_busy) & 0x1) { return BOOT_CHK_SKIP; } if ((bootmode >> boot_chk_offset_err) & 0x1) { /* CRC error */ t_dev_err(dev, "boot fail: boot sts = %08Xh\n", bootmode); return 0x1; } return 0; } static int siw_hal_chk_boot_status(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_status_mask_bit *mask_bit = &chip->status_mask_bit; u32 boot_failed = 0; u32 tc_status = 0; u32 valid_cfg_crc_mask = 0; u32 valid_code_crc_mask = 0; int ret = 0; valid_cfg_crc_mask = (mask_bit->valid_cfg_crc) ? mask_bit->valid_cfg_crc : (1<<STS_POS_VALID_CFG_CRC); valid_code_crc_mask = (mask_bit->valid_code_crc) ? mask_bit->valid_code_crc : (1<<STS_POS_VALID_CODE_CRC); ret = siw_hal_read_value(dev, reg->tc_status, &tc_status); if (ret < 0) { return ret; } /* maybe nReset is low state */ if (!tc_status || (tc_status == ~0)) { return BOOT_CHK_SKIP; } if (!(tc_status & valid_cfg_crc_mask)) { boot_failed |= (1<<5); } if (!(tc_status & valid_code_crc_mask)) { boot_failed |= (1<<4); } if (boot_failed) { t_dev_err(dev, "boot fail: tc_status = %08Xh(%02Xh)\n", tc_status, boot_failed); } return boot_failed; } enum { BOOT_CHK_MODE_RETRY = 2, BOOT_CHK_STS_RETRY = 2, /* */ BOOT_CHK_MODE_DELAY = 10, BOOT_CHK_STS_DELAY = 10, }; static int siw_hal_chk_boot(struct device *dev) { u32 boot_failed = 0; int retry; int ret = 0; retry = BOOT_CHK_MODE_RETRY; while (retry--) { ret = siw_hal_chk_boot_mode(dev); if (ret < 0) { return ret; } if (ret == BOOT_CHK_SKIP) { return 0; } if (!ret) { break; } touch_msleep(BOOT_CHK_MODE_DELAY); } boot_failed |= ret; retry = BOOT_CHK_STS_RETRY; while (retry--) { ret = siw_hal_chk_boot_status(dev); if (ret < 0) { return ret; } if (ret == BOOT_CHK_SKIP) { return boot_failed; } if (!ret) { break; } touch_msleep(BOOT_CHK_STS_DELAY); } boot_failed |= ret; return boot_failed; } enum { IC_DEBUG_SIZE = 16, // byte // IC_CHK_LOG_MAX = (1<<9), // INT_IC_ABNORMAL_STATUS = (1<<0), // INT_IC_ERROR_STATUS = ((1<<5) | (1<<3)), }; static const struct siw_hal_status_filter status_filter_type_0[] = { _STS_FILTER(STS_ID_VALID_DEV_CTL, 1, STS_POS_VALID_DEV_CTL, 0, "device ctl not set"), _STS_FILTER(STS_ID_VALID_CODE_CRC, 1, STS_POS_VALID_CODE_CRC_TYPE_0, 0, "code crc invalid"), _STS_FILTER(STS_ID_ERROR_ABNORMAL, 1, STS_POS_ERROR_ABNORMAL, STS_FILTER_FLAG_TYPE_ERROR | STS_FILTER_FLAG_CHK_FAULT, "abnormal status detected"), _STS_FILTER(STS_ID_ERROR_SYSTEM, 1, STS_POS_ERROR_SYSTEM, STS_FILTER_FLAG_TYPE_ERROR | STS_FILTER_FLAG_ESD_SEND, "system error detected"), _STS_FILTER(STS_ID_ERROR_MISMTACH, 2, STS_POS_ERROR_MISMTACH, STS_FILTER_FLAG_TYPE_ERROR, "display mode mismatch"), _STS_FILTER(STS_ID_VALID_IRQ_PIN, 1, STS_POS_VALID_IRQ_PIN, 0, "irq pin invalid"), _STS_FILTER(STS_ID_VALID_IRQ_EN, 1, STS_POS_VALID_IRQ_EN, 0, "irq status invalid"), /* end mask */ _STS_FILTER(STS_ID_NONE, 0, 0, 0, NULL), }; static const struct siw_hal_status_filter status_filter_type_1[] = { _STS_FILTER(STS_ID_VALID_DEV_CTL, 1, STS_POS_VALID_DEV_CTL, 0, "device ctl not set"), _STS_FILTER(STS_ID_VALID_CODE_CRC, 1, STS_POS_VALID_CODE_CRC, 0, "code crc invalid"), _STS_FILTER(STS_ID_VALID_CFG_CRC, 1, STS_POS_VALID_CFG_CRC, 0, "cfg crc invalid"), _STS_FILTER(STS_ID_ERROR_ABNORMAL, 1, STS_POS_ERROR_ABNORMAL, STS_FILTER_FLAG_TYPE_ERROR | STS_FILTER_FLAG_CHK_FAULT, "abnormal status detected"), _STS_FILTER(STS_ID_ERROR_SYSTEM, 1, STS_POS_ERROR_SYSTEM, STS_FILTER_FLAG_TYPE_ERROR | STS_FILTER_FLAG_ESD_SEND, "system error detected"), _STS_FILTER(STS_ID_ERROR_MISMTACH, 1, STS_POS_ERROR_MISMTACH, STS_FILTER_FLAG_TYPE_ERROR, "display mode mismatch"), _STS_FILTER(STS_ID_VALID_IRQ_PIN, 1, STS_POS_VALID_IRQ_PIN, 0, "irq pin invalid"), _STS_FILTER(STS_ID_VALID_IRQ_EN, 1, STS_POS_VALID_IRQ_EN, 0, "irq status invalid"), _STS_FILTER(STS_ID_VALID_TC_DRV, 1, STS_POS_VALID_TC_DRV, 0, "driving invalid"), /* end mask */ _STS_FILTER(STS_ID_NONE, 0, 0, 0, NULL), }; static const struct siw_hal_status_filter status_filter_type_2[] = { _STS_FILTER(STS_ID_VALID_DEV_CTL, 1, STS_POS_VALID_DEV_CTL, 0, "device ctl not set"), _STS_FILTER(STS_ID_ERROR_ABNORMAL, 1, STS_POS_ERROR_ABNORMAL, STS_FILTER_FLAG_TYPE_ERROR | STS_FILTER_FLAG_CHK_FAULT, "re-init required"), _STS_FILTER(STS_ID_VALID_IRQ_PIN, 1, STS_POS_VALID_IRQ_PIN, 0, "irq pin invalid"), _STS_FILTER(STS_ID_VALID_IRQ_EN, 1, STS_POS_VALID_IRQ_EN, 0, "irq status invalid"), _STS_FILTER(STS_ID_VALID_TC_DRV, 1, STS_POS_VALID_TC_DRV, 0, "driving invalid"), /* end mask */ _STS_FILTER(STS_ID_NONE, 0, 0, 0, NULL), }; static u32 siw_hal_get_status_mask(struct device *dev, int id) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_hal_status_filter *filter = chip->status_filter; u32 mask = 0; if (filter == NULL) goto out; while (1) { if (!filter->id || !filter->width) { break; } if (filter->id == id) { mask = ((1<<filter->width)-1)<<filter->pos; break; } filter++; } out: return mask; } static int siw_hal_chk_status_type(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_fw_info *fw = &chip->fw; struct siw_hal_status_mask_bit *mask_bit = &chip->status_mask_bit; if (chip->status_type) { return 0; } if (!fw->product_id[0]) { return -EINVAL; } switch (touch_chip_type(ts)) { case CHIP_SW42101: chip->status_type = CHIP_STATUS_TYPE_2; break; case CHIP_LG4894: if (!strncmp(fw->product_id, "L0W53K6P", 8)) { chip->status_type = CHIP_STATUS_TYPE_0; } else { chip->status_type = CHIP_STATUS_TYPE_1; } default: chip->status_type = CHIP_STATUS_TYPE_1; break; } switch (chip->status_type) { case CHIP_STATUS_TYPE_2: chip->status_filter = (struct siw_hal_status_filter *)status_filter_type_2; break; case CHIP_STATUS_TYPE_0: chip->status_filter = (struct siw_hal_status_filter *)status_filter_type_0; break; default: chip->status_filter = (struct siw_hal_status_filter *)status_filter_type_1; break; } mask_bit->valid_dev_ctl = siw_hal_get_status_mask(dev, STS_ID_VALID_DEV_CTL); mask_bit->valid_code_crc = siw_hal_get_status_mask(dev, STS_ID_VALID_CODE_CRC); mask_bit->valid_cfg_crc = siw_hal_get_status_mask(dev, STS_ID_VALID_CFG_CRC);; mask_bit->error_abnormal = siw_hal_get_status_mask(dev, STS_ID_ERROR_ABNORMAL); mask_bit->error_system = siw_hal_get_status_mask(dev, STS_ID_ERROR_SYSTEM); mask_bit->error_mismtach = siw_hal_get_status_mask(dev, STS_ID_ERROR_MISMTACH); mask_bit->valid_irq_pin = siw_hal_get_status_mask(dev, STS_ID_VALID_IRQ_PIN); mask_bit->valid_irq_en = siw_hal_get_status_mask(dev, STS_ID_VALID_IRQ_EN); mask_bit->valid_tv_drv = siw_hal_get_status_mask(dev, STS_ID_VALID_TC_DRV); t_dev_dbg_base(dev, "mask[v_dev] : %08Xh\n", mask_bit->valid_dev_ctl); t_dev_dbg_base(dev, "mask[v_code] : %08Xh\n", mask_bit->valid_code_crc); t_dev_dbg_base(dev, "mask[v_cfg] : %08Xh\n", mask_bit->valid_cfg_crc); t_dev_dbg_base(dev, "mask[e_abn] : %08Xh\n", mask_bit->error_abnormal); t_dev_dbg_base(dev, "mask[e_sys] : %08Xh\n", mask_bit->error_system); t_dev_dbg_base(dev, "mask[e_mis] : %08Xh\n", mask_bit->error_mismtach); t_dev_dbg_base(dev, "mask[v_i_p] : %08Xh\n", mask_bit->valid_irq_pin); t_dev_dbg_base(dev, "mask[v_i_e] : %08Xh\n", mask_bit->valid_irq_en); t_dev_dbg_base(dev, "mask[v_tc] : %08Xh\n", mask_bit->valid_tv_drv); chip->status_mask_normal = mask_bit->valid_dev_ctl | mask_bit->valid_code_crc | mask_bit->valid_cfg_crc | mask_bit->valid_irq_pin | mask_bit->valid_irq_en | mask_bit->valid_tv_drv | 0; chip->status_mask_logging = mask_bit->error_mismtach | mask_bit->valid_irq_pin | mask_bit->valid_irq_en | mask_bit->valid_tv_drv | 0; chip->status_mask_reset = mask_bit->valid_dev_ctl | mask_bit->valid_code_crc | mask_bit->valid_cfg_crc | mask_bit->error_abnormal | mask_bit->error_system | 0; chip->status_mask = chip->status_mask_normal | chip->status_mask_logging | chip->status_mask_reset | 0; chip->status_mask_ic_abnormal = INT_IC_ABNORMAL_STATUS; chip->status_mask_ic_error = INT_IC_ERROR_STATUS; switch (chip->opt.t_sts_mask) { case 1: chip->status_mask_ic_abnormal |= (0x3<<6); chip->status_mask_ic_valid = 0xFFFF; break; default: chip->status_mask_ic_valid = 0xFF; break; } t_dev_info(dev, "status type : %d\n", chip->status_type); t_dev_info(dev, "status mask : %08Xh\n", chip->status_mask); t_dev_info(dev, " normal : %08Xh\n", chip->status_mask_normal); t_dev_info(dev, " logging : %08Xh\n", chip->status_mask_logging); t_dev_info(dev, " reset : %08Xh\n", chip->status_mask_reset); t_dev_info(dev, " ic abnormal : %08Xh\n", chip->status_mask_ic_abnormal); t_dev_info(dev, " ic error : %08Xh\n", chip->status_mask_ic_error); return 0; } struct siw_ic_info_chip_proto { int chip_type; int vchip; int vproto; }; static const struct siw_ic_info_chip_proto siw_ic_info_chip_protos[] = { { CHIP_LG4894, 4, 4 }, { CHIP_LG4895, 8, 4 }, { CHIP_LG4946, 7, 4 }, { CHIP_LG4951, 7, 4 }, { CHIP_SW1828, 9, 4 }, { CHIP_SW49105, 10, 4 }, { CHIP_SW49406, 7, 4 }, { CHIP_SW49407, 9, 4 }, { CHIP_SW49408, 12, 4 }, { CHIP_SW42101, 15, 4 }, { CHIP_NONE, 0, 0 }, //End mark }; static int siw_hal_ic_info_ver_check(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_fw_info *fw = &chip->fw; struct siw_ic_info_chip_proto *chip_proto; // u32 version = fw->v.version_raw; u32 vchip = fw->v.version.chip; u32 vproto = fw->v.version.protocol; // int ret = 0; chip_proto = (struct siw_ic_info_chip_proto *)siw_ic_info_chip_protos; while (1) { if (chip_proto->chip_type == CHIP_NONE) { break; } if (touch_chip_type(ts) == chip_proto->chip_type) { if ((chip_proto->vchip != vchip) || (chip_proto->vproto != vproto)) { break; } t_dev_info(dev, "[%s] IC info is good: %d, %d\n", touch_chip_name(ts), vchip, vproto); return 0; } chip_proto++; } t_dev_err(dev, "[%s] IC info is abnormal: %d, %d\n", touch_chip_name(ts), vchip, vproto); return -EINVAL; } static int siw_hal_do_ic_info(struct device *dev, int prt_on) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_fw_info *fw = &chip->fw; struct touch_xfer_msg *xfer = ts->xfer; u32 product[2] = {0}; u32 chip_id = 0; u32 version = 0; u32 version_ext = 0; u32 revision = 0; u32 bootmode = 0; u32 boot_chk_offset; int ret = 0; siw_hal_xfer_init(dev, xfer); siw_hal_xfer_add_rx(xfer, reg->spr_chip_id, (void *)&chip_id, sizeof(chip_id)); siw_hal_xfer_add_rx(xfer, reg->tc_version, (void *)&version, sizeof(version)); siw_hal_xfer_add_rx(xfer, reg->info_chip_version, (void *)&revision, sizeof(revision)); siw_hal_xfer_add_rx(xfer, reg->tc_product_id1, (void *)&product[0], sizeof(product)); if (chip->opt.f_ver_ext) { siw_hal_xfer_add_rx(xfer, reg->tc_version_ext, (void *)&version_ext, sizeof(version_ext)); } siw_hal_xfer_add_rx(xfer, reg->spr_boot_status, (void *)&bootmode, sizeof(bootmode)); ret = siw_hal_xfer_msg(dev, ts->xfer); if (ret < 0) { t_dev_err(dev, "ic_info(1): xfer failed, %d\n", ret); return ret; } if (chip->opt.f_info_more) { siw_hal_xfer_init(dev, xfer); siw_hal_xfer_add_rx(xfer, reg->info_fpc_type, (void *)&fw->fpc, sizeof(fw->fpc)); siw_hal_xfer_add_rx(xfer, reg->info_wfr_type, (void *)&fw->wfr, sizeof(fw->wfr)); siw_hal_xfer_add_rx(xfer, reg->info_cg_type, (void *)&fw->cg, sizeof(fw->cg)); siw_hal_xfer_add_rx(xfer, reg->info_lot_num, (void *)&fw->lot, sizeof(fw->lot)); siw_hal_xfer_add_rx(xfer, reg->info_serial_num, (void *)&fw->sn, sizeof(fw->sn)); siw_hal_xfer_add_rx(xfer, reg->info_date, (void *)&fw->date, sizeof(fw->date)); siw_hal_xfer_add_rx(xfer, reg->info_time, (void *)&fw->time, sizeof(fw->time)); ret = siw_hal_xfer_msg(dev, ts->xfer); if (ret < 0) { t_dev_err(dev, "ic_info(2): xfer failed, %d\n", ret); return ret; } } siw_hal_fw_set_chip_id(fw, chip_id); siw_hal_fw_set_version(fw, version, version_ext); siw_hal_fw_set_revision(fw, revision); siw_hal_fw_set_prod_id(fw, (u8 *)product, sizeof(product)); siw_hal_chk_status_type(dev); fw->wfr &= WAFER_TYPE_MASK; if (fw->version_ext) { int ferr; ferr = siw_hal_fw_chk_version_ext(fw->version_ext, fw->v.version.ext); t_dev_info_sel(dev, prt_on, "[T] chip id %s, version %08X(%u.%02u) (0x%02X) %s\n", chip->fw.chip_id, fw->version_ext, fw->v.version.major, fw->v.version.minor, fw->revision, (ferr < 0) ? "(invalid)" : ""); } else { t_dev_info_sel(dev, prt_on, "[T] chip id %s, version v%u.%02u (0x%08X, 0x%02X)\n", fw->chip_id, fw->v.version.major, fw->v.version.minor, version, fw->revision); } switch (chip->opt.t_boot_mode) { case 1: boot_chk_offset = 0; break; default: boot_chk_offset = 1; break; } t_dev_info_sel(dev, prt_on, "[T] product id %s, flash boot %s(%s), crc %s (0x%08X)\n", fw->product_id, ((bootmode >> boot_chk_offset) & 0x1) ? "BUSY" : "idle", ((bootmode >> (boot_chk_offset + 1)) & 0x1) ? "done" : "booting", ((bootmode >> (boot_chk_offset + 2)) & 0x1) ? "ERROR" : "ok", bootmode); ret = siw_hal_chk_boot(dev); if (ret < 0) { return ret; } if (ret) { int boot_fail_cnt = chip->boot_fail_cnt; atomic_set(&chip->boot, IC_BOOT_FAIL); /* Limit to avoid infinite repetition */ if (boot_fail_cnt >= BOOT_FAIL_RECOVERY_MAX) { t_dev_err(dev, "Boot fail can't be recovered(%d) - %02Xh\n", boot_fail_cnt, ret); return -EFAULT; } t_dev_err(dev, "Boot fail detected(%d) - %02Xh\n", boot_fail_cnt, ret); chip->boot_fail_cnt++; /* return special flag to let the core layer know */ return -ETDBOOTFAIL; } chip->boot_fail_cnt = 0; if (chip->opt.f_info_more) { t_dev_info_sel(dev, prt_on, "[T] fpc %d, wfr %d, cg %d, lot %d\n", fw->fpc, fw->wfr, fw->cg, fw->lot); t_dev_info_sel(dev, prt_on, "[T] sn %Xh, " "date %04d.%02d.%02d, time %02d:%02d:%02d site%d\n", fw->sn, fw->date & 0xFFFF, ((fw->date>>16) & 0xFF), ((fw->date>>24) & 0xFF), fw->time & 0xFF, ((fw->time>>8) & 0xFF), ((fw->time>>16) & 0xFF), ((fw->time>>24) & 0xFF)); } if (strcmp(fw->chip_id, touch_chip_id(ts))) { t_dev_err(dev, "Invalid chip id(%s), shall be %s\n", fw->chip_id, touch_chip_id(ts)); return -EINVAL; } ret = siw_hal_ic_info_ver_check(dev); if (ret < 0) { #if 0 #if 1 siw_hal_reset_ctrl(dev, HW_RESET_ASYNC); #else siw_hal_power(dev, POWER_OFF); siw_hal_power(dev, POWER_ON); touch_msleep(ts->caps.hw_reset_delay); #endif #endif } return ret; } static int siw_hal_ic_info(struct device *dev) { return siw_hal_do_ic_info(dev, 1); } #if defined(__SIW_CONFIG_FB) static int siw_hal_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct siw_ts *ts = container_of(self, struct siw_ts, fb_notif); struct fb_event *ev = (struct fb_event *)data; if (ev && ev->data && event == FB_EVENT_BLANK) { int *blank = (int *)ev->data; if (*blank == FB_BLANK_UNBLANK) t_dev_info(ts->dev, "FB_UNBLANK\n"); else if (*blank == FB_BLANK_POWERDOWN) t_dev_info(ts->dev, "FB_BLANK\n"); } return 0; } /* * Change notifier to siw_hal_fb_notifier_callback * instead of siw_touch_fb_notifier_callback and * siw_touch_suspend/resume will be called via * siw_touch_fb_work_func * : siw_touch_notify -> siw_touch_qd_fb_work_now */ static int siw_hal_fb_notifier_init(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; t_dev_dbg_base(dev, "fb_notif change\n"); fb_unregister_client(&ts->fb_notif); ts->fb_notif.notifier_call = siw_hal_fb_notifier_callback; fb_register_client(&ts->fb_notif); return 0; } #else /* __SIW_CONFIG_FB */ static int siw_hal_fb_notifier_init(struct device *dev) { return 0; } #endif /* __SIW_CONFIG_FB */ static int siw_hal_init_reg_verify(struct device *dev, u32 addr, u32 data, int retry, const char *name) { u32 rdata = ~0; int i; int ret = 0; for (i = 0; i < retry; i++) { ret = siw_hal_write_value(dev, addr, data); if (ret < 0) { t_dev_err(dev, "failed to write %s, %d\n", name, ret); return ret; } ret = siw_hal_read_value(dev, addr, &rdata); if (ret < 0) { t_dev_err(dev, "failed to read %s, %d\n", name, ret); return ret; } if (data == rdata) { t_dev_dbg_base(dev, "init reg done: %s(%08Xh)\n", name, rdata); return 0; } } t_dev_err(dev, "init reg failed: %08Xh, %08Xh\n", data, rdata); return -EFAULT; } static int siw_hal_init_reg_set_pre(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int ret = 0; if (chip->opt.f_attn_opt) { u32 addr = 0; if (touch_bus_type(ts) == BUS_IF_I2C) { addr = 0xFE4; } else { addr = 0xFE5; } if (addr) { ret = siw_hal_write_value(dev, addr, 0); if (ret < 0) { goto out; } } ret = siw_hal_init_reg_verify(dev, 0xFF3, ABNORMAL_IC_DETECTION, 3, "spi_tattn_opt"); if (ret < 0) { t_dev_err(dev, "failed to set spi_tattn_opt, %d\n", ret); goto out; } } out: return ret; } static int siw_hal_init_reg_set_post(struct device *dev) { return 0; } static int siw_hal_init_reg_set(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 data = 1; int ret = 0; siw_hal_init_reg_set_pre(dev); ret = siw_hal_write_value(dev, reg->tc_device_ctl, 1); if (ret < 0) { t_dev_err(dev, "failed to start chip, %d\n", ret); goto out; } ret = siw_hal_write_value(dev, reg->tc_interrupt_ctl, 1); if (ret < 0) { t_dev_err(dev, "failed to start chip irq, %d\n", ret); goto out; } #if 0 ret = siw_hal_write_value(dev, reg->spr_charger_status, chip->charger); if (ret < 0) { goto out; } #endif data = atomic_read(&ts->state.ime); ret = siw_hal_write_value(dev, reg->ime_state, data); if (ret < 0) { goto out; } siw_hal_init_reg_set_post(dev); out: return ret; } #if defined(__SIW_SUPPORT_WATCH) static int siw_hal_check_watch(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); siw_hal_watch_chk_font_status(chip->dev); if ((chip->lcd_mode == LCD_MODE_U2) && siw_hal_watch_is_disp_waton(dev) && siw_hal_watch_is_rtc_run(dev)) { siw_hal_watch_get_curr_time(dev, NULL, NULL); } return 0; } static int siw_hal_check_mode_type_0(struct device *dev, int lcd_mode, int chk_mode) { // struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; int ret = 0; if (lcd_mode == LCD_MODE_U3) { goto out; } if (lcd_mode == LCD_MODE_U2) { if (chk_mode == LCD_MODE_U2_UNBLANK) { t_dev_info(dev, "U1 -> U2 : watch on\n"); siw_hal_watch_init(dev); // knockon mode change + swipe enable ret = siw_hal_tc_driving(dev, LCD_MODE_U2); if (!ret) ret = 1; } else { t_dev_info(dev, "U2 mode change\n"); } goto out; } if (lcd_mode == LCD_MODE_U2_UNBLANK) { switch (chk_mode) { case LCD_MODE_STOP: t_dev_info(dev, "Skip mode change : LCD_MODE_STOP -> U1\n"); siw_hal_watch_display_off(dev); ret = 1; break; case LCD_MODE_U2: t_dev_info(dev, "U2 -> U1 : watch off\n"); siw_hal_watch_display_off(dev); // abs mode change + swipe disable ret = siw_hal_tc_driving(dev, LCD_MODE_U2_UNBLANK); if (!ret) ret = 1; break; case LCD_MODE_U0: t_dev_info(dev, "U0 -> U1 mode change\n"); break; default: t_dev_info(dev, "Not Defined Mode, %d\n", chk_mode); break; } goto out; } if (lcd_mode == LCD_MODE_U0) { t_dev_info(dev, "U0 mode change\n"); goto out; } t_dev_info(dev, "Not defined mode, %d\n", lcd_mode); out: return ret; } static int siw_hal_check_mode_type_1(struct device *dev, int lcd_mode, int chk_mode) { // struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; int ret = 0; if (lcd_mode == LCD_MODE_U3) { goto out; } if (lcd_mode == LCD_MODE_U2) { if (chk_mode == LCD_MODE_U2_UNBLANK) { t_dev_info(dev, "U1 -> U2 : watch on\n"); siw_hal_watch_init(dev); ret = 1; } else { t_dev_info(dev, "U2 mode change\n"); siw_hal_watch_init(dev); } goto out; } if (lcd_mode == LCD_MODE_U2_UNBLANK) { switch (chk_mode) { case LCD_MODE_U2: t_dev_info(dev, "U2 -> U1\n"); break; case LCD_MODE_U0: t_dev_info(dev, "U0 -> U1 mode change\n"); siw_hal_watch_init(dev); break; default: t_dev_info(dev, "Not Defined Mode, %d\n", chk_mode); break; } goto out; } if (lcd_mode == LCD_MODE_U0) { t_dev_info(dev, "U0 mode change\n"); goto out; } t_dev_info(dev, "Not defined mode, %d\n", lcd_mode); out: return ret; } static int siw_hal_check_mode(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; int ret = 0; switch (chip->opt.t_chk_mode) { case 1: ret = siw_hal_check_mode_type_1(dev, chip->lcd_mode, chip->prev_lcd_mode); break; default: ret = siw_hal_check_mode_type_0(dev, chip->lcd_mode, chip->driving_mode); break; } return ret; } static void siw_hal_lcd_event_read_reg(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct touch_xfer_msg *xfer = ts->xfer; u32 rdata[5] = {0, 0}; int ret = 0; siw_hal_xfer_init(dev, xfer); siw_hal_xfer_add_rx(xfer, reg->tc_ic_status, (void *)&rdata[0], sizeof(rdata[0])); siw_hal_xfer_add_rx(xfer, reg->tc_status, (void *)&rdata[1], sizeof(rdata[1])); siw_hal_xfer_add_rx(xfer, reg->spr_subdisp_status, (void *)&rdata[2], sizeof(rdata[2])); siw_hal_xfer_add_rx(xfer, reg->tc_version, (void *)&rdata[3], sizeof(rdata[3])); siw_hal_xfer_add_rx(xfer, reg->spr_chip_id, (void *)&rdata[4], sizeof(rdata[4])); ret = siw_hal_xfer_msg(dev, xfer); if (ret < 0) { t_dev_err(dev, "xfer failed, %d\n", ret); return; } t_dev_info(dev, "r[%04X] %08Xh, r[%04X] %08Xh, r[%04X] %08Xh, r[%04X] %08Xh, r[%04X] %08Xh\n", reg->tc_ic_status, rdata[0], reg->tc_status, rdata[1], reg->spr_subdisp_status, rdata[2], reg->tc_version, rdata[3], reg->spr_chip_id, rdata[4]); t_dev_info(dev, "v%d.%02d\n", (rdata[3] >> 8) & 0xF, rdata[3] & 0xFF); } #else /* __SIW_SUPPORT_WATCH */ static int siw_hal_check_watch(struct device *dev){ return 0; } static int siw_hal_check_mode(struct device *dev){ return 0; } static void siw_hal_lcd_event_read_reg(struct device *dev){ } #endif /* __SIW_SUPPORT_WATCH */ static int siw_hal_send_esd_notifier(struct device *dev, int type) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int esd = type; int ret; if (touch_flags(ts) & TOUCH_SKIP_ESD_EVENT) { t_dev_info(dev, "skip sending ESD notifier\n"); return 0; } ret = siw_touch_atomic_notifier_call(LCD_EVENT_TOUCH_ESD_DETECTED, (void*)&esd); if (ret) t_dev_err(dev, "check the value, %d\n", ret); /* Sending Event done */ return 1; } static int siw_hal_init_quirk(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; u8 temp[10+4]; int ret = 0; switch (touch_chip_type(ts)) { case CHIP_SW42101: memset(temp, 0, sizeof(temp)); ret = siw_hal_reg_read(dev, 0x150, temp, 10); if (ret < 0) { t_dev_err(dev, "init quirk for SW42101 failed, %d\n", ret); return ret; } t_dev_info(dev, "init quirk for SW42101: %s\n", temp); break; } return 0; } static int siw_hal_init(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int init_retry = CHIP_INIT_RETRY_MAX; int i; int ret = 0; atomic_set(&chip->boot, IC_BOOT_DONE); if (atomic_read(&ts->state.core) == CORE_PROBE) { siw_hal_fb_notifier_init(dev); init_retry = CHIP_INIT_RETRY_PROBE; } else { siw_hal_init_quirk(dev); if (ret < 0) { goto out; } } t_dev_dbg_base(dev, "charger_state = 0x%02X\n", chip->charger); if (atomic_read(&ts->state.debug_tool) == DEBUG_TOOL_ENABLE) { siw_hal_abt_init(dev); } for (i = 0; i < init_retry; i++) { ret = siw_hal_ic_info(dev); if (ret >= 0) { break; } /* * When boot fail detected * * 1. At the fisrt detection, * it sends esd noti for LCD recovery(full reset procedure) * and skip fw_upgrade. * 2. LCD driver is suppsed to send lcd mode notifier * back to touch side after its recovery. * 3. The lcd mode notifier restarts init work again * via siw_touch_resume. * 4. If boot fail detected again(counted by boot_fail_cnt) * it goes to fw_upgrade stage. * (See siw_touch_init_work_func in siw_touch.c) */ if (ret == -ETDBOOTFAIL) { /* For the probe stage */ if (atomic_read(&ts->state.core) == CORE_PROBE) { break; } /* Don't do recovery twice continuously */ if (atomic_read(&chip->esd_noti_sent)) { break; } /* At the first boot fail */ if (chip->boot_fail_cnt > 1) { break; } if (siw_hal_send_esd_notifier(dev, 2)) { ret = -ETDSENTESD; break; } } t_dev_dbg_base(dev, "retry getting ic info (%d)\n", i); siw_touch_irq_control(dev, INTERRUPT_DISABLE); siw_hal_power(dev, POWER_OFF); siw_hal_power(dev, POWER_ON); touch_msleep(ts->caps.hw_reset_delay); } if (ret < 0) { goto out; } atomic_set(&chip->esd_noti_sent, 0); siw_hal_init_reg_set(dev); siw_hal_watch_rtc_on(dev); atomic_set(&chip->init, IC_INIT_DONE); atomic_set(&ts->state.sleep, IC_NORMAL); ret = siw_hal_lpwg_mode(dev); if (ret < 0) { t_dev_err(dev, "failed to lpwg_control, %d\n", ret); goto out; } ret = siw_hal_check_watch(dev); if (ret < 0) { t_dev_err(dev, "failed to check watch, %d\n", ret); goto out; } out: if (ret) { t_dev_err(dev, "%s init failed, %d\n", touch_chip_name(ts), ret); } else { t_dev_info(dev, "%s init done\n", touch_chip_name(ts)); } siwmon_submit_ops_step_chip_wh_name(dev, "%s init done", touch_chip_name(ts), ret); return ret; } static int siw_hal_reinit(struct device *dev, int pwr_con, int delay, int irq_enable, int (*do_call)(struct device *dev)) { struct siw_touch_chip *chip = to_touch_chip(dev); siw_touch_irq_control(dev, INTERRUPT_DISABLE); if (pwr_con) { siw_hal_power(dev, POWER_OFF); siw_hal_power(dev, POWER_ON); } else { siw_hal_set_gpio_reset(dev, GPIO_OUT_ZERO); touch_msleep(1 + hal_dbg_delay(chip, HAL_DBG_DLY_HW_RST_0)); siw_hal_set_gpio_reset(dev, GPIO_OUT_ONE); } atomic_set(&chip->init, IC_INIT_NEED); touch_msleep(delay); if (do_call) do_call(dev); if (irq_enable) siw_touch_irq_control(dev, INTERRUPT_ENABLE); return 0; } static int siw_hal_sw_reset_wh_cmd(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; siw_hal_cmd_write(dev, CMD_ENA); siw_hal_cmd_write(dev, CMD_RESET_LOW); touch_msleep(1 + hal_dbg_delay(chip, HAL_DBG_DLY_SW_RST_1)); siw_hal_cmd_write(dev, CMD_RESET_HIGH); siw_hal_cmd_write(dev, CMD_DIS); touch_msleep(ts->caps.sw_reset_delay); return 0; } static int siw_hal_sw_reset_default(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 chk_resp; u32 data; int ret = 0; siw_touch_irq_control(dev, INTERRUPT_DISABLE); /****************************************************** * Siliconworks does not recommend to use SW reset * * due to ist limitation in stability in LG4894. * ******************************************************/ t_dev_info(dev, "SW Reset\n"); ret = siw_hal_write_value(dev, reg->spr_rst_ctl, 7); ret = siw_hal_write_value(dev, reg->spr_rst_ctl, 0); /* Boot Start */ ret = siw_hal_write_value(dev, reg->spr_boot_ctl, 1); /* firmware boot done check */ chk_resp = FLASH_BOOTCHK_VALUE; ret = siw_hal_condition_wait(dev, reg->tc_flash_dn_status, &data, chk_resp, ~0, 10 + hal_dbg_delay(chip, HAL_DBG_DLY_SW_RST_0), 200); if (ret < 0) { t_dev_err(dev, "failed : boot check(%Xh), %Xh\n", chk_resp, data); goto out; } siw_touch_qd_init_work_sw(ts); out: return ret; } static int siw_hal_sw_reset(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; int ret = 0; switch (chip->opt.t_sw_rst) { case 1: ret = siw_hal_sw_reset_wh_cmd(dev); atomic_set(&chip->init, IC_INIT_NEED); break; default: ret = siw_hal_sw_reset_default(dev); atomic_set(&chip->init, IC_INIT_NEED); break; } return ret; } static int siw_hal_hw_reset(struct device *dev, int ctrl) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; t_dev_info(dev, "HW Reset(%s)\n", (ctrl == HW_RESET_ASYNC) ? "Async" : "Sync"); if (ctrl == HW_RESET_ASYNC) { siw_hal_reinit(dev, 0, hal_dbg_delay(chip, HAL_DBG_DLY_HW_RST_1), 0, NULL); siw_touch_qd_init_work_hw(ts); return 0; } siw_hal_reinit(dev, 0, ts->caps.hw_reset_delay, 1, siw_hal_init); return 0; } static int siw_hal_reset_ctrl(struct device *dev, int ctrl) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int ret = -EINVAL; mutex_lock(&ts->reset_lock); t_dev_info(dev, "%s reset control(%d)\n", touch_chip_name(ts), ctrl); siw_hal_watch_set_rtc_clear(dev); switch (ctrl) { case SW_RESET: ret = siw_hal_sw_reset(dev); break; case HW_RESET_ASYNC: case HW_RESET_SYNC: ret = siw_hal_hw_reset(dev, ctrl); break; default: t_dev_err(dev, "unknown reset type, %d\n", ctrl); break; } mutex_unlock(&ts->reset_lock); return ret; } static int siw_hal_fw_rd_value(struct device *dev, u32 addr, u32 *value) { u32 data; int ret; ret = siw_hal_read_value(dev, addr, &data); if (ret < 0) { return ret; } t_dev_dbg_base(dev, "FW upgrade: reg rd: addr[%04Xh], value[%08Xh], %d\n", addr, data, ret); if (value) *value = data; return 0; } static int siw_hal_fw_wr_value(struct device *dev, u32 addr, u32 value) { int ret; ret = siw_hal_write_value(dev, addr, value); if (ret < 0) { return ret; } t_dev_dbg_base(dev, "FW upgrade: reg wr: addr[%04Xh], value[%08Xh], %d\n", addr, value, ret); return 0; } static int siw_hal_fw_wr_seq(struct device *dev, u32 addr, u8 *data, int size) { int ret; ret = siw_hal_reg_write(dev, addr, (void *)data, size); if (ret < 0) { return ret; } t_dev_dbg_base(dev, "FW upgrade: reg wr: addr[%04Xh], data[%02X ...], %d\n", addr, data[0], ret); return 0; } static int siw_hal_fw_sram_wr_enable(struct device *dev, int onoff) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 data; int ret = 0; #if 0 ret = siw_hal_fw_rd_value(dev, reg->spr_sram_ctl, &data); if (ret < 0) { goto out; } if (onoff) data |= 0x01; else data &= ~0x01; ret = siw_hal_fw_wr_value(dev, reg->spr_sram_ctl, data); if (ret < 0) { goto out; } #else // data = !!onoff; data = (onoff) ? 0x03 : 0x00; ret = siw_hal_fw_wr_value(dev, reg->spr_sram_ctl, data); if (ret < 0) { goto out; } #endif out: return ret; } static int siw_hal_fw_upgrade_fw_core(struct device *dev, u8 *dn_buf, int dn_size) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u8 *fw_data; int fw_size; int fw_pos, curr_size; int ret = 0; fw_data = dn_buf; fw_size = dn_size; fw_pos = 0; while (fw_size) { t_dev_dbg_base(dev, "FW upgrade: fw_pos[%06Xh ...] = %02X %02X %02X %02X ...\n", fw_pos, fw_data[0], fw_data[1], fw_data[2], fw_data[3]); curr_size = min(fw_size, MAX_RW_SIZE); /* code sram base address write */ ret = siw_hal_fw_wr_value(dev, reg->spr_code_offset, fw_pos>>2); if (ret < 0) { goto out; } ret = siw_hal_fw_wr_seq(dev, reg->code_access_addr, (void *)fw_data, curr_size); if (ret < 0) { goto out; } fw_data += curr_size; fw_pos += curr_size; fw_size -= curr_size; } out: return ret; } static int siw_hal_fw_upgrade_conf_core(struct device *dev, u32 addr, u8 *dn_buf, int dn_size) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; int ret; /* conf sram base address write */ ret = siw_hal_fw_wr_value(dev, reg->serial_data_offset, addr); if (ret < 0) { goto out; } /* Conf data download to conf sram */ ret = siw_hal_fw_wr_seq(dev, reg->data_i2cbase_addr, (void *)dn_buf, dn_size); if (ret < 0) { goto out; } out: return ret; } #if defined(__SIW_FW_TYPE_1) /* * Common CONF + Specific CONF(s) */ enum { POW_C_CONF = 9, POW_S_CONF = 10, }; enum { NUM_C_CONF = 1, MIN_S_CONF = 1, MAX_S_CONF = 31, }; enum { MIN_S_CONF_IDX = 1, MAX_S_CONF_IDX = (MAX_S_CONF + 1), }; #define FW_BOOT_LOADER_INIT (0x74696E69) //"init" #define FW_BOOT_LOADER_CODE (0x544F4F42) //"BOOT" #define FW_BOOT_CODE_ADDR (0x044) #define FW_S_CONF_IDX_ADDR (0x260) #define FW_S_CONF_DN_ADDR (0x267) #define FW_TYPE_STR "FW_TYPE_1" #define FLASH_CONF_DNCHK_VALUE_TYPE_X (FLASH_CONF_DNCHK_VALUE | 0x0C) #define FLASH_CONF_SIZE_TYPE_X (1<<9) #define FW_POST_QUIRK_DELAY 20 #define FW_POST_QUIRK_COUNT 200 static int siw_hal_fw_upgrade_fw_post_quirk(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 chk_resp, data; int ret; ret = siw_hal_fw_wr_value(dev, FW_BOOT_CODE_ADDR, FW_BOOT_LOADER_INIT); if (ret < 0) { goto out; } /* Set Serial Dump Done */ ret = siw_hal_fw_wr_value(dev, reg->spr_boot_ctl, 1); if (ret < 0) { goto out; } /* Release CM3 core */ ret = siw_hal_fw_wr_value(dev, reg->spr_rst_ctl, 0); if (ret < 0) { goto out; } /* firmware boot done check */ chk_resp = FW_BOOT_LOADER_CODE; ret = siw_hal_condition_wait(dev, FW_BOOT_CODE_ADDR, &data, chk_resp, ~0, FW_POST_QUIRK_DELAY + hal_dbg_delay(chip, HAL_DBG_DLY_FW_0), FW_POST_QUIRK_COUNT); if (ret < 0) { t_dev_err(dev, "FW upgrade: failed - boot check(%Xh), %08Xh\n", chk_resp, data); goto out; } t_dev_info(dev, "FW upgrade: boot check done\n"); out: return ret; } static int siw_hal_fw_upgrade_conf_quirk(struct device *dev, u8 *fw_buf, int fw_size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int fw_size_max; u32 conf_dn_addr; u32 data; int ret = 0; if (!chip->fw.conf_index) { goto out; } fw_size_max = touch_fw_size(ts); ret = siw_hal_fw_rd_value(dev, FW_S_CONF_DN_ADDR, &data); if (ret < 0) { goto out; } conf_dn_addr = (data & 0xFFFF); t_dev_dbg_base(dev, "FW upgrade: s_conf_dn_addr %04Xh (%08Xh)\n", conf_dn_addr, data); data = fw_size_max + \ (NUM_C_CONF<<POW_C_CONF) + \ ((chip->fw.conf_index - 1)<<POW_S_CONF); ret = siw_hal_fw_upgrade_conf_core(dev, conf_dn_addr, (u8 *)&fw_buf[data], FLASH_CONF_SIZE); if (ret < 0) { goto out; } out: return ret; } #define S_CFG_DBG_IDX 0 static int siw_hal_fw_size_check(struct device *dev, int fw_size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int fw_size_max = touch_fw_size(ts); int size_min = (fw_size_max + (NUM_C_CONF<<POW_C_CONF) + (MIN_S_CONF<<POW_S_CONF)); int size_max = (fw_size_max + (NUM_C_CONF<<POW_C_CONF) + (MAX_S_CONF<<POW_S_CONF)); chip->fw.conf_index = 0; if ((fw_size < size_min) || (fw_size > size_max)) { t_dev_err(dev, "FW upgrade: wrong file size - %Xh,\n", fw_size); t_dev_err(dev, " shall be '%Xh <= x <= %Xh'\n", size_min, size_max); return -EFAULT; } return 0; } static int siw_hal_fw_size_check_post(struct device *dev, int fw_size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int fw_size_max = touch_fw_size(ts); int required_size; u32 index = 0; int ret = 0; #if (S_CFG_DBG_IDX != 0) index = S_CFG_DBG_IDX; t_dev_warn(dev, "FW upgrade: conf_index fixed for debugging: %d\n", index); #else ret = siw_hal_read_value(dev, FW_S_CONF_IDX_ADDR, &index); #endif if (ret < 0) { t_dev_err(dev, "FW upgrade: failed - conf_index(%04Xh) read, %d\n", FW_S_CONF_IDX_ADDR, ret); return ret; } if ((index < MIN_S_CONF_IDX) || (index > MAX_S_CONF_IDX)) { t_dev_err(dev, "FW upgrade: failed - wrong cfg index, %d\n", index); return -EFAULT; } t_dev_info(dev, "FW upgrade: conf_index: %d\n", index); required_size = fw_size_max + (NUM_C_CONF<<POW_C_CONF) + (index<<POW_S_CONF); if (fw_size < required_size) { t_dev_err(dev, "FW upgrade: wrong file size - %Xh < %Xh,\n", fw_size, required_size); return -EFAULT; } chip->fw.conf_index = index; return 0; } #else /* __FW_TYPE_1 */ #define FW_TYPE_STR "FW_TYPE_0" #define FLASH_CONF_DNCHK_VALUE_TYPE_X (FLASH_CONF_DNCHK_VALUE) #define FLASH_CONF_SIZE_TYPE_X FLASH_CONF_SIZE #define FW_POST_QUIRK_DELAY 20 #define FW_POST_QUIRK_COUNT 200 static int siw_hal_fw_upgrade_fw_post_quirk(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 chk_resp, data; int ret; /* Release CM3 core */ ret = siw_hal_fw_wr_value(dev, reg->spr_rst_ctl, 0); if (ret < 0) { goto out; } /* Set Serial Dump Done */ ret = siw_hal_fw_wr_value(dev, reg->spr_boot_ctl, 1); if (ret < 0) { goto out; } /* firmware boot done check */ chk_resp = FLASH_BOOTCHK_VALUE; ret = siw_hal_condition_wait(dev, reg->tc_flash_dn_status, &data, chk_resp, ~0, FW_POST_QUIRK_DELAY + hal_dbg_delay(chip, HAL_DBG_DLY_FW_0), FW_POST_QUIRK_COUNT); if (ret < 0) { t_dev_err(dev, "FW upgrade: failed - boot check(%Xh), %08Xh\n", chk_resp, data); goto out; } t_dev_info(dev, "FW upgrade: boot check done\n"); out: return ret; } static int siw_hal_fw_upgrade_conf_quirk(struct device *dev, u8 *fw_buf, int fw_size) { return 0; } static int siw_hal_fw_size_check(struct device *dev, int fw_size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int fw_size_max = touch_fw_size(ts); chip->fw.conf_index = 0; if ((fw_size != fw_size_max) && (fw_size != (fw_size_max + FLASH_CONF_SIZE))) { t_dev_err(dev, "FW upgrade: wrong file size - %Xh,\n", fw_size); t_dev_err(dev, " shall be '%Xh' or '%Xh + %Xh'\n", fw_size_max, fw_size_max, FLASH_CONF_SIZE); return -EFAULT; } return 0; } static int siw_hal_fw_size_check_post(struct device *dev, int fw_size) { return 0; } #endif /* __FW_TYPE_1 */ enum { BIN_VER_OFFSET_POS = 0xE8, BIN_VER_EXT_OFFSET_POS = 0xDC, BIN_PID_OFFSET_POS = 0xF0, }; static int siw_hal_fw_compare(struct device *dev, u8 *fw_buf) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_fw_info *fw = &chip->fw; struct siw_touch_fquirks *fquirks = touch_fquirks(ts); struct siw_hal_tc_version_bin *bin_ver; int fw_max_size = touch_fw_size(ts); u32 bin_ver_offset = 0; u32 bin_ver_ext_offset = 0; u32 bin_pid_offset = 0; u32 dev_major = 0; u32 dev_minor = 0; char pid[12] = {0, }; u32 bin_major = 0; u32 bin_minor = 0; // u32 bin_raw = 0; u32 bin_raw_ext = 0; int bin_diff = 0; int update = 0; // int ret = 0; if (fquirks->fwup_check) { update = fquirks->fwup_check(dev, fw_buf); if (update != -EAGAIN) { if (update < 0) { return update; } goto out; } update = 0; } if (fw->version_ext) { dev_major = fw->version_ext >> 8; dev_minor = fw->version_ext & 0xFF; } else { dev_major = fw->v.version.major; dev_minor = fw->v.version.minor; } if (atomic_read(&chip->boot) == IC_BOOT_FAIL) { update |= (1<<7); goto out; } if (!dev_major && !dev_minor){ t_dev_err(dev, "fw can not be 0.0!! Check your panel connection!!\n"); return 0; } bin_ver_offset = *((u32 *)&fw_buf[BIN_VER_OFFSET_POS]); if (!bin_ver_offset) { t_dev_err(dev, "FW compare: zero ver offset\n"); return -EINVAL; } if (chip->opt.f_ver_ext) { bin_ver_ext_offset = *((u32 *)&fw_buf[BIN_VER_EXT_OFFSET_POS]); } else { bin_ver_ext_offset = 0; } if ((fw->version_ext && !bin_ver_ext_offset) || (!fw->version_ext && bin_ver_ext_offset)) { if (!ts->force_fwup) { t_dev_warn(dev, "FW compare: different version format, " "use force update %s", (fw->version_ext) ? "(ext)" : ""); return -EINVAL; } bin_diff = 1; } bin_pid_offset = *((u32 *)&fw_buf[BIN_PID_OFFSET_POS]); if (!bin_pid_offset) { t_dev_err(dev, "FW compare: zero pid offset\n"); return -EINVAL; } memcpy(pid, &fw_buf[bin_pid_offset], 8); t_dev_dbg_base(dev, "pid %s\n", pid); if ((bin_ver_offset > fw_max_size) || (bin_ver_ext_offset > fw_max_size) || (bin_pid_offset > fw_max_size)) { t_dev_err(dev, "FW compare: invalid offset - ver %06Xh, ver_ext %06Xh pid %06Xh, max %06Xh\n", bin_ver_offset, bin_ver_ext_offset, bin_pid_offset, fw_max_size); return -EINVAL; } t_dev_dbg_base(dev, "ver %06Xh, ver_ext %06Xh, pid %06Xh\n", bin_ver_offset, bin_ver_ext_offset, bin_pid_offset); bin_ver = (struct siw_hal_tc_version_bin *)&fw_buf[bin_ver_offset]; bin_major = bin_ver->major; bin_minor = bin_ver->minor; if (bin_ver_ext_offset) { if (!bin_ver->ext) { t_dev_err(dev, "FW compare: (no ext flag in binary)\n"); return -EINVAL; } memcpy(&bin_raw_ext, &fw_buf[bin_ver_ext_offset], sizeof(bin_raw_ext)); bin_major = bin_raw_ext >> 8; bin_minor = bin_raw_ext & 0xFF; t_dev_info(dev, "FW compare: bin-ver: %08X (%s)(%d)\n", bin_raw_ext, pid, bin_diff); if (siw_hal_fw_chk_version_ext(bin_raw_ext, bin_ver->ext) < 0) { t_dev_err(dev, "FW compare: (invalid extension in binary)\n"); return -EINVAL; } } else { t_dev_info(dev, "FW compare: bin-ver: %d.%02d (%s)(%d)\n", bin_major, bin_minor, pid, bin_diff); } if (fw->version_ext) { t_dev_info(dev, "FW compare: dev-ver: %08X (%s)\n", fw->version_ext, fw->product_id); } else { t_dev_info(dev, "FW compare: dev-ver: %d.%02d (%s)\n", dev_major, dev_minor, fw->product_id); } if (ts->force_fwup) { update |= (1<<0); } else { if (bin_major > dev_major) { update |= (1<<1); } else if (bin_major == dev_major) { if (bin_minor > dev_minor) { update |= (1<<2); } } } if (memcmp(pid, fw->product_id, 8)) { t_dev_err(dev, "FW compare: bin-pid[%s] != dev-pid[%s], halted (up %02X, fup %02X)\n", pid, fw->product_id, update, ts->force_fwup); return -EINVAL; } out: t_dev_info(dev, "FW compare: up %02X, fup %02X\n", update, ts->force_fwup); return update; } #if defined(__FW_VERIFY_TEST) static int __siw_hal_fw_up_verify(struct device *dev, u8 *chk_buf, int chk_size) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u8 *fw_rd_data, *fw_data; u8 *r_data, *w_data; int fw_size; int fw_pos, curr_size; int i; int ret = 0; fw_size = chk_size; fw_rd_data = kmalloc(fw_size, GFP_KERNEL); if (!fw_rd_data) { t_dev_err(dev, "FW upgrade: failed to allocate verifying memory\n"); ret = -ENOMEM; goto out; } fw_data = fw_rd_data; fw_pos = 0; while (fw_size && fw_data) { curr_size = min(fw_size, MAX_RW_SIZE); /* code sram base address write */ ret = siw_hal_write_value(dev, reg->spr_code_offset, fw_pos>>2); if (ret < 0) { goto out_free; } ret = siw_hal_reg_read(dev, reg->code_access_addr, (void *)fw_data, curr_size); if (ret < 0) { goto out_free; } fw_data += curr_size; fw_pos += curr_size; fw_size -= curr_size; } r_data = fw_rd_data; w_data = chk_buf; fw_size = chk_size; for (i = 0; i < fw_size; i++) { if ((*r_data) != (*w_data)) { t_dev_err(dev, "* Err [%06X] rd(%02X) != wr(%02X)\n", i, (*r_data), (*w_data)); ret = -EFAULT; } else { #if 0 t_dev_info(dev, " OK! [%06X] rd(%02X) == wr(%02X)\n", i, (*r_data), (*w_data)); #endif } r_data++; w_data++; } if (ret >= 0) { t_dev_info(dev, "FW dn verified\n"); } out_free: kfree(fw_rd_data); out: return ret; } #else /* __FW_VERIFY_TEST */ static int __siw_hal_fw_up_verify(struct device *dev, u8 *chk_buf, int chk_size) { return 0; } #endif /* __FW_VERIFY_TEST */ static int siw_hal_fw_upgrade_fw_pre(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; int ret; /* Reset CM3 core */ ret = siw_hal_fw_wr_value(dev, reg->spr_rst_ctl, 2); if (ret < 0) { goto out; } /* Disable SRAM write protection */ ret = siw_hal_fw_sram_wr_enable(dev, 1); if (ret < 0) { goto out; } out: return ret; } #define FW_POST_DELAY 20 #define FW_POST_COUNT 200 static int siw_hal_fw_upgrade_fw_post(struct device *dev, int fw_size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 dn_cmd, chk_resp, data; int ret; /* Enable SRAM write protection */ ret = siw_hal_fw_sram_wr_enable(dev, 0); if (ret < 0) { goto out; } ret = siw_hal_fw_upgrade_fw_post_quirk(dev); if (ret < 0) { goto out; } ret = siw_hal_fw_size_check_post(dev, fw_size); if (ret < 0) { goto out; } /* Firmware Download Start */ dn_cmd = (FLASH_KEY_CODE_CMD << 16) | 1; ret = siw_hal_fw_wr_value(dev, reg->tc_flash_dn_ctl, dn_cmd); if (ret < 0) { goto out; } touch_msleep(ts->caps.hw_reset_delay); /* download check */ chk_resp = FLASH_CODE_DNCHK_VALUE; ret = siw_hal_condition_wait(dev, reg->tc_flash_dn_status, &data, chk_resp, 0xFFFF, FW_POST_DELAY + hal_dbg_delay(chip, HAL_DBG_DLY_FW_1), FW_POST_COUNT); if (ret < 0) { t_dev_err(dev, "FW upgrade: failed - code check(%Xh), %08Xh\n", chk_resp, data); goto out; } t_dev_info(dev, "FW upgrade: code check done\n"); out: return ret; } static int siw_hal_fw_upgrade_fw(struct device *dev, u8 *fw_buf, int fw_size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; u8 *fw_data; int fw_size_max; int ret = 0; /* * Stage 1-1 : download code data */ fw_size_max = touch_fw_size(ts); ret = siw_hal_fw_upgrade_fw_pre(dev); if (ret < 0) { goto out; } /* * [Caution] * The size for F/W upgrade is fw_size_max, not fw->size * because the fw file can have config area. */ fw_data = fw_buf; ret = siw_hal_fw_upgrade_fw_core(dev, fw_data, fw_size_max); if (ret < 0) { goto out; } ret = __siw_hal_fw_up_verify(dev, fw_data, fw_size_max); if (ret < 0) { goto out; } /* * Stage 1-2: upgrade code data */ ret = siw_hal_fw_upgrade_fw_post(dev, fw_size); if (ret < 0) { goto out; } out: return ret; } static int siw_hal_fw_upgrade_conf_pre(struct device *dev, u32 *value) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; int data = 0; int ret; ret = siw_hal_fw_rd_value(dev, reg->tc_confdn_base_addr, &data); if (ret < 0) { goto out; } out: if (value) *value = data; return ret; } #define CONF_POST_DELAY 20 #define CONF_POST_COUNT 200 static int siw_hal_fw_upgrade_conf_post(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 dn_cmd, chk_resp, data; int ret; /* Conf Download Start */ dn_cmd = (FLASH_KEY_CONF_CMD << 16) | 2; ret = siw_hal_fw_wr_value(dev, reg->tc_flash_dn_ctl, dn_cmd); if (ret < 0) { goto out; } /* Conf check */ chk_resp = FLASH_CONF_DNCHK_VALUE_TYPE_X; ret = siw_hal_condition_wait(dev, reg->tc_flash_dn_status, &data, chk_resp, 0xFFFF, CONF_POST_DELAY + hal_dbg_delay(chip, HAL_DBG_DLY_FW_2), CONF_POST_COUNT); if (ret < 0) { t_dev_err(dev, "FW upgrade: failed - conf check(%Xh), %X\n", chk_resp, data); ret = -EPERM; goto out; } t_dev_info(dev, "FW upgrade: conf check done\n"); /* Release & Reset CM3 */ ret = siw_hal_fw_wr_value(dev, reg->spr_rst_ctl, 1); if (ret < 0) { goto out; } out: return ret; } static int siw_hal_fw_upgrade_conf(struct device *dev, u8 *fw_buf, int fw_size) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int fw_size_max; u32 conf_dn_addr; u32 data; int ret; fw_size_max = touch_fw_size(ts); /* * Stage 2-1: download config data */ ret = siw_hal_fw_upgrade_conf_pre(dev, &data); if (ret < 0) { goto out; } conf_dn_addr = ((data >> 16) & 0xFFFF); t_dev_dbg_base(dev, "FW upgrade: conf_dn_addr %04Xh (%08Xh)\n", conf_dn_addr, data); #if 0 if (conf_dn_addr >= (0x1200) || conf_dn_addr < (0x8C0)) { t_dev_err(dev, "FW upgrade: failed - conf base invalid\n"); ret = -EPERM; goto out; } #endif /* C_CFG */ ret = siw_hal_fw_upgrade_conf_core(dev, conf_dn_addr, (u8 *)&fw_buf[fw_size_max], FLASH_CONF_SIZE_TYPE_X); if (ret < 0) { goto out; } ret = siw_hal_fw_upgrade_conf_quirk(dev, fw_buf, fw_size); if (ret < 0) { goto out; } /* * Stage 2-2: upgrade config data */ ret = siw_hal_fw_upgrade_conf_post(dev); if (ret < 0) { goto out; } out: return ret; } static int siw_hal_fw_upgrade(struct device *dev, u8 *fw_buf, int fw_size, int retry) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_touch_fquirks *fquirks = touch_fquirks(ts); int fw_size_max; u32 include_conf; int ret = 0; t_dev_info(dev, "===== FW upgrade: start (%d) =====\n", retry); if (fquirks->fwup_upgrade) { ret = fquirks->fwup_upgrade(dev, fw_buf, fw_size, retry); if (ret < 0) { goto out; } goto out_done; } fw_size_max = touch_fw_size(ts); ret = siw_hal_fw_size_check(dev, fw_size); if (ret < 0) { goto out; } include_conf = !!(fw_size > fw_size_max); t_dev_info(dev, "FW upgrade:%s include conf data\n", (include_conf) ? "" : " not"); t_dev_dbg_base(dev, "FW upgrade: fw size %08Xh, fw_size_max %08Xh\n", fw_size, fw_size_max); ret = siw_hal_fw_upgrade_fw(dev, fw_buf, fw_size); if (ret < 0) { goto out; } if (include_conf) { ret = siw_hal_fw_upgrade_conf(dev, fw_buf, fw_size); if (ret < 0) { goto out; } } out_done: t_dev_info(dev, "===== FW upgrade: done (%d) =====\n", retry); out: return ret; } static int siw_hal_fw_do_get_fw_abs(const struct firmware **fw_p, const char *name, struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct firmware *fw = NULL; struct file *filp = NULL; char *buf = NULL; loff_t size; int rd_size; int ret = 0; fw = kzalloc(sizeof(*fw), GFP_KERNEL); if (fw == NULL) { dev_err(dev, "can't allocate fw(struct firmware)\n"); return -ENOMEM; } filp = filp_open(name, O_RDONLY, 0); if (IS_ERR(filp)) { dev_err(dev, "can't open %s\n", name); return (int)PTR_ERR(filp); } size = vfs_llseek(filp, 0, SEEK_END); if (size < 0) { t_dev_err(dev, "invalid file size, %d\n", (int)size); ret = -EINVAL; goto out; } buf = kzalloc((size_t)size, GFP_KERNEL); if (buf == NULL) { t_dev_err(dev, "can't allocate firm buf\n"); ret = -ENOMEM; goto out; } rd_size = kernel_read(filp, 0, (char *)buf, (unsigned long)size); if (rd_size != (int)size) { t_dev_err(dev, "can't read[%d], %d\n", (int)size, (int)rd_size); ret = (rd_size < 0) ? rd_size : -EFAULT; goto out; } fw->data = buf; fw->size = size; fw->priv = ts; //for identification if (fw_p) { *fw_p = fw; } filp_close(filp, 0); return 0; out: if (buf) kfree(buf); if (fw) kfree(fw); filp_close(filp, 0); return ret; } static int siw_hal_fw_do_get_file(const struct firmware **fw_p, const char *name, struct device *dev, int abs_path) { if (abs_path) { return siw_hal_fw_do_get_fw_abs(fw_p, name, dev); } return request_firmware(fw_p, name, dev); } static int siw_hal_fw_get_file(const struct firmware **fw_p, char *fwpath, struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; const struct firmware *fw = NULL; char *src_path; int src_len; int abs_path = 0; int ret = 0; if (atomic_read(&ts->state.fb) >= FB_SUSPEND) { t_dev_warn(dev, "state.fb is not FB_RESUME\n"); ret = -EPERM; goto out; } if (ts->test_fwpath[0]) { src_path = (char *)ts->test_fwpath; } else if (ts->def_fwcnt) { src_path = (char *)ts->def_fwpath[0]; } else { t_dev_err(dev, "no target fw defined\n"); ret = -ENOENT; goto out; } /* * Absolute path option * ex) echo {root}/.../target_fw_img > fw_upgrade * ++++++~~~~~~~~~~~~~~~~~~ * flag | * absolute path */ src_len = strlen(src_path); if (strncmp(src_path, "{root}", 6) == 0) { abs_path = 1; src_path += 6; src_len -= 6; } strncpy(fwpath, src_path, src_len); fwpath[src_len] = 0; t_dev_info(dev, "target fw: %s (%s)\n", fwpath, (abs_path) ? "abs" : "rel"); ret = siw_hal_fw_do_get_file(&fw, (const char *)fwpath, dev, abs_path); if (ret < 0) { if (ret == -ENOENT) { t_dev_err(dev, "can't find fw: %s\n", fwpath); } else { t_dev_err(dev, "can't %s fw: %s, %d\n", (abs_path) ? "read" : "request", fwpath, ret); } goto out; } if (fw_p) { *fw_p = fw; } out: return ret; } static void siw_hal_fw_release_firm(struct device *dev, const struct firmware *fw) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; if (fw->priv == (void *)ts) { kfree(fw->data); kfree(fw); return; } release_firmware(fw); } /* * FW upgrade option * * 1. If TOUCH_USE_FW_BINARY used * 1-1 Default upgrade (through version comparison) * do upgarde using binary header link * 1-2 echo {bin} > fw_upgrade * do force-upgrade using binary header link (same as 1-1) * 1-3 echo /.../fw_img > fw_upgrade * do force-upgrade using request_firmware (relative path) * 1-4 echo {root}/.../fw_img > fw_upgrade * do force-upgrade using normal file open control (absolute path) * * 2. Else * 2-1 Default upgrade (through version comparison) * do upgarde using request_firmware (relative path) * 2-2 echo /.../fw_img > fw_upgrade * do force-upgrade using request_firmware (relative path) * 2-3 echo {root}/.../fw_img > fw_upgrade * do force-upgrade using normal file open control (absolute path) */ static int siw_hal_upgrade(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_touch_fw_bin *fw_bin = NULL; const struct firmware *fw = NULL; char *fwpath = NULL; u8 *fw_buf = NULL; int fw_max_size = touch_fw_size(ts); int fw_size = 0; int fw_up_binary = 0; int i = 0; int ret_val = 0; int ret = 0; t_dev_info(dev, "fw type: %s\n", FW_TYPE_STR); if (atomic_read(&ts->state.fb) >= FB_SUSPEND) { t_dev_warn(dev, "state.fb is not FB_RESUME\n"); return -EPERM; } fwpath = touch_getname(); if (fwpath == NULL) { t_dev_err(dev, "failed to allocate name buffer - fwpath\n"); return -ENOMEM; } if (touch_flags(ts) & TOUCH_USE_FW_BINARY) { fw_up_binary = 1; if (ts->force_fwup & FORCE_FWUP_SYS_STORE) { switch (ts->test_fwpath[0]) { case 0: /* fall through */ case ' ': /* ignore space */ break; default: /* if target string is not "{bin}" */ if (strncmp(ts->test_fwpath, "{bin}", 5) != 0) { fw_up_binary = 0; } break; } } } if (fw_up_binary) { t_dev_info(dev, "getting fw from binary header data\n"); fw_bin = touch_fw_bin(ts); if (fw_bin != NULL) { fw_buf = fw_bin->fw_data; fw_size = fw_bin->fw_size; } else { t_dev_warn(dev, "empty fw info\n"); } } else { t_dev_info(dev, "getting fw from file\n"); ret = siw_hal_fw_get_file(&fw, fwpath, dev); if (ret < 0) { goto out; } fw_buf = (u8 *)fw->data; fw_size = (int)fw->size; } // ret = -EINVAL; ret = -EPERM; if ((fw_buf == NULL) || !fw_size) { t_dev_err(dev, "invalid fw info\n"); goto out; } if (fw_size < fw_max_size) { t_dev_err(dev, "invalid fw size: %Xh < %Xh\n", fw_size, fw_max_size); goto out; } t_dev_info(dev, "fw size: %d\n", fw_size); ret_val = siw_hal_fw_compare(dev, fw_buf); if (ret_val < 0) { ret = ret_val; } else if (ret_val) { touch_msleep(200); for (i = 0; i < 2 && ret; i++) { ret = siw_hal_fw_upgrade(dev, fw_buf, fw_size, i); } } if (fw) { siw_hal_fw_release_firm(dev, fw); } out: if (ret) { siwmon_submit_ops_step_chip_wh_name(dev, "%s - FW upgrade halted", touch_chip_name(ts), ret); } else { siwmon_submit_ops_step_chip_wh_name(dev, "%s - FW upgrade done", touch_chip_name(ts), ret); } touch_putname(fwpath); return ret; } #if defined(__SIW_CONFIG_KNOCK) static void siw_hal_set_debug_reason(struct device *dev, int type) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 wdata[2] = {0, }; // int ret = 0; if (!chip->tci_debug_type) return; wdata[0] = (u32)type; wdata[0] |= (chip->tci_debug_type == 1) ? 0x01 << 2 : 0x01 << 3; wdata[1] = TCI_DEBUG_ALL; t_dev_info(dev, "TCI%d-type:%d\n", type + 1, wdata[0]); siw_hal_reg_write(dev, reg->tci_fail_debug_w, (void *)wdata, sizeof(wdata)); } static int siw_hal_tci_knock(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct tci_info *info1 = &ts->tci.info[TCI_1]; struct tci_info *info2 = &ts->tci.info[TCI_2]; u32 lpwg_data[7]; int ret = 0; siw_hal_set_debug_reason(dev, TCI_1); lpwg_data[0] = ts->tci.mode; lpwg_data[1] = info1->tap_count | (info2->tap_count << 16); lpwg_data[2] = info1->min_intertap | (info2->min_intertap << 16); lpwg_data[3] = info1->max_intertap | (info2->max_intertap << 16); lpwg_data[4] = info1->touch_slop | (info2->touch_slop << 16); lpwg_data[5] = info1->tap_distance | (info2->tap_distance << 16); lpwg_data[6] = info1->intr_delay | (info2->intr_delay << 16); t_dev_dbg_base(dev, "lpwg_data[0] : %08Xh\n", lpwg_data[0]); t_dev_dbg_base(dev, "lpwg_data[1] : %08Xh\n", lpwg_data[1]); t_dev_dbg_base(dev, "lpwg_data[2] : %08Xh\n", lpwg_data[2]); t_dev_dbg_base(dev, "lpwg_data[3] : %08Xh\n", lpwg_data[3]); t_dev_dbg_base(dev, "lpwg_data[4] : %08Xh\n", lpwg_data[4]); t_dev_dbg_base(dev, "lpwg_data[5] : %08Xh\n", lpwg_data[5]); t_dev_dbg_base(dev, "lpwg_data[6] : %08Xh\n", lpwg_data[6]); ret = siw_hal_reg_write(dev, reg->tci_enable_w, (void *)lpwg_data, sizeof(lpwg_data)); return ret; } static int siw_hal_tci_password(struct device *dev) { // struct siw_touch_chip *chip = to_touch_chip(dev); siw_hal_set_debug_reason(dev, TCI_2); return siw_hal_tci_knock(dev); } static int siw_hal_do_tci_active_area(struct device *dev, u32 x1, u32 y1, u32 x2, u32 y2) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; int ret = 0; ret = siw_hal_write_value(dev, reg->act_area_x1_w, x1); if (ret < 0) { goto out; } ret = siw_hal_write_value(dev, reg->act_area_y1_w, y1); if (ret < 0) { goto out; } ret = siw_hal_write_value(dev, reg->act_area_x2_w, x2); if (ret < 0) { goto out; } ret = siw_hal_write_value(dev, reg->act_area_y2_w, y2); if (ret < 0) { goto out; } out: return ret; } static int siw_hal_tci_active_area(struct device *dev, u32 x1, u32 y1, u32 x2, u32 y2, int type) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; // struct siw_hal_reg *reg = chip->reg; int margin = touch_senseless_margin(ts); u32 area[4] = { 0, }; int i; t_dev_info(dev, "tci_active_area[%d]: x1[%Xh], y1[%Xh], x2[%Xh], y2[%Xh]\n", type, x1, y1, x2, y2); if (type == ACTIVE_AREA_RESET_CTRL) { return siw_hal_do_tci_active_area(dev, x1, y1, x2, y2); } area[0] = (x1 + margin) & 0xFFFF; area[1] = (y1 + margin) & 0xFFFF; area[2] = (x2 - margin) & 0xFFFF; area[3] = (y2 - margin) & 0xFFFF; for (i = 0; i < ARRAY_SIZE(area); i++) { area[i] = (area[i]) | (area[i]<<16); } return siw_hal_do_tci_active_area(dev, area[0], area[1], area[2], area[3]); } static int siw_hal_tci_area_set(struct device *dev, int cover_status) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct reset_area *qcover; const char *msg; if (touch_mode_not_allowed(ts, LCD_MODE_U3_QUICKCOVER)) { return 0; } qcover = (cover_status == QUICKCOVER_CLOSE) ? &ts->tci.qcover_close : &ts->tci.qcover_open; msg = (cover_status == QUICKCOVER_CLOSE) ? "close" : "open"; if (qcover->x1 != ~0) { siw_hal_tci_active_area(dev, qcover->x1, qcover->y1, qcover->x2, qcover->y2, 0); t_dev_info(dev, "lpwg active area - qcover %s\n", msg); } return 0; } static int siw_hal_tci_control(struct device *dev, int type) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct tci_ctrl *tci = &ts->tci; struct active_area *area = &tci->area; struct reset_area *rst_area = &tci->rst_area; struct tci_info *info1 = &tci->info[TCI_1]; struct tci_info *info2 = &tci->info[TCI_2]; u32 reg_w = ~0; u32 data; int ret = 0; switch (type) { case ENABLE_CTRL: reg_w = reg->tci_enable_w; data = tci->mode; break; case TAP_COUNT_CTRL: reg_w = reg->tap_count_w; data = info1->tap_count | (info2->tap_count << 16); break; case MIN_INTERTAP_CTRL: reg_w = reg->min_intertap_w; data = info1->min_intertap | (info2->min_intertap << 16); break; case MAX_INTERTAP_CTRL: reg_w = reg->max_intertap_w; data = info1->max_intertap | (info2->max_intertap << 16); break; case TOUCH_SLOP_CTRL: reg_w = reg->touch_slop_w; data = info1->touch_slop | (info2->touch_slop << 16); break; case TAP_DISTANCE_CTRL: reg_w = reg->tap_distance_w; data = info1->tap_distance | (info2->tap_distance << 16); break; case INTERRUPT_DELAY_CTRL: reg_w = reg->int_delay_w; data = info1->intr_delay | (info2->intr_delay << 16); break; case ACTIVE_AREA_CTRL: ret = siw_hal_tci_active_area(dev, area->x1, area->y1, area->x2, area->y2, type); break; case ACTIVE_AREA_RESET_CTRL: ret = siw_hal_tci_active_area(dev, rst_area->x1, rst_area->y1, rst_area->x2, rst_area->y2, type); break; default: break; } if (reg_w != ~0) { ret = siw_hal_write_value(dev, reg_w, data); } return ret; } static int siw_hal_lpwg_control(struct device *dev, int mode) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct tci_info *info1 = &ts->tci.info[TCI_1]; int ret = 0; switch (mode) { case LPWG_DOUBLE_TAP: ts->tci.mode = 0x01; info1->intr_delay = 0; info1->tap_distance = 10; if (touch_senseless_margin(ts)) { ret = siw_hal_tci_control(dev, ACTIVE_AREA_CTRL); if (ret < 0) { break; } } ret = siw_hal_tci_knock(dev); break; case LPWG_PASSWORD: ts->tci.mode = 0x01 | (0x01 << 16); info1->intr_delay = ts->tci.double_tap_check ? 68 : 0; info1->tap_distance = 7; if (touch_senseless_margin(ts)) { ret = siw_hal_tci_control(dev, ACTIVE_AREA_CTRL); if (ret < 0) { break; } } ret = siw_hal_tci_password(dev); break; default: ts->tci.mode = 0; ret = siw_hal_tci_control(dev, ENABLE_CTRL); break; } t_dev_info(dev, "lpwg_control mode = %d\n", mode); return ret; } #else /* __SIW_SUPPORT_KNOCK */ static int siw_hal_tci_area_set(struct device *dev, int cover_status) { return 0; } static int siw_hal_lpwg_control(struct device *dev, int mode) { return 0; } #endif /* __SIW_SUPPORT_KNOCK */ static int siw_hal_clock_type_1(struct device *dev, bool onoff) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; siw_hal_cmd_write(dev, CMD_ENA); if (onoff) { siw_hal_cmd_write(dev, CMD_OSC_ON); siw_hal_cmd_write(dev, CMD_CLK_ON); atomic_set(&ts->state.sleep, IC_NORMAL); } else { if (chip->lcd_mode == LCD_MODE_U0) { siw_hal_cmd_write(dev, CMD_CLK_OFF); siw_hal_cmd_write(dev, CMD_OSC_OFF); atomic_set(&ts->state.sleep, IC_DEEP_SLEEP); } } siw_hal_cmd_write(dev, CMD_DIS); t_dev_info(dev, "siw_hal_clock -> %s\n", (onoff) ? "ON" : (chip->lcd_mode) == 0 ? "OFF" : "SKIP"); return 0; } static int siw_hal_clock(struct device *dev, bool onoff) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int ret = 0; siw_touch_sys_osc(dev, onoff); switch (chip->opt.t_clock) { case 1: ret = siw_hal_clock_type_1(dev, onoff); break; default: atomic_set(&ts->state.sleep, (onoff) ? IC_NORMAL : IC_DEEP_SLEEP); t_dev_info(dev, "sleep state -> %s\n", (onoff) ? "IC_NORMAL" : "IC_DEEP_SLEEP"); break; } return ret; } #if defined(__SIW_CONFIG_SWIPE) static int siw_hal_swipe_active_area(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_swipe_info *left = &chip->swipe.info[SWIPE_L]; struct siw_hal_swipe_info *right = &chip->swipe.info[SWIPE_R]; u32 active_area[4] = {0x0, }; int ret = 0; active_area[0] = (right->area.x1) | (left->area.x1 << 16); active_area[1] = (right->area.y1) | (left->area.y1 << 16); active_area[2] = (right->area.x2) | (left->area.x2 << 16); active_area[3] = (right->area.y2) | (left->area.y2 << 16); ret = siw_hal_reg_write(dev, reg->swipe_act_area_x1_w, (void *)active_area, sizeof(active_area)); return ret; } static int siw_hal_swipe_control(struct device *dev, int type) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_swipe_info *left = &chip->swipe.info[SWIPE_L]; struct siw_hal_swipe_info *right = &chip->swipe.info[SWIPE_R]; u32 reg_w = ~0; u32 data = 0; int ret = 0; switch (type) { case SWIPE_ENABLE_CTRL: case SWIPE_DISABLE_CTRL: reg_w = reg->swipe_enable_w; data = (type == SWIPE_ENABLE_CTRL) ? chip->swipe.mode : 0; break; case SWIPE_DIST_CTRL: reg_w = reg->swipe_dist_w; data = (right->distance) | (left->distance << 16); break; case SWIPE_RATIO_THR_CTRL: reg_w = reg->swipe_ratio_thr_w; data = (right->ratio_thres) | (left->ratio_thres << 16); break; case SWIPE_RATIO_PERIOD_CTRL: reg_w = reg->swipe_ratio_period_w; data = (right->ratio_period) | (left->ratio_period << 16); break; case SWIPE_RATIO_DIST_CTRL: reg_w = reg->swipe_ratio_dist_w; data = (right->ratio_distance) | (left->ratio_distance << 16); break; case SWIPE_TIME_MIN_CTRL: reg_w = reg->swipe_time_min_w; data = (right->min_time) | (left->min_time << 16); break; case SWIPE_TIME_MAX_CTRL: reg_w = reg->swipe_time_max_w; data = (right->max_time) | (left->max_time << 16); break; case SWIPE_AREA_CTRL: ret = siw_hal_swipe_active_area(dev); break; default: break; } if (reg_w != ~0) { ret = siw_hal_write_value(dev, reg_w, data); } return ret; } static int siw_hal_swipe_mode(struct device *dev, int mode) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_swipe_info *left = &chip->swipe.info[SWIPE_L]; struct siw_hal_swipe_info *right = &chip->swipe.info[SWIPE_R]; u32 swipe_data[11] = {0x0, }; int ret = 0; if (!chip->swipe.mode || (mode != LCD_MODE_U2)) { ret = siw_hal_swipe_control(dev, SWIPE_DISABLE_CTRL); t_dev_dbg_base(dev, "swipe disabled\n"); goto out; } swipe_data[0] = chip->swipe.mode; swipe_data[1] = (right->distance) | (left->distance << 16); swipe_data[2] = (right->ratio_thres) | (left->ratio_thres << 16); swipe_data[3] = (right->ratio_distance) | (left->ratio_distance << 16); swipe_data[4] = (right->ratio_period) | (left->ratio_period << 16); swipe_data[5] = (right->min_time) | (left->min_time << 16); swipe_data[6] = (right->max_time) | (left->max_time << 16); swipe_data[7] = (right->area.x1) | (left->area.x1 << 16); swipe_data[8] = (right->area.y1) | (left->area.y1 << 16); swipe_data[9] = (right->area.x2) | (left->area.x2 << 16); swipe_data[10] = (right->area.y2) | (left->area.y2 << 16); ret = siw_hal_reg_write(dev, reg->swipe_enable_w, (void *)swipe_data, sizeof(swipe_data)); if (ret >= 0) { t_dev_info(dev, "swipe enabled\n"); } out: return ret; } #else /* __SIW_CONFIG_SWIPE */ static int siw_hal_swipe_mode(struct device *dev, int mode) { return 0; } #endif /* __SIW_CONFIG_SWIPE */ static int siw_hal_tc_con_type_g(struct device *dev, u32 addr, int value, char *name) { int ret = 0; ret = siw_hal_write_value(dev, addr, value); if (ret < 0) { t_dev_err(dev, "failed to set %s[%04Xh], %d\n", name, addr, ret); goto out; } t_dev_info(dev, "%s[%04Xh]: %s(%08Xh)\n", name, addr, (value & 0x1) ? "ON" : "OFF", value); out: return ret; } static int siw_hal_tc_con_glove(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 addr = reg->glove_en; int value = atomic_read(&ts->state.glove); int ret = 0; if (chip->opt.f_glove_en) { ret = siw_hal_tc_con_type_g(dev, addr, value, "glove_en"); } return ret; } static int siw_hal_tc_con_grab(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 addr = reg->grab_en; int value = atomic_read(&ts->state.grab); int ret = 0; if (chip->opt.f_grab_en) { ret = siw_hal_tc_con_type_g(dev, addr, value, "grab_en"); } return ret; } static int siw_hal_tc_con(struct device *dev, u32 code, void *param) { // struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; int ret = 0; switch (code) { case TCON_GLOVE: ret = siw_hal_tc_con_glove(dev); break; case TCON_GRAB: ret = siw_hal_tc_con_grab(dev); break; } return ret; } #define HAL_TC_DRIVING_DELAY 20 static inline int __used siw_hal_tc_driving_u0(struct device *dev) { return TC_DRIVE_CTL_START; } static inline int __used siw_hal_tc_driving_u2(struct device *dev) { return (TC_DRIVE_CTL_DISP_U2 | TC_DRIVE_CTL_START); //0x101 } static inline int __used siw_hal_tc_driving_u3(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int ctrl = (TC_DRIVE_CTL_DISP_U3 | TC_DRIVE_CTL_MODE_6LHB | TC_DRIVE_CTL_START); if (touch_flags(ts) & TOUCH_USE_VBLANK) ctrl &= ~TC_DRIVE_CTL_MODE_6LHB; if (atomic_read(&ts->state.debug_option_mask) & DEBUG_OPTION_1) ctrl &= ~TC_DRIVE_CTL_MODE_6LHB; return ctrl; } static inline int __used siw_hal_tc_driving_u3_partial(struct device *dev) { return (TC_DRIVE_CTL_PARTIAL | siw_hal_tc_driving_u3(dev)); } static inline int __used siw_hal_tc_driving_u3_qcover(struct device *dev) { return (TC_DRIVE_CTL_QCOVER | siw_hal_tc_driving_u3(dev)); } static inline int siw_hal_tc_driving_stop(struct device *dev) { return TC_DRIVE_CTL_STOP; } static void siw_hal_chk_dbg_report(struct device *dev, u32 status, int irq) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; u32 debug_mask = (status >> 16) & 0x0F; u32 ic_debug[4]; u32 debug_info = 0; u32 debug_len = 0; u32 debug_type = 0; int ret = 0; if (!chip->opt.f_dbg_report) { return; } /* * 0x03 : Error report * 0x04 : Debug report */ switch (debug_mask) { case 0x03: case 0x04: break; default: return; } ret = siw_hal_reg_read(dev, 0x23E, ic_debug, sizeof(ic_debug)); if (ret < 0) { return; } debug_info = ic_debug[3]; debug_len = ((debug_info>>24) & 0xFF); debug_type = (debug_info & ((1<<24)-1)); t_dev_info(dev, "[%d] ic debug: s %08Xh / m %Xh, l %Xh, t %Xh (%08Xh)\n", irq, status, debug_mask, debug_len, debug_type, debug_info); t_dev_info(dev, "[%d] ic debug: log %08Xh %08Xh %08Xh\n", irq, ic_debug[0], ic_debug[1], ic_debug[2]); } static int siw_hal_tc_driving_post(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_fw_info *fw = &chip->fw; u32 addr[4] = { 0, }; u32 rdata; int ret = 0; switch (chip->opt.t_chk_mipi) { case 1: if (chip->driving_mode != LCD_MODE_U3) { break; } rdata = 0; switch (fw->v.version.major) { case 0 : case 1 : rdata = !!(fw->v.version.minor > 14); break; } addr[0] = (rdata) ? 0x284 : 0; break; default: goto out; } if (addr[0]) { rdata = 0; ret = siw_hal_read_value(dev, addr[0], &rdata); if (ret < 0) { goto out; } if (rdata) { t_dev_err(dev, "!! [Warning] !!\n"); t_dev_err(dev, " Check MIPI script (%d)\n", rdata); t_dev_err(dev, " Maybe, MIPI(VIDEO) vs. FW(CMD) or vice versa.\n"); } } out: return 0; } static int siw_hal_tc_driving(struct device *dev, int mode) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 tc_status = 0; u32 running_status = 0; u32 ctrl = 0; u32 rdata; int re_init = 0; int ret = 0; if (atomic_read(&ts->state.sleep) == IC_DEEP_SLEEP) { t_dev_warn(dev, "can not control tc driving - deep sleep state\n"); return 0; } chip->driving_mode = mode; if (touch_mode_not_allowed(ts, mode)) { return -EPERM; } switch (mode) { case LCD_MODE_U0: ctrl = siw_hal_tc_driving_u0(dev); break; case LCD_MODE_U2_UNBLANK: case LCD_MODE_U2: ctrl = siw_hal_tc_driving_u2(dev); break; case LCD_MODE_U3: ctrl = siw_hal_tc_driving_u3(dev); break; case LCD_MODE_U3_PARTIAL: ctrl = siw_hal_tc_driving_u3_partial(dev); break; case LCD_MODE_U3_QUICKCOVER: ctrl = siw_hal_tc_driving_u3_qcover(dev); break; case LCD_MODE_STOP: ctrl = siw_hal_tc_driving_stop(dev); break; default: t_dev_err(dev, "mode(%d) not supported\n", mode); return -ESRCH; } /* swipe set */ ret = siw_hal_swipe_mode(dev, mode); if (ret < 0) { t_dev_warn(dev, "swipe mode err, %d", ret); } if ((mode == LCD_MODE_U0) || (mode == LCD_MODE_U2)) { int middle_delay = 0; switch (touch_chip_type(ts)) { case CHIP_LG4895: middle_delay = 200; break; } touch_msleep(middle_delay); } touch_msleep(hal_dbg_delay(chip, HAL_DBG_DLY_TC_DRIVING_0)); t_dev_info(dev, "current driving mode is %s\n", siw_lcd_driving_mode_str(mode)); ret = siw_hal_read_value(dev, reg->spr_subdisp_status, &rdata); t_dev_info(dev, "DDI Display Mode[%04Xh] = 0x%08X\n", reg->spr_subdisp_status, rdata); ret = siw_hal_write_value(dev, reg->tc_drive_ctl, ctrl); t_dev_info(dev, "TC Driving[%04Xh] wr 0x%08X\n", reg->tc_drive_ctl, ctrl); rdata = HAL_TC_DRIVING_DELAY + hal_dbg_delay(chip, HAL_DBG_DLY_TC_DRIVING_1); touch_msleep(rdata); t_dev_dbg_base(dev, "waiting %d msecs\n", rdata); if (siw_touch_boot_mode_tc_check(dev)) { goto out; } if (mode == LCD_MODE_U3_PARTIAL) { goto out; } siw_hal_tc_driving_post(dev); ret = siw_hal_read_value(dev, reg->tc_status, &tc_status); if (ret < 0) { t_dev_err(dev, "failed to get tc_status\n"); atomic_set(&ts->recur_chk, 0); return ret; } siw_hal_chk_dbg_report(dev, tc_status, 0); running_status = tc_status & 0x1F; re_init = 0; if (mode == LCD_MODE_STOP) { re_init = !!running_status; } else { if (!running_status || (running_status == 0x10) || (running_status == 0x0F)){ re_init = 1; } } if (re_init) { ret = siw_hal_read_value(dev, reg->spr_subdisp_status, &rdata); if (atomic_read(&ts->recur_chk)) { t_dev_err(dev, "command failed: mode %d, tc_status %08Xh, DDI %08Xh\n", mode, tc_status, rdata); atomic_set(&ts->recur_chk, 0); return -EFAULT; } t_dev_err(dev, "command missed: mode %d, tc_status %08Xh, DDI %08Xh\n", mode, tc_status, rdata); atomic_set(&ts->recur_chk, 1); siw_hal_reinit(dev, 1, 100 + hal_dbg_delay(chip, HAL_DBG_DLY_HW_RST_2), 1, siw_hal_init); } else { t_dev_info(dev, "command done: mode %d, running_sts %02Xh\n", mode, running_status); } out: siw_hal_tc_con_glove(dev); siw_hal_tc_con_grab(dev); atomic_set(&ts->recur_chk, 0); return 0; } static void siw_hal_deep_sleep(struct device *dev) { t_dev_info(dev, "deep sleep\n"); siw_hal_tc_driving(dev, LCD_MODE_STOP); siw_hal_clock(dev, 0); } #if defined(__SIW_CONFIG_KNOCK) static void siw_hal_debug_tci(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u8 debug_reason_buf[TCI_MAX_NUM][TCI_DEBUG_MAX_NUM]; u32 rdata[9] = {0, }; u8 count[2] = {0, }; u8 count_max = 0; u32 i, j = 0; u8 buf = 0; int ret = 0; if (!chip->tci_debug_type) return; ret = siw_hal_reg_read(dev, reg->tci_debug_r, (void *)&rdata, sizeof(rdata)); count[TCI_1] = (rdata[0] & 0xFFFF); count[TCI_2] = ((rdata[0] >> 16) & 0xFFFF); count_max = (count[TCI_1] > count[TCI_2]) ? count[TCI_1] : count[TCI_2]; if (count_max == 0) return; if (count_max > TCI_DEBUG_MAX_NUM) { count_max = TCI_DEBUG_MAX_NUM; if (count[TCI_1] > TCI_DEBUG_MAX_NUM) count[TCI_1] = TCI_DEBUG_MAX_NUM; if (count[TCI_2] > TCI_DEBUG_MAX_NUM) count[TCI_2] = TCI_DEBUG_MAX_NUM; } for (i = 0; i < ((count_max-1)>>2)+1; i++) { memcpy(&debug_reason_buf[TCI_1][i<<2], &rdata[i+1], sizeof(u32)); memcpy(&debug_reason_buf[TCI_2][i<<2], &rdata[i+5], sizeof(u32)); } t_dev_info(dev, "TCI count_max = %d\n", count_max); for (i = 0; i < TCI_MAX_NUM; i++) { t_dev_info(dev, "TCI count[%d] = %d\n", i, count[i]); for (j = 0; j < count[i]; j++) { buf = debug_reason_buf[i][j]; t_dev_info(dev, "TCI_%d - DBG[%d/%d]: %s(%d)\n", i + 1, j + 1, count[i], (buf > 0 && buf < TCI_FAIL_NUM) ? siw_hal_tci_debug_str[buf] : siw_hal_tci_debug_str[0], buf); } } } #else /* __SIW_CONFIG_KNOCK */ static void siw_hal_debug_tci(struct device *dev) { } #endif /* __SIW_CONFIG_KNOCK */ #if defined(__SIW_CONFIG_SWIPE) static void siw_hal_debug_swipe(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u8 debug_reason_buf[SWIPE_MAX_NUM][SWIPE_DEBUG_MAX_NUM]; u32 rdata[5] = {0 , }; u8 count[2] = {0, }; u8 count_max = 0; u32 i, j = 0; u8 buf = 0; int ret = 0; if (!chip->swipe_debug_type) return; ret = siw_hal_reg_read(dev, reg->swipe_debug_r, (void *)&rdata, sizeof(rdata)); count[SWIPE_R] = (rdata[0] & 0xFFFF); count[SWIPE_L] = ((rdata[0] >> 16) & 0xFFFF); count_max = (count[SWIPE_R] > count[SWIPE_L]) ? count[SWIPE_R] : count[SWIPE_L]; if (count_max == 0) return; if (count_max > SWIPE_DEBUG_MAX_NUM) { count_max = SWIPE_DEBUG_MAX_NUM; if (count[SWIPE_R] > SWIPE_DEBUG_MAX_NUM) count[SWIPE_R] = SWIPE_DEBUG_MAX_NUM; if (count[SWIPE_L] > SWIPE_DEBUG_MAX_NUM) count[SWIPE_L] = SWIPE_DEBUG_MAX_NUM; } for (i = 0; i < ((count_max-1)>>2)+1; i++) { memcpy(&debug_reason_buf[SWIPE_R][i<<2], &rdata[i+1], sizeof(u32)); memcpy(&debug_reason_buf[SWIPE_L][i<<2], &rdata[i+3], sizeof(u32)); } for (i = 0; i < SWIPE_MAX_NUM; i++) { for (j = 0; j < count[i]; j++) { buf = debug_reason_buf[i][j]; t_dev_info(dev, "SWIPE_%s - DBG[%d/%d]: %s\n", i == SWIPE_R ? "Right" : "Left", j + 1, count[i], (buf > 0 && buf < SWIPE_FAIL_NUM) ? siw_hal_swipe_debug_str[buf] : siw_hal_swipe_debug_str[0]); } } } #else /* __SIW_CONFIG_SWIPE */ static void siw_hal_debug_swipe(struct device *dev) { } #endif /* __SIW_CONFIG_SWIPE */ static void siw_hal_lpwg_ctrl_init(struct lpwg_mode_ctrl *ctrl) { ctrl->clk = LPWG_SET_SKIP; ctrl->qcover = LPWG_SET_SKIP; ctrl->lpwg = LPWG_SET_SKIP; ctrl->lcd = LPWG_SET_SKIP; } static int siw_hal_lpwg_ctrl(struct device *dev, struct lpwg_mode_ctrl *ctrl) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int ret = 0; if (ctrl->clk != LPWG_SET_SKIP) { if (atomic_read(&ts->state.sleep) == IC_DEEP_SLEEP) { siw_hal_clock(dev, ctrl->clk); } } if (ctrl->qcover != LPWG_SET_SKIP) { ret = siw_hal_tci_area_set(dev, ctrl->qcover); if (ret < 0) { goto out; } } if (ctrl->lpwg != LPWG_SET_SKIP) { ret = siw_hal_lpwg_control(dev, ctrl->lpwg); if (ret < 0) { goto out; } } if (ctrl->lcd != LPWG_SET_SKIP) { ret = siw_hal_tc_driving(dev, ctrl->lcd); } out: return ret; } static int siw_hal_lpwg_ctrl_skip(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; t_dev_info(dev, "skip lpwg_mode\n"); if (atomic_read(&ts->state.sleep) == IC_DEEP_SLEEP) { siw_hal_clock(dev, 1); } siw_hal_debug_tci(dev); siw_hal_debug_swipe(dev); return 0; } static int siw_hal_lpwg_mode_suspend(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct lpwg_mode_ctrl ctrl; int changed = 0; int ret = 0; siw_hal_lpwg_ctrl_init(&ctrl); t_dev_info(dev, "lpwg suspend: mode %d, screen %d\n", ts->lpwg.mode, ts->lpwg.screen); if (ts->role.mfts_lpwg) { t_dev_info(dev, "lpwg suspend: mfts_lpwg\n"); ctrl.lpwg = LPWG_DOUBLE_TAP, ctrl.lcd = chip->lcd_mode; goto out_con; } if (ts->lpwg.mode == LPWG_NONE) { if (ts->lpwg.screen) { siw_hal_clock(dev, 1); } else { siw_hal_deep_sleep(dev); } goto out; } if (ts->lpwg.screen) { siw_hal_lpwg_ctrl_skip(dev); goto out; } #if defined(__SIW_CONFIG_PROX_ON_SUSPEND) if (ts->lpwg.sensor == PROX_NEAR) { t_dev_info(dev, "lpwg suspend: (ts->lpwg.sensor == PROX_NEAR)\n"); siw_hal_deep_sleep(dev); goto out; } #endif if (ts->lpwg.qcover == HOLE_NEAR) { /* knock on/code disable */ ctrl.clk = 1; ctrl.qcover = QUICKCOVER_CLOSE; ctrl.lpwg = LPWG_NONE; ctrl.lcd = chip->lcd_mode; goto out_con; } /* knock on/code */ ctrl.clk = 1; ctrl.qcover = QUICKCOVER_OPEN; ctrl.lpwg = ts->lpwg.mode; ctrl.lcd = chip->lcd_mode; out_con: ret = siw_hal_lpwg_ctrl(dev, &ctrl); changed = 1; out: t_dev_info(dev, "lpwg suspend(%d, %d): lcd_mode %d, driving_mode %d\n", changed, ret, chip->lcd_mode, chip->driving_mode); return ret; } static int siw_hal_lpwg_mode_resume(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct lpwg_mode_ctrl ctrl; int changed = 0; int ret = 0; siw_hal_lpwg_ctrl_init(&ctrl); t_dev_info(dev, "lpwg resume: mode %d, screen %d\n", ts->lpwg.mode, ts->lpwg.screen); siw_touch_report_all_event(ts); //clear (?) #if defined(__SIW_CONFIG_PROX_ON_RESUME) if (ts->lpwg.sensor == PROX_NEAR) { t_dev_info(dev, "lpwg resume: (ts->lpwg.sensor == PROX_NEAR)\n"); ctrl.lcd = LCD_MODE_STOP; goto out_con; } #endif if (ts->lpwg.screen) { int mode = chip->lcd_mode; /* normal */ t_dev_info(dev, "lpwg resume: screen\n"); if (touch_mode_allowed(ts, LCD_MODE_U3_QUICKCOVER)) { mode = (ts->lpwg.qcover == HOLE_NEAR) ? LCD_MODE_U3_QUICKCOVER : mode; } ctrl.lpwg = LPWG_NONE; ctrl.lcd = mode; goto out_con; } if (touch_mode_not_allowed(ts, LCD_MODE_U3_PARTIAL)) { goto out; } t_dev_info(dev, "lpwg resume: partial\n"); if (touch_mode_allowed(ts, LCD_MODE_U3_QUICKCOVER)) { ctrl.qcover = (ts->lpwg.qcover == HOLE_NEAR) ? QUICKCOVER_CLOSE : QUICKCOVER_OPEN; ctrl.lpwg = ts->lpwg.mode; ctrl.lcd = LCD_MODE_U3_PARTIAL; goto out_con; } ctrl.lpwg = (ts->lpwg.qcover == HOLE_NEAR) ? LPWG_NONE : ts->lpwg.mode; ctrl.lcd = LCD_MODE_U3_PARTIAL; out_con: ret = siw_hal_lpwg_ctrl(dev, &ctrl); changed = 1; out: t_dev_info(dev, "lpwg resume(%d, %d): lcd_mode %d, driving_mode %d\n", changed, ret, chip->lcd_mode, chip->driving_mode); return ret; } static int siw_hal_lpwg_mode(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; if (atomic_read(&chip->init) == IC_INIT_NEED) { t_dev_info(dev, "Not Ready, Need IC init\n"); return 0; } if (atomic_read(&ts->state.fb) == FB_SUSPEND) { return siw_hal_lpwg_mode_suspend(dev); } return siw_hal_lpwg_mode_resume(dev); } static int siw_hal_lpwg(struct device *dev, u32 code, void *param) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct tci_ctrl *tci = &ts->tci; struct active_area *area = &tci->area; struct lpwg_info *lpwg = &ts->lpwg; int *value = (int *)param; int ret = 0; // if (!touch_test_quirks(ts, CHIP_QUIRK_SUPPORT_LPWG)) { if (!ts->role.use_lpwg) { t_dev_warn(dev, "LPWG control not supported in %s\n", touch_chip_name(ts)); return 0; } touch_msleep(hal_dbg_delay(chip, HAL_DBG_DLY_LPWG)); switch (code) { case LPWG_ACTIVE_AREA: area->x1 = value[0]; area->x2 = value[1]; area->y1 = value[2]; area->y2 = value[3]; t_dev_info(dev, "LPWG_ACTIVE_AREA: x1[%d], y1[%d], x2[%d], y2[%d]\n", area->x1, area->y1, area->x2, area->y2); break; case LPWG_TAP_COUNT: tci->info[TCI_2].tap_count = value[0]; break; case LPWG_DOUBLE_TAP_CHECK: tci->double_tap_check = value[0]; break; case LPWG_UPDATE_ALL: lpwg->mode = value[0]; lpwg->screen = value[1]; lpwg->sensor = value[2]; lpwg->qcover = value[3]; t_lpwg_mode = lpwg->mode; t_lpwg_screen = lpwg->screen; t_lpwg_sensor = lpwg->sensor; t_lpwg_qcover = lpwg->qcover; t_dev_info(dev, "LPWG_UPDATE_ALL: mode[%d], screen[%s], sensor[%s], qcover[%s]\n", lpwg->mode, lpwg->screen ? "ON" : "OFF", lpwg->sensor ? "FAR" : "NEAR", lpwg->qcover ? "CLOSE" : "OPEN"); ret = siw_hal_lpwg_mode(dev); break; case LPWG_REPLY: break; } return ret; } #if defined(__SIW_SUPPORT_ASC) static int siw_hal_asc(struct device *dev, u32 code, u32 value) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_asc_info *asc = &chip->asc; u32 rdata = 0; u32 wdata = 0; u32 asc_ret = 0; size_t mon_data[6] = { 0, }; int mon_cnt = 0; int ret = 0; mon_data[mon_cnt++] = code; switch (code) { case ASC_READ_MAX_DELTA: ret = siw_hal_reg_read(dev, reg->max_delta, (void *)&rdata, sizeof(rdata)); mon_data[mon_cnt++] = (size_t)reg->max_delta; mon_data[mon_cnt++] = (size_t)rdata; if (ret < 0) { break; } asc_ret = rdata; break; case ASC_GET_FW_SENSITIVITY: /* fall through */ case ASC_WRITE_SENSITIVITY: ret = siw_hal_reg_read(dev, reg->touch_max_r, (void *)&rdata, sizeof(rdata)); mon_data[mon_cnt++] = (size_t)reg->touch_max_r; mon_data[mon_cnt++] = (size_t)rdata; if (ret < 0) { break; } asc->normal_s = rdata; asc->acute_s = (rdata / 10) * 6; asc->obtuse_s = rdata; if (code == ASC_GET_FW_SENSITIVITY) { t_dev_info(dev, "max_r(%04Xh) = %d, n_s %d, a_s = %d, o_s = %d\n", reg->touch_max_r, rdata, asc->normal_s, asc->acute_s, asc->obtuse_s); break; } switch (value) { case NORMAL_SENSITIVITY : wdata = asc->normal_s; break; case ACUTE_SENSITIVITY : wdata = asc->acute_s; break; case OBTUSE_SENSITIVITY : wdata = asc->obtuse_s; break; default: wdata = rdata; break; } ret = siw_hal_write_value(dev, reg->touch_max_w, wdata); mon_data[mon_cnt++] = (size_t)reg->touch_max_w; mon_data[mon_cnt++] = (size_t)wdata; if (ret < 0) { break; } t_dev_info(dev, "max_w(%04Xh) changed (%d -> %d)\n", reg->touch_max_w, rdata, wdata); break; default: break; } siwmon_submit_ops_wh_name(dev, "%s asc done", touch_chip_name(ts), mon_data, mon_cnt, asc_ret); return asc_ret; } #else /* __SIW_SUPPORT_ASC */ static int siw_hal_asc(struct device *dev, u32 code, u32 value) { return 0; } #endif /* __SIW_SUPPORT_ASC */ #define siw_chk_sts_snprintf(_dev, _buf, _buf_max, _size, _fmt, _args...) \ ({ \ int _n_size = 0; \ _n_size = __siw_snprintf(_buf, _buf_max, _size, _fmt, ##_args); \ t_dev_dbg_trace(_dev, (const char *)_fmt, ##_args); \ _n_size; \ }) static int siw_hal_check_fault_type(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); u32 addr = 0; int fault_type = NON_FAULT_INT; int ret = 0; switch (chip->opt.t_chk_fault) { case 1 : addr = 0x283; break; default : return NON_FAULT_INT; } ret = siw_hal_read_value(dev, addr, (u32 *)&fault_type); if (ret < 0) { return NON_FAULT_INT; } return fault_type; } static u32 siw_hal_check_sys_error_type(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); u32 addr = 0; u32 fault_type = NON_FAULT_U32; int ret = 0; switch (chip->opt.t_chk_sys_error) { case 1: addr = 0x020; break; case 2: addr = 0x021; break; case 3: addr = 0x01C; break; default : return NON_FAULT_U32; } ret = siw_hal_read_value(dev, addr, (u32 *)&fault_type); if (ret < 0) { return NON_FAULT_U32; } return fault_type; } static u32 siw_hal_check_sys_fault_type(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); u32 addr = 0; u32 fault_type = NON_FAULT_U32; int ret = 0; switch (chip->opt.t_chk_sys_fault) { case 1: addr = 0xFF4; break; default : return NON_FAULT_U32; } ret = siw_hal_read_value(dev, addr, (u32 *)&fault_type); if (ret < 0) { return NON_FAULT_U32; } return fault_type; } static int siw_hal_check_status_type_x(struct device *dev, u32 status, u32 ic_status, int irq) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_hal_status_filter *filter = chip->status_filter; u32 check_mask, detected; int type_error, type_esd, type_fault; u32 dbg_mask = 0; u32 log_flag = 0; u32 esd_send = 0; u32 ic_abnormal, ic_error; int log_max = IC_CHK_LOG_MAX; char log[IC_CHK_LOG_MAX] = {0, }; int fault_val; int len = 0; int ret = 0; if (filter == NULL) { return -EINVAL; } if (ic_status & ~chip->status_mask_ic_valid) { t_dev_err(dev, "[%d] status %08Xh, ic_status %08Xh, ic_status invalid\n", irq, status, ic_status); if (chip->lcd_mode != LCD_MODE_U0) { if (siw_hal_send_esd_notifier(dev, 8)) { atomic_set(&chip->esd_noti_sent, 1); return -ETDSENTESDIRQ; } } return -ERESTART; } while (1) { if (!filter->id || !filter->width) { break; } type_error = !!(filter->flag & STS_FILTER_FLAG_TYPE_ERROR); type_esd = !!(filter->flag & STS_FILTER_FLAG_ESD_SEND); type_fault = !!(filter->flag & STS_FILTER_FLAG_CHK_FAULT); check_mask = ((1<<filter->width)-1)<<filter->pos; detected = (type_error) ? (status & check_mask) : !(status & check_mask); if (check_mask && detected) { log_flag |= check_mask; esd_send |= (type_esd) ? check_mask : 0; fault_val = (type_fault) ? siw_hal_check_fault_type(dev) : -1; if (type_fault && (fault_val >= 0)) { len += siw_chk_sts_snprintf(dev, log, log_max, len, "[b%d] %s(%Xh) ", filter->pos, filter->str, fault_val); } else { len += siw_chk_sts_snprintf(dev, log, log_max, len, "[b%d] %s ", filter->pos, filter->str); } } filter++; } if (log_flag) { t_dev_err(dev, "[%d] status %08Xh, ic_status %08Xh, (%08Xh) %s\n", irq, status, ic_status, log_flag, log); } ic_abnormal = ic_status & chip->status_mask_ic_abnormal; ic_error = ic_status & chip->status_mask_ic_error; if (ic_abnormal || ic_error) { u32 sys_error, sys_fault; int log_add = !log_flag; sys_error = siw_hal_check_sys_error_type(dev); sys_fault = siw_hal_check_sys_fault_type(dev); log_add |= (!!((sys_error != NON_FAULT_U32) || (sys_fault != NON_FAULT_U32)))<<1; len = siw_chk_sts_snprintf(dev, log, log_max, 0, "[%d] watchdog exception", irq); if (log_add) { len += siw_chk_sts_snprintf(dev, log, log_max, len, " - "); if (log_add & 0x01) { len += siw_chk_sts_snprintf(dev, log, log_max, len, "status %08Xh, ic_status %08Xh%s", status, ic_status, (log_add & 0x02) ? ", " : " "); } if (log_add & 0x02) { len += siw_chk_sts_snprintf(dev, log, log_max, len, "sys_error %08Xh, sys_fault %08Xh", sys_error, sys_fault); } } t_dev_err(dev, "%s\n", log); esd_send |= ic_abnormal; if (!esd_send) { ret = -ERESTART; //touch reset } } if (esd_send) { ret = -ERESTART; if (chip->lcd_mode != LCD_MODE_U0) { if (siw_hal_send_esd_notifier(dev, 1)) { atomic_set(&chip->esd_noti_sent, 1); return -ETDSENTESDIRQ; } } } if (ret == -ERESTART) { return ret; } dbg_mask = ((status>>16) & 0xF); switch (dbg_mask) { case 0x2 : t_dev_info(dev, "[%d] TC Driving OK\n", irq); ret = -ERANGE; break; case 0x3 : /* fall through */ case 0x4 : t_dev_dbg_trace(dev, "[%d] dbg_mask %Xh\n", irq, dbg_mask); ret = -ERANGE; break; } return ret; } static int siw_hal_do_check_status(struct device *dev, u32 status, u32 ic_status, int irq) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; u32 reset_clr_bit = 0; u32 logging_clr_bit = 0; u32 int_norm_mask = 0; u32 status_mask = 0; int ret_pre = 0; int ret = 0; if (!status && !ic_status) { t_dev_err(dev, "all low detected\n"); return -ERANGE; } if ((status == ~0) && (ic_status == ~0)) { t_dev_err(dev, "all high detected\n"); return -ERANGE; } ret = siw_hal_chk_status_type(dev); if (ret < 0) { return ret; } reset_clr_bit = chip->status_mask_reset; logging_clr_bit = chip->status_mask_logging; int_norm_mask = chip->status_mask_normal; status_mask = status ^ int_norm_mask; if (!(irq & 0x80)) { t_dev_dbg_trace(dev, "[%d] h/w:%Xh, f/w:%Xh(%Xh)\n", irq, ic_status, status, status_mask); } irq &= 0x01; if (status_mask & reset_clr_bit) { t_dev_err(dev, "[%d] need reset : status %08Xh, ic_status %08Xh, chk %08Xh (%08Xh)\n", irq, status, ic_status, status_mask & reset_clr_bit, reset_clr_bit); ret_pre = -ERESTART; } else if (status_mask & logging_clr_bit) { t_dev_err(dev, "[%d] need logging : status %08Xh, ic_status %08Xh, chk %08Xh (%08Xh)\n", irq, status, ic_status, status_mask & logging_clr_bit, logging_clr_bit); ret_pre = -ERANGE; } switch (chip->status_type) { case CHIP_STATUS_TYPE_2: case CHIP_STATUS_TYPE_1: case CHIP_STATUS_TYPE_0: ret = siw_hal_check_status_type_x(dev, status, ic_status, irq); siw_hal_chk_dbg_report(dev, status, irq); break; default: t_dev_warn(dev, "unknown status type, %d\n", chip->status_type); break; } if (ret == -ETDSENTESDIRQ) { return ret; } if (ret_pre) { if (ret != -ERESTART) { ret = ret_pre; } } return ret; } static int siw_hal_check_status(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; u32 ic_status = chip->info.ic_status; u32 status = chip->info.device_status; return siw_hal_do_check_status(dev, status, ic_status, 1); } static int siw_hal_irq_abs_data(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_touch_data *data = chip->info.data; struct touch_data *tdata; u32 touch_count = 0; u8 finger_index = 0; int ret = 0; int i = 0; touch_count = chip->info.touch_cnt; ts->new_mask = 0; /* check if palm detected */ if (data->track_id == PALM_ID) { if (data->event == TOUCHSTS_DOWN) { ts->is_palm = 1; t_dev_info(dev, "Palm Detected\n"); } else if (data->event == TOUCHSTS_UP) { ts->is_palm = 0; t_dev_info(dev, "Palm Released\n"); } ts->tcount = 0; ts->intr_status = TOUCH_IRQ_FINGER; return ret; } data = chip->info.data; for (i = 0; i < touch_count; i++, data++) { if (data->track_id >= touch_max_finger(ts)) { continue; } if ((data->event == TOUCHSTS_DOWN) || (data->event == TOUCHSTS_MOVE)) { ts->new_mask |= (1 << data->track_id); tdata = ts->tdata + data->track_id; tdata->id = data->track_id; tdata->type = data->tool_type; tdata->event = data->event; tdata->x = data->x; tdata->y = data->y; tdata->pressure = data->pressure; tdata->width_major = data->width_major; tdata->width_minor = data->width_minor; if (data->width_major == data->width_minor) tdata->orientation = 1; else tdata->orientation = data->angle; finger_index++; t_dev_dbg_abs(dev, "touch data [id %d, t %d, e %d, x %d, y %d, z %d - %d, %d, %d]\n", tdata->id, tdata->type, tdata->event, tdata->x, tdata->y, tdata->pressure, tdata->width_major, tdata->width_minor, tdata->orientation); } } ts->tcount = finger_index; ts->intr_status = TOUCH_IRQ_FINGER; return ret; } static int siw_hal_irq_abs(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; /* check if touch cnt is valid */ if (chip->info.touch_cnt == 0 || chip->info.touch_cnt > ts->caps.max_id) { struct siw_hal_touch_data *data = chip->info.data; t_dev_dbg_abs(dev, "Invalid touch count, %d(%d)\n", chip->info.touch_cnt, ts->caps.max_id); /* debugging */ t_dev_dbg_abs(dev, "t %d, ev %d, id %d, x %d, y %d, p %d, a %d, w %d %d\n", data->tool_type, data->event, data->track_id, data->x, data->y, data->pressure, data->angle, data->width_major, data->width_minor); return -ERANGE; } return siw_hal_irq_abs_data(dev); } static int siw_hal_get_tci_data(struct device *dev, int count) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; u8 i = 0; u32 rdata[MAX_LPWG_CODE]; if (!count) return 0; ts->lpwg.code_num = count; memcpy(&rdata, chip->info.data, sizeof(u32) * count); for (i = 0; i < count; i++) { ts->lpwg.code[i].x = rdata[i] & 0xffff; ts->lpwg.code[i].y = (rdata[i] >> 16) & 0xffff; if (ts->lpwg.mode == LPWG_PASSWORD) t_dev_info(dev, "LPWG data xxxx, xxxx\n"); else t_dev_info(dev, "LPWG data %d, %d\n", ts->lpwg.code[i].x, ts->lpwg.code[i].y); } ts->lpwg.code[count].x = -1; ts->lpwg.code[count].y = -1; return 0; } static int siw_hal_get_swipe_data(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; u32 rdata[3]; int count = 1; /* swipe_info */ /* start (X, Y), end (X, Y), time = 2bytes * 5 = 10 bytes */ memcpy(&rdata, chip->info.data, sizeof(u32) * 3); t_dev_info(dev, "Swipe Gesture: start(%4d, %4d) end(%4d, %4d) swipe_time(%dms)\n", rdata[0] & 0xffff, rdata[0] >> 16, rdata[1] & 0xffff, rdata[1] >> 16, rdata[2] & 0xffff); ts->lpwg.code_num = count; ts->lpwg.code[0].x = rdata[1] & 0xffff; ts->lpwg.code[0].x = rdata[1] >> 16; ts->lpwg.code[count].x = -1; ts->lpwg.code[count].y = -1; return 0; } static int siw_hal_irq_lpwg_base(struct siw_ts *ts, int type) { struct device *dev = ts->dev; int ret = 0; switch (type) { case KNOCK_1: if (ts->lpwg.mode == LPWG_NONE) { break; } t_dev_info(dev, "LPWG: TOUCH_IRQ_KNOCK\n"); siw_hal_get_tci_data(dev, ts->tci.info[TCI_1].tap_count); ts->intr_status = TOUCH_IRQ_KNOCK; break; case KNOCK_2: if (ts->lpwg.mode != LPWG_PASSWORD) { break; } t_dev_info(dev, "LPWG: TOUCH_IRQ_PASSWD\n"); siw_hal_get_tci_data(dev, ts->tci.info[TCI_2].tap_count); ts->intr_status = TOUCH_IRQ_PASSWD; break; case SWIPE_RIGHT: t_dev_info(dev, "LPWG: SWIPE_RIGHT\n"); siw_hal_get_swipe_data(dev); ts->intr_status = TOUCH_IRQ_SWIPE_RIGHT; break; case SWIPE_LEFT: t_dev_info(dev, "LPWG: SWIPE_LEFT\n"); siw_hal_get_swipe_data(dev); ts->intr_status = TOUCH_IRQ_SWIPE_LEFT; break; default: // t_dev_warn(dev, "unkown lpwg: %d\n", type); break; } return ret; } static int siw_hal_irq_lpwg_gesture(struct siw_ts *ts, int type) { struct device *dev = ts->dev; int index = 0; int ret = 0; t_dev_info(dev, "lpwg gesture: %d\n", type); ts->intr_status = TOUCH_IRQ_GESTURE; ts->intr_gesture = TOUCH_UEVENT_GESTURE_C + index; return ret; } static int siw_hal_irq_lpwg_dir(struct siw_ts *ts, int type) { struct device *dev = ts->dev; int index = 0; int ret = 0; t_dev_info(dev, "lpwg dir: %d\n", type); ts->intr_status = TOUCH_IRQ_GESTURE; ts->intr_gesture = TOUCH_UEVENT_GESTURE_DIR_RIGHT + index; return ret; } static int siw_hal_irq_lpwg_custom_debug(struct siw_ts *ts) { struct device *dev = ts->dev; t_dev_info(dev, "LPWG: CUSTOM_DEBUG\n"); siw_hal_debug_tci(dev); siw_hal_debug_swipe(dev); return 0; } static int siw_hal_irq_lpwg_knock_overtap(struct siw_ts *ts) { struct device *dev = ts->dev; t_dev_info(dev, "LPWG: overtap\n"); // siw_hal_get_tci_data(dev, 1); siw_hal_get_tci_data(dev, ts->tci.info[TCI_2].tap_count + 1); ts->intr_status = TOUCH_IRQ_PASSWD; return 0; } static int siw_hal_irq_lpwg(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; u32 type = chip->info.wakeup_type; int ret = 0; if (!type || (type > KNOCK_OVERTAP)) { goto out; } if (type == CUSTOM_DEBUG) { ret = siw_hal_irq_lpwg_custom_debug(ts); } else if (type == KNOCK_OVERTAP) { ret = siw_hal_irq_lpwg_knock_overtap(ts); } else if (type <= SWIPE_LEFT) { ret = siw_hal_irq_lpwg_base(ts, type); } else if (type <= GESTURE_Z) { ret = siw_hal_irq_lpwg_gesture(ts, type); } else if ((type >= GESTURE_DIR_RIGHT) || (type <= GESTURE_DIR_UP)) { ret = siw_hal_irq_lpwg_dir(ts, type); } else { goto out; } return ret; out: t_dev_err(dev, "LPWG: unknown type, %d\n", type); return -EINVAL; } static int siw_hal_irq_handler(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; int ret = 0; if (atomic_read(&chip->init) == IC_INIT_NEED) { t_dev_warn(dev, "Not Ready, Need IC init\n"); return 0; } #if defined(__SIW_SUPPORT_PM_QOS) pm_qos_update_request(&chip->pm_qos_req, 10); #endif ret = siw_hal_reg_read(dev, reg->tc_ic_status, (void *)&chip->info, sizeof(chip->info)); #if defined(__SIW_SUPPORT_PM_QOS) pm_qos_update_request(&chip->pm_qos_req, PM_QOS_DEFAULT_VALUE); #endif if (ret < 0) { goto out; } ret = siw_hal_check_status(dev); if (ret < 0) { goto out; } t_dev_dbg_irq(dev, "hal irq handler: wakeup_type %d\n", chip->info.wakeup_type); if (chip->info.wakeup_type == ABS_MODE) { ret = siw_hal_irq_abs(dev); if (ret) { t_dev_err(dev, "siw_hal_irq_abs failed, %d/n", ret); goto out; } } else { ret = siw_hal_irq_lpwg(dev); if (ret) { t_dev_err(dev, "siw_hal_irq_lpwg failed, %d/n", ret); goto out; } } if (atomic_read(&ts->state.debug_option_mask) & DEBUG_OPTION_2) { /* */ } out: return ret; } static void siw_hal_connect(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; int charger_state = atomic_read(&ts->state.connect); int wireless_state = atomic_read(&ts->state.wireless); #if 1 if (wireless_state) { chip->charger = CONNECT_WIRELESS; } else { if ((charger_state < 0) || (charger_state > CONNECT_OTG)) { t_dev_err(dev, "invalid charger status, %d\n", charger_state); return; } chip->charger = charger_state; } #else chip->charger = 0; switch (charger_state) { case CONNECT_INVALID: chip->charger = CONNECT_NONE; break; case CONNECT_DCP: /* fall through */ case CONNECT_PROPRIETARY: chip->charger = CONNECT_TA; break; case CONNECT_HUB: chip->charger = CONNECT_OTG; break; default: chip->charger = CONNECT_USB; break; } #if 0 /* code for TA simulator */ if (atomic_read(&ts->state.debug_option_mask) & DEBUG_OPTION_4) { t_dev_info(dev, "TA simulator mode, set CONNECT_TA\n"); chip->charger = CONNECT_TA; } #endif /* wireless */ chip->charger |= (wireless_state) ? CONNECT_WIRELESS : 0; #endif t_dev_info(dev, "charger_state = %Xh (%Xh, %Xh)\n", chip->charger, charger_state, wireless_state); if (atomic_read(&ts->state.pm) > DEV_PM_RESUME) { t_dev_warn(dev, "DEV_PM_SUSPEND - Don't try SPI\n"); return; } siw_hal_write_value(dev, reg->spr_charger_status, chip->charger); t_dev_info(dev, "charger_state set done\n"); } static int siw_hal_lcd_mode(struct device *dev, u32 mode) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; if (touch_mode_not_allowed(ts, mode)) { return -EPERM; } if ((chip->lcd_mode == LCD_MODE_U2) && siw_hal_watch_is_disp_waton(dev)) { siw_hal_watch_get_curr_time(dev, NULL, NULL); } if (chip->opt.f_u2_blank_chg) { if (mode == LCD_MODE_U2_UNBLANK) { mode = LCD_MODE_U2; } } chip->prev_lcd_mode = chip->lcd_mode; chip->lcd_mode = mode; t_dev_info(dev, "lcd_mode: %d (prev: %d)\n", mode, chip->prev_lcd_mode); return 0; } static int siw_hal_usb_status(struct device *dev, u32 mode) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; t_dev_info(dev, "TA Type: %d\n", atomic_read(&ts->state.connect)); siw_hal_connect(dev); return 0; } static int siw_hal_wireless_status(struct device *dev, u32 onoff) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; t_dev_info(dev, "Wireless charger: 0x%02X\n", atomic_read(&ts->state.wireless)); siw_hal_connect(dev); return 0; } static int siw_hal_earjack_status(struct device *dev, u32 onoff) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; t_dev_info(dev, "Earjack Type: 0x%02X\n", atomic_read(&ts->state.earjack)); return 0; } #if defined(__SIW_SUPPORT_ABT) extern void siw_hal_switch_to_abt_irq_handler(struct siw_ts *ts); static int siw_hal_debug_tool(struct device *dev, u32 value) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; if (value >= DEBUG_TOOL_MAX) { t_dev_err(dev, "wrong index, debug tool select failed, %d\n", value); return -EINVAL; } mutex_lock(&ts->lock); switch (value) { case DEBUG_TOOL_ENABLE: siw_hal_switch_to_abt_irq_handler(ts); break; default: siw_ops_restore_irq_handler(ts); t_dev_info(dev, "restore irq handler\n"); break; } mutex_unlock(&ts->lock); return 0; } #else /* __SIW_SUPPORT_ABT */ static int siw_hal_debug_tool(struct device *dev, u32 value) { t_dev_info(dev, "Nop ...\n"); return 0; } #endif /* __SIW_SUPPORT_ABT */ static int siw_hal_notify(struct device *dev, ulong event, void *data) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; char *noti_str = "(unknown)"; u32 value = 0; int ret = 0; if (data) { value = *((u32 *)data); } switch (event) { case LCD_EVENT_TOUCH_RESET_START: case LCD_EVENT_TOUCH_RESET_END: break; default: touch_msleep(hal_dbg_delay(chip, HAL_DBG_DLY_NOTIFY)); break; } t_dev_dbg_noti(dev, "notify event(%d)\n", (u32)event); switch (event) { case NOTIFY_TOUCH_RESET: #if 0 ret = !!(atomic_read(&ts->state.debug_option_mask) & DEBUG_OPTION_1); t_dev_info(dev, "notify: reset, %d\n", ret); #else t_dev_info(dev, "notify: reset\n"); #endif atomic_set(&chip->init, IC_INIT_NEED); siw_hal_watch_set_rtc_clear(dev); #if 0 siw_hal_watch_set_font_empty(dev); siw_hal_watch_set_cfg_blocked(dev); #endif noti_str = "TOUCH_RESET"; break; case LCD_EVENT_TOUCH_RESET_START: atomic_set(&ts->state.hw_reset, event); t_dev_info(dev, "notify: lcd_event: touch reset start\n"); siw_touch_irq_control(ts->dev, INTERRUPT_DISABLE); siw_hal_set_gpio_reset(dev, GPIO_OUT_ZERO); touch_msleep(1 + hal_dbg_delay(chip, HAL_DBG_DLY_HW_RST_0)); noti_str = "TOUCH_RESET_START"; break; case LCD_EVENT_TOUCH_RESET_END: atomic_set(&ts->state.hw_reset, event); t_dev_info(dev, "notify: lcd_event: touch reset end\n"); siw_hal_set_gpio_reset(dev, GPIO_OUT_ONE); siw_touch_qd_init_work_hw(ts); noti_str = "TOUCH_RESET_END"; break; case LCD_EVENT_LCD_MODE: noti_str = "LCD_MODE"; t_dev_info(dev, "notify: lcd_event: lcd mode\n"); if (data == NULL) { t_dev_err(dev, "data is null, cancled\n"); break; } ret = siw_hal_lcd_mode(dev, value); if (ret < 0) { break; } ret = siw_hal_check_mode(dev); if (!ret) { queue_delayed_work(ts->wq, &chip->fb_notify_work, 0); } ret = 0; break; case LCD_EVENT_READ_REG: t_dev_info(dev, "notify: lcd event: read reg\n"); siw_hal_lcd_event_read_reg(dev); noti_str = "READ_REG"; break; case NOTIFY_CONNECTION: t_dev_info(dev, "notify: connection\n"); ret = siw_hal_usb_status(dev, value); noti_str = "CONNECTION"; break; case NOTIFY_WIRELEES: t_dev_info(dev, "notify: wireless\n"); ret = siw_hal_wireless_status(dev, value); noti_str = "WIRELESS"; break; case NOTIFY_EARJACK: t_dev_info(dev, "notify: earjack\n"); ret = siw_hal_earjack_status(dev, value); noti_str = "EARJACK"; break; case NOTIFY_IME_STATE: #if 0 t_dev_info(dev, "notify: ime state\n"); ret = siw_hal_write_value(dev, reg->ime_state, value); #else t_dev_info(dev, "notify: do nothing for ime\n"); #endif noti_str = "IME_STATE"; break; case NOTIFY_DEBUG_TOOL: ret = siw_hal_debug_tool(dev, value); t_dev_info(dev, "notify: debug tool\n"); noti_str = "DEBUG_TOOL"; break; case NOTIFY_CALL_STATE: t_dev_info(dev, "notify: call state\n"); ret = siw_hal_write_value(dev, reg->call_state, value); noti_str = "CALL_STATE"; break; case LCD_EVENT_TOUCH_DRIVER_REGISTERED: case LCD_EVENT_TOUCH_DRIVER_UNREGISTERED: if (0) { /* from siw_touch_probe */ t_dev_info(dev, "notify: driver %s\n", (event == LCD_EVENT_TOUCH_DRIVER_REGISTERED) ? "registered" : "unregistered"); } noti_str = "DRV"; break; case LCD_EVENT_TOUCH_WATCH_LUT_UPDATE: t_dev_info(dev, "notify: WATCH_LUT_UPDATE(%lu)\n", event); noti_str = "WATCH_LUT"; break; case LCD_EVENT_TOUCH_WATCH_POS_UPDATE: t_dev_info(dev, "notify: WATCH_POS_UPDATE(%lu)\n", event); noti_str = "WATCH_POS"; break; case LCD_EVENT_TOUCH_PROXY_STATUS: t_dev_info(dev, "notify: PROXY_STATUS(%lu)\n", event); noti_str = "PROXY"; break; case LCD_EVENT_TOUCH_ESD_DETECTED: t_dev_info(dev, "notify: ESD_DETECTED(%lu, %d)\n", event, value); noti_str = "ESD"; break; default: t_dev_err(dev, "notify: %lu is not supported\n", event); break; } siwmon_submit_evt(dev, "NOTIFY", 0, noti_str, event, value, ret); return ret; } enum { SIW_GET_CHIP_NAME = (1<<0), SIW_GET_VERSION = (1<<1), SIW_GET_REVISION = (1<<2), SIW_GET_PRODUCT = (1<<3), /* */ SIW_GET_OPT1 = (1<<8), /* */ SIW_GET_VER_SIMPLE = (1<<16), /* */ SIW_GET_ALL = 0xFFFF, }; static int siw_hal_get_cmd_version(struct device *dev, char *buf, int flag) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; // struct siw_hal_reg *reg = chip->reg; struct siw_hal_fw_info *fw = &chip->fw; int offset = 0; // int ret = 0; if (!flag) return 0; if (flag & SIW_GET_CHIP_NAME) { offset += siw_snprintf(buf, offset, "chip : %s\n", touch_chip_name(ts)); } if (flag & (SIW_GET_VERSION|SIW_GET_VER_SIMPLE)) { char *ver_tag = (flag & SIW_GET_VER_SIMPLE) ? "" : "version : "; if (fw->version_ext) { offset += siw_snprintf(buf, offset, "%s%08X(%u.%02u)\n", ver_tag, fw->version_ext, fw->v.version.major, fw->v.version.minor); } else { offset += siw_snprintf(buf, offset, "%sv%u.%02u\n", ver_tag, fw->v.version.major, fw->v.version.minor); } } if (flag & SIW_GET_REVISION) { if (chip->fw.revision == 0xFF) { offset += siw_snprintf(buf, offset, "revision : Flash Erased(0xFF)\n"); } else { offset += siw_snprintf(buf, offset, "revision : %d\n", fw->revision); } } if (flag & SIW_GET_PRODUCT) { offset += siw_snprintf(buf, offset, "product id : %s\n", fw->product_id); } if (flag & SIW_GET_OPT1) { if (chip->opt.f_info_more) { offset += siw_snprintf(buf, offset, "fpc : %d\n", fw->fpc); offset += siw_snprintf(buf, offset, "wfr : %d\n", fw->wfr); offset += siw_snprintf(buf, offset, "cg : %d\n", fw->cg); offset += siw_snprintf(buf, offset, "lot : %d\n", fw->lot); offset += siw_snprintf(buf, offset, "serial : 0x%X\n", fw->sn); offset += siw_snprintf(buf, offset, "date : %04d.%02d.%02d %02d:%02d:%02d Site%d\n", fw->date & 0xFFFF, ((fw->date>>16) & 0xFF), ((fw->date>>24) & 0xFF), fw->time & 0xFF, ((fw->time>>8) & 0xFF), ((fw->time>>16) & 0xFF), ((fw->time>>24) & 0xFF)); } } return offset; } static int siw_hal_set(struct device *dev, u32 cmd, void *buf) { return 0; } static int siw_hal_get(struct device *dev, u32 cmd, void *buf) { int ret = 0; t_dev_dbg_base(dev, "cmd %d\n", cmd); switch (cmd) { case CMD_VERSION: ret = siw_hal_get_cmd_version(dev, (char *)buf, SIW_GET_ALL); break; case CMD_ATCMD_VERSION: ret = siw_hal_get_cmd_version(dev, (char *)buf, SIW_GET_VER_SIMPLE); break; default: break; } return ret; } u32 t_mon_dbg_mask = 0; /* usage * (1) echo <value> > /sys/module/{Siw Touch Module Name}/parameters/mon_dbg_mask * (2) insmod {Siw Touch Module Name}.ko mon_dbg_mask=<value> */ module_param_named(mon_dbg_mask, t_mon_dbg_mask, uint, S_IRUGO|S_IWUSR|S_IWGRP); #if 1 #define t_mon_info(_dev, fmt, args...) __t_dev_info(_dev, "mon: " fmt, ##args) #define t_mon_warn(_dev, fmt, args...) __t_dev_warn(_dev, "mon: " fmt, ##args) #else #define t_mon_info(_dev, fmt, args...) __t_dev_none() #define t_mon_warn(_dev, fmt, args...) __t_dev_none() #endif #define t_mon_err(_dev, fmt, args...) __t_dev_err(_dev, "mon: " fmt, ##args) #define t_mon_dbg(condition, _dev, fmt, args...) \ do { \ if (unlikely(t_mon_dbg_mask & (condition))) \ __t_dev_info(_dev, "mon: " fmt, ##args); \ } while (0) #define t_mon_dbg_base(_dev, fmt, args...) \ t_mon_dbg(DBG_BASE, _dev, fmt, ##args) #define t_mon_dbg_trace(_dev, fmt, args...) \ t_mon_dbg(DBG_TRACE, _dev, fmt, ##args) static int siw_hal_mon_handler_chk_frame(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; // struct siw_hal_reg *reg = chip->reg; u32 frame_addr = 0; u32 frame_s = 0; u32 frame_e = 0; u32 delay = 0; int cnt = 0; int i; int ret = 0; switch (chip->opt.t_chk_frame) { case 1: frame_addr = 0x24F; cnt = 20; delay = 1; break; default: return 0; } ret = siw_hal_read_value(dev, frame_addr, (void *)&frame_s); if (ret < 0){ goto out; } for (i = 0; i < cnt; i++) { touch_msleep(delay); ret = siw_hal_read_value(dev, frame_addr, (void *)&frame_e); if (ret < 0){ goto out; } if (frame_e != frame_s) { t_mon_dbg_trace(dev, "frame ok: %d(%d), %d x %d ms\n", frame_e, frame_s, i, delay); return 0; } } t_mon_err(dev, "frame not changed: %d, %d x %d ms\n", frame_s, cnt, delay); ret = -ERESTART; out: return ret; } static int siw_hal_mon_handler_chk_status(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 dbg_mask = (t_mon_dbg_mask & DBG_TRACE) ? 0 : 0x80; u32 ic_status; u32 status; int ret = 0; ret = siw_hal_reg_read(dev, reg->tc_ic_status, (void *)&ic_status, sizeof(ic_status)); if (ret < 0){ goto out; } ret = siw_hal_reg_read(dev, reg->tc_status, (void *)&status, sizeof(status)); if (ret < 0){ goto out; } status |= 0x8000; //Valid IRQ ret = siw_hal_do_check_status(dev, status, ic_status, dbg_mask); if (ret < 0) { if (ret == -ERESTART) { goto out; } ret = 0; } out: return ret; } static int siw_hal_mon_handler_chk_id(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_fw_info *fw = &chip->fw; u32 chip_id; int ret = 0; ret = siw_hal_read_value(dev, reg->spr_chip_id, &chip_id); if (ret < 0) { goto out; } if (fw->chip_id_raw != chip_id) { ret = -ERESTART; goto out; } out: return ret; } struct siw_mon_hanlder_op { unsigned int step; unsigned int delay; //msec unsigned int retry; char *name; int (*func)(struct device *dev); }; #define SIW_MON_HANDLER_OP_SET(_step, _delay, _retry, _name, _func) \ [_step] = { \ .step = _step, \ .delay = _delay, \ .retry = _retry, \ .name = _name, \ .func = _func, \ } static const struct siw_mon_hanlder_op siw_mon_hanlder_ops[] = { SIW_MON_HANDLER_OP_SET(0, 10, 3, "id", siw_hal_mon_handler_chk_id), SIW_MON_HANDLER_OP_SET(1, 10, 3, "status", siw_hal_mon_handler_chk_status), SIW_MON_HANDLER_OP_SET(2, 10, 3, "frame", siw_hal_mon_handler_chk_frame), }; static int siw_hal_mon_hanlder_do_op(struct device *dev, const struct siw_mon_hanlder_op *op, char *p_name) { unsigned int delay = op->delay; unsigned int retry = op->retry; unsigned int i; int ret = 0; for (i = 0; i < retry; i++) { ret = op->func(dev); if (ret >= 0) { t_mon_dbg_trace(dev, "%s : [%d] %s check done\n", p_name, op->step, op->name); break; } t_mon_err(dev, "%s : [%d] %s check failed(%d), %d (%d)\n", p_name, op->step, op->name, i, ret, op->delay); touch_msleep(delay); } return ret; } static void siw_hal_mon_handler_self_reset(struct device *dev, char *title) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; const struct siw_mon_hanlder_op *ops = siw_mon_hanlder_ops; unsigned int ops_num = ARRAY_SIZE(siw_mon_hanlder_ops); char name[32]; int step; int ret = 0; if (atomic_read(&ts->state.core) != CORE_NORMAL) { return; } if (atomic_read(&chip->init) == IC_INIT_NEED) { return; } if (chip->lcd_mode != LCD_MODE_U3) { return; } mutex_lock(&ts->lock); snprintf(name, sizeof(name), "%s self-reset", title); for (step = 0 ; step<ops_num ; step++, ops++) { if ((ops->step >= ops_num) || (ops->name == NULL) || (ops->func == NULL)) { break; } ret = siw_hal_mon_hanlder_do_op(dev, ops, name); if (ret < 0){ break; } } if (ret < 0) { t_mon_err(dev, "%s : recovery begins(hw reset)\n", name); siw_hal_reset_ctrl(dev, HW_RESET_ASYNC); } else { t_mon_dbg_trace(dev, "%s : check ok\n", name); } mutex_unlock(&ts->lock); } static int siw_hal_mon_handler(struct device *dev, u32 opt) { char *name; name = (opt & MON_FLAG_RST_ONLY) ? "reset cond" : "mon handler"; t_mon_dbg_trace(dev, "%s begins\n", name); siw_hal_mon_handler_self_reset(dev, name); if (opt & MON_FLAG_RST_ONLY) { goto out; } /* * For other controls */ out: t_mon_dbg_trace(dev, "%s ends\n", name); return 0; } static int siw_hal_early_probe(struct device *dev) { return 0; } enum { IC_TEST_ADDR_NOT_VALID = 0x8000, }; int siw_hal_ic_test_unit(struct device *dev, u32 data) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; u32 data_rd; int ret; if (!reg->spr_chip_test) { t_dev_warn(dev, "ic test addr not valid, skip\n"); return IC_TEST_ADDR_NOT_VALID; } ret = siw_hal_write_value(dev, reg->spr_chip_test, data); if (ret < 0) { t_dev_err(dev, "ic test wr err, %08Xh, %d\n", data, ret); goto out; } ret = siw_hal_read_value(dev, reg->spr_chip_test, &data_rd); if (ret < 0) { t_dev_err(dev, "ic test rd err: %08Xh, %d\n", data, ret); goto out; } if (data != data_rd) { t_dev_err(dev, "ic test cmp err, %08Xh, %08Xh\n", data, data_rd); ret = -EFAULT; goto out; } out: return ret; } static int siw_hal_ic_test(struct device *dev) { u32 data[] = { 0x5A5A5A5A, 0xA5A5A5A5, 0xF0F0F0F0, 0x0F0F0F0F, 0xFF00FF00, 0x00FF00FF, 0xFFFF0000, 0x0000FFFF, 0xFFFFFFFF, 0x00000000, }; int i; int ret = 0; for (i = 0; i < ARRAY_SIZE(data); i++) { ret = siw_hal_ic_test_unit(dev, data[i]); if ((ret == IC_TEST_ADDR_NOT_VALID) || (ret < 0)) { break; } } if (ret >= 0) { t_dev_dbg_base(dev, "ic bus r/w test done\n"); } return ret; } static int siw_hal_get_product_id(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); // struct siw_ts *ts = chip->ts; struct siw_hal_reg *reg = chip->reg; struct siw_hal_fw_info *fw = &chip->fw; u8 product_id[8+4] = { 0, }; //dummy 4-byte int ret; ret = siw_hal_reg_read(dev, reg->tc_product_id1, (void *)product_id, 8); if (ret < 0) { t_dev_err(dev, "failed to read product id, %d\n", ret); return ret; } siw_hal_fw_set_prod_id(fw, (u8 *)product_id, 8); t_dev_dbg_base(dev, "product id - %s\n", fw->product_id); return 0; } static int siw_hal_chipset_check(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int ret = 0; touch_msleep(ts->caps.hw_reset_delay); ret = siw_hal_init_quirk(dev); if (ret < 0) { goto out; } ret = siw_hal_ic_test(dev); if (ret < 0) { goto out; } ret = siw_hal_chk_boot(dev); if (ret < 0) { goto out; } if (ret) { t_dev_err(dev, "Boot fail detected\n"); return 0; } /* * Preceding process * : get reference value to cope with product variation */ ret = siw_hal_get_product_id(dev); if (ret < 0) { goto out; } out: return ret; } static int siw_hal_chipset_option(struct siw_touch_chip *chip) { struct device *dev = chip->dev; struct siw_touch_chip_opt *opt = &chip->opt; struct siw_ts *ts = chip->ts; switch (touch_chip_type(ts)) { case CHIP_LG4895: opt->f_u2_blank_chg = 1; opt->t_clock = 1; opt->t_sw_rst = 1; break; case CHIP_LG4946: opt->f_info_more = 1; opt->f_glove_en = 1; opt->t_chk_mode = 1; opt->t_clock = 1; opt->t_sw_rst = 1; break; case CHIP_SW1828 : opt->f_ver_ext = 1; opt->f_dbg_report = 1; opt->t_chk_frame = 1; break; case CHIP_SW49105: opt->f_attn_opt = 1; opt->t_chk_sys_error = 1; opt->t_chk_sys_fault = 1; break; case CHIP_SW49406: opt->f_attn_opt = 1; break; case CHIP_SW49407: opt->f_attn_opt = 1; opt->f_glove_en = 1; opt->f_grab_en = 1; opt->f_dbg_report = 1; opt->f_u2_blank_chg = 1; opt->t_chk_mipi = 1; opt->t_chk_sys_error = 1; opt->t_chk_sys_fault = 1; opt->t_chk_fault = 1; break; case CHIP_SW49408: opt->f_attn_opt = 1; opt->t_chk_mode = 1; opt->t_chk_sys_error = 2; opt->t_chk_sys_fault = 1; break; case CHIP_SW49409: opt->t_chk_sys_error = 3; opt->t_chk_sys_fault = 1; break; } t_dev_info(dev, "[opt summary]\n"); t_dev_info(dev, " f_info_more : %d\n", opt->f_info_more); t_dev_info(dev, " f_ver_ext : %d\n", opt->f_ver_ext); t_dev_info(dev, " f_attn_opt : %d\n", opt->f_attn_opt); t_dev_info(dev, " f_glove_en : %d\n", opt->f_glove_en); t_dev_info(dev, " f_grab_en : %d\n", opt->f_grab_en); t_dev_info(dev, " f_dbg_report : %d\n", opt->f_dbg_report); t_dev_info(dev, " f_u2_blank_chg : %d\n", opt->f_u2_blank_chg); t_dev_info(dev, " t_boot_mode : %d\n", opt->t_boot_mode); t_dev_info(dev, " t_sts_mask : %d\n", opt->t_sts_mask); t_dev_info(dev, " t_chk_mode : %d\n", opt->t_chk_mode); t_dev_info(dev, " t_sw_rst : %d\n", opt->t_sw_rst); t_dev_info(dev, " t_clock : %d\n", opt->t_clock); t_dev_info(dev, " t_chk_mipi : %d\n", opt->t_chk_mipi); t_dev_info(dev, " t_chk_frame : %d\n", opt->t_chk_frame); t_dev_info(dev, " t_chk_sys_error : %d\n", opt->t_chk_sys_error); t_dev_info(dev, " t_chk_sys_fault : %d\n", opt->t_chk_sys_fault); t_dev_info(dev, " t_chk_fault : %d\n", opt->t_chk_fault); return 0; } static void __siw_hal_do_remove(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; #if defined(__SIW_SUPPORT_PM_QOS) pm_qos_remove_request(&chip->pm_qos_req); #endif siw_hal_free_works(chip); siw_hal_free_locks(chip); siw_hal_power_free(dev); siw_hal_free_gpios(dev); touch_set_dev_data(ts, NULL); touch_kfree(dev, chip); } static int siw_hal_probe(struct device *dev) { struct siw_ts *ts = to_touch_core(dev); struct siw_touch_chip *chip = NULL; int ret = 0; chip = touch_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) { t_dev_err(dev, "failed to allocate %s data\n", touch_chip_name(ts)); return -ENOMEM; } chip->dev = dev; chip->reg = siw_ops_reg(ts); chip->ts = ts; touch_set_dev_data(ts, chip); siw_hal_chipset_option(chip); siw_hal_init_gpios(dev); siw_hal_power_init(dev); siw_hal_init_locks(chip); siw_hal_init_works(chip); if (siw_touch_get_boot_mode() == SIW_TOUCH_CHARGER_MODE) { if (touch_mode_allowed(ts, LCD_MODE_U3_PARTIAL)) { /* U3P driving and maintain 100ms before Deep sleep */ ret = siw_hal_tc_driving(dev, LCD_MODE_U3_PARTIAL); if (ret < 0) { __siw_hal_do_remove(dev); siwmon_submit_ops_step_chip_wh_name(dev, "%s probe failed(charger mode)", touch_chip_name(ts), 0); return ret; } touch_msleep(80); } /* Deep Sleep */ siw_hal_deep_sleep(dev); siwmon_submit_ops_step_chip_wh_name(dev, "%s probe done(charger mode)", touch_chip_name(ts), 0); return 0; } siw_hal_get_tci_info(dev); siw_hal_get_swipe_info(dev); #if defined(__SIW_SUPPORT_PM_QOS) pm_qos_add_request(&chip->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); #endif ret = siw_hal_chipset_check(dev); if (ret < 0) { __siw_hal_do_remove(dev); goto out; } chip->lcd_mode = LCD_MODE_U3; chip->tci_debug_type = 1; t_dev_dbg_base(dev, "%s probe done\n", touch_chip_name(ts)); siwmon_submit_ops_step_chip_wh_name(dev, "%s probe done", touch_chip_name(ts), 0); return 0; out: t_dev_dbg_base(dev, "%s probe failed\n", touch_chip_name(ts)); siwmon_submit_ops_step_chip_wh_name(dev, "%s probe failed", touch_chip_name(ts), 0); return ret; } static int siw_hal_remove(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; __siw_hal_do_remove(dev); t_dev_dbg_base(dev, "%s remove done\n", touch_chip_name(ts)); return 0; } static int siw_hal_suspend(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int mfst_mode = 0; int ret = 0; if (siw_touch_get_boot_mode() == SIW_TOUCH_CHARGER_MODE) return -EPERM; mfst_mode = siw_touch_boot_mode_check(dev); if ((mfst_mode >= MINIOS_MFTS_FOLDER) && !ts->role.mfts_lpwg) { t_dev_info(dev, "touch_suspend - MFTS\n"); siw_touch_irq_control(dev, INTERRUPT_DISABLE); siw_hal_power(dev, POWER_OFF); return -EPERM; } siw_touch_irq_control(dev, INTERRUPT_DISABLE); if ((chip->lcd_mode == LCD_MODE_U2) && siw_hal_watch_is_disp_waton(dev) && siw_hal_watch_is_rtc_run(dev)) { siw_hal_watch_get_curr_time(dev, NULL, NULL); } if (atomic_read(&chip->init) == IC_INIT_DONE) siw_hal_lpwg_mode(dev); else /* need init */ ret = 1; siw_hal_power(dev, POWER_OFF); t_dev_dbg_pm(dev, "%s suspend done\n", touch_chip_name(ts)); return ret; } static int siw_hal_resume(struct device *dev) { struct siw_touch_chip *chip = to_touch_chip(dev); struct siw_ts *ts = chip->ts; int mfst_mode = 0; int ret = 0; mfst_mode = siw_touch_boot_mode_check(dev); if ((mfst_mode >= MINIOS_MFTS_FOLDER) && !ts->role.mfts_lpwg) { siw_hal_power(dev, POWER_ON); touch_msleep(ts->caps.hw_reset_delay); ret = siw_hal_ic_info(dev); if (ret < 0) { t_dev_err(dev, "ic info err, %d\n", ret); } if (siw_hal_upgrade(dev) == 0) { siw_hal_power(dev, POWER_OFF); siw_hal_power(dev, POWER_ON); touch_msleep(ts->caps.hw_reset_delay); } } if (siw_touch_get_boot_mode() == SIW_TOUCH_CHARGER_MODE) { if (touch_mode_allowed(ts, LCD_MODE_U3_PARTIAL)) { /* U3P driving and maintain 100ms at Resume */ ret = siw_hal_tc_driving(dev, LCD_MODE_U3_PARTIAL); if (ret < 0) { return ret; } touch_msleep(80); } siw_hal_deep_sleep(dev); return -EPERM; } siw_hal_power(dev, POWER_ON); t_dev_dbg_pm(dev, "%s resume done\n", touch_chip_name(ts)); return 0; } static const struct siw_hal_reg siw_touch_default_reg = { .spr_chip_test = SPR_CHIP_TEST, .spr_chip_id = SPR_CHIP_ID, .spr_rst_ctl = SPR_RST_CTL, .spr_boot_ctl = SPR_BOOT_CTL, .spr_sram_ctl = SPR_SRAM_CTL, .spr_boot_status = SPR_BOOT_STS, .spr_subdisp_status = SPR_SUBDISP_STS, .spr_code_offset = SPR_CODE_OFFSET, .tc_ic_status = TC_IC_STATUS, .tc_status = TC_STS, .tc_version = TC_VERSION, .tc_product_id1 = TC_PRODUCT_ID1, .tc_product_id2 = TC_PRODUCT_ID2, .tc_version_ext = TC_VERSION_EXT, .info_fpc_type = INFO_FPC_TYPE, .info_wfr_type = INFO_WFR_TYPE, .info_chip_version = INFO_CHIP_VERSION, .info_cg_type = INFO_CG_TYPE, .info_lot_num = INFO_LOT_NUM, .info_serial_num = INFO_SERIAL_NUM, .info_date = INFO_DATE, .info_time = INFO_TIME, .cmd_abt_loc_x_start_read = CMD_ABT_LOC_X_START_READ, .cmd_abt_loc_x_end_read = CMD_ABT_LOC_X_END_READ, .cmd_abt_loc_y_start_read = CMD_ABT_LOC_Y_START_READ, .cmd_abt_loc_y_end_read = CMD_ABT_LOC_Y_END_READ, .code_access_addr = CODE_ACCESS_ADDR, .data_i2cbase_addr = DATA_I2CBASE_ADDR, .prd_tcm_base_addr = PRD_TCM_BASE_ADDR, .tc_device_ctl = TC_DEVICE_CTL, .tc_interrupt_ctl = TC_INTERRUPT_CTL, .tc_interrupt_status = TC_INTERRUPT_STS, .tc_drive_ctl = TC_DRIVE_CTL, .tci_fail_debug_r = TCI_FAIL_DEBUG_R, .tic_fail_bit_r = TCI_FAIL_BIT_R, .tci_debug_r = TCI_DEBUG_R, .tci_enable_w = TCI_ENABLE_W, .tci_fail_debug_w = TCI_FAIL_DEBUG_W, .tci_fail_bit_w = TCI_FAIL_BIT_W, .tap_count_w = TAP_COUNT_W, .min_intertap_w = MIN_INTERTAP_W, .max_intertap_w = MAX_INTERTAP_W, .touch_slop_w = TOUCH_SLOP_W, .tap_distance_w = TAP_DISTANCE_W, .int_delay_w = INT_DELAY_W, .act_area_x1_w = ACT_AREA_X1_W, .act_area_y1_w = ACT_AREA_Y1_W, .act_area_x2_w = ACT_AREA_X2_W, .act_area_y2_w = ACT_AREA_Y2_W, .swipe_enable_w = SWIPE_ENABLE_W, .swipe_dist_w = SWIPE_DIST_W, .swipe_ratio_thr_w = SWIPE_RATIO_THR_W, .swipe_ratio_period_w = SWIPE_RATIO_PERIOD_W, .swipe_ratio_dist_w = SWIPE_RATIO_DIST_W, .swipe_time_min_w = SWIPE_TIME_MIN_W, .swipe_time_max_w = SWIPE_TIME_MAX_W, .swipe_act_area_x1_w = SWIPE_ACT_AREA_X1_W, .swipe_act_area_y1_w = SWIPE_ACT_AREA_Y1_W, .swipe_act_area_x2_w = SWIPE_ACT_AREA_X2_W, .swipe_act_area_y2_w = SWIPE_ACT_AREA_Y2_W, .swipe_fail_debug_w = SWIPE_FAIL_DEBUG_W, .swipe_fail_debug_r = SWIPE_FAIL_DEBUG_R, .swipe_debug_r = SWIPE_DEBUG_R, .cmd_raw_data_report_mode_read = CMD_RAW_DATA_REPORT_MODE_READ, .cmd_raw_data_compress_write = CMD_RAW_DATA_COMPRESS_WRITE, .cmd_raw_data_report_mode_write = CMD_RAW_DATA_REPORT_MODE_WRITE, .spr_charger_status = SPR_CHARGER_STS, .ime_state = IME_STATE, .max_delta = MAX_DELTA, .touch_max_w = TOUCH_MAX_W, .touch_max_r = TOUCH_MAX_R, .call_state = CALL_STATE, .tc_tsp_test_ctl = TC_TSP_TEST_CTL, .tc_tsp_test_status = TC_TSP_TEST_STS, .tc_tsp_test_pf_result = TC_TSP_TEST_PF_RESULT, .tc_tsp_test_off_info = TC_TSP_TEST_OFF_INFO, .tc_flash_dn_status = TC_FLASH_DN_STS, .tc_confdn_base_addr = TC_CONFDN_BASE_ADDR, .tc_flash_dn_ctl = TC_FLASH_DN_CTL, .raw_data_ctl_read = RAW_DATA_CTL_READ, .raw_data_ctl_write = RAW_DATA_CTL_WRITE, .serial_data_offset = SERIAL_DATA_OFFSET, /* __SIW_SUPPORT_WATCH */ .ext_watch_font_offset = EXT_WATCH_FONT_OFFSET, .ext_watch_font_addr = EXT_WATCH_FONT_ADDR, .ext_watch_font_dn_addr_info = EXT_WATCH_FONT_DN_ADDR_INFO, .ext_watch_font_crc = EXT_WATCH_FONT_CRC, .ext_watch_dcs_ctrl = EXT_WATCH_DCS_CTRL, .ext_watch_mem_ctrl = EXT_WATCH_MEM_CTRL, .ext_watch_ctrl = EXT_WATCH_CTRL, .ext_watch_area_x = EXT_WATCH_AREA_X, .ext_watch_area_y = EXT_WATCH_AREA_Y, .ext_watch_blink_area = EXT_WATCH_BLINK_AREA, .ext_watch_lut = EXT_WATCH_LUT, .ext_watch_display_on = EXT_WATCH_DISPLAY_ON, .ext_watch_display_status = EXT_WATCH_DISPLAY_STATUS, .ext_watch_rtc_sct = EXT_WATCH_RTC_SCT, .ext_watch_rtc_sctcnt = EXT_WATCH_RTC_SCTCNT, .ext_watch_rtc_capture = EXT_WATCH_RTC_CAPTURE, .ext_watch_rtc_ctst = EXT_WATCH_RTC_CTST, .ext_watch_rtc_ecnt = EXT_WATCH_RTC_ECNT, .ext_watch_hour_disp = EXT_WATCH_HOUR_DISP, .ext_watch_blink_prd = EXT_WATCH_BLINK_PRD, .ext_watch_rtc_run = EXT_WATCH_RTC_RUN, .ext_watch_position = EXT_WATCH_POSITION, .ext_watch_position_r = EXT_WATCH_POSITION_R, .ext_watch_state = EXT_WATCH_STATE, .sys_dispmode_status = SYS_DISPMODE_STATUS, /* __SIW_SUPPORT_PRD */ .prd_serial_tcm_offset = PRD_SERIAL_TCM_OFFSET, .prd_tc_mem_sel = PRD_TC_MEM_SEL, .prd_tc_test_mode_ctl = PRD_TC_TEST_MODE_CTL, .prd_m1_m2_raw_offset = PRD_M1_M2_RAW_OFFSET, .prd_tune_result_offset = PRD_TUNE_RESULT_OFFSET, .prd_open3_short_offset = PRD_OPEN3_SHORT_OFFSET, .prd_ic_ait_start_reg = PRD_IC_AIT_START_REG, .prd_ic_ait_data_readystatus= PRD_IC_AIT_DATA_READYSTATUS, /* */ .glove_en = GLOVE_EN, .grab_en = GRAB_EN, }; enum { HAL_MON_INTERVAL_DEFAULT = 5, }; static const struct siw_touch_operations siw_touch_default_ops = { /* Register Map */ .reg = (void *)&siw_touch_default_reg, /* Functions */ .early_probe = siw_hal_early_probe, .probe = siw_hal_probe, .remove = siw_hal_remove, .suspend = siw_hal_suspend, .resume = siw_hal_resume, .init = siw_hal_init, .reset = siw_hal_reset_ctrl, .ic_info = siw_hal_ic_info, .tc_con = siw_hal_tc_con, .tc_driving = siw_hal_tc_driving, .chk_status = siw_hal_check_status, .irq_handler = siw_hal_irq_handler, .irq_abs = siw_hal_irq_abs, .irq_lpwg = siw_hal_irq_lpwg, .power = siw_hal_power, .upgrade = siw_hal_upgrade, .lpwg = siw_hal_lpwg, .asc = siw_hal_asc, .notify = siw_hal_notify, .set = siw_hal_set, .get = siw_hal_get, /* */ .sysfs = siw_hal_sysfs, /* */ .mon_handler = siw_hal_mon_handler, .mon_interval = HAL_MON_INTERVAL_DEFAULT, /* */ .abt_sysfs = siw_hal_abt_sysfs, .prd_sysfs = siw_hal_prd_sysfs, .watch_sysfs = siw_hal_watch_sysfs, }; struct siw_touch_operations *siw_hal_get_default_ops(int opt) { return (struct siw_touch_operations *)&siw_touch_default_ops; }