Merge tag 'v4.15-rc1' into drm-misc-fixes
[linux-2.6-block.git] / drivers / thermal / hisi_thermal.c
index bd3572c41585caedde615301f7ff68d73c235b6c..2d855a96cdd9886c5f3abbcfb4e1d8a5c1ea8666 100644 (file)
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/of_device.h>
 
 #include "thermal_core.h"
 
-#define TEMP0_TH                       (0x4)
-#define TEMP0_RST_TH                   (0x8)
-#define TEMP0_CFG                      (0xC)
-#define TEMP0_EN                       (0x10)
-#define TEMP0_INT_EN                   (0x14)
-#define TEMP0_INT_CLR                  (0x18)
-#define TEMP0_RST_MSK                  (0x1C)
-#define TEMP0_VALUE                    (0x28)
-
-#define HISI_TEMP_BASE                 (-60)
-#define HISI_TEMP_RESET                        (100000)
-
-#define HISI_MAX_SENSORS               4
+#define HI6220_TEMP0_LAG                       (0x0)
+#define HI6220_TEMP0_TH                                (0x4)
+#define HI6220_TEMP0_RST_TH                    (0x8)
+#define HI6220_TEMP0_CFG                       (0xC)
+#define HI6220_TEMP0_CFG_SS_MSK                        (0xF000)
+#define HI6220_TEMP0_CFG_HDAK_MSK              (0x30)
+#define HI6220_TEMP0_EN                                (0x10)
+#define HI6220_TEMP0_INT_EN                    (0x14)
+#define HI6220_TEMP0_INT_CLR                   (0x18)
+#define HI6220_TEMP0_RST_MSK                   (0x1C)
+#define HI6220_TEMP0_VALUE                     (0x28)
+
+#define HI3660_OFFSET(chan)            ((chan) * 0x40)
+#define HI3660_TEMP(chan)              (HI3660_OFFSET(chan) + 0x1C)
+#define HI3660_TH(chan)                        (HI3660_OFFSET(chan) + 0x20)
+#define HI3660_LAG(chan)               (HI3660_OFFSET(chan) + 0x28)
+#define HI3660_INT_EN(chan)            (HI3660_OFFSET(chan) + 0x2C)
+#define HI3660_INT_CLR(chan)           (HI3660_OFFSET(chan) + 0x30)
+
+#define HI6220_TEMP_BASE                       (-60000)
+#define HI6220_TEMP_RESET                      (100000)
+#define HI6220_TEMP_STEP                       (785)
+#define HI6220_TEMP_LAG                                (3500)
+
+#define HI3660_TEMP_BASE               (-63780)
+#define HI3660_TEMP_STEP               (205)
+#define HI3660_TEMP_LAG                        (4000)
+
+#define HI6220_DEFAULT_SENSOR          2
+#define HI3660_DEFAULT_SENSOR          1
 
 struct hisi_thermal_sensor {
-       struct hisi_thermal_data *thermal;
        struct thermal_zone_device *tzd;
-
-       long sensor_temp;
        uint32_t id;
        uint32_t thres_temp;
 };
 
 struct hisi_thermal_data {
-       struct mutex thermal_lock;    /* protects register data */
+       int (*get_temp)(struct hisi_thermal_data *data);
+       int (*enable_sensor)(struct hisi_thermal_data *data);
+       int (*disable_sensor)(struct hisi_thermal_data *data);
+       int (*irq_handler)(struct hisi_thermal_data *data);
        struct platform_device *pdev;
        struct clk *clk;
-       struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];
-
-       int irq, irq_bind_sensor;
-       bool irq_enabled;
-
+       struct hisi_thermal_sensor sensor;
        void __iomem *regs;
+       int irq;
 };
 
-/* in millicelsius */
-static inline int _step_to_temp(int step)
+/*
+ * The temperature computation on the tsensor is as follow:
+ *     Unit: millidegree Celsius
+ *     Step: 200/255 (0.7843)
+ *     Temperature base: -60°C
+ *
+ * The register is programmed in temperature steps, every step is 785
+ * millidegree and begins at -60 000 m°C
+ *
+ * The temperature from the steps:
+ *
+ *     Temp = TempBase + (steps x 785)
+ *
+ * and the steps from the temperature:
+ *
+ *     steps = (Temp - TempBase) / 785
+ *
+ */
+static inline int hi6220_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 HI6220_TEMP_BASE + (step * HI6220_TEMP_STEP);
 }
 
