65
65
66
66
#define TSC_MAX_NUM 5
67
67
68
- /* Structure for thermal temperature calculation */
69
- struct equation_coefs {
70
- int a1 ;
71
- int b1 ;
72
- int a2 ;
73
- int b2 ;
74
- };
75
-
76
68
struct rcar_gen3_thermal_priv ;
77
69
78
70
struct rcar_thermal_info {
79
- int ths_tj_1 ;
71
+ int scale ;
72
+ int adj_below ;
73
+ int adj_above ;
80
74
void (* read_fuses )(struct rcar_gen3_thermal_priv * priv );
81
75
};
82
76
77
+ struct equation_set_coef {
78
+ int a ;
79
+ int b ;
80
+ };
81
+
83
82
struct rcar_gen3_thermal_tsc {
84
83
struct rcar_gen3_thermal_priv * priv ;
85
84
void __iomem * base ;
86
85
struct thermal_zone_device * zone ;
87
- struct equation_coefs coef ;
86
+ /* Different coefficients are used depending on a threshold. */
87
+ struct {
88
+ struct equation_set_coef below ;
89
+ struct equation_set_coef above ;
90
+ } coef ;
88
91
int thcode [3 ];
89
92
};
90
93
@@ -112,90 +115,75 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
112
115
/*
113
116
* Linear approximation for temperature
114
117
*
115
- * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
118
+ * [temp] = ((thadj - [reg]) * a) / b + adj
119
+ * [reg] = thadj - ([temp] - adj) * b / a
116
120
*
117
121
* The constants a and b are calculated using two triplets of int values PTAT
118
122
* and THCODE. PTAT and THCODE can either be read from hardware or use hard
119
- * coded values from driver. The formula to calculate a and b are taken from
120
- * BSP and sparsely documented and understood.
123
+ * coded values from the driver. The formula to calculate a and b are taken from
124
+ * the datasheet. Different calculations are needed for a and b depending on
125
+ * if the input variables ([temp] or [reg]) are above or below a threshold. The
126
+ * threshold is also calculated from PTAT and THCODE using formulas from the
127
+ * datasheet.
128
+ *
129
+ * The constant thadj is one of the THCODE values, which one to use depends on
130
+ * the threshold and input value.
121
131
*
122
- * Examining the linear formula and the formula used to calculate constants a
123
- * and b while knowing that the span for PTAT and THCODE values are between
124
- * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
125
- * Integer also needs to be signed so that leaves 7 bits for binary
126
- * fixed point scaling.
132
+ * The constants adj is taken verbatim from the datasheet. Two values exists,
133
+ * which one to use depends on the input value and the calculated threshold.
134
+ * Furthermore different SoC models supported by the driver have different sets
135
+ * of values. The values for each model are stored in the device match data.
127
136
*/
128
137
129
- #define FIXPT_SHIFT 7
130
- #define FIXPT_INT (_x ) ((_x) << FIXPT_SHIFT)
131
- #define INT_FIXPT (_x ) ((_x) >> FIXPT_SHIFT)
132
- #define FIXPT_DIV (_a , _b ) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
133
- #define FIXPT_TO_MCELSIUS (_x ) ((_x) * 1000 >> FIXPT_SHIFT)
134
-
135
- #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
136
-
137
- /* no idea where these constants come from */
138
- #define TJ_3 -41
139
-
140
138
static void rcar_gen3_thermal_shared_coefs (struct rcar_gen3_thermal_priv * priv )
141
139
{
142
- int tj1 = priv -> info -> ths_tj_1 ;
143
-
144
- priv -> tj_t = ( FIXPT_INT (( priv -> ptat [1 ] - priv -> ptat [2 ]) * ( tj1 - TJ_3 ) )
145
- / ( priv -> ptat [ 0 ] - priv -> ptat [ 2 ])) + FIXPT_INT ( TJ_3 ) ;
140
+ priv -> tj_t =
141
+ DIV_ROUND_CLOSEST (( priv -> ptat [ 1 ] - priv -> ptat [ 2 ]) * priv -> info -> scale ,
142
+ priv -> ptat [0 ] - priv -> ptat [2 ])
143
+ + priv -> info -> adj_below ;
146
144
}
147
-
148
145
static void rcar_gen3_thermal_tsc_coefs (struct rcar_gen3_thermal_priv * priv ,
149
146
struct rcar_gen3_thermal_tsc * tsc )
150
147
{
151
- int tj1 = priv -> info -> ths_tj_1 ;
152
-
153
- /* TODO: Find documentation and document constant calculation formula */
154
-
155
- /*
156
- * Division is not scaled in BSP and if scaled it might overflow
157
- * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
158
- */
159
- tsc -> coef .a1 = FIXPT_DIV (FIXPT_INT (tsc -> thcode [1 ] - tsc -> thcode [2 ]),
160
- priv -> tj_t - FIXPT_INT (TJ_3 ));
161
- tsc -> coef .b1 = FIXPT_INT (tsc -> thcode [2 ]) - tsc -> coef .a1 * TJ_3 ;
162
-
163
- tsc -> coef .a2 = FIXPT_DIV (FIXPT_INT (tsc -> thcode [1 ] - tsc -> thcode [0 ]),
164
- priv -> tj_t - FIXPT_INT (tj1 ));
165
- tsc -> coef .b2 = FIXPT_INT (tsc -> thcode [0 ]) - tsc -> coef .a2 * tj1 ;
166
- }
167
-
168
- static int rcar_gen3_thermal_round (int temp )
169
- {
170
- int result , round_offs ;
148
+ tsc -> coef .below .a = priv -> info -> scale * (priv -> ptat [2 ] - priv -> ptat [1 ]);
149
+ tsc -> coef .above .a = priv -> info -> scale * (priv -> ptat [0 ] - priv -> ptat [1 ]);
171
150
172
- round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
173
- - RCAR3_THERMAL_GRAN / 2 ;
174
- result = (temp + round_offs ) / RCAR3_THERMAL_GRAN ;
175
- return result * RCAR3_THERMAL_GRAN ;
151
+ tsc -> coef .below .b = (priv -> ptat [2 ] - priv -> ptat [0 ]) * (tsc -> thcode [2 ] - tsc -> thcode [1 ]);
152
+ tsc -> coef .above .b = (priv -> ptat [0 ] - priv -> ptat [2 ]) * (tsc -> thcode [1 ] - tsc -> thcode [0 ]);
176
153
}
177
154
178
155
static int rcar_gen3_thermal_get_temp (struct thermal_zone_device * tz , int * temp )
179
156
{
180
157
struct rcar_gen3_thermal_tsc * tsc = thermal_zone_device_priv (tz );
181
- int mcelsius , val ;
182
- int reg ;
158
+ struct rcar_gen3_thermal_priv * priv = tsc -> priv ;
159
+ const struct equation_set_coef * coef ;
160
+ int adj , decicelsius , reg , thcode ;
183
161
184
162
/* Read register and convert to mili Celsius */
185
163
reg = rcar_gen3_thermal_read (tsc , REG_GEN3_TEMP ) & CTEMP_MASK ;
186
164
187
- if (reg <= tsc -> thcode [1 ])
188
- val = FIXPT_DIV (FIXPT_INT (reg ) - tsc -> coef .b1 ,
189
- tsc -> coef .a1 );
190
- else
191
- val = FIXPT_DIV (FIXPT_INT (reg ) - tsc -> coef .b2 ,
192
- tsc -> coef .a2 );
193
- mcelsius = FIXPT_TO_MCELSIUS (val );
165
+ if (reg < tsc -> thcode [1 ]) {
166
+ adj = priv -> info -> adj_below ;
167
+ coef = & tsc -> coef .below ;
168
+ thcode = tsc -> thcode [2 ];
169
+ } else {
170
+ adj = priv -> info -> adj_above ;
171
+ coef = & tsc -> coef .above ;
172
+ thcode = tsc -> thcode [0 ];
173
+ }
174
+
175
+ /*
176
+ * The dividend can't be grown as it might overflow, instead shorten the
177
+ * divisor to convert to decidegree Celsius. If we convert after the
178
+ * division precision is lost as we will scale up from whole degrees
179
+ * Celsius.
180
+ */
181
+ decicelsius = DIV_ROUND_CLOSEST (coef -> a * (thcode - reg ), coef -> b / 10 );
194
182
195
183
/* Guaranteed operating range is -40C to 125C. */
196
184
197
- /* Round value to device granularity setting */
198
- * temp = rcar_gen3_thermal_round ( mcelsius ) ;
185
+ /* Reporting is done in millidegree Celsius */
186
+ * temp = decicelsius * 100 + adj * 1000 ;
199
187
200
188
return 0 ;
201
189
}
@@ -204,15 +192,21 @@ static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
204
192
int mcelsius )
205
193
{
206
194
struct rcar_gen3_thermal_priv * priv = tsc -> priv ;
207
- int celsius , val ;
195
+ const struct equation_set_coef * coef ;
196
+ int adj , celsius , thcode ;
208
197
209
198
celsius = DIV_ROUND_CLOSEST (mcelsius , 1000 );
210
- if (celsius <= INT_FIXPT (priv -> tj_t ))
211
- val = celsius * tsc -> coef .a1 + tsc -> coef .b1 ;
212
- else
213
- val = celsius * tsc -> coef .a2 + tsc -> coef .b2 ;
199
+ if (celsius < priv -> tj_t ) {
200
+ coef = & tsc -> coef .below ;
201
+ adj = priv -> info -> adj_below ;
202
+ thcode = tsc -> thcode [2 ];
203
+ } else {
204
+ coef = & tsc -> coef .above ;
205
+ adj = priv -> info -> adj_above ;
206
+ thcode = tsc -> thcode [0 ];
207
+ }
214
208
215
- return INT_FIXPT ( val );
209
+ return thcode - DIV_ROUND_CLOSEST (( celsius - adj ) * coef -> b , coef -> a );
216
210
}
217
211
218
212
static int rcar_gen3_thermal_set_trips (struct thermal_zone_device * tz , int low , int high )
@@ -377,17 +371,23 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv,
377
371
}
378
372
379
373
static const struct rcar_thermal_info rcar_m3w_thermal_info = {
380
- .ths_tj_1 = 116 ,
374
+ .scale = 157 ,
375
+ .adj_below = -41 ,
376
+ .adj_above = 116 ,
381
377
.read_fuses = rcar_gen3_thermal_read_fuses_gen3 ,
382
378
};
383
379
384
380
static const struct rcar_thermal_info rcar_gen3_thermal_info = {
385
- .ths_tj_1 = 126 ,
381
+ .scale = 167 ,
382
+ .adj_below = -41 ,
383
+ .adj_above = 126 ,
386
384
.read_fuses = rcar_gen3_thermal_read_fuses_gen3 ,
387
385
};
388
386
389
387
static const struct rcar_thermal_info rcar_gen4_thermal_info = {
390
- .ths_tj_1 = 126 ,
388
+ .scale = 167 ,
389
+ .adj_below = -41 ,
390
+ .adj_above = 126 ,
391
391
.read_fuses = rcar_gen3_thermal_read_fuses_gen4 ,
392
392
};
393
393
0 commit comments