diff options
Diffstat (limited to 'drivers/thermal/rcar_gen3_thermal.c')
-rw-r--r-- | drivers/thermal/rcar_gen3_thermal.c | 143 |
1 files changed, 74 insertions, 69 deletions
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 88fa41cf16e8..a56463308694 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -14,7 +14,6 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/spinlock.h> #include <linux/sys_soc.h> #include <linux/thermal.h> @@ -63,6 +62,13 @@ #define TSC_MAX_NUM 3 +/* default THCODE values if FUSEs are missing */ +static const int thcode[TSC_MAX_NUM][3] = { + { 3397, 2800, 2221 }, + { 3393, 2795, 2216 }, + { 3389, 2805, 2237 }, +}; + /* Structure for thermal temperature calculation */ struct equation_coefs { int a1; @@ -77,12 +83,13 @@ struct rcar_gen3_thermal_tsc { struct equation_coefs coef; int low; int high; + int tj_t; + int id; /* thermal channel id */ }; struct rcar_gen3_thermal_priv { struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM]; unsigned int num_tscs; - spinlock_t lock; /* Protect interrupts on and off */ void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc); }; @@ -124,30 +131,28 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc, #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */ /* no idea where these constants come from */ -#define TJ_1 116 #define TJ_3 -41 -static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef, - int *ptat, int *thcode) +static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc, + int *ptat, const int *thcode, + int ths_tj_1) { - int tj_2; - /* TODO: Find documentation and document constant calculation formula */ /* * Division is not scaled in BSP and if scaled it might overflow * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled */ - tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 157) - / (ptat[0] - ptat[2])) - FIXPT_INT(41); + tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * 157) + / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3); - coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), - tj_2 - FIXPT_INT(TJ_3)); - coef->b1 = FIXPT_INT(thcode[2]) - coef->a1 * TJ_3; + tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), + tsc->tj_t - FIXPT_INT(TJ_3)); + tsc->coef.b1 = FIXPT_INT(thcode[2]) - tsc->coef.a1 * TJ_3; - coef->a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]), - tj_2 - FIXPT_INT(TJ_1)); - coef->b2 = FIXPT_INT(thcode[0]) - coef->a2 * TJ_1; + tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]), + tsc->tj_t - FIXPT_INT(ths_tj_1)); + tsc->coef.b2 = FIXPT_INT(thcode[0]) - tsc->coef.a2 * ths_tj_1; } static int rcar_gen3_thermal_round(int temp) @@ -163,15 +168,19 @@ static int rcar_gen3_thermal_round(int temp) static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) { struct rcar_gen3_thermal_tsc *tsc = devdata; - int mcelsius, val1, val2; + int mcelsius, val; u32 reg; /* Read register and convert to mili Celsius */ reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; - val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1); - val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2); - mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2); + if (reg <= thcode[tsc->id][1]) + val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, + tsc->coef.a1); + else + val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, + tsc->coef.a2); + mcelsius = FIXPT_TO_MCELSIUS(val); /* Make sure we are inside specifications */ if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125))) @@ -186,13 +195,15 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc, int mcelsius) { - int celsius, val1, val2; + int celsius, val; celsius = DIV_ROUND_CLOSEST(mcelsius, 1000); - val1 = celsius * tsc->coef.a1 + tsc->coef.b1; - val2 = celsius * tsc->coef.a2 + tsc->coef.b2; + if (celsius <= INT_FIXPT(tsc->tj_t)) + val = celsius * tsc->coef.a1 + tsc->coef.b1; + else + val = celsius * tsc->coef.a2 + tsc->coef.b2; - return INT_FIXPT((val1 + val2) / 2); + return INT_FIXPT(val); } static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high) @@ -232,38 +243,16 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data) { struct rcar_gen3_thermal_priv *priv = data; u32 status; - int i, ret = IRQ_HANDLED; + int i; - spin_lock(&priv->lock); for (i = 0; i < priv->num_tscs; i++) { status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR); rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0); if (status) - ret = IRQ_WAKE_THREAD; + thermal_zone_device_update(priv->tscs[i]->zone, + THERMAL_EVENT_UNSPECIFIED); } - if (ret == IRQ_WAKE_THREAD) - rcar_thermal_irq_set(priv, false); - - spin_unlock(&priv->lock); - - return ret; -} - -static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data) -{ - struct rcar_gen3_thermal_priv *priv = data; - unsigned long flags; - int i; - - for (i = 0; i < priv->num_tscs; i++) - thermal_zone_device_update(priv->tscs[i]->zone, - THERMAL_EVENT_UNSPECIFIED); - - spin_lock_irqsave(&priv->lock, flags); - rcar_thermal_irq_set(priv, true); - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_HANDLED; } @@ -307,7 +296,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) usleep_range(1000, 2000); - rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2); @@ -318,12 +307,29 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) usleep_range(1000, 2000); } +static const int rcar_gen3_ths_tj_1 = 126; +static const int rcar_gen3_ths_tj_1_m3_w = 116; static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { - { .compatible = "renesas,r8a774a1-thermal", }, - { .compatible = "renesas,r8a7795-thermal", }, - { .compatible = "renesas,r8a7796-thermal", }, - { .compatible = "renesas,r8a77965-thermal", }, - { .compatible = "renesas,r8a77980-thermal", }, + { + .compatible = "renesas,r8a774a1-thermal", + .data = &rcar_gen3_ths_tj_1_m3_w, + }, + { + .compatible = "renesas,r8a7795-thermal", + .data = &rcar_gen3_ths_tj_1, + }, + { + .compatible = "renesas,r8a7796-thermal", + .data = &rcar_gen3_ths_tj_1_m3_w, + }, + { + .compatible = "renesas,r8a77965-thermal", + .data = &rcar_gen3_ths_tj_1, + }, + { + .compatible = "renesas,r8a77980-thermal", + .data = &rcar_gen3_ths_tj_1, + }, {}, }; MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); @@ -331,6 +337,9 @@ MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); static int rcar_gen3_thermal_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev); + + rcar_thermal_irq_set(priv, false); pm_runtime_put(dev); pm_runtime_disable(dev); @@ -349,6 +358,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) { struct rcar_gen3_thermal_priv *priv; struct device *dev = &pdev->dev; + const int *rcar_gen3_ths_tj_1 = of_device_get_match_data(dev); struct resource *res; struct thermal_zone_device *zone; int ret, irq, i; @@ -357,11 +367,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) /* default values if FUSEs are missing */ /* TODO: Read values from hardware on supported platforms */ int ptat[3] = { 2631, 1509, 435 }; - int thcode[TSC_MAX_NUM][3] = { - { 3397, 2800, 2221 }, - { 3393, 2795, 2216 }, - { 3389, 2805, 2237 }, - }; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -371,8 +376,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (soc_device_match(r8a7795es1)) priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1; - spin_lock_init(&priv->lock); - platform_set_drvdata(pdev, priv); /* @@ -390,9 +393,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (!irqname) return -ENOMEM; - ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq, - rcar_gen3_thermal_irq_thread, - IRQF_SHARED, irqname, priv); + ret = devm_request_threaded_irq(dev, irq, NULL, + rcar_gen3_thermal_irq, + IRQF_ONESHOT, irqname, priv); if (ret) return ret; } @@ -418,11 +421,13 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) ret = PTR_ERR(tsc->base); goto error_unregister; } + tsc->id = i; priv->tscs[i] = tsc; priv->thermal_init(tsc); - rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]); + rcar_gen3_thermal_calc_coefs(tsc, ptat, thcode[i], + *rcar_gen3_ths_tj_1); zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, &rcar_gen3_tz_of_ops); @@ -433,10 +438,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) } tsc->zone = zone; - ret = of_thermal_get_ntrips(tsc->zone); - if (ret < 0) - goto error_unregister; - tsc->zone->tzp->no_hwmon = false; ret = thermal_add_hwmon_sysfs(tsc->zone); if (ret) @@ -448,6 +449,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) goto error_unregister; } + ret = of_thermal_get_ntrips(tsc->zone); + if (ret < 0) + goto error_unregister; + dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret); } |