-static inline long _temp_to_step(long temp)
+static inline int hi6220_thermal_temp_to_step(int temp)
 {
-       return ((temp - HISI_TEMP_BASE * 1000) * 255) / 200000;
+       return DIV_ROUND_UP(temp - HI6220_TEMP_BASE, HI6220_TEMP_STEP);
 }
 
-static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
-                                        struct hisi_thermal_sensor *sensor)
+/*
+ * for Hi3660,
+ *     Step: 189/922 (0.205)
+ *     Temperature base: -63.780°C
+ *
+ * The register is programmed in temperature steps, every step is 205
+ * millidegree and begins at -63 780 m°C
+ */
+static inline int hi3660_thermal_step_to_temp(int step)
 {
-       long val;
+       return HI3660_TEMP_BASE + step * HI3660_TEMP_STEP;
+}
 
-       mutex_lock(&data->thermal_lock);
+static inline int hi3660_thermal_temp_to_step(int temp)
+{
+       return DIV_ROUND_UP(temp - HI3660_TEMP_BASE, HI3660_TEMP_STEP);
+}
 
-       /* disable interrupt */
-       writel(0x0, data->regs + TEMP0_INT_EN);
-       writel(0x1, data->regs + TEMP0_INT_CLR);
+/*
+ * The lag register contains 5 bits encoding the temperature in steps.
+ *
+ * Each time the temperature crosses the threshold boundary, an
+ * interrupt is raised. It could be when the temperature is going
+ * above the threshold or below. However, if the temperature is
+ * fluctuating around this value due to the load, we can receive
+ * several interrupts which may not desired.
+ *
+ * We can setup a temperature representing the delta between the
+ * threshold and the current temperature when the temperature is
+ * decreasing.
+ *
+ * For instance: the lag register is 5°C, the threshold is 65°C, when
+ * the temperature reaches 65°C an interrupt is raised and when the
+ * temperature decrease to 65°C - 5°C another interrupt is raised.
+ *
+ * A very short lag can lead to an interrupt storm, a long lag
+ * increase the latency to react to the temperature changes.  In our
+ * case, that is not really a problem as we are polling the
+ * temperature.
+ *
+ * [0:4] : lag register
+ *
+ * The temperature is coded in steps, cf. HI6220_TEMP_STEP.
+ *
+ * Min : 0x00 :  0.0 °C
+ * Max : 0x1F : 24.3 °C
+ *
+ * The 'value' parameter is in milliCelsius.
+ */
+static inline void hi6220_thermal_set_lag(void __iomem *addr, int value)
+{
+       writel(DIV_ROUND_UP(value, HI6220_TEMP_STEP) & 0x1F,
+                       addr + HI6220_TEMP0_LAG);
+}
 
-       /* disable module firstly */
-       writel(0x0, data->regs + TEMP0_EN);
+static inline void hi6220_thermal_alarm_clear(void __iomem *addr, int value)
+{
+       writel(value, addr + HI6220_TEMP0_INT_CLR);
+}
 
-       /* select sensor id */
-       writel((sensor->id << 12), data->regs + TEMP0_CFG);
+static inline void hi6220_thermal_alarm_enable(void __iomem *addr, int value)
+{
+       writel(value, addr + HI6220_TEMP0_INT_EN);
+}
 
-       /* enable module */
-       writel(0x1, data->regs + TEMP0_EN);
+static inline void hi6220_thermal_alarm_set(void __iomem *addr, int temp)
+{
+       writel(hi6220_thermal_temp_to_step(temp) | 0x0FFFFFF00,
+              addr + HI6220_TEMP0_TH);
+}
 
-       usleep_range(3000, 5000);
+static inline void hi6220_thermal_reset_set(void __iomem *addr, int temp)
+{
+       writel(hi6220_thermal_temp_to_step(temp), addr + HI6220_TEMP0_RST_TH);
+}
 
-       val = readl(data->regs + TEMP0_VALUE);
-       val = _step_to_temp(val);
+static inline void hi6220_thermal_reset_enable(void __iomem *addr, int value)
+{
+       writel(value, addr + HI6220_TEMP0_RST_MSK);
+}
 
-       mutex_unlock(&data->thermal_lock);
+static inline void hi6220_thermal_enable(void __iomem *addr, int value)
+{
+       writel(value, addr + HI6220_TEMP0_EN);
+}
 
