1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <soc/tegra/fuse.h>
18
19#include "soctherm.h"
20
21#define NOMINAL_CALIB_FT 105
22#define NOMINAL_CALIB_CP 25
23
24#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
25#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
26#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
27
28#define FUSE_TSENSOR_COMMON 0x180
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#define CALIB_COEFFICIENT 1000000LL
59
60
61
62
63
64
65
66
67
68
69
70
71static s64 div64_s64_precise(s64 a, s32 b)
72{
73 s64 r, al;
74
75
76 al = a << 16;
77
78 r = div64_s64(al * 2 + 1, 2 * b);
79 return r >> 16;
80}
81
82int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
83 struct tsensor_shared_calib *shared)
84{
85 u32 val;
86 s32 shifted_cp, shifted_ft;
87 int err;
88
89 err = tegra_fuse_readl(FUSE_TSENSOR_COMMON, &val);
90 if (err)
91 return err;
92
93 shared->base_cp = (val & tfuse->fuse_base_cp_mask) >>
94 tfuse->fuse_base_cp_shift;
95 shared->base_ft = (val & tfuse->fuse_base_ft_mask) >>
96 tfuse->fuse_base_ft_shift;
97
98 shifted_ft = (val & tfuse->fuse_shift_ft_mask) >>
99 tfuse->fuse_shift_ft_shift;
100 shifted_ft = sign_extend32(shifted_ft, 4);
101
102 if (tfuse->fuse_spare_realignment) {
103 err = tegra_fuse_readl(tfuse->fuse_spare_realignment, &val);
104 if (err)
105 return err;
106 }
107
108 shifted_cp = sign_extend32(val, 5);
109
110 shared->actual_temp_cp = 2 * NOMINAL_CALIB_CP + shifted_cp;
111 shared->actual_temp_ft = 2 * NOMINAL_CALIB_FT + shifted_ft;
112
113 return 0;
114}
115
116int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor,
117 const struct tsensor_shared_calib *shared,
118 u32 *calibration)
119{
120 const struct tegra_tsensor_group *sensor_group;
121 u32 val, calib;
122 s32 actual_tsensor_ft, actual_tsensor_cp;
123 s32 delta_sens, delta_temp;
124 s32 mult, div;
125 s16 therma, thermb;
126 s64 temp;
127 int err;
128
129 sensor_group = sensor->group;
130
131 err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
132 if (err)
133 return err;
134
135 actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
136 val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) >>
137 FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
138 actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
139
140 delta_sens = actual_tsensor_ft - actual_tsensor_cp;
141 delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
142
143 mult = sensor_group->pdiv * sensor->config->tsample_ate;
144 div = sensor->config->tsample * sensor_group->pdiv_ate;
145
146 temp = (s64)delta_temp * (1LL << 13) * mult;
147 therma = div64_s64_precise(temp, (s64)delta_sens * div);
148
149 temp = ((s64)actual_tsensor_ft * shared->actual_temp_cp) -
150 ((s64)actual_tsensor_cp * shared->actual_temp_ft);
151 thermb = div64_s64_precise(temp, delta_sens);
152
153 temp = (s64)therma * sensor->fuse_corr_alpha;
154 therma = div64_s64_precise(temp, CALIB_COEFFICIENT);
155
156 temp = (s64)thermb * sensor->fuse_corr_alpha + sensor->fuse_corr_beta;
157 thermb = div64_s64_precise(temp, CALIB_COEFFICIENT);
158
159 calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
160 ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
161
162 *calibration = calib;
163
164 return 0;
165}
166
167MODULE_AUTHOR("Wei Ni <wni@nvidia.com>");
168MODULE_DESCRIPTION("Tegra SOCTHERM fuse management");
169MODULE_LICENSE("GPL v2");
170