summaryrefslogtreecommitdiff
path: root/bsp/allwinner/libraries/sunxi-hal/hal/source/thermal/hal_thermal.c
blob: ea488854b3f46190a020e0fb924acc775a435a03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <stdint.h>
#include <stdio.h>

#include <hal_cmd.h>
#include <hal_timer.h>
#include <sunxi_hal_thermal.h>
#include <sunxi_hal_common.h>
#include <hal_log.h>

#if 0
#define THS_DBG(fmt,arg...)   printf("THS:" fmt, ##arg)
#else
#define THS_DBG(fmt,arg...)   do{}while(0)
#endif

extern int hal_efuse_get_thermal_cdata(unsigned char *buffer);

/* Temp Unit: millidegree Celsius */
static int hal_ths_reg2temp(int reg)
{
    THS_DBG("OFFSET:%d[0x%x], SCALE:%d[0x%x], reg:%d[0x%x]\n", OFFSET, OFFSET, SCALE, SCALE, reg, reg);

    return (reg + OFFSET) * SCALE;
}

static void hal_ths_calibrate(short int *buf, unsigned int len)
{
    unsigned int i;
    int ft_temp;

    if (!buf[0] || len < 2 + 2 * THS_NUM)
        return;

    ft_temp = buf[0] & FT_TEMP_MASK;

    for (i = 0; i < THS_NUM; i++) {
        int reg = (int)buf[i + 1];
        int sensor_temp = hal_ths_reg2temp(reg);
        int delta, cdata, calib_offest;

        /*
         * To calculate the calibration value:
         *
         * X(in Celsius) = Ts - ft_temp
         * delta = X * 10000 / TEMP_TO_REG
         * cdata = CALIBRATE_DEFAULT - delta
         *
         * cdata: calibration value
         */
        delta = (sensor_temp - ft_temp * 100) * 10 / TEMP_TO_REG;
        cdata = CALIBRATE_DEFAULT - delta;

        THS_DBG("sensor_temp:%d[0x%x], ft_temp:%d[0x%x], TEMP_TO_REG:%d[0x%x],"
               "delta:%d[0x%x], CALIBRATE_DEFAULT:%d[0x%x], cdata:%d[0x%x]\n",
               sensor_temp, sensor_temp, ft_temp, ft_temp, TEMP_TO_REG, TEMP_TO_REG,
               delta, delta, CALIBRATE_DEFAULT, CALIBRATE_DEFAULT, cdata, cdata);

        if (cdata & ~TEMP_CALIB_MASK) {
            /*
             * Calibration value more than 12-bit, but calibration
             * register is 12-bit. In this case, ths hardware can
             * still work without calibration, although the data
             * won't be so accurate.
             */
            continue;
        }

        calib_offest = THS_CALIB + (i / 2) * 0x4;

        THS_DBG("calib_offest:%d[0x%x], THS_CALIB:%d[0x%x]\n", calib_offest, calib_offest, THS_CALIB, THS_CALIB);

        if (i % 2) {
            hal_writel((hal_readl((unsigned long)THS_CALIB) & TEMP_CALIB_MASK) | (cdata << 16), (unsigned long)calib_offest);
        } else {
            hal_writel(cdata, (unsigned long)calib_offest);
        }
    }
}


int hal_ths_init(void)
{
    int ret = 0;
    char buffer[8] = {0};

    //TODO: clk init
    hal_writel(0x10001, (unsigned long)0x020019fc);

    /*
     * clkin = 24MHz
     * T acquire = clkin / (x + 1)
     *           = 20us
     */
    hal_log_err("0x%x, 0x%x, 0x%x, 0x%x", THS_EN, THS_CTL, THS_MFC, THS_PCTL);
    hal_writel(THS_CTRL_T_ACQ(479), (unsigned long)THS_CTL);
    /* average over 4 samples */
    hal_writel(THS_FILTER_EN | THS_FILTER_TYPE(1), (unsigned long)THS_MFC);
    /* period = (x + 1) * 4096 / clkin; ~10ms */
    hal_writel(THS_PC_TEMP_PERIOD(58), (unsigned long)THS_PCTL);
    /* enable sensor */
    hal_writel(THS_NUM, (unsigned long)THS_EN);

    ret = hal_efuse_get_thermal_cdata(buffer);
    if (ret < 0) {
        printf("get thermal calibration data failed.\n");
        return ret;
    }

    hal_ths_calibrate((short int *)buffer, 8);
    return ret ;

}

int hal_ths_uninit(void)
{
    hal_writel(0x0, (unsigned long)0x020019fc);

    return 0;
}

int hal_ths_get_temp(unsigned int num, int *temp)
{
    uint32_t val;

    val = hal_readl((unsigned long)THS_DATA + 0x4 * num);
    THS_DBG("num:%d[0x%x], val:%d[0x%x]\n", num, num, val, val);

    /* ths have no data yet */
    if (!val)
        return -1;

    *temp = hal_ths_reg2temp(val);

    return 0;
}