.. | .. |
---|
18 | 18 | #include <linux/thermal.h> |
---|
19 | 19 | |
---|
20 | 20 | #include "thermal_core.h" |
---|
| 21 | +#include "thermal_hwmon.h" |
---|
21 | 22 | |
---|
22 | 23 | /* Register offsets */ |
---|
23 | 24 | #define REG_GEN3_IRQSTR 0x04 |
---|
.. | .. |
---|
61 | 62 | |
---|
62 | 63 | #define TSC_MAX_NUM 3 |
---|
63 | 64 | |
---|
| 65 | +/* default THCODE values if FUSEs are missing */ |
---|
| 66 | +static const int thcodes[TSC_MAX_NUM][3] = { |
---|
| 67 | + { 3397, 2800, 2221 }, |
---|
| 68 | + { 3393, 2795, 2216 }, |
---|
| 69 | + { 3389, 2805, 2237 }, |
---|
| 70 | +}; |
---|
| 71 | + |
---|
64 | 72 | /* Structure for thermal temperature calculation */ |
---|
65 | 73 | struct equation_coefs { |
---|
66 | 74 | int a1; |
---|
.. | .. |
---|
73 | 81 | void __iomem *base; |
---|
74 | 82 | struct thermal_zone_device *zone; |
---|
75 | 83 | struct equation_coefs coef; |
---|
76 | | - int low; |
---|
77 | | - int high; |
---|
| 84 | + int tj_t; |
---|
| 85 | + int id; /* thermal channel id */ |
---|
78 | 86 | }; |
---|
79 | 87 | |
---|
80 | 88 | struct rcar_gen3_thermal_priv { |
---|
.. | .. |
---|
121 | 129 | #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */ |
---|
122 | 130 | |
---|
123 | 131 | /* no idea where these constants come from */ |
---|
124 | | -#define TJ_1 116 |
---|
125 | 132 | #define TJ_3 -41 |
---|
126 | 133 | |
---|
127 | | -static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef, |
---|
128 | | - int *ptat, int *thcode) |
---|
| 134 | +static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc, |
---|
| 135 | + int *ptat, const int *thcode, |
---|
| 136 | + int ths_tj_1) |
---|
129 | 137 | { |
---|
130 | | - int tj_2; |
---|
131 | | - |
---|
132 | 138 | /* TODO: Find documentation and document constant calculation formula */ |
---|
133 | 139 | |
---|
134 | 140 | /* |
---|
135 | 141 | * Division is not scaled in BSP and if scaled it might overflow |
---|
136 | 142 | * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled |
---|
137 | 143 | */ |
---|
138 | | - tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 157) |
---|
139 | | - / (ptat[0] - ptat[2])) - FIXPT_INT(41); |
---|
| 144 | + tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3)) |
---|
| 145 | + / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3); |
---|
140 | 146 | |
---|
141 | | - coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), |
---|
142 | | - tj_2 - FIXPT_INT(TJ_3)); |
---|
143 | | - coef->b1 = FIXPT_INT(thcode[2]) - coef->a1 * TJ_3; |
---|
| 147 | + tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), |
---|
| 148 | + tsc->tj_t - FIXPT_INT(TJ_3)); |
---|
| 149 | + tsc->coef.b1 = FIXPT_INT(thcode[2]) - tsc->coef.a1 * TJ_3; |
---|
144 | 150 | |
---|
145 | | - coef->a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]), |
---|
146 | | - tj_2 - FIXPT_INT(TJ_1)); |
---|
147 | | - coef->b2 = FIXPT_INT(thcode[0]) - coef->a2 * TJ_1; |
---|
| 151 | + tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]), |
---|
| 152 | + tsc->tj_t - FIXPT_INT(ths_tj_1)); |
---|
| 153 | + tsc->coef.b2 = FIXPT_INT(thcode[0]) - tsc->coef.a2 * ths_tj_1; |
---|
148 | 154 | } |
---|
149 | 155 | |
---|
150 | 156 | static int rcar_gen3_thermal_round(int temp) |
---|
.. | .. |
---|
160 | 166 | static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) |
---|
161 | 167 | { |
---|
162 | 168 | struct rcar_gen3_thermal_tsc *tsc = devdata; |
---|
163 | | - int mcelsius, val1, val2; |
---|
164 | | - u32 reg; |
---|
| 169 | + int mcelsius, val; |
---|
| 170 | + int reg; |
---|
165 | 171 | |
---|
166 | 172 | /* Read register and convert to mili Celsius */ |
---|
167 | 173 | reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; |
---|
168 | 174 | |
---|
169 | | - val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1); |
---|
170 | | - val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2); |
---|
171 | | - mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2); |
---|
| 175 | + if (reg <= thcodes[tsc->id][1]) |
---|
| 176 | + val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, |
---|
| 177 | + tsc->coef.a1); |
---|
| 178 | + else |
---|
| 179 | + val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, |
---|
| 180 | + tsc->coef.a2); |
---|
| 181 | + mcelsius = FIXPT_TO_MCELSIUS(val); |
---|
172 | 182 | |
---|
173 | | - /* Make sure we are inside specifications */ |
---|
174 | | - if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125))) |
---|
175 | | - return -EIO; |
---|
| 183 | + /* Guaranteed operating range is -40C to 125C. */ |
---|
176 | 184 | |
---|
177 | 185 | /* Round value to device granularity setting */ |
---|
178 | 186 | *temp = rcar_gen3_thermal_round(mcelsius); |
---|
.. | .. |
---|
183 | 191 | static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc, |
---|
184 | 192 | int mcelsius) |
---|
185 | 193 | { |
---|
186 | | - int celsius, val1, val2; |
---|
| 194 | + int celsius, val; |
---|
187 | 195 | |
---|
188 | 196 | celsius = DIV_ROUND_CLOSEST(mcelsius, 1000); |
---|
189 | | - val1 = celsius * tsc->coef.a1 + tsc->coef.b1; |
---|
190 | | - val2 = celsius * tsc->coef.a2 + tsc->coef.b2; |
---|
| 197 | + if (celsius <= INT_FIXPT(tsc->tj_t)) |
---|
| 198 | + val = celsius * tsc->coef.a1 + tsc->coef.b1; |
---|
| 199 | + else |
---|
| 200 | + val = celsius * tsc->coef.a2 + tsc->coef.b2; |
---|
191 | 201 | |
---|
192 | | - return INT_FIXPT((val1 + val2) / 2); |
---|
| 202 | + return INT_FIXPT(val); |
---|
193 | 203 | } |
---|
194 | 204 | |
---|
195 | | -static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high) |
---|
| 205 | +static int rcar_gen3_thermal_update_range(struct rcar_gen3_thermal_tsc *tsc) |
---|
196 | 206 | { |
---|
197 | | - struct rcar_gen3_thermal_tsc *tsc = devdata; |
---|
| 207 | + int temperature, low, high; |
---|
198 | 208 | |
---|
199 | | - low = clamp_val(low, -40000, 120000); |
---|
200 | | - high = clamp_val(high, -40000, 120000); |
---|
| 209 | + rcar_gen3_thermal_get_temp(tsc, &temperature); |
---|
| 210 | + |
---|
| 211 | + low = temperature - MCELSIUS(1); |
---|
| 212 | + high = temperature + MCELSIUS(1); |
---|
201 | 213 | |
---|
202 | 214 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1, |
---|
203 | 215 | rcar_gen3_thermal_mcelsius_to_temp(tsc, low)); |
---|
.. | .. |
---|
205 | 217 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2, |
---|
206 | 218 | rcar_gen3_thermal_mcelsius_to_temp(tsc, high)); |
---|
207 | 219 | |
---|
208 | | - tsc->low = low; |
---|
209 | | - tsc->high = high; |
---|
210 | | - |
---|
211 | 220 | return 0; |
---|
212 | 221 | } |
---|
213 | 222 | |
---|
214 | 223 | static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = { |
---|
215 | 224 | .get_temp = rcar_gen3_thermal_get_temp, |
---|
216 | | - .set_trips = rcar_gen3_thermal_set_trips, |
---|
217 | 225 | }; |
---|
218 | 226 | |
---|
219 | 227 | static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on) |
---|
.. | .. |
---|
234 | 242 | for (i = 0; i < priv->num_tscs; i++) { |
---|
235 | 243 | status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR); |
---|
236 | 244 | rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0); |
---|
237 | | - if (status) |
---|
| 245 | + if (status) { |
---|
| 246 | + rcar_gen3_thermal_update_range(priv->tscs[i]); |
---|
238 | 247 | thermal_zone_device_update(priv->tscs[i]->zone, |
---|
239 | 248 | THERMAL_EVENT_UNSPECIFIED); |
---|
| 249 | + } |
---|
240 | 250 | } |
---|
241 | 251 | |
---|
242 | 252 | return IRQ_HANDLED; |
---|
.. | .. |
---|
282 | 292 | |
---|
283 | 293 | usleep_range(1000, 2000); |
---|
284 | 294 | |
---|
285 | | - rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); |
---|
| 295 | + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0); |
---|
286 | 296 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); |
---|
287 | 297 | rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2); |
---|
288 | 298 | |
---|
.. | .. |
---|
293 | 303 | usleep_range(1000, 2000); |
---|
294 | 304 | } |
---|
295 | 305 | |
---|
| 306 | +static const int rcar_gen3_ths_tj_1 = 126; |
---|
| 307 | +static const int rcar_gen3_ths_tj_1_m3_w = 116; |
---|
296 | 308 | static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { |
---|
297 | | - { .compatible = "renesas,r8a7795-thermal", }, |
---|
298 | | - { .compatible = "renesas,r8a7796-thermal", }, |
---|
299 | | - { .compatible = "renesas,r8a77965-thermal", }, |
---|
| 309 | + { |
---|
| 310 | + .compatible = "renesas,r8a774a1-thermal", |
---|
| 311 | + .data = &rcar_gen3_ths_tj_1_m3_w, |
---|
| 312 | + }, |
---|
| 313 | + { |
---|
| 314 | + .compatible = "renesas,r8a774b1-thermal", |
---|
| 315 | + .data = &rcar_gen3_ths_tj_1, |
---|
| 316 | + }, |
---|
| 317 | + { |
---|
| 318 | + .compatible = "renesas,r8a774e1-thermal", |
---|
| 319 | + .data = &rcar_gen3_ths_tj_1, |
---|
| 320 | + }, |
---|
| 321 | + { |
---|
| 322 | + .compatible = "renesas,r8a7795-thermal", |
---|
| 323 | + .data = &rcar_gen3_ths_tj_1, |
---|
| 324 | + }, |
---|
| 325 | + { |
---|
| 326 | + .compatible = "renesas,r8a7796-thermal", |
---|
| 327 | + .data = &rcar_gen3_ths_tj_1_m3_w, |
---|
| 328 | + }, |
---|
| 329 | + { |
---|
| 330 | + .compatible = "renesas,r8a77961-thermal", |
---|
| 331 | + .data = &rcar_gen3_ths_tj_1_m3_w, |
---|
| 332 | + }, |
---|
| 333 | + { |
---|
| 334 | + .compatible = "renesas,r8a77965-thermal", |
---|
| 335 | + .data = &rcar_gen3_ths_tj_1, |
---|
| 336 | + }, |
---|
| 337 | + { |
---|
| 338 | + .compatible = "renesas,r8a77980-thermal", |
---|
| 339 | + .data = &rcar_gen3_ths_tj_1, |
---|
| 340 | + }, |
---|
300 | 341 | {}, |
---|
301 | 342 | }; |
---|
302 | 343 | MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); |
---|
.. | .. |
---|
314 | 355 | return 0; |
---|
315 | 356 | } |
---|
316 | 357 | |
---|
| 358 | +static void rcar_gen3_hwmon_action(void *data) |
---|
| 359 | +{ |
---|
| 360 | + struct thermal_zone_device *zone = data; |
---|
| 361 | + |
---|
| 362 | + thermal_remove_hwmon_sysfs(zone); |
---|
| 363 | +} |
---|
| 364 | + |
---|
317 | 365 | static int rcar_gen3_thermal_probe(struct platform_device *pdev) |
---|
318 | 366 | { |
---|
319 | 367 | struct rcar_gen3_thermal_priv *priv; |
---|
320 | 368 | struct device *dev = &pdev->dev; |
---|
| 369 | + const int *ths_tj_1 = of_device_get_match_data(dev); |
---|
321 | 370 | struct resource *res; |
---|
322 | 371 | struct thermal_zone_device *zone; |
---|
323 | 372 | int ret, irq, i; |
---|
.. | .. |
---|
326 | 375 | /* default values if FUSEs are missing */ |
---|
327 | 376 | /* TODO: Read values from hardware on supported platforms */ |
---|
328 | 377 | int ptat[3] = { 2631, 1509, 435 }; |
---|
329 | | - int thcode[TSC_MAX_NUM][3] = { |
---|
330 | | - { 3397, 2800, 2221 }, |
---|
331 | | - { 3393, 2795, 2216 }, |
---|
332 | | - { 3389, 2805, 2237 }, |
---|
333 | | - }; |
---|
334 | 378 | |
---|
335 | 379 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
---|
336 | 380 | if (!priv) |
---|
.. | .. |
---|
385 | 429 | ret = PTR_ERR(tsc->base); |
---|
386 | 430 | goto error_unregister; |
---|
387 | 431 | } |
---|
| 432 | + tsc->id = i; |
---|
388 | 433 | |
---|
389 | 434 | priv->tscs[i] = tsc; |
---|
390 | 435 | |
---|
391 | 436 | priv->thermal_init(tsc); |
---|
392 | | - rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]); |
---|
| 437 | + rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); |
---|
393 | 438 | |
---|
394 | 439 | zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, |
---|
395 | 440 | &rcar_gen3_tz_of_ops); |
---|
.. | .. |
---|
400 | 445 | } |
---|
401 | 446 | tsc->zone = zone; |
---|
402 | 447 | |
---|
| 448 | + tsc->zone->tzp->no_hwmon = false; |
---|
| 449 | + ret = thermal_add_hwmon_sysfs(tsc->zone); |
---|
| 450 | + if (ret) |
---|
| 451 | + goto error_unregister; |
---|
| 452 | + |
---|
| 453 | + ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone); |
---|
| 454 | + if (ret) |
---|
| 455 | + goto error_unregister; |
---|
| 456 | + |
---|
403 | 457 | ret = of_thermal_get_ntrips(tsc->zone); |
---|
404 | 458 | if (ret < 0) |
---|
405 | 459 | goto error_unregister; |
---|
| 460 | + |
---|
| 461 | + rcar_gen3_thermal_update_range(tsc); |
---|
406 | 462 | |
---|
407 | 463 | dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret); |
---|
408 | 464 | } |
---|
.. | .. |
---|
442 | 498 | struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; |
---|
443 | 499 | |
---|
444 | 500 | priv->thermal_init(tsc); |
---|
445 | | - rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high); |
---|
| 501 | + rcar_gen3_thermal_update_range(tsc); |
---|
446 | 502 | } |
---|
447 | 503 | |
---|
448 | 504 | rcar_thermal_irq_set(priv, true); |
---|