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