-       return val;
+static inline int hi6220_thermal_get_temperature(void __iomem *addr)
+{
+       return hi6220_thermal_step_to_temp(readl(addr + HI6220_TEMP0_VALUE));
 }
 
-static void hisi_thermal_enable_bind_irq_sensor
-                       (struct hisi_thermal_data *data)
+/*
+ * [0:6] lag register
+ *
+ * The temperature is coded in steps, cf. HI3660_TEMP_STEP.
+ *
+ * Min : 0x00 :  0.0 °C
+ * Max : 0x7F : 26.0 °C
+ *
+ */
+static inline void hi3660_thermal_set_lag(void __iomem *addr,
+                                         int id, int value)
 {
-       struct hisi_thermal_sensor *sensor;
+       writel(DIV_ROUND_UP(value, HI3660_TEMP_STEP) & 0x7F,
+                       addr + HI3660_LAG(id));
+}
 
-       mutex_lock(&data->thermal_lock);
+static inline void hi3660_thermal_alarm_clear(void __iomem *addr,
+                                             int id, int value)
+{
+       writel(value, addr + HI3660_INT_CLR(id));
+}
 
-       sensor = &data->sensors[data->irq_bind_sensor];
+static inline void hi3660_thermal_alarm_enable(void __iomem *addr,
+                                              int id, int value)
+{
+       writel(value, addr + HI3660_INT_EN(id));
+}
 
-       /* setting the hdak time */
-       writel(0x0, data->regs + TEMP0_CFG);
+static inline void hi3660_thermal_alarm_set(void __iomem *addr,
+                                           int id, int value)
+{
+       writel(value, addr + HI3660_TH(id));
+}
+
+static inline int hi3660_thermal_get_temperature(void __iomem *addr, int id)
+{
+       return hi3660_thermal_step_to_temp(readl(addr + HI3660_TEMP(id)));
+}
+
+/*
+ * Temperature configuration register - Sensor selection
+ *
+ * Bits [19:12]
+ *
+ * 0x0: local sensor (default)
+ * 0x1: remote sensor 1 (ACPU cluster 1)
+ * 0x2: remote sensor 2 (ACPU cluster 0)
+ * 0x3: remote sensor 3 (G3D)
+ */
+static inline void hi6220_thermal_sensor_select(void __iomem *addr, int sensor)
+{
+       writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_SS_MSK) |
+              (sensor << 12), addr + HI6220_TEMP0_CFG);
+}
+
+/*
+ * Temperature configuration register - Hdak conversion polling interval
+ *
+ * Bits [5:4]
+ *
+ * 0x0 :   0.768 ms
+ * 0x1 :   6.144 ms
+ * 0x2 :  49.152 ms
+ * 0x3 : 393.216 ms
+ */
+static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value)
+{
+       writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_HDAK_MSK) |
+              (value << 4), addr + HI6220_TEMP0_CFG);
+}
+
+static int hi6220_thermal_irq_handler(struct hisi_thermal_data *data)
+{
+       hi6220_thermal_alarm_clear(data->regs, 1);
+       return 0;
+}
+
+static int hi3660_thermal_irq_handler(struct hisi_thermal_data *data)
+{
+       hi3660_thermal_alarm_clear(data->regs, data->sensor.id, 1);
+       return 0;
+}
+
+static int hi6220_thermal_get_temp(struct hisi_thermal_data *data)
+{
+       return hi6220_thermal_get_temperature(data->regs);
+}
+
+static int hi3660_thermal_get_temp(struct hisi_thermal_data *data)
+{
+       return hi3660_thermal_get_temperature(data->regs, data->sensor.id);
+}
+
+static int hi6220_thermal_disable_sensor(struct hisi_thermal_data *data)
+{
+       /* disable sensor module */
+       hi6220_thermal_enable(data->regs, 0);
+       hi6220_thermal_alarm_enable(data->regs, 0);
+       hi6220_thermal_reset_enable(data->regs, 0);
+
+       clk_disable_unprepare(data->clk);
+
+       return 0;
+}
+
+static int hi3660_thermal_disable_sensor(struct hisi_thermal_data *data)
+{
+       /* disable sensor module */
+       hi3660_thermal_alarm_enable(data->regs, data->sensor.id, 0);
+       return 0;
+}
+
+static int hi6220_thermal_enable_sensor(struct hisi_thermal_data *data)
+{
+       struct hisi_thermal_sensor *sensor = &data->sensor;
+       int ret;
+
+       /* enable clock for tsensor */
+       ret = clk_prepare_enable(data->clk);
+       if (ret)
+               return ret;
 
        /* disable module firstly */
-       writel(0x0, data->regs + TEMP0_RST_MSK);
-       writel(0x0, data->regs + TEMP0_EN);
+       hi6220_thermal_reset_enable(data->regs, 0);
+       hi6220_thermal_enable(data->regs, 0);
 
        /* select sensor id */
-       writel((sensor->id << 12), data->regs + TEMP0_CFG);
+       hi6220_thermal_sensor_select(data->regs, sensor->id);
+
+       /* setting the hdak time */
+       hi6220_thermal_hdak_set(data->regs, 0);
+
+       /* setting lag value between current temp and the threshold */
+       hi6220_thermal_set_lag(data->regs, HI6220_TEMP_LAG);
 
        /* enable for interrupt */
-       writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,
-              data->regs + TEMP0_TH);
+       hi6220_thermal_alarm_set(data->regs, sensor->thres_temp);
 
