Commit | Line | Data |
---|---|---|
e8c24c6f AK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2019, Linaro Limited | |
4 | */ | |
5 | ||
6 | #include <linux/bitops.h> | |
7 | #include <linux/regmap.h> | |
8 | #include <linux/delay.h> | |
9 | #include "tsens.h" | |
10 | ||
11 | /* ----- SROT ------ */ | |
12 | #define SROT_HW_VER_OFF 0x0000 | |
13 | #define SROT_CTRL_OFF 0x0004 | |
14 | ||
15 | /* ----- TM ------ */ | |
16 | #define TM_INT_EN_OFF 0x0000 | |
17 | #define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF 0x0004 | |
18 | #define TM_Sn_STATUS_OFF 0x0044 | |
19 | #define TM_TRDY_OFF 0x0084 | |
20 | ||
21 | /* eeprom layout data for qcs404/405 (v1) */ | |
22 | #define BASE0_MASK 0x000007f8 | |
23 | #define BASE1_MASK 0x0007f800 | |
24 | #define BASE0_SHIFT 3 | |
25 | #define BASE1_SHIFT 11 | |
26 | ||
27 | #define S0_P1_MASK 0x0000003f | |
28 | #define S1_P1_MASK 0x0003f000 | |
29 | #define S2_P1_MASK 0x3f000000 | |
30 | #define S3_P1_MASK 0x000003f0 | |
31 | #define S4_P1_MASK 0x003f0000 | |
32 | #define S5_P1_MASK 0x0000003f | |
33 | #define S6_P1_MASK 0x0003f000 | |
34 | #define S7_P1_MASK 0x3f000000 | |
35 | #define S8_P1_MASK 0x000003f0 | |
36 | #define S9_P1_MASK 0x003f0000 | |
37 | ||
38 | #define S0_P2_MASK 0x00000fc0 | |
39 | #define S1_P2_MASK 0x00fc0000 | |
40 | #define S2_P2_MASK_1_0 0xc0000000 | |
41 | #define S2_P2_MASK_5_2 0x0000000f | |
42 | #define S3_P2_MASK 0x0000fc00 | |
43 | #define S4_P2_MASK 0x0fc00000 | |
44 | #define S5_P2_MASK 0x00000fc0 | |
45 | #define S6_P2_MASK 0x00fc0000 | |
46 | #define S7_P2_MASK_1_0 0xc0000000 | |
47 | #define S7_P2_MASK_5_2 0x0000000f | |
48 | #define S8_P2_MASK 0x0000fc00 | |
49 | #define S9_P2_MASK 0x0fc00000 | |
50 | ||
51 | #define S0_P1_SHIFT 0 | |
52 | #define S0_P2_SHIFT 6 | |
53 | #define S1_P1_SHIFT 12 | |
54 | #define S1_P2_SHIFT 18 | |
55 | #define S2_P1_SHIFT 24 | |
56 | #define S2_P2_SHIFT_1_0 30 | |
57 | ||
58 | #define S2_P2_SHIFT_5_2 0 | |
59 | #define S3_P1_SHIFT 4 | |
60 | #define S3_P2_SHIFT 10 | |
61 | #define S4_P1_SHIFT 16 | |
62 | #define S4_P2_SHIFT 22 | |
63 | ||
64 | #define S5_P1_SHIFT 0 | |
65 | #define S5_P2_SHIFT 6 | |
66 | #define S6_P1_SHIFT 12 | |
67 | #define S6_P2_SHIFT 18 | |
68 | #define S7_P1_SHIFT 24 | |
69 | #define S7_P2_SHIFT_1_0 30 | |
70 | ||
71 | #define S7_P2_SHIFT_5_2 0 | |
72 | #define S8_P1_SHIFT 4 | |
73 | #define S8_P2_SHIFT 10 | |
74 | #define S9_P1_SHIFT 16 | |
75 | #define S9_P2_SHIFT 22 | |
76 | ||
77 | #define CAL_SEL_MASK 7 | |
78 | #define CAL_SEL_SHIFT 0 | |
79 | ||
80 | static int calibrate_v1(struct tsens_priv *priv) | |
81 | { | |
82 | u32 base0 = 0, base1 = 0; | |
83 | u32 p1[10], p2[10]; | |
84 | u32 mode = 0, lsb = 0, msb = 0; | |
85 | u32 *qfprom_cdata; | |
86 | int i; | |
87 | ||
88 | qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib"); | |
89 | if (IS_ERR(qfprom_cdata)) | |
90 | return PTR_ERR(qfprom_cdata); | |
91 | ||
92 | mode = (qfprom_cdata[4] & CAL_SEL_MASK) >> CAL_SEL_SHIFT; | |
93 | dev_dbg(priv->dev, "calibration mode is %d\n", mode); | |
94 | ||
95 | switch (mode) { | |
96 | case TWO_PT_CALIB: | |
97 | base1 = (qfprom_cdata[4] & BASE1_MASK) >> BASE1_SHIFT; | |
98 | p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT; | |
99 | p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT; | |
100 | /* This value is split over two registers, 2 bits and 4 bits */ | |
101 | lsb = (qfprom_cdata[0] & S2_P2_MASK_1_0) >> S2_P2_SHIFT_1_0; | |
102 | msb = (qfprom_cdata[1] & S2_P2_MASK_5_2) >> S2_P2_SHIFT_5_2; | |
103 | p2[2] = msb << 2 | lsb; | |
104 | p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT; | |
105 | p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT; | |
106 | p2[5] = (qfprom_cdata[2] & S5_P2_MASK) >> S5_P2_SHIFT; | |
107 | p2[6] = (qfprom_cdata[2] & S6_P2_MASK) >> S6_P2_SHIFT; | |
108 | /* This value is split over two registers, 2 bits and 4 bits */ | |
109 | lsb = (qfprom_cdata[2] & S7_P2_MASK_1_0) >> S7_P2_SHIFT_1_0; | |
110 | msb = (qfprom_cdata[3] & S7_P2_MASK_5_2) >> S7_P2_SHIFT_5_2; | |
111 | p2[7] = msb << 2 | lsb; | |
112 | p2[8] = (qfprom_cdata[3] & S8_P2_MASK) >> S8_P2_SHIFT; | |
113 | p2[9] = (qfprom_cdata[3] & S9_P2_MASK) >> S9_P2_SHIFT; | |
114 | for (i = 0; i < priv->num_sensors; i++) | |
115 | p2[i] = ((base1 + p2[i]) << 2); | |
116 | /* Fall through */ | |
117 | case ONE_PT_CALIB2: | |
118 | base0 = (qfprom_cdata[4] & BASE0_MASK) >> BASE0_SHIFT; | |
119 | p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT; | |
120 | p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT; | |
121 | p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT; | |
122 | p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT; | |
123 | p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT; | |
124 | p1[5] = (qfprom_cdata[2] & S5_P1_MASK) >> S5_P1_SHIFT; | |
125 | p1[6] = (qfprom_cdata[2] & S6_P1_MASK) >> S6_P1_SHIFT; | |
126 | p1[7] = (qfprom_cdata[2] & S7_P1_MASK) >> S7_P1_SHIFT; | |
127 | p1[8] = (qfprom_cdata[3] & S8_P1_MASK) >> S8_P1_SHIFT; | |
128 | p1[9] = (qfprom_cdata[3] & S9_P1_MASK) >> S9_P1_SHIFT; | |
129 | for (i = 0; i < priv->num_sensors; i++) | |
130 | p1[i] = (((base0) + p1[i]) << 2); | |
131 | break; | |
132 | default: | |
133 | for (i = 0; i < priv->num_sensors; i++) { | |
134 | p1[i] = 500; | |
135 | p2[i] = 780; | |
136 | } | |
137 | break; | |
138 | } | |
139 | ||
140 | compute_intercept_slope(priv, p1, p2, mode); | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | /* v1.x: qcs404,405 */ | |
146 | ||
147 | static const struct tsens_features tsens_v1_feat = { | |
148 | .ver_major = VER_1_X, | |
149 | .crit_int = 0, | |
150 | .adc = 1, | |
151 | .srot_split = 1, | |
152 | .max_sensors = 11, | |
153 | }; | |
154 | ||
155 | static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = { | |
156 | /* ----- SROT ------ */ | |
157 | /* VERSION */ | |
158 | [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31), | |
159 | [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27), | |
160 | [VER_STEP] = REG_FIELD(SROT_HW_VER_OFF, 0, 15), | |
161 | /* CTRL_OFFSET */ | |
162 | [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), | |
163 | [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), | |
164 | [SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 13), | |
165 | ||
166 | /* ----- TM ------ */ | |
167 | /* INTERRUPT ENABLE */ | |
168 | [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0), | |
169 | ||
170 | /* Sn_STATUS */ | |
171 | REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 9), | |
172 | REG_FIELD_FOR_EACH_SENSOR11(VALID, TM_Sn_STATUS_OFF, 14, 14), | |
173 | REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS, TM_Sn_STATUS_OFF, 10, 10), | |
174 | REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11), | |
175 | REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12), | |
176 | /* No CRITICAL field on v1.x */ | |
177 | REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS, TM_Sn_STATUS_OFF, 13, 13), | |
178 | ||
179 | /* TRDY: 1=ready, 0=in progress */ | |
180 | [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0), | |
181 | }; | |
182 | ||
183 | static const struct tsens_ops ops_generic_v1 = { | |
184 | .init = init_common, | |
185 | .calibrate = calibrate_v1, | |
186 | .get_temp = get_temp_tsens_valid, | |
187 | }; | |
188 | ||
189 | const struct tsens_plat_data data_tsens_v1 = { | |
190 | .ops = &ops_generic_v1, | |
191 | .feat = &tsens_v1_feat, | |
192 | .fields = tsens_v1_regfields, | |
193 | }; |