]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/thermal/hisi_thermal.c
thermal/drivers/hisi: Encapsulate register writes into helpers
[linux.git] / drivers / thermal / hisi_thermal.c
index 9c3ce341eb97563822d510398b8b4d06c71af3f1..7747b96002e3e966feb8dab7f1feda3cbabb4e79 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "thermal_core.h"
 
+#define TEMP0_LAG                      (0x0)
 #define TEMP0_TH                       (0x4)
 #define TEMP0_RST_TH                   (0x8)
 #define TEMP0_CFG                      (0xC)
 #define TEMP0_RST_MSK                  (0x1C)
 #define TEMP0_VALUE                    (0x28)
 
-#define HISI_TEMP_BASE                 (-60)
+#define HISI_TEMP_BASE                 (-60000)
 #define HISI_TEMP_RESET                        (100000)
+#define HISI_TEMP_STEP                 (784)
 
 #define HISI_MAX_SENSORS               4
+#define HISI_DEFAULT_SENSOR            2
 
 struct hisi_thermal_sensor {
        struct hisi_thermal_data *thermal;
@@ -53,27 +56,95 @@ struct hisi_thermal_data {
        struct mutex thermal_lock;    /* protects register data */
        struct platform_device *pdev;
        struct clk *clk;
-       struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];
-
-       int irq, irq_bind_sensor;
+       struct hisi_thermal_sensor sensors;
+       int irq;
        bool irq_enabled;
 
        void __iomem *regs;
 };
 
-/* in millicelsius */
-static inline int _step_to_temp(int step)
+/*
+ * The temperature computation on the tsensor is as follow:
+ *     Unit: millidegree Celsius
+ *     Step: 255/200 (0.7843)
+ *     Temperature base: -60°C
+ *
+ * The register is programmed in temperature steps, every step is 784
+ * millidegree and begins at -60 000 m°C
+ *
+ * The temperature from the steps:
+ *
+ *     Temp = TempBase + (steps x 784)
+ *
+ * and the steps from the temperature:
+ *
+ *     steps = (Temp - TempBase) / 784
+ *
+ */
+static inline int hisi_thermal_step_to_temp(int step)
 {
-       /*
-        * Every step equals (1 * 200) / 255 celsius, and finally
-        * need convert to millicelsius.
-        */
-       return (HISI_TEMP_BASE * 1000 + (step * 200000 / 255));
+       return HISI_TEMP_BASE + (step * HISI_TEMP_STEP);
+}
+
+static inline long hisi_thermal_temp_to_step(long temp)
+{
+       return (temp - HISI_TEMP_BASE) / HISI_TEMP_STEP;
+}
+
+static inline long hisi_thermal_round_temp(int temp)
+{
+       return hisi_thermal_step_to_temp(
+               hisi_thermal_temp_to_step(temp));
+}
+
+static inline void hisi_thermal_set_lag(void __iomem *addr, int value)
+{
+       writel(value, addr + TEMP0_LAG);
+}
+
+static inline void hisi_thermal_alarm_clear(void __iomem *addr, int value)
+{
+       writel(value, addr + TEMP0_INT_CLR);
 }
 
-static inline long _temp_to_step(long temp)
+static inline void hisi_thermal_alarm_enable(void __iomem *addr, int value)
 {
-       return ((temp - HISI_TEMP_BASE * 1000) * 255) / 200000;
+       writel(value, addr + TEMP0_INT_EN);
+}
+
+static inline void hisi_thermal_alarm_set(void __iomem *addr, int temp)
+{
+       writel(hisi_thermal_temp_to_step(temp) | 0x0FFFFFF00, addr + TEMP0_TH);
+}
+
+static inline void hisi_thermal_reset_set(void __iomem *addr, int temp)
+{
+       writel(hisi_thermal_temp_to_step(temp), addr + TEMP0_RST_TH);
+}
+
+static inline void hisi_thermal_reset_enable(void __iomem *addr, int value)
+{
+       writel(value, addr + TEMP0_RST_MSK);
+}
+
+static inline void hisi_thermal_enable(void __iomem *addr, int value)
+{
+       writel(value, addr + TEMP0_EN);
+}
+
+static inline void hisi_thermal_sensor_select(void __iomem *addr, int sensor)
+{
+       writel((sensor << 12), addr + TEMP0_CFG);
+}
+
+static inline int hisi_thermal_get_temperature(void __iomem *addr)
+{
+       return hisi_thermal_step_to_temp(readl(addr + TEMP0_VALUE));
+}
+
+static inline void hisi_thermal_hdak_set(void __iomem *addr, int value)
+{
+       writel(value, addr + TEMP0_CFG);
 }
 
 static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
