]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/thermal/rcar_gen3_thermal.c
rbd: cancel lock_dwork if the wait is interrupted
[linux.git] / drivers / thermal / rcar_gen3_thermal.c
index 88fa41cf16e83e67f670295988897542e90bb7d9..755d2b5bd2c2b552eb16effcfd2f7fe27777d66f 100644 (file)
@@ -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>
 
 
 #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,21 +438,20 @@ 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)
                        goto error_unregister;
 
-               ret = devm_add_action(dev, rcar_gen3_hwmon_action, zone);
+               ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone);
                if (ret) {
-                       rcar_gen3_hwmon_action(zone);
                        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);
        }