[Feature][Modem]Update MTK MODEM V1.6 baseline version: MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6

MTK modem version: MT2735_IVT_MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6.tar.gz
RF  modem version: NA

Change-Id: I45a4c2752fa9d1a618beacd5d40737fb39ab64fb
diff --git a/mcu/driver/devdrv/tia/src/tia.c b/mcu/driver/devdrv/tia/src/tia.c
new file mode 100644
index 0000000..61256ca
--- /dev/null
+++ b/mcu/driver/devdrv/tia/src/tia.c
@@ -0,0 +1,754 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2017
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ *    tia.c
+ *
+ * Project:
+ * --------
+ *    VMOLY
+ *
+ * Description:
+ * ------------
+ *    TIA (Thermal Information Acquisition) driver for MD thermal
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *============================================================================
+ ****************************************************************************/
+
+#include "kal_public_api.h"
+#include "kal_ex_api.h"
+#include "drv_comm.h"
+#include "us_timer.h"
+#include "cache_sw.h"
+#include "tia_reg.h"
+#include "tia.h"
+
+// sensor information
+static tfwk_sensor_info_t tia_sensor_info[TIA_SENSOR_NUM] = {
+    {.sensor_id=1, .min_temperature=-200, .max_temperature=1150, .warning_temperature=9999, .accuracy=30, .resolution=10, .sensor_name="PA_Group_2_NTC"},
+    {.sensor_id=2, .min_temperature=-200, .max_temperature=1150, .warning_temperature=9999, .accuracy=30, .resolution=10, .sensor_name="PA_Group_1_NTC"},
+    {.sensor_id=3, .min_temperature=-200, .max_temperature=1150, .warning_temperature=9999, .accuracy=30, .resolution=10, .sensor_name="RF_IC_NTC"},
+    {.sensor_id=4, .min_temperature=-200, .max_temperature=1150, .warning_temperature=9999, .accuracy=30, .resolution=10, .sensor_name="SOC_NTC"},
+};
+static kal_uint32 tia_sensor_hwShutdownTemp[TIA_SENSOR_NUM] = {9999, 9999, 9999, 9999};
+const kal_uint32 tia_sensor_map[TIA_SENSOR_NUM] = {
+  //PA_G2, PA_G1, RF_IC, SOC
+    2,     1,     3,     0
+};
+#if defined(CHIP10992)
+    static kal_bool tia_sensor_fake_en = KAL_FALSE;
+    static kal_uint32 tia_sensor_fake_ohm[TIA_SENSOR_NUM];
+#else
+    static kal_bool tia_sensor_fake_en = KAL_TRUE;
+    static kal_uint32 tia_sensor_fake_ohm[TIA_SENSOR_NUM] = {0x000186A0, 0x000186A0, 0x000186A0, 0x000186A0};
+#endif
+
+// threshold monitor
+#define TIA_THR_TMP_MAX     (TIA_ADC_TMP_MAX * 10) // threshold temperature: valid max
+#define TIA_THR_TMP_MIN     (TIA_ADC_TMP_MIN * 10) // threshold temperature: valid max
+#define TIA_THR_TMP_HW_NEAR (100) // threshold temperature, near HW shutdown (>= HW - this_DEF)
+#define TIA_THR_PP_NUM      2 // ping-pong number
+#define TIA_THR_ALM_NUM     2 // alarm number
+enum {  // threshold type
+    TIA_THR_TYP_HW = 0,
+    TIA_THR_TYP_SW,
+    TIA_THR_TYP_WRN,
+    TIA_THR_TYP_AL0,
+    TIA_THR_TYP_AL1,
+    TIA_THR_TYP_MAX
+};
+static const kal_char *tia_thr_typ_str[TIA_THR_TYP_MAX] = {"hw", "sw", "wrn", "al0", "al1"};
+enum {  // alarm type
+    TIA_ALM_TYP_RISING = 0,
+    TIA_ALM_TYP_FALLING,
+    TIA_ALM_TYP_DISABLE
+};
+static tfwk_thermal_cfg_t tia_thr_cfgs[TIA_SENSOR_NUM][TIA_THR_PP_NUM][TIA_THR_ALM_NUM];
+static struct tia_thr_mon_s {
+    kal_bool            vld; // valid or not
+    kal_int32           thr; // threshold value, order: hw > sw > fim > al0 > al1
+    tfwk_thermal_cfg_t *cfg; // pointer to tia_thr_cfgs (for sw/fim/alarm, not hw)
+} tia_thr_mons[TIA_SENSOR_NUM][TIA_THR_PP_NUM][TIA_THR_TYP_MAX];
+static kal_uint32 tia_thr_ppi[TIA_SENSOR_NUM]; // current ppi, update to ~ppi
+static kal_uint32 tia_thr_hw;
+#define TIA_HW_RESET_RECORD(tid) \
+        DRV_WriteReg32(TOPRGU_WDT_NONRST_REG2, DRV_Reg32(TOPRGU_WDT_NONRST_REG2) | TOPRGU_TID_STATUS(tid))
+
+#define TIA_TMR_MS_DFT 1000     // default polling period
+#define TIA_TMR_MS_ITS 100      // intensive polling period
+#define TIA_TMR_MS_MIN 64       // minimax polling period
+static kal_timerid tia_tmr_id;
+static kal_spinlockid tia_tmr_sl;
+static void tia_tmr_set(kal_uint32 ms, kal_bool imm);
+
+//#define TIA_STACK_PRF
+#ifdef TIA_STACK_PRF
+#define STACK_SIZE_MAX   0x1000
+#define STACK_GUARD_PTN0 0x43415453 // STACKEND
+#define STACK_GUARD_PTN1 0x444E454B
+#define STACK_GUARD_TST  0xFEFEFEFE
+
+static struct {
+    kal_uint32 init_bas;
+    kal_uint32 init_cur;
+    kal_uint32 init_us;
+    kal_uint32 done_cur;
+    kal_uint32 done_use;
+    kal_uint32 done_us;
+} tia_stack_prf;
+
+static void __attribute__((noinline)) tia_stack_prf_init(void)
+{
+    void *sp_ptr = NULL;
+    register kal_uint32 adr;
+
+    tia_stack_prf.init_cur = (kal_uint32) &sp_ptr;
+    for (adr = tia_stack_prf.init_cur & ~0x7; adr > tia_stack_prf.init_cur - STACK_SIZE_MAX; adr -= 8) {
+        if ((DRV_Reg32(adr) == STACK_GUARD_PTN0) && (DRV_Reg32(adr+4) == STACK_GUARD_PTN1)) {
+            adr = CPU_CACHE_LINE_ALIGN_ADDR(adr) + CPU_CACHE_LINE_ALIGN_LEN(adr, 8);
+            break;
+        }
+    }
+    tia_stack_prf.init_bas = adr;
+    for (; adr < tia_stack_prf.init_cur - 0x10; adr += 4) {
+        DRV_WriteReg32(adr, STACK_GUARD_TST);
+    }
+    tia_stack_prf.init_us = ust_get_current_time();
+}
+
+static void __attribute__((noinline)) tia_stack_prf_done(void)
+{
+    void *sp_ptr = NULL;
+    register kal_uint32 adr;
+
+    tia_stack_prf.done_us = ust_get_current_time();
+    tia_stack_prf.done_cur = (kal_uint32) &sp_ptr;
+    for (adr = tia_stack_prf.init_bas; adr < tia_stack_prf.init_cur; adr += 4) {
+        if (DRV_Reg32(adr) != STACK_GUARD_TST) {
+            break;
+        }
+    }
+    tia_stack_prf.done_use = adr;
+}
+
+static void __attribute__((noinline)) tia_stack_prf_result(void)
+{
+    MD_TRC(TIA_MSG_STACK_INFO,
+           tia_stack_prf.init_cur, tia_stack_prf.init_bas, tia_stack_prf.init_cur - tia_stack_prf.init_bas,
+           tia_stack_prf.done_cur, tia_stack_prf.done_use, tia_stack_prf.done_cur - tia_stack_prf.done_use,
+           ust_us_duration(tia_stack_prf.init_us, tia_stack_prf.done_us));
+}
+#endif
+
+static kal_int32 tia_temp(kal_uint32 tid)
+{
+    static struct {
+        kal_uint32 frc;
+        kal_int32  tmp;
+    } tmps[TIA_SENSOR_NUM];
+    kal_uint32 nid, reg, dbg, frc, rc, adc;
+    kal_int32  tmp;
+
+    if (tia_sensor_fake_en) {
+        rc  = TIA_ADC_RC_FAKE;
+        adc = tia_sensor_fake_ohm[tid];
+        tmp = tia_adc_to_tmp(rc, adc);
+        MD_TRC(TIA_MSG_AUXADC_TMP, tid, TIA_ADC_RC2K(rc), adc, tmp, tia_sensor_fake_en);
+    } else {
+        nid = TIA_SENSOR_NID(tid);
+        reg = DRV_Reg32(TIA_HW_RC_ADC(nid));
+        frc = ust_get_current_time();
+        if (TIA_HW_ADC_VLD(reg)) {
+            rc  = TIA_HW_RC_VAL(reg);
+            adc = TIA_HW_ADC_VAL(reg);
+            tmp = tia_adc_to_tmp(rc, adc);
+            EXT_ASSERT(tmp != TIA_ADC_TMP_ERR, rc, adc, (kal_uint32) tmp);
+            tmps[tid].frc = frc;
+            tmps[tid].tmp = tmp;
+            MD_TRC(TIA_MSG_AUXADC_TMP, tid, TIA_ADC_RC2K(rc), adc, tmp, tia_sensor_fake_en);
+        } else {
+            dbg = DRV_Reg32(TIA_TIA2_DEBUG);
+            EXT_ASSERT((tmps[tid].frc != 0) && (tmps[tid].tmp != 0), tid, reg, dbg);
+            tmp = tmps[tid].tmp;
+            MD_TRC(TIA_MSG_ERR_ADC_INVALID, __func__, tid, reg, dbg, tmp, ust_us_duration(tmps[tid].frc, frc));
+        }
+    }
+
+    return tmp;
+}
+
+static void tia_notify(kal_uint32 tid, kal_int32 tmp, tfwk_thermal_cfg_t* cfg)
+{
+    static thermal_sta_info_t tia_thr_ntf; // declare "static" in global bss, dont use stack area (kal timer limitation)
+    kal_uint32 sid, idx;
+
+    tia_thr_ntf.temp = tmp;
+    memcpy(&tia_thr_ntf.cfg, cfg, sizeof(thermal_cfg_t));
+
+    for (sid = THERMAL_LVTS_SENSOR_ID(0); sid < THERMAL_LVTS_SENSOR_ID(THERMAL_LVTS_SENSOR_NUM); sid++) {
+        tia_thr_ntf.others[sid].sensor_id = sid;
+        TIA_LVTS_GET_TEMP(sid, &tia_thr_ntf.others[sid].temp);
+    }
+    idx = sid;
+    for (sid = THERMAL_TIA_SENSOR_ID(0); sid < THERMAL_TIA_SENSOR_ID(TIA_SENSOR_NUM); sid++) {
+        if (TIA_SENSOR_TID(sid) == tid) {
+            continue;
+        }
+        tia_thr_ntf.others[idx].sensor_id = sid;
+        tia_thr_ntf.others[idx].temp = tia_temp(TIA_SENSOR_TID(sid));
+        idx++;
+    }
+
+    tfwk_sensor_notify(&tia_thr_ntf);
+}
+
+static void tia_tmr_handler(void *param_ptr)
+{
+    kal_uint32 tid, idx, tms = 0;
+    kal_int32 tmp;
+    kal_bool hit, ins = KAL_FALSE;
+    struct tia_thr_mon_s *mon;
+
+    #ifdef TIA_STACK_PRF
+    tia_stack_prf_init();
+    #endif
+    // check threshold
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        tmp = tia_temp(tid); // always update temperature locally
+        mon = tia_thr_mons[tid][tia_thr_ppi[tid]];
+        hit = KAL_FALSE;
+        for (idx = 0; idx < TIA_THR_TYP_MAX; idx++) {
+            if (mon[idx].vld) { hit = KAL_TRUE; break; }
+        }
+        if (!hit) { continue; }
+        // hw threshold
+        if (mon[TIA_THR_TYP_HW].vld) {
+            if (tmp >= mon[TIA_THR_TYP_HW].thr) {
+                MD_TRC(TIA_MSG_ERR_OVER_HW_THRESHOLD, __func__, tid, tmp, mon[TIA_THR_TYP_HW].thr);
+                TIA_HW_RESET_RECORD(tid);
+                TIA_LVTS_HW_RGU_RESET();
+                break;
+            } else if (tmp >= (mon[TIA_THR_TYP_HW].thr - TIA_THR_TMP_HW_NEAR)) {
+                MD_TRC(TIA_MSG_NEAR_HW_THRESHOLD, tid, tmp, mon[TIA_THR_TYP_HW].thr);
+            }
+        }
+        // rising sw/fim/alarm threshold
+        hit = KAL_FALSE;
+        for (idx = TIA_THR_TYP_SW; idx < TIA_THR_TYP_MAX; idx++) {
+            if ((mon[idx].vld == KAL_FALSE) || (mon[idx].cfg->sensor_alarm_type != TIA_ALM_TYP_RISING)) {
+                continue;
+            }
+            if (hit) { // disable lower threhold
+                mon[idx].vld = KAL_FALSE;
+                continue;
+            }
+            if (tmp >= mon[idx].thr) {
+                tia_notify(tid, tmp, mon[idx].cfg);
+                mon[idx].vld = KAL_FALSE;
+                hit = KAL_TRUE;
+                MD_TRC(TIA_MSG_OVER_THRESHOLD, tid, tmp, tia_thr_typ_str[idx], mon[idx].thr);
+                MD_TRC(TIA_MSG_ALARM_INFO, mon[idx].cfg->enable, mon[idx].cfg->sensor_id, mon[idx].cfg->alarm_id,
+                    mon[idx].cfg->threshold_value, mon[idx].cfg->hysteresis_value, mon[idx].cfg->sampling_period,
+                    mon[idx].cfg->sensor_alarm_type);
+            }
+        }
+        // falling alarm threshold
+        hit = KAL_FALSE;
+        for (idx = TIA_THR_TYP_AL1; idx >= TIA_THR_TYP_AL0; idx--) {
+            if ((mon[idx].vld == KAL_FALSE) || (mon[idx].cfg->sensor_alarm_type != TIA_ALM_TYP_FALLING)) {
+                continue;
+            }
+            if (hit) { // disable higher threhold
+                mon[idx].vld = KAL_FALSE;
+                continue;
+            }
+            if (tmp <= mon[idx].thr) {
+                tia_notify(tid, tmp, mon[idx].cfg);
+                mon[idx].vld = KAL_FALSE;
+                hit = KAL_TRUE;
+                MD_TRC(TIA_MSG_UNDER_THRESHOLD, tid, tmp, tia_thr_typ_str[idx], mon[idx].thr);
+                MD_TRC(TIA_MSG_ALARM_INFO, mon[idx].cfg->enable, mon[idx].cfg->sensor_id, mon[idx].cfg->alarm_id,
+                    mon[idx].cfg->threshold_value, mon[idx].cfg->hysteresis_value, mon[idx].cfg->sampling_period,
+                    mon[idx].cfg->sensor_alarm_type);
+            }
+        }
+
+        // sample period (config and insensive)
+        for (idx = TIA_THR_TYP_SW; idx < TIA_THR_TYP_MAX; idx++) {
+            kal_uint32 t;
+            if (mon[idx].vld == KAL_FALSE) {
+                continue;
+            }
+            t = mon[idx].cfg->sampling_period;
+            if ((tms == 0) || (tms > t)) {
+                tms = (t < TIA_TMR_MS_MIN)? TIA_TMR_MS_MIN: t;
+            }
+            if ((mon[idx].cfg->sensor_alarm_type == TIA_ALM_TYP_RISING) &&
+                (tmp >= (mon[idx].cfg->threshold_value - (kal_int32) mon[idx].cfg->hysteresis_value))) {
+                ins = KAL_TRUE;
+                continue;
+            }
+            if ((mon[idx].cfg->sensor_alarm_type == TIA_ALM_TYP_FALLING) &&
+                (tmp <= (mon[idx].cfg->threshold_value + (kal_int32) mon[idx].cfg->hysteresis_value))) {
+                ins = KAL_TRUE;
+                continue;
+            }
+        }
+    }
+
+    // update timer period
+    if ((ins) && (tms > TIA_TMR_MS_ITS)) {
+        tms = TIA_TMR_MS_ITS;
+    }
+    tia_tmr_set(tms, KAL_FALSE);
+    #ifdef TIA_STACK_PRF
+    tia_stack_prf_done();
+    tia_stack_prf_result();
+    #endif
+}
+
+static void tia_tmr_set(kal_uint32 ms, kal_bool imm)
+{
+    static kal_uint32 ms_cfg;
+    kal_bool ms_trc = KAL_FALSE;
+    kal_uint32 tck;
+
+    if ((ms == 0) && tia_thr_hw) {
+        ms = TIA_TMR_MS_DFT;
+    }
+    tck = kal_milli_secs_to_ticks(ms);
+
+    kal_take_spinlock(tia_tmr_sl, KAL_INFINITE_WAIT);
+    if (ms != ms_cfg) {
+        if (ms_cfg != 1) {
+            ms_trc = KAL_TRUE;
+        }
+        if (ms == 0) {
+            kal_cancel_timer(tia_tmr_id);
+            ms_cfg = 0;
+        } else if (imm) {
+            kal_disable_delayed_timer(tia_tmr_id);
+            kal_set_timer(tia_tmr_id, tia_tmr_handler, NULL, 1, tck);
+            ms_cfg = 1;
+        } else {
+            kal_enable_delayed_timer(tia_tmr_id, MAX_DELAY_UNLIMITED);
+            kal_set_timer(tia_tmr_id, tia_tmr_handler, NULL, tck, tck);
+            ms_cfg = ms;
+        }
+    }
+    kal_give_spinlock(tia_tmr_sl);
+
+    if (ms_trc) {
+        MD_TRC(TIA_MSG_SAMPLING_PERIOD, ms);
+    }
+}
+
+static kal_int32 thr_alarm_temp_max(kal_uint32 tid)
+{
+    struct tia_thr_mon_s *mon;
+    kal_int32 idx, tmp = TIA_THR_TMP_MAX;
+
+    mon = tia_thr_mons[tid][tia_thr_ppi[tid]];
+    for (idx = 0; idx < TIA_THR_TYP_AL0; idx++) {
+        if (tmp > mon[idx].thr) {
+            tmp = mon[idx].thr;
+        }
+    }
+    return tmp;
+}
+
+static kal_int32 thr_alarm_temp_min(kal_uint32 tid)
+{
+    kal_int32 tmp = TIA_THR_TMP_MIN;
+
+    if (tmp < tia_sensor_info[tid].min_temperature) {
+        tmp = tia_sensor_info[tid].min_temperature;
+    }
+    return tmp;
+}
+
+kal_int32 tia_set_alarm(kal_uint32 ncfg, tfwk_thermal_cfg_t* tcfgs)
+{
+    #define _upd_err_code(r,e) do {if ((r)==THERMAL_ERR_NONE) (r) = (e);} while (0)
+    kal_int32 ret = THERMAL_ERR_NONE, tmp;
+    kal_uint32 tid, ppi, idx, tms;
+    struct tia_thr_mon_s *mon;
+    tfwk_thermal_cfg_t *cfg;
+    tfwk_thermal_cfg_t *cfg_f[TIA_SENSOR_NUM][TIA_THR_ALM_NUM] = {NULL}; // filter cfg list
+
+    EXT_ASSERT(ncfg && tcfgs, ncfg, (kal_uint32) tcfgs, 0);
+
+    // filter cfg
+    for (idx = 0; idx < ncfg; idx++) {
+        cfg = &tcfgs[idx];
+        if (!TIA_SENSOR_SID_VALID(cfg->sensor_id)) {
+            MD_TRC(TIA_MSG_ERR_SENSOR_ID, __func__, cfg->sensor_id);
+            _upd_err_code(ret, THERMAL_ERR_SENSOR_ID);
+            continue;
+        }
+        if (cfg->alarm_id >= TIA_THR_ALM_NUM) {
+            MD_TRC(TIA_MSG_ERR_ALARM_ID, __func__, cfg->alarm_id);
+            _upd_err_code(ret, THERMAL_ERR_ALARM_ID);
+            continue;
+        }
+        tid = TIA_SENSOR_TID(cfg->sensor_id);
+        tmp = thr_alarm_temp_max(tid);
+        if (cfg->threshold_value >= tmp) {
+            MD_TRC(TIA_MSG_ERR_THRESHOLD_RANGE_MAX, __func__, cfg->threshold_value, tmp);
+            _upd_err_code(ret, THERMAL_ERR_THRESHOLD_RANGE);
+            continue;
+        }
+        tmp = thr_alarm_temp_min(tid);
+        if (cfg->threshold_value <= tmp) {
+            MD_TRC(TIA_MSG_ERR_THRESHOLD_RANGE_MIN, __func__, cfg->threshold_value, tmp);
+            _upd_err_code(ret, THERMAL_ERR_THRESHOLD_RANGE);
+            continue;
+        }
+        cfg_f[tid][cfg->alarm_id] = cfg;
+        MD_TRC(TIA_MSG_ALARM_INFO,cfg->enable, cfg->sensor_id, cfg->alarm_id, cfg->threshold_value,
+            cfg->hysteresis_value, cfg->sampling_period, cfg->sensor_alarm_type);
+    }
+
+    // update internal cfg
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        if ((cfg_f[tid][0]==NULL) && (cfg_f[tid][1]==NULL)) {
+            continue;
+        }
+        // clean first
+        ppi = !tia_thr_ppi[tid];
+        mon = tia_thr_mons[tid][ppi];
+        mon[TIA_THR_TYP_SW].vld = KAL_FALSE;
+        mon[TIA_THR_TYP_SW].cfg = NULL;
+        mon[TIA_THR_TYP_WRN].vld = KAL_FALSE;
+        mon[TIA_THR_TYP_WRN].cfg = NULL;
+        memset(&mon[TIA_THR_TYP_AL0], 0x0, sizeof(struct tia_thr_mon_s)*TIA_THR_ALM_NUM);
+        // update alarm
+        if ((cfg_f[tid][0] == NULL) || (cfg_f[tid][1] == NULL)) {
+            idx = (cfg_f[tid][0] == NULL);
+            memcpy(&tia_thr_cfgs[tid][ppi][idx], cfg_f[tid][idx], sizeof(tfwk_thermal_cfg_t));
+            if ((cfg_f[tid][idx]->enable != 0) && (cfg_f[tid][idx]->sensor_alarm_type < TIA_ALM_TYP_DISABLE)) {
+                mon[TIA_THR_TYP_AL0].vld = KAL_TRUE;
+                mon[TIA_THR_TYP_AL0].thr = cfg_f[tid][idx]->threshold_value;
+                mon[TIA_THR_TYP_AL0].cfg = &tia_thr_cfgs[tid][ppi][idx];
+            }
+            idx = !idx;
+            memset(&tia_thr_cfgs[tid][ppi][idx], 0x0, sizeof(tfwk_thermal_cfg_t));
+        } else {
+            memcpy(&tia_thr_cfgs[tid][ppi][0], cfg_f[tid][0], sizeof(tfwk_thermal_cfg_t));
+            memcpy(&tia_thr_cfgs[tid][ppi][1], cfg_f[tid][1], sizeof(tfwk_thermal_cfg_t));
+            idx = (cfg_f[tid][0]->threshold_value < cfg_f[tid][1]->threshold_value);
+            tmp = TIA_THR_TYP_AL0;
+            if ((cfg_f[tid][idx]->enable != 0) && (cfg_f[tid][idx]->sensor_alarm_type < TIA_ALM_TYP_DISABLE)) {
+                mon[tmp].vld = KAL_TRUE;
+                mon[tmp].thr = cfg_f[tid][idx]->threshold_value;
+                mon[tmp].cfg = &tia_thr_cfgs[tid][ppi][idx];
+                tmp++;
+            }
+            idx = !idx;
+            if ((cfg_f[tid][idx]->enable != 0) && (cfg_f[tid][idx]->sensor_alarm_type < TIA_ALM_TYP_DISABLE)) {
+                mon[tmp].vld = KAL_TRUE;
+                mon[tmp].thr = cfg_f[tid][idx]->threshold_value;
+                mon[tmp].cfg = &tia_thr_cfgs[tid][ppi][idx];
+            }
+        }
+        // update sw/fim threshold if one more rising alarm
+        for (idx = TIA_THR_TYP_AL0; idx <= TIA_THR_TYP_AL1; idx++) {
+            if (mon[idx].vld && (mon[idx].cfg->sensor_alarm_type == TIA_ALM_TYP_RISING)) {
+                mon[TIA_THR_TYP_SW].vld = (mon[TIA_THR_TYP_SW].thr <= TIA_THR_TMP_MAX);
+                mon[TIA_THR_TYP_SW].cfg = mon[TIA_THR_TYP_SW].vld? mon[idx].cfg: NULL;
+                mon[TIA_THR_TYP_WRN].vld = (mon[TIA_THR_TYP_WRN].thr <= TIA_THR_TMP_MAX);
+                mon[TIA_THR_TYP_WRN].cfg = mon[TIA_THR_TYP_WRN].vld? mon[idx].cfg: NULL;
+                break;
+            }
+        }
+        tia_thr_ppi[tid] = ppi;
+    }
+
+    // update sampling period
+    tms = 0;
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        mon = tia_thr_mons[tid][tia_thr_ppi[tid]];
+        for (idx = TIA_THR_TYP_AL0; idx <= TIA_THR_TYP_AL1; idx++) {
+            kal_uint32 t;
+            if (mon[idx].vld == KAL_FALSE) {
+                continue;
+            }
+            t = mon[idx].cfg->sampling_period;
+            if ((tms == 0) || (tms > t)) {
+                tms = (t < TIA_TMR_MS_MIN)? TIA_TMR_MS_MIN: t;
+            }
+        }
+    }
+    tia_tmr_set(tms, KAL_TRUE);
+
+    if (ret != THERMAL_ERR_NONE) {
+        MD_TRC(TIA_MSG_ERR_CODE, __func__, ret);
+    }
+    return ret;
+}
+
+kal_int32 tia_get_temp(kal_uint32 sensor_id, kal_int32 *temp)
+{
+    if (!TIA_SENSOR_SID_VALID(sensor_id)) {
+        MD_TRC(TIA_MSG_ERR_SENSOR_ID, __func__, sensor_id);
+        return THERMAL_ERR_SENSOR_ID;
+    }
+    EXT_ASSERT(temp!=NULL, sensor_id, (kal_uint32) temp, 0);
+
+    *temp = tia_temp(TIA_SENSOR_TID(sensor_id));
+
+    return THERMAL_ERR_NONE;
+}
+
+kal_int32 tia_get_temp_all(kal_uint32 ninfo, thermal_temp_info_t *infos)
+{
+    kal_uint32 idx;
+    thermal_temp_info_t *inf;
+
+    EXT_ASSERT((ninfo==TIA_SENSOR_NUM) && (infos!=NULL), ninfo, (kal_uint32) infos, 0);
+
+    for (idx = 0; idx < TIA_SENSOR_NUM; idx++) {
+        inf = &infos[idx];
+        inf->temp = tia_temp(idx);
+        inf->sensor_id = TIA_SENSOR_SID(idx);
+    }
+
+    return THERMAL_ERR_NONE;
+}
+
+void tia_init(void)
+{
+    tfwk_sensor_if_t sif = {.get_temp_fp = tia_get_temp, .set_alarm_fp = tia_set_alarm};
+    tfwk_sensor_info_t *sinfo_rt;
+    kal_uint32 tid, ppi;
+    struct tia_thr_mon_s *act;
+
+    UNUSED_PARAMETER(tia_thr_typ_str);
+
+    tia_adc_init();
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        tia_temp(tid); // update first record
+    }
+
+    #ifndef NVRAM_NOT_PRESENT // update from nvram
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        nvram_thermal_sensor_info_struct sinfo_nv;
+        if (tia_nvram_read_sensor_info(TIA_SENSOR_SID(tid), &sinfo_nv)) {
+            sinfo_rt = &tia_sensor_info[tid];
+            sinfo_rt->sensor_id           = sinfo_nv.sensor_id;
+            sinfo_rt->min_temperature     = sinfo_nv.min_temp;
+            sinfo_rt->max_temperature     = sinfo_nv.max_temp;
+            sinfo_rt->warning_temperature = sinfo_nv.warn_temp;
+            sinfo_rt->accuracy            = sinfo_nv.accuracy;
+            sinfo_rt->resolution          = sinfo_nv.resolution;
+            memcpy(sinfo_rt->sensor_name, sinfo_nv.sensor_name, sizeof(sinfo_rt->sensor_name));
+            tia_sensor_hwShutdownTemp[tid] = sinfo_nv.hws_temp;
+        }
+    }
+    #endif
+
+    // update to tia_thr_mons, tia_thr_hw
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        kal_uint32 hws = tia_sensor_hwShutdownTemp[tid];
+        kal_bool vld = (hws <= TIA_THR_TMP_MAX);
+        tia_thr_hw += vld;
+        sinfo_rt = &tia_sensor_info[tid];
+        for (ppi = 0; ppi < TIA_THR_PP_NUM; ppi++) {
+            act = tia_thr_mons[tid][ppi];
+            act[TIA_THR_TYP_HW].thr = hws;
+            act[TIA_THR_TYP_HW].vld = vld;
+            act[TIA_THR_TYP_SW].thr = sinfo_rt->max_temperature;
+            act[TIA_THR_TYP_WRN].thr = sinfo_rt->warning_temperature;
+        }
+    }
+
+    // register to tfwk
+    tfwk_sensor_reg(TFWK_TIA, TIA_SENSOR_NUM, tia_sensor_info, &sif);
+
+    // kal timer
+    tia_tmr_id = kal_create_timer("TIA");
+    tia_tmr_sl = kal_create_spinlock("TIA");
+    tia_tmr_set(0, KAL_TRUE);
+}
+
+void tia_dbg_sns_infs(kal_uint32 tid)
+{
+    kal_uint32 msk;
+    tfwk_sensor_info_t *inf;
+
+    msk = (tid >= TIA_SENSOR_NUM)? ((1 << TIA_SENSOR_NUM) - 1): (1 << tid);
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        if (msk & (1 << tid)) {
+            inf = &tia_sensor_info[tid]; UNUSED_PARAMETER(inf);
+            MD_TRC(TIA_MSG_SENSOR_INFO, inf->sensor_id, inf->min_temperature, inf->max_temperature,
+                inf->warning_temperature, tia_sensor_hwShutdownTemp[tid], inf->accuracy,
+                inf->resolution, TIA_SENSOR_NID(tid), inf->sensor_name);
+        }
+    }
+}
+
+void tia_dbg_thr_cfgs(kal_uint32 tid)
+{
+    kal_uint32 msk, idx;
+    tfwk_thermal_cfg_t *cfg;
+
+    msk = (tid >= TIA_SENSOR_NUM)? ((1 << TIA_SENSOR_NUM) - 1): (1 << tid);
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        if ((msk & (1 << tid)) == 0) {
+            continue;
+        }
+        for (idx = 0; idx < TIA_THR_ALM_NUM; idx++) {
+            cfg = &tia_thr_cfgs[tid][tia_thr_ppi[tid]][idx]; UNUSED_PARAMETER(cfg);
+            MD_TRC(TIA_MSG_ALARM_INFO, cfg->enable, cfg->sensor_id, cfg->alarm_id,
+                cfg->threshold_value, cfg->hysteresis_value, cfg->sampling_period,
+                cfg->sensor_alarm_type);
+        }
+    }
+}
+
+void tia_dbg_thr_mons(kal_uint32 tid)
+{
+    kal_uint32 msk, idx;
+    struct tia_thr_mon_s *mon;
+
+    msk = (tid >= TIA_SENSOR_NUM)? ((1 << TIA_SENSOR_NUM) - 1): (1 << tid);
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        if ((msk & (1 << tid)) == 0) {
+            continue;
+        }
+        for (idx = 0; idx < TIA_THR_TYP_MAX; idx++) {
+            mon = &tia_thr_mons[tid][tia_thr_ppi[tid]][idx];
+            MD_TRC(TIA_MSG_MONITOR_INFO, tid, tia_thr_typ_str[idx], mon->vld, mon->thr);
+            if (mon->vld && mon->cfg) {
+                MD_TRC(TIA_MSG_ALARM_INFO, mon->cfg->enable, mon->cfg->sensor_id, mon->cfg->alarm_id,
+                    mon->cfg->threshold_value, mon->cfg->hysteresis_value, mon->cfg->sampling_period,
+                    mon->cfg->sensor_alarm_type);
+            }
+        }
+    }
+}
+
+void tia_dbg_fake_en(kal_bool en)
+{
+    #ifdef __MTK_INTERNAL__
+    tia_sensor_fake_en = en;
+    #endif
+}
+
+void tia_dbg_fake_ohm(kal_uint32 tid, kal_uint32 ohm)
+{
+    #ifdef __MTK_INTERNAL__
+    kal_uint32 msk;
+
+    msk = (tid >= TIA_SENSOR_NUM)? ((1 << TIA_SENSOR_NUM) - 1): (1 << tid);
+    for (tid = 0; tid < TIA_SENSOR_NUM; tid++) {
+        if (msk & (1 << tid)) {
+            tia_sensor_fake_ohm[tid] = ohm;
+        }
+    }
+    #endif
+}
+
+void tia_dbg_sw_reset(void)
+{
+    #ifdef __MTK_INTERNAL__
+    /// WDT_DEBUG_CTL3: [13] debugsys_thermal_req=0, [14] debugsys_req=0
+    DRV_WriteReg32(0xC00070a8, 0x51000000);
+    // TOPRGU_CH_DEBUGSYS_EAP_SEL: [1] DEBUGSYS_HAND_SHAKE_REQ_EN=0
+    DRV_WriteReg32(0xC0007718, 0x00000000);
+    // TOPRGU_CH_DEBUGSYS_EAP_MODE: [0] DEBUGSYS_EN=0
+    DRV_WriteReg32(0xC0007714, 0x00000000);
+    // DRM_LATCH_CTL: [0] rg_latch_en=0, [6] rg_dramc_latch_en=0,
+    //                [11] rg_dramc_rd_test_en=0, [12] rg_dramc_rdwt_test_en=0,
+    //                [13] dvfsrc_latch_en=0, [14] emi_latch_en=0
+    DRV_WriteReg32(0xC0010044, 0x95000000);
+    // DRM_DEBUG_CTL2: [9] dvfsrc_en=0, [8] emi_dcs_en=0
+    DRV_WriteReg32(0xC00100a0, (DRV_Reg32(0xC00100a0) & ~0xff000300) | 0x55000000);
+    // DRM_MODE: [7] ddr_reserve_mode_wo=1
+    DRV_WriteReg32(0xC0010000, 0x22000000);
+
+    ust_us_busyloop(100);
+
+    // TOPRGUWDT_RESTART
+    DRV_WriteReg32(0xC0007008, 0x00001971);
+    // TOPRGUWDT_MODE
+    DRV_WriteReg32(0xC0007000, (DRV_Reg32(0xC0007000) & ~0xff000048) | 0x22000000);
+    // TOPRGUWDT_SWRST
+    DRV_WriteReg32(0xC0007014, 0x00001209);
+    #endif
+}
+
+void* tia_dbg_symbol(kal_char *sym)
+{
+    #ifdef __MTK_INTERNAL__
+    if (strcmp(sym, "tia_thr_mons") == 0) {
+        return (void *) tia_thr_mons;
+    } else if (strcmp(sym, "tia_thr_ppi") == 0) {
+        return (void *) tia_thr_ppi;
+    } else if (strcmp(sym, "tia_tmr_handler") == 0) {
+        return (void *) tia_tmr_handler;
+    }
+    #endif
+    return NULL;
+}
diff --git a/mcu/driver/devdrv/tia/src/tia_adc.c b/mcu/driver/devdrv/tia/src/tia_adc.c
new file mode 100644
index 0000000..77d4686
--- /dev/null
+++ b/mcu/driver/devdrv/tia/src/tia_adc.c
@@ -0,0 +1,233 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2017
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ *    tia_adc.c
+ *
+ * Project:
+ * --------
+ *    VMOLY
+ *
+ * Description:
+ * ------------
+ *    TIA (Thermal Information Acquisition) driver - adc
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ * removed!
+ * removed!
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *============================================================================
+ ****************************************************************************/
+
+#include "dcl.h"
+#include "tia.h"
+
+const kal_uint32 tia_adc_rc2k_map[TIA_ADC_RC_MAX+1] = {100, 30, 400, 0};
+
+// NCP15WF104F03RC, NCP03WF104F05RL
+static const kal_uint32 tia_adc_tbl[TIA_ADC_TMP_CNT] =
+{
+    0x0043183F, 0x003E73CA, 0x003A2985, 0x00363205, 0x00328684, // -40~-36 'C
+    0x002F20D7, 0x002BFB5C, 0x002910EE, 0x00265CD9, 0x0023DAD2, // -35~-31 'C
+    0x002186E9, 0x001F5D86, 0x001D5B5C, 0x001B7D65, 0x0019C0DD, // -30~-26 'C
+    0x00182339, 0x0016A15C, 0x00153A09, 0x0013EB45, 0x0012B33B, // -25~-21 'C
+    0x0011903D, 0x001080BF, 0x000F8355, 0x000E96B0, 0x000DB999, // -20~-16 'C
+    0x000CEAF3, 0x000C29B7, 0x000B74F2, 0x000ACBC4, 0x000A2D5C, // -15~-11 'C
+    0x000998FC, 0x00090DBE, 0x00088B3B, 0x000810DA, 0x00079E0C, // -10~ -6 'C
+    0x00073250, 0x0006CD4C, 0x00066E68, 0x0006153C, 0x0005C169, //  -5~ -1 'C
+    0x00057294, 0x00052856, 0x0004E27A, 0x0004A0B7, 0x000462CA, //   0~  4 'C
+    0x00042874, 0x0003F17A, 0x0003BDA8, 0x00038CC9, 0x00035EAF, //   5~  9 'C
+    0x0003332E, 0x00030A1C, 0x0002E354, 0x0002BEB2, 0x00029C14, //  10~ 14 'C
+    0x00027B5B, 0x00025C66, 0x00023F20, 0x0002236E, 0x00020938, //  15~ 19 'C
+    0x0001F068, 0x0001D8EA, 0x0001C2A8, 0x0001AD92, 0x00019994, //  20~ 24 'C
+    0x000186A0, 0x000174A6, 0x00016398, 0x00015369, 0x0001440C, //  25~ 29 'C
+    0x00013576, 0x0001279B, 0x00011A72, 0x00010DF0, 0x0001020D, //  30~ 34 'C
+    0x0000F6BF, 0x0000EBFF, 0x0000E1C5, 0x0000D80A, 0x0000CEC6, //  35~ 39 'C
+    0x0000C5F5, 0x0000BD90, 0x0000B592, 0x0000ADF5, 0x0000A6B3, //  40~ 44 'C
+    0x00009FC8, 0x0000992D, 0x000092E1, 0x00008CDF, 0x00008723, //  45~ 49 'C
+    0x000081AB, 0x00007C73, 0x00007778, 0x000072B6, 0x00006E2B, //  50~ 54 'C
+    0x000069D3, 0x000065AC, 0x000061B5, 0x00005DEA, 0x00005A49, //  55~ 59 'C
+    0x000056D0, 0x0000537E, 0x00005051, 0x00004D46, 0x00004A5C, //  60~ 64 'C
+    0x00004793, 0x000044E8, 0x0000425A, 0x00003FE8, 0x00003D90, //  65~ 69 'C
+    0x00003B50, 0x00003927, 0x00003715, 0x00003518, 0x00003330, //  70~ 74 'C
+    0x0000315B, 0x00002F9B, 0x00002DED, 0x00002C50, 0x00002AC3, //  75~ 79 'C
+    0x00002946, 0x000027D8, 0x00002678, 0x00002526, 0x000023E1, //  80~ 84 'C
+    0x000022A9, 0x0000217C, 0x0000205B, 0x00001F46, 0x00001E3A, //  85~ 89 'C
+    0x00001D39, 0x00001C42, 0x00001B55, 0x00001A71, 0x00001994, //  90~ 94 'C
+    0x000018C1, 0x000017F4, 0x0000172E, 0x00001670, 0x000015B9, //  95~ 99 'C
+    0x00001508, 0x0000145E, 0x000013BB, 0x0000131D, 0x00001285, // 100~104 'C
+    0x000011F2, 0x00001165, 0x000010DC, 0x00001058, 0x00000FD9, // 105~109 'C
+    0x00000F5E, 0x00000EE8, 0x00000E75, 0x00000E07, 0x00000D9C, // 110~114 'C
+    0x00000D34, 0x00000CD1, 0x00000C71, 0x00000C15, 0x00000BBB, // 115~119 'C
+    0x00000B64, 0x00000B10, 0x00000ABF, 0x00000A70, 0x00000A24, // 120~124 'C
+    0x000009DA                                                  // 125     'C
+};
+
+static struct {
+    kal_int32 efuse_V18;  // 7 bits 2's complement
+    kal_int32 efuse_Rinb; // 16 bits 2's complement
+    kal_uint32 V18;       // /10^4 V
+    kal_uint32 Rinb;      // *10 ohm
+} tia_adc_cal_par;
+
+kal_uint32 tia_adc_to_ohm(tia_adc_rc_type_e rc, kal_uint32 adc)
+{
+    // V = /10^4 volt
+    // R = *10   ohm                                        || range
+    // Vin = 1.9 - code / 16384                             => ~19000  /10^4 V
+    // V18 = AUXADC_EFUSE_VAUX18[6:0] * 0.0005 + 1.84       => ~18720  /10^4 V
+    // Rint = {100K, 30K, 400K}                             => ~40000  *10 ohm
+    // Rinb = RG_AUXADC_SDMADC_RIN_BUFFER[15:0] * 10 + 10^6 => ~132767 *10 ohm
+    // a = (Rint/2 + Rinb) / (Rint + Rinb)
+    // Rprl = Rint * Rinb / (Rint + Rinb)
+    // Rntc = Vin * Rprl / (a * V18 - Vin)
+    //      = Vin * Rprl / {[(Rint/2 + Rinb) / (Rint + Rinb)] * V18 - Vin}
+    //      = Vin * Rprl / [(Rint/2 + Rinb) * V18 - (Rint + Rinb) * Vin] * (Rint + Rinb)
+
+    const kal_uint32 Rints[] = {10000, 3000, 40000};
+    kal_int32 T32i;
+    kal_uint32 T32u, T32u2, Vin, Rint, Rprl, Rntc;
+
+    // Vin = 1.9 - code / 16384
+    T32i = 19000 - adc * 10000 / 16384;
+    Vin = (T32i < 0)? 0: T32i;
+
+    // Rprl = Rint * Rinb / (Rint + Rinb)
+    Rint = Rints[rc];
+    Rprl = ((kal_uint64) Rint * tia_adc_cal_par.Rinb) / (Rint + tia_adc_cal_par.Rinb);
+
+    // T32u - T32u2 = [(Rint/2 + Rinb) * V18 - (Rint + Rinb) * Vin]
+    T32u  = (Rint / 2 + tia_adc_cal_par.Rinb) * tia_adc_cal_par.V18;
+    T32u2 = (Rint + tia_adc_cal_par.Rinb) * Vin;
+    if (T32u <= T32u2) {
+        Rntc = 0xFFFFFFFF;
+    } else {
+        // Rntc = Vin * Rprl / [(Rint/2 + Rinb) * V18 - (Rint + Rinb) * Vin] * (Rint + Rinb)
+        Rntc = ((kal_uint64) (Vin * Rprl) * (Rint + tia_adc_cal_par.Rinb) * 10/*ohm*/) / (T32u - T32u2);
+    }
+
+    return Rntc;
+}
+
+kal_int32 tia_adc_to_tmp(tia_adc_rc_type_e rc, kal_uint32 adc)
+{
+    kal_int32 l = 0, r = sizeof(tia_adc_tbl)/sizeof(tia_adc_tbl[0])-1, m;
+    kal_uint32 ohm;
+
+    if (rc < TIA_ADC_RC_MAX) {
+        ohm = tia_adc_to_ohm(rc, adc);
+    } else if (rc == TIA_ADC_RC_FAKE) {
+        ohm = adc;
+    } else {
+        return TIA_ADC_TMP_ERR;
+    }
+
+    if (ohm > tia_adc_tbl[0]) {
+        return TIA_ADC_TMP_MIN * 10;
+    }
+    if (ohm < tia_adc_tbl[r]) {
+        return TIA_ADC_TMP_MAX * 10;
+    }
+
+    // binary search with inversed order
+    while (l <= r) {
+        m = l + (r - l) / 2;
+        if (tia_adc_tbl[m] == ohm) {
+            return (m + TIA_ADC_TMP_MIN) * 10;
+        }
+        if (tia_adc_tbl[m] < ohm) {
+            r = m - 1;
+        } else {
+            l = m + 1;
+        }
+    }
+
+    m = (((tia_adc_tbl[r] - ohm) * 100) / (tia_adc_tbl[r] - tia_adc_tbl[l]) + 5/*rounding*/) / 10;
+    return (r + TIA_ADC_TMP_MIN) * 10 + m;
+}
+
+void tia_adc_init(void)
+{
+    kal_uint32 V18 = 0 , Rinb = 0;
+
+    #if defined(CHIP10992)
+    {
+        DCL_HANDLE hdl;
+        SPMI_CTRL_EXT_REGISTER_READL cmd = {.type=DCL_MAIN_PMIC, .len=1};
+
+        hdl = DclSPMI_Open(DCL_SPMI, FLAGS_NONE);
+        cmd.addr = 0x11f8; // AUXADC_DIG_3_ELR54 = AUXADC_EFUSE_VAUX18
+        if (DclSPMI_Control(hdl, EXT_REGISTER_READL, (DCL_CTRL_DATA_T *)&cmd) == STATUS_OK) {
+            V18 = cmd.value & 0x7F;
+        }
+        cmd.addr = 0x11d2; // AUXADC_DIG_3_ELR16 = EFUSE_GAIN_CH12_TRIM_L
+        if (DclSPMI_Control(hdl, EXT_REGISTER_READL, (DCL_CTRL_DATA_T *)&cmd) == STATUS_OK) {
+            Rinb |= (cmd.value & 0xFF) << 0;
+        }
+        cmd.addr = 0x11d4; // AUXADC_DIG_3_ELR18 = EFUSE_OFFSET_CH12_TRIM_L
+        if (DclSPMI_Control(hdl, EXT_REGISTER_READL, (DCL_CTRL_DATA_T *)&cmd) == STATUS_OK) {
+            Rinb |= (cmd.value & 0xFF) << 8;
+        }
+        DclSPMI_Close(hdl);
+    }
+    #endif
+
+    // V18 = AUXADC_EFUSE_VAUX18[6:0] * 0.0005 + 1.84
+    tia_adc_cal_par.efuse_V18 = (V18 & (1<<6))? (signed char) (V18 | (1<<7)): V18;
+    tia_adc_cal_par.V18 = tia_adc_cal_par.efuse_V18 * 5 + 18400;
+
+    // Rinb = RG_AUXADC_SDMADC_RIN_BUFFER[15:0] * 10 + 10^6
+    tia_adc_cal_par.efuse_Rinb = (kal_int16) Rinb;
+    tia_adc_cal_par.Rinb = tia_adc_cal_par.efuse_Rinb * 1 + 100000;
+}
+
+void tia_adc_dbg_efuse(kal_int32 *V18, kal_int32 *Rinb)
+{
+    if (V18)  *V18  = tia_adc_cal_par.efuse_V18;
+    if (Rinb) *Rinb = tia_adc_cal_par.efuse_Rinb;
+    MD_TRC(TIA_MSG_AUXADC_EFUSE, tia_adc_cal_par.efuse_V18, tia_adc_cal_par.efuse_Rinb);
+}
diff --git a/mcu/driver/devdrv/tia/src/tia_atcmd.c b/mcu/driver/devdrv/tia/src/tia_atcmd.c
new file mode 100644
index 0000000..d9eb29a
--- /dev/null
+++ b/mcu/driver/devdrv/tia/src/tia_atcmd.c
@@ -0,0 +1,322 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2017
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ *    tia_atcmd.c
+ *
+ * Project:
+ * --------
+ *    VMOLY
+ *
+ * Description:
+ * ------------
+ *    TIA (Thermal Information Acquisition) driver - atcmd
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *============================================================================
+ ****************************************************************************/
+
+#include "kal_public_api.h"
+#include "drv_comm.h"
+#include "us_timer.h"
+#include "tia_reg.h"
+#include "tia.h"
+
+static kal_timerid atcmd_tmr_id;
+
+static kal_bool tia_atcmd_sensor_info(kal_uint32 len, kal_uint8 *dat)
+{
+    // B0 B1  B2 B3 description
+    // ..           all
+    // .. TID       TID = 0~3, 4:all
+    tia_dbg_sns_infs((len < 2)? TIA_SENSOR_NUM: dat[1]);
+    return KAL_TRUE;
+}
+
+static kal_bool tia_atcmd_sensor_state(kal_uint32 len, kal_uint8 *dat)
+{
+    // B0 B1  B2 B3 description
+    // ..           all
+    // .. TID       TID = 0~3, 4:all
+    tia_dbg_thr_cfgs((len < 2)? TIA_SENSOR_NUM: dat[1]);
+    return KAL_TRUE;
+}
+
+static kal_bool tia_atcmd_monitor_state(kal_uint32 len, kal_uint8 *dat)
+{
+    // B0 B1  B2 B3 description
+    // ..           all
+    // .. TID       TID = 0~3, 4:all
+    tia_dbg_thr_mons((len < 2)? TIA_SENSOR_NUM: dat[1]);
+    return KAL_TRUE;
+}
+
+static kal_bool tia_atcmd_auxadc_efuse(void)
+{
+    tia_adc_dbg_efuse(NULL, NULL);
+    return KAL_TRUE;
+}
+
+static kal_bool tia_atcmd_fake_tmp(kal_uint32 len, kal_uint8 *dat)
+{
+    #ifdef __MTK_INTERNAL__
+    // B0 B1  B2 B3 B4 description
+    // ..              disable
+    // .. TID XX YY ZZ enable, TID={0~3, 4:all}, 0xXXYYZZ={ohm}
+    kal_bool ret = KAL_TRUE;
+
+    if (len < 2) {
+        tia_dbg_fake_en(KAL_FALSE);
+    } else if (len >= 5) {
+        kal_uint32 tid, val;
+        tid = dat[1];
+        val = (dat[2] << 16) | (dat[3] << 8) | (dat[4] << 0);
+        tia_dbg_fake_ohm(tid, val);
+        tia_dbg_fake_en(KAL_TRUE);
+    } else {
+        ret = KAL_FALSE;
+    }
+
+    return ret;
+    #else
+    return KAL_FALSE;
+    #endif
+}
+
+static kal_bool tia_atcmd_set_alarm(kal_uint32 len, kal_uint8 *dat)
+{
+    #ifdef __MTK_INTERNAL__
+    kal_uint32 idx, cid;
+    tfwk_thermal_cfg_t cfg[4]={};
+
+    // B1={enable,type}, B2={sid,aid}, B3=thres(signed'C), B4=hyst('C), B5=period(ms) => loop 1~4
+    if ((len != 1+5*1) && (len != 1+5*2) && (len != 1+5*3) && (len != 1+5*4)) {
+        return KAL_FALSE;
+    }
+    for (idx = 1, cid = 0; idx + 5 <= len; idx += 5, cid++) {
+        cfg[cid].enable            = dat[idx+0] >> 4;
+        cfg[cid].sensor_alarm_type = dat[idx+0] & 0xF;
+        cfg[cid].sensor_id         = dat[idx+1] >> 4;
+        cfg[cid].alarm_id          = dat[idx+1] & 0xF;
+        cfg[cid].threshold_value   = ((signed char) dat[idx+2]) * 10;
+        cfg[cid].hysteresis_value  = dat[idx+3] * 10;
+        cfg[cid].sampling_period   = dat[idx+4];
+    }
+    tia_set_alarm(cid, cfg);
+
+    return KAL_TRUE;
+    #else
+    return KAL_FALSE;
+    #endif
+}
+
+static kal_bool tia_atcmd_set_rc(kal_uint32 len, kal_uint8 *dat)
+{
+    #ifdef __MTK_INTERNAL__
+    // B0 B1  B2 description
+    // .. UID RC UID={0:MD,1:GPS,2:AP,3:all}, RC={0:100K,1:30K,2:400K}
+    kal_bool ret = KAL_FALSE;
+    kal_uint32 idx, msk, val;
+    kal_uint32 adr[] = {TIA_TIA2_MD_RC_CTRL, TIA_TIA2_GPS_RC_CTRL, TIA_TIA2_AP_RC_CTRL};
+
+    if ((len >= 3) /*&& (dat[1] <= 3)*/ && (dat[2] <= 2)) {
+        msk = (dat[1] < 3)? (1 << dat[1]): 0x7;
+        val = TIA_TIA2_GPS_RC_CTRL_TSX_RC_SEL_GPS(dat[2])|
+              TIA_TIA2_GPS_RC_CTRL_T0_RC_SEL_GPS(dat[2]) |
+              TIA_TIA2_GPS_RC_CTRL_T1_RC_SEL_GPS(dat[2]) |
+              TIA_TIA2_GPS_RC_CTRL_T2_RC_SEL_GPS(dat[2]) |
+              TIA_TIA2_GPS_RC_CTRL_T3_RC_SEL_GPS(dat[2]);
+        for (idx = 0; idx <= 2; idx++) {
+            if (msk & (1 << idx)) {
+                DRV_WriteReg32(adr[idx], val);
+            }
+        }
+        ret = KAL_TRUE;
+    }
+
+    return ret;
+    #else
+    return KAL_FALSE;
+    #endif
+}
+
+static kal_bool tia_atcmd_all_sensor_temp(void)
+{
+    kal_uint32 idx, us;
+    kal_int32  tmp[TIA_LVTS_GET_ALL_NUM+TIA_SENSOR_NUM] = {};
+
+    us = ust_get_current_time(); UNUSED_PARAMETER(us);
+    TIA_LVTS_GET_ALL_TEMP(TIA_LVTS_GET_ALL_NUM, &tmp[0]);
+    for (idx = 0; idx < TIA_SENSOR_NUM; idx++) {
+        tia_get_temp(TIA_SENSOR_SID(idx), &tmp[TIA_LVTS_GET_ALL_NUM+idx]);
+    }
+    MD_TRC(TIA_MSG_THERMAL_TMP_ALL_8, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], us);
+
+    return KAL_TRUE;
+}
+
+static void atcmd_tmr_handler(void *param_ptr)
+{
+    tia_atcmd_all_sensor_temp();
+}
+
+static kal_bool atcmd_tmr_enable(
+    kal_uint32 en/*0:disable,1:enable,2:toggle*/,
+    kal_uint32 ms/*0:default(1000ms),others:XXms*/)
+{
+    static kal_bool tmr_st = KAL_FALSE;
+    kal_uint32 cfg_en = (en == 2)? (!tmr_st): en;
+    kal_uint32 cfg_ms = (ms == 0)? 1000: ms;
+    kal_uint32 tick;
+
+    switch (cfg_en) {
+    case 0:
+        kal_cancel_timer(atcmd_tmr_id);
+        tmr_st = KAL_FALSE;
+        break;
+    case 1:
+        tick = kal_milli_secs_to_ticks(cfg_ms);
+        kal_set_timer(atcmd_tmr_id, atcmd_tmr_handler, NULL, 1, tick);
+        tmr_st = KAL_TRUE;
+        break;
+    default:
+        return KAL_FALSE;
+    }
+    return KAL_TRUE;
+}
+
+static kal_bool tia_atcmd_all_sensor_temp_periodic(kal_uint32 len, kal_uint8 *dat)
+{
+    // B0 B1  B2 B3  description
+    // ..            all temperature log periodic - toggle
+    // .. 00         disable
+    // .. 01 [XX YY] enable, default: 1000 ms, others: 0xXXYY ms
+    kal_bool ret = KAL_FALSE;
+
+    if (len == 1) {
+        ret = atcmd_tmr_enable(2, 0);
+    } else if (dat[1] == 0x00) {
+        ret = atcmd_tmr_enable(0, 0);
+    } else if (dat[1] == 0x01) {
+        if (len == 2) {
+            ret = atcmd_tmr_enable(1, 0);
+        } else if (len >= 4) {
+            kal_uint32 ms = (dat[2] << 8) + dat[3];
+            ret = atcmd_tmr_enable(1, ms);
+        }
+    }
+
+    return ret;
+}
+
+void tia_atcmd_init(void)
+{
+    atcmd_tmr_id = kal_create_timer("TIA_ATCMD");
+}
+
+kal_bool tia_atcmd_public(kal_uint32 data_len, kal_uint8 *data_str)
+{
+    kal_bool ret = KAL_FALSE;
+
+    if (data_len < 1) {
+        goto T_EXIT;
+    }
+
+    switch (data_str[0]) {
+    // 0x2x for tia only
+    case 0x20:
+        ret = tia_atcmd_sensor_info(data_len, data_str);
+        break;
+    case 0x21:
+        ret = tia_atcmd_sensor_state(data_len, data_str);
+        break;
+    case 0x22:
+        ret = tia_atcmd_monitor_state(data_len, data_str);
+        break;
+    case 0x24:
+        ret = tia_atcmd_auxadc_efuse();
+        break;
+    case 0x29:
+        ret = tia_atcmd_fake_tmp(data_len, data_str);
+        break;
+    case 0x2A:
+        ret = tia_atcmd_set_alarm(data_len, data_str);
+        break;
+    case 0x2C:
+        ret = tia_atcmd_set_rc(data_len, data_str);
+        break;
+
+    // 0x3x for thermal cross modules (lvts + tia + ...)
+    case 0x30:
+        ret = tia_atcmd_all_sensor_temp();
+        break;
+    case 0x31:
+        ret = tia_atcmd_all_sensor_temp_periodic(data_len, data_str);
+        break;
+    default:
+        break;
+    }
+
+T_EXIT:
+    return ret;
+}
diff --git a/mcu/driver/devdrv/tia/src/tia_task.c b/mcu/driver/devdrv/tia/src/tia_task.c
new file mode 100644
index 0000000..adca821
--- /dev/null
+++ b/mcu/driver/devdrv/tia/src/tia_task.c
@@ -0,0 +1,129 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2017
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ *    tia_task.c
+ *
+ * Project:
+ * --------
+ *    VMOLY
+ *
+ * Description:
+ * ------------
+ *    TIA (Thermal Information Acquisition) driver - task
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ * removed!
+ * removed!
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *============================================================================
+ ****************************************************************************/
+
+#include "kal_public_api.h"
+#include "syscomp_config.h"
+#include "task_config.h"
+#include "tia.h"
+
+#ifndef NVRAM_NOT_PRESENT
+#include "thermal_nvram_def.h"
+#include "nvram_interface.h"
+#if NVRAM_EF_THERMAL_SENSOR_INFO_TOTAL != THERMAL_TOTAL_SENSOR_NUM
+    #error "NVRAM_EF_THERMAL_SENSOR_INFO_TOTAL != THERMAL_TOTAL_SENSOR_NUM"
+#endif
+extern nvram_ltable_entry_struct logical_data_item_table_thermal[];
+
+kal_bool tia_nvram_read_sensor_info(kal_uint32 sensor_id, nvram_thermal_sensor_info_struct *info)
+{
+    kal_uint16 rid = sensor_id + 1; // record_id from 1, sensor_id from 0
+
+    return nvram_external_read_data(NVRAM_EF_THERMAL_SENSOR_INFO_LID, rid,
+           (kal_uint8 *) info, sizeof(nvram_thermal_sensor_info_struct));
+}
+#endif //NVRAM_NOT_PRESENT
+
+static kal_eventgrpid tia_event_grp;
+
+static kal_bool tia_task_init(void)
+{
+    #ifndef NVRAM_NOT_PRESENT
+    nvram_ltable_register(logical_data_item_table_thermal);
+    #endif
+
+    tia_event_grp = kal_create_event_group("TIA_EVENT");
+
+    lvts_task_init();
+
+    tia_init();
+    tia_atcmd_init();
+
+    return KAL_TRUE;
+}
+
+static void tia_task_main(task_entry_struct *task_entry_ptr)
+{
+    kal_uint32 evt;
+
+    while (1) {
+        kal_retrieve_eg_events(tia_event_grp, 0xffffffff, KAL_OR_CONSUME, &evt, KAL_SUSPEND);
+        #if defined(MT6297) && defined(__MTK_INTERNAL__)
+        ASSERT(0);
+        #else
+        DEBUG_ASSERT(0);
+        #endif
+    }
+}
+
+kal_bool tia_create(comptask_handler_struct **handle)
+{
+    static const comptask_handler_struct tia_task_info = {
+        tia_task_main, /* task entry function */
+        tia_task_init, /* task initialization function */
+        NULL, /* task reset handler */
+    };
+    *handle = (comptask_handler_struct *)&tia_task_info;
+    return KAL_TRUE; /*always return true here*/
+}