1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * ST Thermal Sensor Driver core routines
4 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
6 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
10 #include <linux/module.h>
12 #include <linux/of_device.h>
14 #include "st_thermal.h"
15 #include "../thermal_hwmon.h"
17 /* The Thermal Framework expects millidegrees */
18 #define mcelsius(temp) ((temp) * 1000)
21 * Function to allocate regfields which are common
22 * between syscfg and memory mapped based sensors
24 static int st_thermal_alloc_regfields(struct st_thermal_sensor
*sensor
)
26 struct device
*dev
= sensor
->dev
;
27 struct regmap
*regmap
= sensor
->regmap
;
28 const struct reg_field
*reg_fields
= sensor
->cdata
->reg_fields
;
30 sensor
->dcorrect
= devm_regmap_field_alloc(dev
, regmap
,
31 reg_fields
[DCORRECT
]);
33 sensor
->overflow
= devm_regmap_field_alloc(dev
, regmap
,
34 reg_fields
[OVERFLOW
]);
36 sensor
->temp_data
= devm_regmap_field_alloc(dev
, regmap
,
39 if (IS_ERR(sensor
->dcorrect
) ||
40 IS_ERR(sensor
->overflow
) ||
41 IS_ERR(sensor
->temp_data
)) {
42 dev_err(dev
, "failed to allocate common regfields\n");
46 return sensor
->ops
->alloc_regfields(sensor
);
49 static int st_thermal_sensor_on(struct st_thermal_sensor
*sensor
)
52 struct device
*dev
= sensor
->dev
;
54 ret
= clk_prepare_enable(sensor
->clk
);
56 dev_err(dev
, "failed to enable clk\n");
60 ret
= sensor
->ops
->power_ctrl(sensor
, POWER_ON
);
62 dev_err(dev
, "failed to power on sensor\n");
63 clk_disable_unprepare(sensor
->clk
);
69 static int st_thermal_sensor_off(struct st_thermal_sensor
*sensor
)
73 ret
= sensor
->ops
->power_ctrl(sensor
, POWER_OFF
);
77 clk_disable_unprepare(sensor
->clk
);
82 static int st_thermal_calibration(struct st_thermal_sensor
*sensor
)
86 struct device
*dev
= sensor
->dev
;
88 /* Check if sensor calibration data is already written */
89 ret
= regmap_field_read(sensor
->dcorrect
, &val
);
91 dev_err(dev
, "failed to read calibration data\n");
97 * Sensor calibration value not set by bootloader,
98 * default calibration data to be used
100 ret
= regmap_field_write(sensor
->dcorrect
,
101 sensor
->cdata
->calibration_val
);
103 dev_err(dev
, "failed to set calibration data\n");
109 /* Callback to get temperature from HW*/
110 static int st_thermal_get_temp(struct thermal_zone_device
*th
, int *temperature
)
112 struct st_thermal_sensor
*sensor
= thermal_zone_device_priv(th
);
114 unsigned int overflow
;
117 ret
= regmap_field_read(sensor
->overflow
, &overflow
);
123 ret
= regmap_field_read(sensor
->temp_data
, &temp
);
127 temp
+= sensor
->cdata
->temp_adjust_val
;
128 temp
= mcelsius(temp
);
135 static struct thermal_zone_device_ops st_tz_ops
= {
136 .get_temp
= st_thermal_get_temp
,
139 int st_thermal_register(struct platform_device
*pdev
,
140 const struct of_device_id
*st_thermal_of_match
)
142 struct st_thermal_sensor
*sensor
;
143 struct device
*dev
= &pdev
->dev
;
144 struct device_node
*np
= dev
->of_node
;
145 const struct of_device_id
*match
;
150 dev_err(dev
, "device tree node not found\n");
154 sensor
= devm_kzalloc(dev
, sizeof(*sensor
), GFP_KERNEL
);
160 match
= of_match_device(st_thermal_of_match
, dev
);
161 if (!(match
&& match
->data
))
164 sensor
->cdata
= match
->data
;
165 if (!sensor
->cdata
->ops
)
168 sensor
->ops
= sensor
->cdata
->ops
;
170 ret
= (sensor
->ops
->regmap_init
)(sensor
);
174 ret
= st_thermal_alloc_regfields(sensor
);
178 sensor
->clk
= devm_clk_get(dev
, "thermal");
179 if (IS_ERR(sensor
->clk
)) {
180 dev_err(dev
, "failed to fetch clock\n");
181 return PTR_ERR(sensor
->clk
);
184 if (sensor
->ops
->register_enable_irq
) {
185 ret
= sensor
->ops
->register_enable_irq(sensor
);
190 ret
= st_thermal_sensor_on(sensor
);
194 ret
= st_thermal_calibration(sensor
);
198 sensor
->thermal_dev
=
199 devm_thermal_of_zone_register(dev
, 0, sensor
, &st_tz_ops
);
200 if (IS_ERR(sensor
->thermal_dev
)) {
201 dev_err(dev
, "failed to register thermal of zone\n");
202 ret
= PTR_ERR(sensor
->thermal_dev
);
206 platform_set_drvdata(pdev
, sensor
);
209 * devm_thermal_of_zone_register() doesn't enable hwmon by default
212 devm_thermal_add_hwmon_sysfs(dev
, sensor
->thermal_dev
);
217 st_thermal_sensor_off(sensor
);
221 EXPORT_SYMBOL_GPL(st_thermal_register
);
223 void st_thermal_unregister(struct platform_device
*pdev
)
225 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
227 st_thermal_sensor_off(sensor
);
228 thermal_remove_hwmon_sysfs(sensor
->thermal_dev
);
229 devm_thermal_of_zone_unregister(sensor
->dev
, sensor
->thermal_dev
);
231 EXPORT_SYMBOL_GPL(st_thermal_unregister
);
233 static int st_thermal_suspend(struct device
*dev
)
235 struct st_thermal_sensor
*sensor
= dev_get_drvdata(dev
);
237 return st_thermal_sensor_off(sensor
);
240 static int st_thermal_resume(struct device
*dev
)
243 struct st_thermal_sensor
*sensor
= dev_get_drvdata(dev
);
245 ret
= st_thermal_sensor_on(sensor
);
249 ret
= st_thermal_calibration(sensor
);
253 if (sensor
->ops
->enable_irq
) {
254 ret
= sensor
->ops
->enable_irq(sensor
);
262 DEFINE_SIMPLE_DEV_PM_OPS(st_thermal_pm_ops
, st_thermal_suspend
, st_thermal_resume
);
263 EXPORT_SYMBOL_GPL(st_thermal_pm_ops
);
265 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
266 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
267 MODULE_LICENSE("GPL v2");