0001
0002
0003
0004
0005
0006 #include <linux/module.h>
0007 #include <linux/platform_device.h>
0008 #include <soc/tegra/fuse.h>
0009
0010 #include "soctherm.h"
0011
0012 #define NOMINAL_CALIB_FT 105
0013 #define NOMINAL_CALIB_CP 25
0014
0015 #define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff
0016 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13)
0017 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
0018
0019 #define FUSE_TSENSOR_COMMON 0x180
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 #define CALIB_COEFFICIENT 1000000LL
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 static s64 div64_s64_precise(s64 a, s32 b)
0063 {
0064 s64 r, al;
0065
0066
0067 al = a << 16;
0068
0069 r = div64_s64(al * 2 + 1, 2 * b);
0070 return r >> 16;
0071 }
0072
0073 int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
0074 struct tsensor_shared_calib *shared)
0075 {
0076 u32 val;
0077 s32 shifted_cp, shifted_ft;
0078 int err;
0079
0080 err = tegra_fuse_readl(FUSE_TSENSOR_COMMON, &val);
0081 if (err)
0082 return err;
0083
0084 shared->base_cp = (val & tfuse->fuse_base_cp_mask) >>
0085 tfuse->fuse_base_cp_shift;
0086 shared->base_ft = (val & tfuse->fuse_base_ft_mask) >>
0087 tfuse->fuse_base_ft_shift;
0088
0089 shifted_ft = (val & tfuse->fuse_shift_ft_mask) >>
0090 tfuse->fuse_shift_ft_shift;
0091 shifted_ft = sign_extend32(shifted_ft, 4);
0092
0093 if (tfuse->fuse_spare_realignment) {
0094 err = tegra_fuse_readl(tfuse->fuse_spare_realignment, &val);
0095 if (err)
0096 return err;
0097 }
0098
0099 shifted_cp = sign_extend32(val, 5);
0100
0101 shared->actual_temp_cp = 2 * NOMINAL_CALIB_CP + shifted_cp;
0102 shared->actual_temp_ft = 2 * NOMINAL_CALIB_FT + shifted_ft;
0103
0104 return 0;
0105 }
0106
0107 int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor,
0108 const struct tsensor_shared_calib *shared,
0109 u32 *calibration)
0110 {
0111 const struct tegra_tsensor_group *sensor_group;
0112 u32 val, calib;
0113 s32 actual_tsensor_ft, actual_tsensor_cp;
0114 s32 delta_sens, delta_temp;
0115 s32 mult, div;
0116 s16 therma, thermb;
0117 s64 temp;
0118 int err;
0119
0120 sensor_group = sensor->group;
0121
0122 err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
0123 if (err)
0124 return err;
0125
0126 actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
0127 val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) >>
0128 FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
0129 actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
0130
0131 delta_sens = actual_tsensor_ft - actual_tsensor_cp;
0132 delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
0133
0134 mult = sensor_group->pdiv * sensor->config->tsample_ate;
0135 div = sensor->config->tsample * sensor_group->pdiv_ate;
0136
0137 temp = (s64)delta_temp * (1LL << 13) * mult;
0138 therma = div64_s64_precise(temp, (s64)delta_sens * div);
0139
0140 temp = ((s64)actual_tsensor_ft * shared->actual_temp_cp) -
0141 ((s64)actual_tsensor_cp * shared->actual_temp_ft);
0142 thermb = div64_s64_precise(temp, delta_sens);
0143
0144 temp = (s64)therma * sensor->fuse_corr_alpha;
0145 therma = div64_s64_precise(temp, CALIB_COEFFICIENT);
0146
0147 temp = (s64)thermb * sensor->fuse_corr_alpha + sensor->fuse_corr_beta;
0148 thermb = div64_s64_precise(temp, CALIB_COEFFICIENT);
0149
0150 calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
0151 ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
0152
0153 *calibration = calib;
0154
0155 return 0;
0156 }
0157
0158 MODULE_AUTHOR("Wei Ni <wni@nvidia.com>");
0159 MODULE_DESCRIPTION("Tegra SOCTHERM fuse management");
0160 MODULE_LICENSE("GPL v2");