@@ -84,22 +155,21 @@ static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
        mutex_lock(&data->thermal_lock);
 
        /* disable interrupt */
-       writel(0x0, data->regs + TEMP0_INT_EN);
-       writel(0x1, data->regs + TEMP0_INT_CLR);
+       hisi_thermal_alarm_enable(data->regs, 0);
+       hisi_thermal_alarm_clear(data->regs, 1);
 
        /* disable module firstly */
-       writel(0x0, data->regs + TEMP0_EN);
+       hisi_thermal_enable(data->regs, 0);
 
        /* select sensor id */
-       writel((sensor->id << 12), data->regs + TEMP0_CFG);
+       hisi_thermal_sensor_select(data->regs, sensor->id);
 
        /* enable module */
-       writel(0x1, data->regs + TEMP0_EN);
+       hisi_thermal_enable(data->regs, 1);
 
        usleep_range(3000, 5000);
 
-       val = readl(data->regs + TEMP0_VALUE);
-       val = _step_to_temp(val);
+       val = hisi_thermal_get_temperature(data->regs);
 
        mutex_unlock(&data->thermal_lock);
 
@@ -113,30 +183,29 @@ static void hisi_thermal_enable_bind_irq_sensor
 
        mutex_lock(&data->thermal_lock);
 
-       sensor = &data->sensors[data->irq_bind_sensor];
+       sensor = &data->sensors;
 
        /* setting the hdak time */
-       writel(0x0, data->regs + TEMP0_CFG);
+       hisi_thermal_hdak_set(data->regs, 0);
 
        /* disable module firstly */
-       writel(0x0, data->regs + TEMP0_RST_MSK);
-       writel(0x0, data->regs + TEMP0_EN);
+       hisi_thermal_reset_enable(data->regs, 0);
+       hisi_thermal_enable(data->regs, 0);
 
        /* select sensor id */
-       writel((sensor->id << 12), data->regs + TEMP0_CFG);
+       hisi_thermal_sensor_select(data->regs, sensor->id);
 
        /* enable for interrupt */
-       writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,
-              data->regs + TEMP0_TH);
+       hisi_thermal_alarm_set(data->regs, sensor->thres_temp);
 
-       writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH);
+       hisi_thermal_reset_set(data->regs, HISI_TEMP_RESET);
 
        /* enable module */
-       writel(0x1, data->regs + TEMP0_RST_MSK);
-       writel(0x1, data->regs + TEMP0_EN);
+       hisi_thermal_reset_enable(data->regs, 1);
+       hisi_thermal_enable(data->regs, 1);
 
-       writel(0x0, data->regs + TEMP0_INT_CLR);
-       writel(0x1, data->regs + TEMP0_INT_EN);
+       hisi_thermal_alarm_clear(data->regs, 0);
+       hisi_thermal_alarm_enable(data->regs, 1);
 
        usleep_range(3000, 5000);
 
@@ -148,9 +217,9 @@ static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)
        mutex_lock(&data->thermal_lock);
 
        /* disable sensor module */
-       writel(0x0, data->regs + TEMP0_INT_EN);
-       writel(0x0, data->regs + TEMP0_RST_MSK);
-       writel(0x0, data->regs + TEMP0_EN);
+       hisi_thermal_enable(data->regs, 0);
+       hisi_thermal_alarm_enable(data->regs, 0);
+       hisi_thermal_reset_enable(data->regs, 0);
 
        mutex_unlock(&data->thermal_lock);
 }
@@ -160,31 +229,8 @@ static int hisi_thermal_get_temp(void *_sensor, int *temp)
        struct hisi_thermal_sensor *sensor = _sensor;
        struct hisi_thermal_data *data = sensor->thermal;
 
-       int sensor_id = -1, i;
-       long max_temp = 0;
-
        *temp = hisi_thermal_get_sensor_temp(data, sensor);
 
