xref: /OK3568_Linux_fs/kernel/drivers/thermal/st/st_thermal.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ST Thermal Sensor Driver core routines
4*4882a593Smuzhiyun  * Author: Ajit Pal Singh <ajitpal.singh@st.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/clk.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/of_device.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "st_thermal.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /* The Thermal Framework expects millidegrees */
17*4882a593Smuzhiyun #define mcelsius(temp)			((temp) * 1000)
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun  * Function to allocate regfields which are common
21*4882a593Smuzhiyun  * between syscfg and memory mapped based sensors
22*4882a593Smuzhiyun  */
st_thermal_alloc_regfields(struct st_thermal_sensor * sensor)23*4882a593Smuzhiyun static int st_thermal_alloc_regfields(struct st_thermal_sensor *sensor)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	struct device *dev = sensor->dev;
26*4882a593Smuzhiyun 	struct regmap *regmap = sensor->regmap;
27*4882a593Smuzhiyun 	const struct reg_field *reg_fields = sensor->cdata->reg_fields;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	sensor->dcorrect = devm_regmap_field_alloc(dev, regmap,
30*4882a593Smuzhiyun 						   reg_fields[DCORRECT]);
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	sensor->overflow = devm_regmap_field_alloc(dev, regmap,
33*4882a593Smuzhiyun 						   reg_fields[OVERFLOW]);
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	sensor->temp_data = devm_regmap_field_alloc(dev, regmap,
36*4882a593Smuzhiyun 						    reg_fields[DATA]);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	if (IS_ERR(sensor->dcorrect) ||
39*4882a593Smuzhiyun 	    IS_ERR(sensor->overflow) ||
40*4882a593Smuzhiyun 	    IS_ERR(sensor->temp_data)) {
41*4882a593Smuzhiyun 		dev_err(dev, "failed to allocate common regfields\n");
42*4882a593Smuzhiyun 		return -EINVAL;
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	return sensor->ops->alloc_regfields(sensor);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
st_thermal_sensor_on(struct st_thermal_sensor * sensor)48*4882a593Smuzhiyun static int st_thermal_sensor_on(struct st_thermal_sensor *sensor)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	int ret;
51*4882a593Smuzhiyun 	struct device *dev = sensor->dev;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	ret = clk_prepare_enable(sensor->clk);
54*4882a593Smuzhiyun 	if (ret) {
55*4882a593Smuzhiyun 		dev_err(dev, "failed to enable clk\n");
56*4882a593Smuzhiyun 		return ret;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	ret = sensor->ops->power_ctrl(sensor, POWER_ON);
60*4882a593Smuzhiyun 	if (ret) {
61*4882a593Smuzhiyun 		dev_err(dev, "failed to power on sensor\n");
62*4882a593Smuzhiyun 		clk_disable_unprepare(sensor->clk);
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	return ret;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
st_thermal_sensor_off(struct st_thermal_sensor * sensor)68*4882a593Smuzhiyun static int st_thermal_sensor_off(struct st_thermal_sensor *sensor)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	int ret;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	ret = sensor->ops->power_ctrl(sensor, POWER_OFF);
73*4882a593Smuzhiyun 	if (ret)
74*4882a593Smuzhiyun 		return ret;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	clk_disable_unprepare(sensor->clk);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	return 0;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
st_thermal_calibration(struct st_thermal_sensor * sensor)81*4882a593Smuzhiyun static int st_thermal_calibration(struct st_thermal_sensor *sensor)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	int ret;
84*4882a593Smuzhiyun 	unsigned int val;
85*4882a593Smuzhiyun 	struct device *dev = sensor->dev;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/* Check if sensor calibration data is already written */
88*4882a593Smuzhiyun 	ret = regmap_field_read(sensor->dcorrect, &val);
89*4882a593Smuzhiyun 	if (ret) {
90*4882a593Smuzhiyun 		dev_err(dev, "failed to read calibration data\n");
91*4882a593Smuzhiyun 		return ret;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (!val) {
95*4882a593Smuzhiyun 		/*
96*4882a593Smuzhiyun 		 * Sensor calibration value not set by bootloader,
97*4882a593Smuzhiyun 		 * default calibration data to be used
98*4882a593Smuzhiyun 		 */
99*4882a593Smuzhiyun 		ret = regmap_field_write(sensor->dcorrect,
100*4882a593Smuzhiyun 					 sensor->cdata->calibration_val);
101*4882a593Smuzhiyun 		if (ret)
102*4882a593Smuzhiyun 			dev_err(dev, "failed to set calibration data\n");
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	return ret;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /* Callback to get temperature from HW*/
st_thermal_get_temp(struct thermal_zone_device * th,int * temperature)109*4882a593Smuzhiyun static int st_thermal_get_temp(struct thermal_zone_device *th, int *temperature)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct st_thermal_sensor *sensor = th->devdata;
112*4882a593Smuzhiyun 	struct device *dev = sensor->dev;
113*4882a593Smuzhiyun 	unsigned int temp;
114*4882a593Smuzhiyun 	unsigned int overflow;
115*4882a593Smuzhiyun 	int ret;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	ret = regmap_field_read(sensor->overflow, &overflow);
118*4882a593Smuzhiyun 	if (ret)
119*4882a593Smuzhiyun 		return ret;
120*4882a593Smuzhiyun 	if (overflow)
121*4882a593Smuzhiyun 		return -EIO;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	ret = regmap_field_read(sensor->temp_data, &temp);
124*4882a593Smuzhiyun 	if (ret)
125*4882a593Smuzhiyun 		return ret;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	temp += sensor->cdata->temp_adjust_val;
128*4882a593Smuzhiyun 	temp = mcelsius(temp);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	dev_dbg(dev, "temperature: %d\n", temp);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	*temperature = temp;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return 0;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
st_thermal_get_trip_type(struct thermal_zone_device * th,int trip,enum thermal_trip_type * type)137*4882a593Smuzhiyun static int st_thermal_get_trip_type(struct thermal_zone_device *th,
138*4882a593Smuzhiyun 				int trip, enum thermal_trip_type *type)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct st_thermal_sensor *sensor = th->devdata;
141*4882a593Smuzhiyun 	struct device *dev = sensor->dev;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	switch (trip) {
144*4882a593Smuzhiyun 	case 0:
145*4882a593Smuzhiyun 		*type = THERMAL_TRIP_CRITICAL;
146*4882a593Smuzhiyun 		break;
147*4882a593Smuzhiyun 	default:
148*4882a593Smuzhiyun 		dev_err(dev, "invalid trip point\n");
149*4882a593Smuzhiyun 		return -EINVAL;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
st_thermal_get_trip_temp(struct thermal_zone_device * th,int trip,int * temp)155*4882a593Smuzhiyun static int st_thermal_get_trip_temp(struct thermal_zone_device *th,
156*4882a593Smuzhiyun 				    int trip, int *temp)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct st_thermal_sensor *sensor = th->devdata;
159*4882a593Smuzhiyun 	struct device *dev = sensor->dev;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	switch (trip) {
162*4882a593Smuzhiyun 	case 0:
163*4882a593Smuzhiyun 		*temp = mcelsius(sensor->cdata->crit_temp);
164*4882a593Smuzhiyun 		break;
165*4882a593Smuzhiyun 	default:
166*4882a593Smuzhiyun 		dev_err(dev, "Invalid trip point\n");
167*4882a593Smuzhiyun 		return -EINVAL;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	return 0;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static struct thermal_zone_device_ops st_tz_ops = {
174*4882a593Smuzhiyun 	.get_temp	= st_thermal_get_temp,
175*4882a593Smuzhiyun 	.get_trip_type	= st_thermal_get_trip_type,
176*4882a593Smuzhiyun 	.get_trip_temp	= st_thermal_get_trip_temp,
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun 
st_thermal_register(struct platform_device * pdev,const struct of_device_id * st_thermal_of_match)179*4882a593Smuzhiyun int st_thermal_register(struct platform_device *pdev,
180*4882a593Smuzhiyun 			const struct of_device_id *st_thermal_of_match)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct st_thermal_sensor *sensor;
183*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
184*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
185*4882a593Smuzhiyun 	const struct of_device_id *match;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	int polling_delay;
188*4882a593Smuzhiyun 	int ret;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (!np) {
191*4882a593Smuzhiyun 		dev_err(dev, "device tree node not found\n");
192*4882a593Smuzhiyun 		return -EINVAL;
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
196*4882a593Smuzhiyun 	if (!sensor)
197*4882a593Smuzhiyun 		return -ENOMEM;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	sensor->dev = dev;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	match = of_match_device(st_thermal_of_match, dev);
202*4882a593Smuzhiyun 	if (!(match && match->data))
203*4882a593Smuzhiyun 		return -EINVAL;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	sensor->cdata = match->data;
206*4882a593Smuzhiyun 	if (!sensor->cdata->ops)
207*4882a593Smuzhiyun 		return -EINVAL;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	sensor->ops = sensor->cdata->ops;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	ret = (sensor->ops->regmap_init)(sensor);
212*4882a593Smuzhiyun 	if (ret)
213*4882a593Smuzhiyun 		return ret;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	ret = st_thermal_alloc_regfields(sensor);
216*4882a593Smuzhiyun 	if (ret)
217*4882a593Smuzhiyun 		return ret;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	sensor->clk = devm_clk_get(dev, "thermal");
220*4882a593Smuzhiyun 	if (IS_ERR(sensor->clk)) {
221*4882a593Smuzhiyun 		dev_err(dev, "failed to fetch clock\n");
222*4882a593Smuzhiyun 		return PTR_ERR(sensor->clk);
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	if (sensor->ops->register_enable_irq) {
226*4882a593Smuzhiyun 		ret = sensor->ops->register_enable_irq(sensor);
227*4882a593Smuzhiyun 		if (ret)
228*4882a593Smuzhiyun 			return ret;
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	ret = st_thermal_sensor_on(sensor);
232*4882a593Smuzhiyun 	if (ret)
233*4882a593Smuzhiyun 		return ret;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	ret = st_thermal_calibration(sensor);
236*4882a593Smuzhiyun 	if (ret)
237*4882a593Smuzhiyun 		goto sensor_off;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	polling_delay = sensor->ops->register_enable_irq ? 0 : 1000;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	sensor->thermal_dev =
242*4882a593Smuzhiyun 		thermal_zone_device_register(dev_name(dev), 1, 0, sensor,
243*4882a593Smuzhiyun 					     &st_tz_ops, NULL, 0, polling_delay);
244*4882a593Smuzhiyun 	if (IS_ERR(sensor->thermal_dev)) {
245*4882a593Smuzhiyun 		dev_err(dev, "failed to register thermal zone device\n");
246*4882a593Smuzhiyun 		ret = PTR_ERR(sensor->thermal_dev);
247*4882a593Smuzhiyun 		goto sensor_off;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 	ret = thermal_zone_device_enable(sensor->thermal_dev);
250*4882a593Smuzhiyun 	if (ret)
251*4882a593Smuzhiyun 		goto tzd_unregister;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	platform_set_drvdata(pdev, sensor);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return 0;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun tzd_unregister:
258*4882a593Smuzhiyun 	thermal_zone_device_unregister(sensor->thermal_dev);
259*4882a593Smuzhiyun sensor_off:
260*4882a593Smuzhiyun 	st_thermal_sensor_off(sensor);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	return ret;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(st_thermal_register);
265*4882a593Smuzhiyun 
st_thermal_unregister(struct platform_device * pdev)266*4882a593Smuzhiyun int st_thermal_unregister(struct platform_device *pdev)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	st_thermal_sensor_off(sensor);
271*4882a593Smuzhiyun 	thermal_zone_device_unregister(sensor->thermal_dev);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(st_thermal_unregister);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
st_thermal_suspend(struct device * dev)278*4882a593Smuzhiyun static int st_thermal_suspend(struct device *dev)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	struct st_thermal_sensor *sensor = dev_get_drvdata(dev);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	return st_thermal_sensor_off(sensor);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
st_thermal_resume(struct device * dev)285*4882a593Smuzhiyun static int st_thermal_resume(struct device *dev)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	int ret;
288*4882a593Smuzhiyun 	struct st_thermal_sensor *sensor = dev_get_drvdata(dev);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	ret = st_thermal_sensor_on(sensor);
291*4882a593Smuzhiyun 	if (ret)
292*4882a593Smuzhiyun 		return ret;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	ret = st_thermal_calibration(sensor);
295*4882a593Smuzhiyun 	if (ret)
296*4882a593Smuzhiyun 		return ret;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (sensor->ops->enable_irq) {
299*4882a593Smuzhiyun 		ret = sensor->ops->enable_irq(sensor);
300*4882a593Smuzhiyun 		if (ret)
301*4882a593Smuzhiyun 			return ret;
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun #endif
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
309*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(st_thermal_pm_ops);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
312*4882a593Smuzhiyun MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver");
313*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
314