Skip to content

Commit 47cf09e

Browse files
Niklas Söderlunddlezcano
authored andcommitted
thermal/drivers/rcar_gen3_thermal: Add support for hardware trip points
All supported hardware except V3U is capable of generating interrupts to the CPU when the temperature go below or above a set value. Use this to implement support for the set_trip() feature of the thermal core on supported hardware. The V3U have its interrupts routed to the ECM module and therefore can not be used to implement set_trip() as the driver can't be made aware of when the interrupt triggers. Each TSC is capable of tracking up-to three different temperatures while only two are needed to implement the tracking of the thermal window. Signed-off-by: Niklas Söderlund <[email protected]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent a414a08 commit 47cf09e

File tree

1 file changed

+99
-4
lines changed

1 file changed

+99
-4
lines changed

drivers/thermal/rcar_gen3_thermal.c

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,64 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
190190
return 0;
191191
}
192192

193-
static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
193+
static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
194+
int mcelsius)
195+
{
196+
int celsius, val;
197+
198+
celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
199+
if (celsius <= INT_FIXPT(tsc->tj_t))
200+
val = celsius * tsc->coef.a1 + tsc->coef.b1;
201+
else
202+
val = celsius * tsc->coef.a2 + tsc->coef.b2;
203+
204+
return INT_FIXPT(val);
205+
}
206+
207+
static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
208+
{
209+
struct rcar_gen3_thermal_tsc *tsc = devdata;
210+
u32 irqmsk = 0;
211+
212+
if (low != -INT_MAX) {
213+
irqmsk |= IRQ_TEMPD1;
214+
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
215+
rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
216+
}
217+
218+
if (high != INT_MAX) {
219+
irqmsk |= IRQ_TEMP2;
220+
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
221+
rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
222+
}
223+
224+
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, irqmsk);
225+
226+
return 0;
227+
}
228+
229+
static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
194230
.get_temp = rcar_gen3_thermal_get_temp,
231+
.set_trips = rcar_gen3_thermal_set_trips,
195232
};
196233

234+
static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
235+
{
236+
struct rcar_gen3_thermal_priv *priv = data;
237+
unsigned int i;
238+
u32 status;
239+
240+
for (i = 0; i < priv->num_tscs; i++) {
241+
status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
242+
rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
243+
if (status)
244+
thermal_zone_device_update(priv->tscs[i]->zone,
245+
THERMAL_EVENT_UNSPECIFIED);
246+
}
247+
248+
return IRQ_HANDLED;
249+
}
250+
197251
static const struct soc_device_attribute r8a7795es1[] = {
198252
{ .soc_id = "r8a7795", .revision = "ES1.*" },
199253
{ /* sentinel */ }
@@ -210,6 +264,9 @@ static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)
210264

211265
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
212266
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
267+
if (tsc->zone->ops->set_trips)
268+
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN,
269+
IRQ_TEMPD1 | IRQ_TEMP2);
213270

214271
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
215272
CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
@@ -235,6 +292,9 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
235292

236293
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
237294
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
295+
if (tsc->zone->ops->set_trips)
296+
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN,
297+
IRQ_TEMPD1 | IRQ_TEMP2);
238298

239299
reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
240300
reg_val |= THCTR_THSST;
@@ -303,6 +363,34 @@ static void rcar_gen3_hwmon_action(void *data)
303363
thermal_remove_hwmon_sysfs(zone);
304364
}
305365

366+
static int rcar_gen3_thermal_request_irqs(struct rcar_gen3_thermal_priv *priv,
367+
struct platform_device *pdev)
368+
{
369+
struct device *dev = &pdev->dev;
370+
unsigned int i;
371+
char *irqname;
372+
int ret, irq;
373+
374+
for (i = 0; i < 2; i++) {
375+
irq = platform_get_irq_optional(pdev, i);
376+
if (irq < 0)
377+
return irq;
378+
379+
irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
380+
dev_name(dev), i);
381+
if (!irqname)
382+
return -ENOMEM;
383+
384+
ret = devm_request_threaded_irq(dev, irq, NULL,
385+
rcar_gen3_thermal_irq,
386+
IRQF_ONESHOT, irqname, priv);
387+
if (ret)
388+
return ret;
389+
}
390+
391+
return 0;
392+
}
393+
306394
static int rcar_gen3_thermal_probe(struct platform_device *pdev)
307395
{
308396
struct rcar_gen3_thermal_priv *priv;
@@ -326,6 +414,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
326414

327415
platform_set_drvdata(pdev, priv);
328416

417+
if (rcar_gen3_thermal_request_irqs(priv, pdev))
418+
rcar_gen3_tz_of_ops.set_trips = NULL;
419+
329420
pm_runtime_enable(dev);
330421
pm_runtime_get_sync(dev);
331422

@@ -351,9 +442,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
351442

352443
priv->tscs[i] = tsc;
353444

354-
priv->thermal_init(tsc);
355-
rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
356-
357445
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
358446
&rcar_gen3_tz_of_ops);
359447
if (IS_ERR(zone)) {
@@ -363,6 +451,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
363451
}
364452
tsc->zone = zone;
365453

454+
priv->thermal_init(tsc);
455+
rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
456+
366457
tsc->zone->tzp->no_hwmon = false;
367458
ret = thermal_add_hwmon_sysfs(tsc->zone);
368459
if (ret)
@@ -401,8 +492,12 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
401492

402493
for (i = 0; i < priv->num_tscs; i++) {
403494
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
495+
struct thermal_zone_device *zone = tsc->zone;
404496

405497
priv->thermal_init(tsc);
498+
if (zone->ops->set_trips)
499+
rcar_gen3_thermal_set_trips(tsc, zone->prev_low_trip,
500+
zone->prev_high_trip);
406501
}
407502

408503
return 0;

0 commit comments

Comments
 (0)