-       writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH);
+       hi6220_thermal_reset_set(data->regs, HI6220_TEMP_RESET);
 
        /* enable module */
-       writel(0x1, data->regs + TEMP0_RST_MSK);
-       writel(0x1, data->regs + TEMP0_EN);
-
-       writel(0x0, data->regs + TEMP0_INT_CLR);
-       writel(0x1, data->regs + TEMP0_INT_EN);
+       hi6220_thermal_reset_enable(data->regs, 1);
+       hi6220_thermal_enable(data->regs, 1);
 
-       usleep_range(3000, 5000);
+       hi6220_thermal_alarm_clear(data->regs, 0);
+       hi6220_thermal_alarm_enable(data->regs, 1);
 
-       mutex_unlock(&data->thermal_lock);
+       return 0;
 }
 
-static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)
+static int hi3660_thermal_enable_sensor(struct hisi_thermal_data *data)
 {
-       mutex_lock(&data->thermal_lock);
+       unsigned int value;
+       struct hisi_thermal_sensor *sensor = &data->sensor;
 
-       /* disable sensor module */
-       writel(0x0, data->regs + TEMP0_INT_EN);
-       writel(0x0, data->regs + TEMP0_RST_MSK);
-       writel(0x0, data->regs + TEMP0_EN);
+       /* disable interrupt */
+       hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
 
-       mutex_unlock(&data->thermal_lock);
-}
+       /* setting lag value between current temp and the threshold */
+       hi3660_thermal_set_lag(data->regs, sensor->id, HI3660_TEMP_LAG);
 
-static int hisi_thermal_get_temp(void *_sensor, int *temp)
-{
-       struct hisi_thermal_sensor *sensor = _sensor;
-       struct hisi_thermal_data *data = sensor->thermal;
+       /* set interrupt threshold */
+       value = hi3660_thermal_temp_to_step(sensor->thres_temp);
+       hi3660_thermal_alarm_set(data->regs, sensor->id, value);
 
-       int sensor_id = -1, i;
-       long max_temp = 0;
+       /* enable interrupt */
+       hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
+       hi3660_thermal_alarm_enable(data->regs, sensor->id, 1);
 
-       *temp = hisi_thermal_get_sensor_temp(data, sensor);
+       return 0;
+}
 
