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"
16 /* The Thermal Framework expects millidegrees */
17 #define mcelsius(temp) ((temp) * 1000)
20 * Function to allocate regfields which are common
21 * between syscfg and memory mapped based sensors
23 static int st_thermal_alloc_regfields(struct st_thermal_sensor
*sensor
)
25 struct device
*dev
= sensor
->dev
;
26 struct regmap
*regmap
= sensor
->regmap
;
27 const struct reg_field
*reg_fields
= sensor
->cdata
->reg_fields
;
29 sensor
->dcorrect
= devm_regmap_field_alloc(dev
, regmap
,
30 reg_fields
[DCORRECT
]);
32 sensor
->overflow
= devm_regmap_field_alloc(dev
, regmap
,
33 reg_fields
[OVERFLOW
]);
35 sensor
->temp_data
= devm_regmap_field_alloc(dev
, regmap
,
38 if (IS_ERR(sensor
->dcorrect
) ||
39 IS_ERR(sensor
->overflow
) ||
40 IS_ERR(sensor
->temp_data
)) {
41 dev_err(dev
, "failed to allocate common regfields\n");
45 return sensor
->ops
->alloc_regfields(sensor
);
48 static int st_thermal_sensor_on(struct st_thermal_sensor
*sensor
)
51 struct device
*dev
= sensor
->dev
;
53 ret
= clk_prepare_enable(sensor
->clk
);
55 dev_err(dev
, "failed to enable clk\n");
59 ret
= sensor
->ops
->power_ctrl(sensor
, POWER_ON
);
61 dev_err(dev
, "failed to power on sensor\n");
62 clk_disable_unprepare(sensor
->clk
);
68 static int st_thermal_sensor_off(struct st_thermal_sensor
*sensor
)
72 ret
= sensor
->ops
->power_ctrl(sensor
, POWER_OFF
);
76 clk_disable_unprepare(sensor
->clk
);
81 static int st_thermal_calibration(struct st_thermal_sensor
*sensor
)
85 struct device
*dev
= sensor
->dev
;
87 /* Check if sensor calibration data is already written */
88 ret
= regmap_field_read(sensor
->dcorrect
, &val
);
90 dev_err(dev
, "failed to read calibration data\n");
96 * Sensor calibration value not set by bootloader,
97 * default calibration data to be used
99 ret
= regmap_field_write(sensor
->dcorrect
,
100 sensor
->cdata
->calibration_val
);
102 dev_err(dev
, "failed to set calibration data\n");
108 /* Callback to get temperature from HW*/
109 static int st_thermal_get_temp(struct thermal_zone_device
*th
, int *temperature
)
111 struct st_thermal_sensor
*sensor
= th
->devdata
;
112 struct device
*dev
= sensor
->dev
;
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
);
130 dev_dbg(dev
, "temperature: %d\n", temp
);
137 static int st_thermal_get_trip_type(struct thermal_zone_device
*th
,
138 int trip
, enum thermal_trip_type
*type
)
140 struct st_thermal_sensor
*sensor
= th
->devdata
;
141 struct device
*dev
= sensor
->dev
;
145 *type
= THERMAL_TRIP_CRITICAL
;
148 dev_err(dev
, "invalid trip point\n");
155 static int st_thermal_get_trip_temp(struct thermal_zone_device
*th
,
158 struct st_thermal_sensor
*sensor
= th
->devdata
;
159 struct device
*dev
= sensor
->dev
;
163 *temp
= mcelsius(sensor
->cdata
->crit_temp
);
166 dev_err(dev
, "Invalid trip point\n");
173 static struct thermal_zone_device_ops st_tz_ops
= {
174 .get_temp
= st_thermal_get_temp
,
175 .get_trip_type
= st_thermal_get_trip_type
,
176 .get_trip_temp
= st_thermal_get_trip_temp
,
179 int st_thermal_register(struct platform_device
*pdev
,
180 const struct of_device_id
*st_thermal_of_match
)
182 struct st_thermal_sensor
*sensor
;
183 struct device
*dev
= &pdev
->dev
;
184 struct device_node
*np
= dev
->of_node
;
185 const struct of_device_id
*match
;
191 dev_err(dev
, "device tree node not found\n");
195 sensor
= devm_kzalloc(dev
, sizeof(*sensor
), GFP_KERNEL
);
201 match
= of_match_device(st_thermal_of_match
, dev
);
202 if (!(match
&& match
->data
))
205 sensor
->cdata
= match
->data
;
206 if (!sensor
->cdata
->ops
)
209 sensor
->ops
= sensor
->cdata
->ops
;
211 ret
= (sensor
->ops
->regmap_init
)(sensor
);
215 ret
= st_thermal_alloc_regfields(sensor
);
219 sensor
->clk
= devm_clk_get(dev
, "thermal");
220 if (IS_ERR(sensor
->clk
)) {
221 dev_err(dev
, "failed to fetch clock\n");
222 return PTR_ERR(sensor
->clk
);
225 if (sensor
->ops
->register_enable_irq
) {
226 ret
= sensor
->ops
->register_enable_irq(sensor
);
231 ret
= st_thermal_sensor_on(sensor
);
235 ret
= st_thermal_calibration(sensor
);
239 polling_delay
= sensor
->ops
->register_enable_irq
? 0 : 1000;
241 sensor
->thermal_dev
=
242 thermal_zone_device_register(dev_name(dev
), 1, 0, sensor
,
243 &st_tz_ops
, NULL
, 0, polling_delay
);
244 if (IS_ERR(sensor
->thermal_dev
)) {
245 dev_err(dev
, "failed to register thermal zone device\n");
246 ret
= PTR_ERR(sensor
->thermal_dev
);
250 platform_set_drvdata(pdev
, sensor
);
255 st_thermal_sensor_off(sensor
);
259 EXPORT_SYMBOL_GPL(st_thermal_register
);
261 int st_thermal_unregister(struct platform_device
*pdev
)
263 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
265 st_thermal_sensor_off(sensor
);
266 thermal_zone_device_unregister(sensor
->thermal_dev
);
270 EXPORT_SYMBOL_GPL(st_thermal_unregister
);
272 #ifdef CONFIG_PM_SLEEP
273 static int st_thermal_suspend(struct device
*dev
)
275 struct st_thermal_sensor
*sensor
= dev_get_drvdata(dev
);
277 return st_thermal_sensor_off(sensor
);
280 static int st_thermal_resume(struct device
*dev
)
283 struct st_thermal_sensor
*sensor
= dev_get_drvdata(dev
);
285 ret
= st_thermal_sensor_on(sensor
);
289 ret
= st_thermal_calibration(sensor
);
293 if (sensor
->ops
->enable_irq
) {
294 ret
= sensor
->ops
->enable_irq(sensor
);
303 SIMPLE_DEV_PM_OPS(st_thermal_pm_ops
, st_thermal_suspend
, st_thermal_resume
);
304 EXPORT_SYMBOL_GPL(st_thermal_pm_ops
);
306 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
307 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
308 MODULE_LICENSE("GPL v2");