2 * ST Thermal Sensor Driver core routines
3 * Author: Ajit Pal Singh <ajitpal.singh@st.com>
5 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
14 #include <linux/clk.h>
15 #include <linux/module.h>
17 #include <linux/of_device.h>
19 #include "st_thermal.h"
21 /* The Thermal Framework expects millidegrees */
22 #define mcelsius(temp) ((temp) * 1000)
25 * Function to allocate regfields which are common
26 * between syscfg and memory mapped based sensors
28 static int st_thermal_alloc_regfields(struct st_thermal_sensor
*sensor
)
30 struct device
*dev
= sensor
->dev
;
31 struct regmap
*regmap
= sensor
->regmap
;
32 const struct reg_field
*reg_fields
= sensor
->cdata
->reg_fields
;
34 sensor
->dcorrect
= devm_regmap_field_alloc(dev
, regmap
,
35 reg_fields
[DCORRECT
]);
37 sensor
->overflow
= devm_regmap_field_alloc(dev
, regmap
,
38 reg_fields
[OVERFLOW
]);
40 sensor
->temp_data
= devm_regmap_field_alloc(dev
, regmap
,
43 if (IS_ERR(sensor
->dcorrect
) ||
44 IS_ERR(sensor
->overflow
) ||
45 IS_ERR(sensor
->temp_data
)) {
46 dev_err(dev
, "failed to allocate common regfields\n");
50 return sensor
->ops
->alloc_regfields(sensor
);
53 static int st_thermal_sensor_on(struct st_thermal_sensor
*sensor
)
56 struct device
*dev
= sensor
->dev
;
58 ret
= clk_prepare_enable(sensor
->clk
);
60 dev_err(dev
, "failed to enable clk\n");
64 ret
= sensor
->ops
->power_ctrl(sensor
, POWER_ON
);
66 dev_err(dev
, "failed to power on sensor\n");
67 clk_disable_unprepare(sensor
->clk
);
73 static int st_thermal_sensor_off(struct st_thermal_sensor
*sensor
)
77 ret
= sensor
->ops
->power_ctrl(sensor
, POWER_OFF
);
81 clk_disable_unprepare(sensor
->clk
);
86 static int st_thermal_calibration(struct st_thermal_sensor
*sensor
)
90 struct device
*dev
= sensor
->dev
;
92 /* Check if sensor calibration data is already written */
93 ret
= regmap_field_read(sensor
->dcorrect
, &val
);
95 dev_err(dev
, "failed to read calibration data\n");
101 * Sensor calibration value not set by bootloader,
102 * default calibration data to be used
104 ret
= regmap_field_write(sensor
->dcorrect
,
105 sensor
->cdata
->calibration_val
);
107 dev_err(dev
, "failed to set calibration data\n");
113 /* Callback to get temperature from HW*/
114 static int st_thermal_get_temp(struct thermal_zone_device
*th
, int *temperature
)
116 struct st_thermal_sensor
*sensor
= th
->devdata
;
117 struct device
*dev
= sensor
->dev
;
119 unsigned int overflow
;
122 ret
= regmap_field_read(sensor
->overflow
, &overflow
);
128 ret
= regmap_field_read(sensor
->temp_data
, &temp
);
132 temp
+= sensor
->cdata
->temp_adjust_val
;
133 temp
= mcelsius(temp
);
135 dev_dbg(dev
, "temperature: %d\n", temp
);
142 static int st_thermal_get_trip_type(struct thermal_zone_device
*th
,
143 int trip
, enum thermal_trip_type
*type
)
145 struct st_thermal_sensor
*sensor
= th
->devdata
;
146 struct device
*dev
= sensor
->dev
;
150 *type
= THERMAL_TRIP_CRITICAL
;
153 dev_err(dev
, "invalid trip point\n");
160 static int st_thermal_get_trip_temp(struct thermal_zone_device
*th
,
163 struct st_thermal_sensor
*sensor
= th
->devdata
;
164 struct device
*dev
= sensor
->dev
;
168 *temp
= mcelsius(sensor
->cdata
->crit_temp
);
171 dev_err(dev
, "Invalid trip point\n");
178 static struct thermal_zone_device_ops st_tz_ops
= {
179 .get_temp
= st_thermal_get_temp
,
180 .get_trip_type
= st_thermal_get_trip_type
,
181 .get_trip_temp
= st_thermal_get_trip_temp
,
184 int st_thermal_register(struct platform_device
*pdev
,
185 const struct of_device_id
*st_thermal_of_match
)
187 struct st_thermal_sensor
*sensor
;
188 struct device
*dev
= &pdev
->dev
;
189 struct device_node
*np
= dev
->of_node
;
190 const struct of_device_id
*match
;
196 dev_err(dev
, "device tree node not found\n");
200 sensor
= devm_kzalloc(dev
, sizeof(*sensor
), GFP_KERNEL
);
206 match
= of_match_device(st_thermal_of_match
, dev
);
207 if (!(match
&& match
->data
))
210 sensor
->cdata
= match
->data
;
211 if (!sensor
->cdata
->ops
)
214 sensor
->ops
= sensor
->cdata
->ops
;
216 ret
= (sensor
->ops
->regmap_init
)(sensor
);
220 ret
= st_thermal_alloc_regfields(sensor
);
224 sensor
->clk
= devm_clk_get(dev
, "thermal");
225 if (IS_ERR(sensor
->clk
)) {
226 dev_err(dev
, "failed to fetch clock\n");
227 return PTR_ERR(sensor
->clk
);
230 if (sensor
->ops
->register_enable_irq
) {
231 ret
= sensor
->ops
->register_enable_irq(sensor
);
236 ret
= st_thermal_sensor_on(sensor
);
240 ret
= st_thermal_calibration(sensor
);
244 polling_delay
= sensor
->ops
->register_enable_irq
? 0 : 1000;
246 sensor
->thermal_dev
=
247 thermal_zone_device_register(dev_name(dev
), 1, 0, sensor
,
248 &st_tz_ops
, NULL
, 0, polling_delay
);
249 if (IS_ERR(sensor
->thermal_dev
)) {
250 dev_err(dev
, "failed to register thermal zone device\n");
251 ret
= PTR_ERR(sensor
->thermal_dev
);
255 platform_set_drvdata(pdev
, sensor
);
260 st_thermal_sensor_off(sensor
);
264 EXPORT_SYMBOL_GPL(st_thermal_register
);
266 int st_thermal_unregister(struct platform_device
*pdev
)
268 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
270 st_thermal_sensor_off(sensor
);
271 thermal_zone_device_unregister(sensor
->thermal_dev
);
275 EXPORT_SYMBOL_GPL(st_thermal_unregister
);
277 #ifdef CONFIG_PM_SLEEP
278 static int st_thermal_suspend(struct device
*dev
)
280 struct platform_device
*pdev
= to_platform_device(dev
);
281 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
283 return st_thermal_sensor_off(sensor
);
286 static int st_thermal_resume(struct device
*dev
)
289 struct platform_device
*pdev
= to_platform_device(dev
);
290 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
292 ret
= st_thermal_sensor_on(sensor
);
296 ret
= st_thermal_calibration(sensor
);
300 if (sensor
->ops
->enable_irq
) {
301 ret
= sensor
->ops
->enable_irq(sensor
);
310 SIMPLE_DEV_PM_OPS(st_thermal_pm_ops
, st_thermal_suspend
, st_thermal_resume
);
311 EXPORT_SYMBOL_GPL(st_thermal_pm_ops
);
313 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
314 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
315 MODULE_LICENSE("GPL v2");