Skip to content

Commit 63d23fb

Browse files
Niklas Söderlunddlezcano
authored andcommitted
thermal/drivers/rcar_gen3: Update temperature approximation calculation
The initial driver used a formula to approximate the temperature and register values reversed engineered from an out-of-tree BSP driver. This was needed as the datasheet at the time did not contain any information on how to do this. Later Gen3 (Rev 2.30) and Gen4 (all) now contains this information. Update the approximation formula to use the datasheet's information instead of the reversed-engineered one. On an idle M3-N without fused calibration values for PTAT and THCODE the old formula reports, zone0: 52000 zone1: 53000 zone2: 52500 While the new formula under the same circumstances reports, zone0: 52500 zone1: 54000 zone2: 54000 Signed-off-by: Niklas Söderlund <[email protected]> Reviewed-by: Geert Uytterhoeven <[email protected]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 566e0ea commit 63d23fb

File tree

1 file changed

+78
-78
lines changed

1 file changed

+78
-78
lines changed

drivers/thermal/rcar_gen3_thermal.c

Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,29 @@
6565

6666
#define TSC_MAX_NUM 5
6767

68-
/* Structure for thermal temperature calculation */
69-
struct equation_coefs {
70-
int a1;
71-
int b1;
72-
int a2;
73-
int b2;
74-
};
75-
7668
struct rcar_gen3_thermal_priv;
7769

7870
struct rcar_thermal_info {
79-
int ths_tj_1;
71+
int scale;
72+
int adj_below;
73+
int adj_above;
8074
void (*read_fuses)(struct rcar_gen3_thermal_priv *priv);
8175
};
8276

77+
struct equation_set_coef {
78+
int a;
79+
int b;
80+
};
81+
8382
struct rcar_gen3_thermal_tsc {
8483
struct rcar_gen3_thermal_priv *priv;
8584
void __iomem *base;
8685
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;
8891
int thcode[3];
8992
};
9093

@@ -112,90 +115,75 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
112115
/*
113116
* Linear approximation for temperature
114117
*
115-
* [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
118+
* [temp] = ((thadj - [reg]) * a) / b + adj
119+
* [reg] = thadj - ([temp] - adj) * b / a
116120
*
117121
* The constants a and b are calculated using two triplets of int values PTAT
118122
* 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.
121131
*
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.
127136
*/
128137

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-
140138
static void rcar_gen3_thermal_shared_coefs(struct rcar_gen3_thermal_priv *priv)
141139
{
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;
146144
}
147-
148145
static void rcar_gen3_thermal_tsc_coefs(struct rcar_gen3_thermal_priv *priv,
149146
struct rcar_gen3_thermal_tsc *tsc)
150147
{
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]);
171150

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]);
176153
}
177154

178155
static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
179156
{
180157
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;
183161

184162
/* Read register and convert to mili Celsius */
185163
reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
186164

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);
194182

195183
/* Guaranteed operating range is -40C to 125C. */
196184

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;
199187

200188
return 0;
201189
}
@@ -204,15 +192,21 @@ static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
204192
int mcelsius)
205193
{
206194
struct rcar_gen3_thermal_priv *priv = tsc->priv;
207-
int celsius, val;
195+
const struct equation_set_coef *coef;
196+
int adj, celsius, thcode;
208197

209198
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+
}
214208

215-
return INT_FIXPT(val);
209+
return thcode - DIV_ROUND_CLOSEST((celsius - adj) * coef->b, coef->a);
216210
}
217211

218212
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,
377371
}
378372

379373
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,
381377
.read_fuses = rcar_gen3_thermal_read_fuses_gen3,
382378
};
383379

384380
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,
386384
.read_fuses = rcar_gen3_thermal_read_fuses_gen3,
387385
};
388386

389387
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,
391391
.read_fuses = rcar_gen3_thermal_read_fuses_gen4,
392392
};
393393

0 commit comments

Comments
 (0)