-       sensor->sensor_temp = *temp;
+static int hi6220_thermal_probe(struct hisi_thermal_data *data)
+{
+       struct platform_device *pdev = data->pdev;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       int ret;
 
-       for (i = 0; i < HISI_MAX_SENSORS; i++) {
-               if (!data->sensors[i].tzd)
-                       continue;
+       data->get_temp = hi6220_thermal_get_temp;
+       data->enable_sensor = hi6220_thermal_enable_sensor;
+       data->disable_sensor = hi6220_thermal_disable_sensor;
+       data->irq_handler = hi6220_thermal_irq_handler;
 
-               if (data->sensors[i].sensor_temp >= max_temp) {
-                       max_temp = data->sensors[i].sensor_temp;
-                       sensor_id = i;
-               }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(data->regs)) {
+               dev_err(dev, "failed to get io address\n");
+               return PTR_ERR(data->regs);
        }
 
-       /* 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);
-       /*
-        * Bind irq to sensor for two cases:
-        *   Reenable alarm IRQ if temperature below threshold;
-        *   if irq has been enabled, always set it;
-        */
-       if (data->irq_enabled) {
-               hisi_thermal_enable_bind_irq_sensor(data);
-               return 0;
+       data->clk = devm_clk_get(dev, "thermal_clk");
+       if (IS_ERR(data->clk)) {
+               ret = PTR_ERR(data->clk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get thermal clk: %d\n", ret);
+               return ret;
        }
 
-       if (max_temp < sensor->thres_temp) {
-               data->irq_enabled = true;
-               hisi_thermal_enable_bind_irq_sensor(data);
-               enable_irq(data->irq);
-       }
+       data->irq = platform_get_irq(pdev, 0);
+       if (data->irq < 0)
+               return data->irq;
+
+       data->sensor.id = HI6220_DEFAULT_SENSOR;
 
        return 0;
 }
 
-static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
-       .get_temp = hisi_thermal_get_temp,
-};
+static int hi3660_thermal_probe(struct hisi_thermal_data *data)
+{
+       struct platform_device *pdev = data->pdev;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+
+       data->get_temp = hi3660_thermal_get_temp;
+       data->enable_sensor = hi3660_thermal_enable_sensor;
+       data->disable_sensor = hi3660_thermal_disable_sensor;
+       data->irq_handler = hi3660_thermal_irq_handler;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(data->regs)) {
+               dev_err(dev, "failed to get io address\n");
+               return PTR_ERR(data->regs);
+       }
 
-static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
+       data->irq = platform_get_irq(pdev, 0);
+       if (data->irq < 0)
+               return data->irq;
+
+       data->sensor.id = HI3660_DEFAULT_SENSOR;
+
+       return 0;
+}
+
+static int hisi_thermal_get_temp(void *__data, int *temp)
 {
-       struct hisi_thermal_data *data = dev;
+       struct hisi_thermal_data *data = __data;
+       struct hisi_thermal_sensor *sensor = &data->sensor;
 
-       disable_irq_nosync(irq);
-       data->irq_enabled = false;
+       *temp = data->get_temp(data);
 
-       return IRQ_WAKE_THREAD;
+       dev_dbg(&data->pdev->dev, "id=%d, temp=%d, thres=%d\n",
+               sensor->id, *temp, sensor->thres_temp);
+
+       return 0;
 }
 
+static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
+       .get_temp = hisi_thermal_get_temp,
+};
+
 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;
+       struct hisi_thermal_sensor *sensor = &data->sensor;
+       int temp = 0;
 
-       mutex_lock(&data->thermal_lock);
-       sensor = &data->sensors[data->irq_bind_sensor];
+       data->irq_handler(data);
 
-       dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
-                sensor->thres_temp / 1000);
-       mutex_unlock(&data->thermal_lock);
+       hisi_thermal_get_temp(data, &temp);
 
-       for (i = 0; i < HISI_MAX_SENSORS; i++) {
-               if (!data->sensors[i].tzd)
-                       continue;
+       if (temp >= sensor->thres_temp) {
+               dev_crit(&data->pdev->dev, "THERMAL ALARM: %d > %d\n",
+                        temp, sensor->thres_temp);
 
-               thermal_zone_device_update(data->sensors[i].tzd,
+               thermal_zone_device_update(data->sensor.tzd,
                                           THERMAL_EVENT_UNSPECIFIED);
+
+       } else {
+               dev_crit(&data->pdev->dev, "THERMAL ALARM stopped: %d < %d\n",
+                        temp, sensor->thres_temp);
        }
 
        return IRQ_HANDLED;
@@ -246,17 +474,14 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
 
 static int hisi_thermal_register_sensor(struct platform_device *pdev,
                                        struct hisi_thermal_data *data,
-                                       struct hisi_thermal_sensor *sensor,
-                                       int index)
+                                       struct hisi_thermal_sensor *sensor)
 {
        int ret, i;
        const struct thermal_trip *trip;
 
-       sensor->id = index;
-       sensor->thermal = data;
-
        sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
-                               sensor->id, sensor, &hisi_of_thermal_ops);
+                                                          sensor->id, data,
+                                                          &hisi_of_thermal_ops);
        if (IS_ERR(sensor->tzd)) {
                ret = PTR_ERR(sensor->tzd);
                sensor->tzd = NULL;
@@ -278,7 +503,14 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev,
 }
 
 static const struct of_device_id of_hisi_thermal_match[] = {
-       { .compatible = "hisilicon,tsensor" },
+       {
+               .compatible = "hisilicon,tsensor",
+               .data = hi6220_thermal_probe
+       },
+       {
+               .compatible = "hisilicon,hi3660-tsensor",
+               .data = hi3660_thermal_probe
+       },
        { /* end */ }
 };
 MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
