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
,
115 unsigned long *temperature
)
117 struct st_thermal_sensor
*sensor
= th
->devdata
;
118 struct device
*dev
= sensor
->dev
;
120 unsigned int overflow
;
123 ret
= regmap_field_read(sensor
->overflow
, &overflow
);
129 ret
= regmap_field_read(sensor
->temp_data
, &temp
);
133 temp
+= sensor
->cdata
->temp_adjust_val
;
134 temp
= mcelsius(temp
);
136 dev_dbg(dev
, "temperature: %d\n", temp
);
143 static int st_thermal_get_trip_type(struct thermal_zone_device
*th
,
144 int trip
, enum thermal_trip_type
*type
)
146 struct st_thermal_sensor
*sensor
= th
->devdata
;
147 struct device
*dev
= sensor
->dev
;
151 *type
= THERMAL_TRIP_CRITICAL
;
154 dev_err(dev
, "invalid trip point\n");
161 static int st_thermal_get_trip_temp(struct thermal_zone_device
*th
,
162 int trip
, unsigned long *temp
)
164 struct st_thermal_sensor
*sensor
= th
->devdata
;
165 struct device
*dev
= sensor
->dev
;
169 *temp
= mcelsius(sensor
->cdata
->crit_temp
);
172 dev_err(dev
, "Invalid trip point\n");
179 static struct thermal_zone_device_ops st_tz_ops
= {
180 .get_temp
= st_thermal_get_temp
,
181 .get_trip_type
= st_thermal_get_trip_type
,
182 .get_trip_temp
= st_thermal_get_trip_temp
,
185 int st_thermal_register(struct platform_device
*pdev
,
186 const struct of_device_id
*st_thermal_of_match
)
188 struct st_thermal_sensor
*sensor
;
189 struct device
*dev
= &pdev
->dev
;
190 struct device_node
*np
= dev
->of_node
;
191 const struct of_device_id
*match
;
197 dev_err(dev
, "device tree node not found\n");
201 sensor
= devm_kzalloc(dev
, sizeof(*sensor
), GFP_KERNEL
);
207 match
= of_match_device(st_thermal_of_match
, dev
);
208 if (!(match
&& match
->data
))
211 sensor
->cdata
= match
->data
;
212 if (!sensor
->cdata
->ops
)
215 sensor
->ops
= sensor
->cdata
->ops
;
217 ret
= sensor
->ops
->regmap_init(sensor
);
221 ret
= st_thermal_alloc_regfields(sensor
);
225 sensor
->clk
= devm_clk_get(dev
, "thermal");
226 if (IS_ERR(sensor
->clk
)) {
227 dev_err(dev
, "failed to fetch clock\n");
228 return PTR_ERR(sensor
->clk
);
231 if (sensor
->ops
->register_enable_irq
) {
232 ret
= sensor
->ops
->register_enable_irq(sensor
);
237 ret
= st_thermal_sensor_on(sensor
);
241 ret
= st_thermal_calibration(sensor
);
245 polling_delay
= sensor
->ops
->register_enable_irq
? 0 : 1000;
247 sensor
->thermal_dev
=
248 thermal_zone_device_register(dev_name(dev
), 1, 0, sensor
,
249 &st_tz_ops
, NULL
, 0, polling_delay
);
250 if (IS_ERR(sensor
->thermal_dev
)) {
251 dev_err(dev
, "failed to register thermal zone device\n");
252 ret
= PTR_ERR(sensor
->thermal_dev
);
256 platform_set_drvdata(pdev
, sensor
);
261 st_thermal_sensor_off(sensor
);
265 EXPORT_SYMBOL_GPL(st_thermal_register
);
267 int st_thermal_unregister(struct platform_device
*pdev
)
269 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
271 st_thermal_sensor_off(sensor
);
272 thermal_zone_device_unregister(sensor
->thermal_dev
);
276 EXPORT_SYMBOL_GPL(st_thermal_unregister
);
278 #ifdef CONFIG_PM_SLEEP
279 static int st_thermal_suspend(struct device
*dev
)
281 struct platform_device
*pdev
= to_platform_device(dev
);
282 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
284 return st_thermal_sensor_off(sensor
);
287 static int st_thermal_resume(struct device
*dev
)
290 struct platform_device
*pdev
= to_platform_device(dev
);
291 struct st_thermal_sensor
*sensor
= platform_get_drvdata(pdev
);
293 ret
= st_thermal_sensor_on(sensor
);
297 ret
= st_thermal_calibration(sensor
);
301 if (sensor
->ops
->enable_irq
) {
302 ret
= sensor
->ops
->enable_irq(sensor
);
311 SIMPLE_DEV_PM_OPS(st_thermal_pm_ops
, st_thermal_suspend
, st_thermal_resume
);
312 EXPORT_SYMBOL_GPL(st_thermal_pm_ops
);
314 MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
315 MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
316 MODULE_LICENSE("GPL v2");