-       sensor->sensor_temp = *temp;
-
-       for (i = 0; i < HISI_MAX_SENSORS; i++) {
-               if (!data->sensors[i].tzd)
-                       continue;
-
-               if (data->sensors[i].sensor_temp >= max_temp) {
-                       max_temp = data->sensors[i].sensor_temp;
-                       sensor_id = i;
-               }
-       }
-
-       /* If no sensor has been enabled, then skip to enable irq */
-       if (sensor_id == -1)
-               return 0;
-
-       mutex_lock(&data->thermal_lock);
-       data->irq_bind_sensor = sensor_id;
-       mutex_unlock(&data->thermal_lock);
-
        dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%d, thres=%d\n",
                sensor->id, data->irq_enabled, *temp, sensor->thres_temp);
        /*
@@ -197,7 +243,7 @@ static int hisi_thermal_get_temp(void *_sensor, int *temp)
                return 0;
        }
 
-       if (max_temp < sensor->thres_temp) {
+       if (*temp < sensor->thres_temp) {
                data->irq_enabled = true;
                hisi_thermal_enable_bind_irq_sensor(data);
                enable_irq(data->irq);
@@ -206,7 +252,7 @@ static int hisi_thermal_get_temp(void *_sensor, int *temp)
        return 0;
 }
 
-static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
+static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
        .get_temp = hisi_thermal_get_temp,
 };
 
@@ -223,23 +269,13 @@ static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
 static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
 {
        struct hisi_thermal_data *data = dev;
-       struct hisi_thermal_sensor *sensor;
-       int i;
-
-       mutex_lock(&data->thermal_lock);
-       sensor = &data->sensors[data->irq_bind_sensor];
+       struct hisi_thermal_sensor *sensor = &data->sensors;
 
        dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
-                sensor->thres_temp / 1000);
-       mutex_unlock(&data->thermal_lock);
+                sensor->thres_temp);
 
-       for (i = 0; i < HISI_MAX_SENSORS; i++) {
-               if (!data->sensors[i].tzd)
-                       continue;
-
-               thermal_zone_device_update(data->sensors[i].tzd,
-                                          THERMAL_EVENT_UNSPECIFIED);
-       }
+       thermal_zone_device_update(data->sensors.tzd,
+                                  THERMAL_EVENT_UNSPECIFIED);
 
        return IRQ_HANDLED;
 }
@@ -269,7 +305,7 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev,
 
        for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
                if (trip[i].type == THERMAL_TRIP_PASSIVE) {
-                       sensor->thres_temp = trip[i].temperature;
+                       sensor->thres_temp = hisi_thermal_round_temp(trip[i].temperature);
                        break;
                }
        }
@@ -296,7 +332,6 @@ static int hisi_thermal_probe(struct platform_device *pdev)
 {
        struct hisi_thermal_data *data;
        struct resource *res;
-       int i;
        int ret;
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
@@ -317,15 +352,6 @@ static int hisi_thermal_probe(struct platform_device *pdev)
        if (data->irq < 0)
                return data->irq;
 
-       ret = devm_request_threaded_irq(&pdev->dev, data->irq,
-                                       hisi_thermal_alarm_irq,
-                                       hisi_thermal_alarm_irq_thread,
-                                       0, "hisi_thermal", data);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
-               return ret;
-       }
-
        platform_set_drvdata(pdev, data);
 
        data->clk = devm_clk_get(&pdev->dev, "thermal_clk");
@@ -345,36 +371,39 @@ static int hisi_thermal_probe(struct platform_device *pdev)
        }
 
        hisi_thermal_enable_bind_irq_sensor(data);
-       irq_get_irqchip_state(data->irq, IRQCHIP_STATE_MASKED,
-                             &data->irq_enabled);
+       data->irq_enabled = true;
 
-       for (i = 0; i < HISI_MAX_SENSORS; ++i) {
-               ret = hisi_thermal_register_sensor(pdev, data,
-                                                  &data->sensors[i], i);
-               if (ret)
-                       dev_err(&pdev->dev,
-                               "failed to register thermal sensor: %d\n", ret);
-               else
-                       hisi_thermal_toggle_sensor(&data->sensors[i], true);
+       ret = hisi_thermal_register_sensor(pdev, data,
+                                          &data->sensors,
+                                          HISI_DEFAULT_SENSOR);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register thermal sensor: %d\n",
+                       ret);
+               return ret;
+       }
+
+       hisi_thermal_toggle_sensor(&data->sensors, true);
+
+       ret = devm_request_threaded_irq(&pdev->dev, data->irq,
+                                       hisi_thermal_alarm_irq,
+                                       hisi_thermal_alarm_irq_thread,
+                                       0, "hisi_thermal", data);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
+               return ret;
        }
 
+       enable_irq(data->irq);
+
        return 0;
 }
 
 static int hisi_thermal_remove(struct platform_device *pdev)
 {
        struct hisi_thermal_data *data = platform_get_drvdata(pdev);
-       int i;
-
-       for (i = 0; i < HISI_MAX_SENSORS; i++) {
-               struct hisi_thermal_sensor *sensor = &data->sensors[i];
-
-               if (!sensor->tzd)
-                       continue;
-
-               hisi_thermal_toggle_sensor(sensor, false);
-       }
+       struct hisi_thermal_sensor *sensor = &data->sensors;
 
+       hisi_thermal_toggle_sensor(sensor, false);
        hisi_thermal_disable_sensor(data);
        clk_disable_unprepare(data->clk);