@@ -295,88 +527,63 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
 static int hisi_thermal_probe(struct platform_device *pdev)
 {
        struct hisi_thermal_data *data;
-       struct resource *res;
-       int i;
+       int const (*platform_probe)(struct hisi_thermal_data *);
+       struct device *dev = &pdev->dev;
        int ret;
 
-       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       mutex_init(&data->thermal_lock);
        data->pdev = pdev;
+       platform_set_drvdata(pdev, data);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(data->regs)) {
-               dev_err(&pdev->dev, "failed to get io address\n");
-               return PTR_ERR(data->regs);
+       platform_probe = of_device_get_match_data(dev);
+       if (!platform_probe) {
+               dev_err(dev, "failed to get probe func\n");
+               return -EINVAL;
        }
 
-       data->irq = platform_get_irq(pdev, 0);
-       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);
+       ret = platform_probe(data);
+       if (ret)
                return ret;
-       }
 
-       platform_set_drvdata(pdev, data);
-
-       data->clk = devm_clk_get(&pdev->dev, "thermal_clk");
-       if (IS_ERR(data->clk)) {
-               ret = PTR_ERR(data->clk);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev,
-                               "failed to get thermal clk: %d\n", ret);
+       ret = hisi_thermal_register_sensor(pdev, data,
+                                          &data->sensor);
+       if (ret) {
+               dev_err(dev, "failed to register thermal sensor: %d\n", ret);
                return ret;
        }
 
-       /* enable clock for thermal */
-       ret = clk_prepare_enable(data->clk);
+       ret = data->enable_sensor(data);
        if (ret) {
-               dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
+               dev_err(dev, "Failed to setup the sensor: %d\n", ret);
                return ret;
        }
 
-       hisi_thermal_enable_bind_irq_sensor(data);
-       irq_get_irqchip_state(data->irq, IRQCHIP_STATE_MASKED,
-                             &data->irq_enabled);
-
-       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);
+       if (data->irq) {
+               ret = devm_request_threaded_irq(dev, data->irq, NULL,
+                               hisi_thermal_alarm_irq_thread,
+                               IRQF_ONESHOT, "hisi_thermal", data);
+               if (ret < 0) {
+                       dev_err(dev, "failed to request alarm irq: %d\n", ret);
+                       return ret;
+               }
        }
 
+       hisi_thermal_toggle_sensor(&data->sensor, true);
+
        return 0;
 }
 
 static int hisi_thermal_remove(struct platform_device *pdev)
 {
        struct hisi_thermal_data *data = platform_get_drvdata(pdev);
-       int i;
+       struct hisi_thermal_sensor *sensor = &data->sensor;
 
-       for (i = 0; i < HISI_MAX_SENSORS; i++) {
-               struct hisi_thermal_sensor *sensor = &data->sensors[i];
+       hisi_thermal_toggle_sensor(sensor, false);
 
-               if (!sensor->tzd)
-                       continue;
-
-               hisi_thermal_toggle_sensor(sensor, false);
-       }
-
-       hisi_thermal_disable_sensor(data);
-       clk_disable_unprepare(data->clk);
+       data->disable_sensor(data);
 
        return 0;
 }
@@ -386,10 +593,7 @@ static int hisi_thermal_suspend(struct device *dev)
 {
        struct hisi_thermal_data *data = dev_get_drvdata(dev);
 
-       hisi_thermal_disable_sensor(data);
-       data->irq_enabled = false;
-
-       clk_disable_unprepare(data->clk);
+       data->disable_sensor(data);
 
        return 0;
 }
@@ -397,16 +601,8 @@ static int hisi_thermal_suspend(struct device *dev)
 static int hisi_thermal_resume(struct device *dev)
 {
        struct hisi_thermal_data *data = dev_get_drvdata(dev);
-       int ret;
 
-       ret = clk_prepare_enable(data->clk);
-       if (ret)
-               return ret;
-
-       data->irq_enabled = true;
-       hisi_thermal_enable_bind_irq_sensor(data);
-
-       return 0;
+       return data->enable_sensor(data);
 }
 #endif