1/*
2 * OMAP thermal driver interface
3 *
4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
5 * Contact:
6 *   Eduardo Valentin <eduardo.valentin@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/device.h>
25#include <linux/err.h>
26#include <linux/mutex.h>
27#include <linux/gfp.h>
28#include <linux/kernel.h>
29#include <linux/workqueue.h>
30#include <linux/thermal.h>
31#include <linux/cpumask.h>
32#include <linux/cpu_cooling.h>
33#include <linux/of.h>
34
35#include "ti-thermal.h"
36#include "ti-bandgap.h"
37
38/* common data structures */
39struct ti_thermal_data {
40	struct thermal_zone_device *ti_thermal;
41	struct thermal_zone_device *pcb_tz;
42	struct thermal_cooling_device *cool_dev;
43	struct ti_bandgap *bgp;
44	enum thermal_device_mode mode;
45	struct work_struct thermal_wq;
46	int sensor_id;
47	bool our_zone;
48};
49
50static void ti_thermal_work(struct work_struct *work)
51{
52	struct ti_thermal_data *data = container_of(work,
53					struct ti_thermal_data, thermal_wq);
54
55	thermal_zone_device_update(data->ti_thermal);
56
57	dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
58		data->ti_thermal->type);
59}
60
61/**
62 * ti_thermal_hotspot_temperature - returns sensor extrapolated temperature
63 * @t:	omap sensor temperature
64 * @s:	omap sensor slope value
65 * @c:	omap sensor const value
66 */
67static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
68{
69	int delta = t * s / 1000 + c;
70
71	if (delta < 0)
72		delta = 0;
73
74	return t + delta;
75}
76
77/* thermal zone ops */
78/* Get temperature callback function for thermal zone*/
79static inline int __ti_thermal_get_temp(void *devdata, long *temp)
80{
81	struct thermal_zone_device *pcb_tz = NULL;
82	struct ti_thermal_data *data = devdata;
83	struct ti_bandgap *bgp;
84	const struct ti_temp_sensor *s;
85	int ret, tmp, slope, constant;
86	unsigned long pcb_temp;
87
88	if (!data)
89		return 0;
90
91	bgp = data->bgp;
92	s = &bgp->conf->sensors[data->sensor_id];
93
94	ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp);
95	if (ret)
96		return ret;
97
98	/* Default constants */
99	slope = s->slope;
100	constant = s->constant;
101
102	pcb_tz = data->pcb_tz;
103	/* In case pcb zone is available, use the extrapolation rule with it */
104	if (!IS_ERR(pcb_tz)) {
105		ret = thermal_zone_get_temp(pcb_tz, &pcb_temp);
106		if (!ret) {
107			tmp -= pcb_temp; /* got a valid PCB temp */
108			slope = s->slope_pcb;
109			constant = s->constant_pcb;
110		} else {
111			dev_err(bgp->dev,
112				"Failed to read PCB state. Using defaults\n");
113			ret = 0;
114		}
115	}
116	*temp = ti_thermal_hotspot_temperature(tmp, slope, constant);
117
118	return ret;
119}
120
121static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
122				      unsigned long *temp)
123{
124	struct ti_thermal_data *data = thermal->devdata;
125
126	return __ti_thermal_get_temp(data, temp);
127}
128
129/* Bind callback functions for thermal zone */
130static int ti_thermal_bind(struct thermal_zone_device *thermal,
131			   struct thermal_cooling_device *cdev)
132{
133	struct ti_thermal_data *data = thermal->devdata;
134	int id;
135
136	if (!data || IS_ERR(data))
137		return -ENODEV;
138
139	/* check if this is the cooling device we registered */
140	if (data->cool_dev != cdev)
141		return 0;
142
143	id = data->sensor_id;
144
145	/* Simple thing, two trips, one passive another critical */
146	return thermal_zone_bind_cooling_device(thermal, 0, cdev,
147	/* bind with min and max states defined by cpu_cooling */
148						THERMAL_NO_LIMIT,
149						THERMAL_NO_LIMIT);
150}
151
152/* Unbind callback functions for thermal zone */
153static int ti_thermal_unbind(struct thermal_zone_device *thermal,
154			     struct thermal_cooling_device *cdev)
155{
156	struct ti_thermal_data *data = thermal->devdata;
157
158	if (!data || IS_ERR(data))
159		return -ENODEV;
160
161	/* check if this is the cooling device we registered */
162	if (data->cool_dev != cdev)
163		return 0;
164
165	/* Simple thing, two trips, one passive another critical */
166	return thermal_zone_unbind_cooling_device(thermal, 0, cdev);
167}
168
169/* Get mode callback functions for thermal zone */
170static int ti_thermal_get_mode(struct thermal_zone_device *thermal,
171			       enum thermal_device_mode *mode)
172{
173	struct ti_thermal_data *data = thermal->devdata;
174
175	if (data)
176		*mode = data->mode;
177
178	return 0;
179}
180
181/* Set mode callback functions for thermal zone */
182static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
183			       enum thermal_device_mode mode)
184{
185	struct ti_thermal_data *data = thermal->devdata;
186	struct ti_bandgap *bgp;
187
188	bgp = data->bgp;
189
190	if (!data->ti_thermal) {
191		dev_notice(&thermal->device, "thermal zone not registered\n");
192		return 0;
193	}
194
195	mutex_lock(&data->ti_thermal->lock);
196
197	if (mode == THERMAL_DEVICE_ENABLED)
198		data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
199	else
200		data->ti_thermal->polling_delay = 0;
201
202	mutex_unlock(&data->ti_thermal->lock);
203
204	data->mode = mode;
205	ti_bandgap_write_update_interval(bgp, data->sensor_id,
206					data->ti_thermal->polling_delay);
207	thermal_zone_device_update(data->ti_thermal);
208	dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
209		data->ti_thermal->polling_delay);
210
211	return 0;
212}
213
214/* Get trip type callback functions for thermal zone */
215static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal,
216				    int trip, enum thermal_trip_type *type)
217{
218	if (!ti_thermal_is_valid_trip(trip))
219		return -EINVAL;
220
221	if (trip + 1 == OMAP_TRIP_NUMBER)
222		*type = THERMAL_TRIP_CRITICAL;
223	else
224		*type = THERMAL_TRIP_PASSIVE;
225
226	return 0;
227}
228
229/* Get trip temperature callback functions for thermal zone */
230static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
231				    int trip, unsigned long *temp)
232{
233	if (!ti_thermal_is_valid_trip(trip))
234		return -EINVAL;
235
236	*temp = ti_thermal_get_trip_value(trip);
237
238	return 0;
239}
240
241static int __ti_thermal_get_trend(void *p, long *trend)
242{
243	struct ti_thermal_data *data = p;
244	struct ti_bandgap *bgp;
245	int id, tr, ret = 0;
246
247	bgp = data->bgp;
248	id = data->sensor_id;
249
250	ret = ti_bandgap_get_trend(bgp, id, &tr);
251	if (ret)
252		return ret;
253
254	*trend = tr;
255
256	return 0;
257}
258
259/* Get the temperature trend callback functions for thermal zone */
260static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
261				int trip, enum thermal_trend *trend)
262{
263	int ret;
264	long tr;
265
266	ret = __ti_thermal_get_trend(thermal->devdata, &tr);
267	if (ret)
268		return ret;
269
270	if (tr > 0)
271		*trend = THERMAL_TREND_RAISING;
272	else if (tr < 0)
273		*trend = THERMAL_TREND_DROPPING;
274	else
275		*trend = THERMAL_TREND_STABLE;
276
277	return 0;
278}
279
280/* Get critical temperature callback functions for thermal zone */
281static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
282				    unsigned long *temp)
283{
284	/* shutdown zone */
285	return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
286}
287
288static const struct thermal_zone_of_device_ops ti_of_thermal_ops = {
289	.get_temp = __ti_thermal_get_temp,
290	.get_trend = __ti_thermal_get_trend,
291};
292
293static struct thermal_zone_device_ops ti_thermal_ops = {
294	.get_temp = ti_thermal_get_temp,
295	.get_trend = ti_thermal_get_trend,
296	.bind = ti_thermal_bind,
297	.unbind = ti_thermal_unbind,
298	.get_mode = ti_thermal_get_mode,
299	.set_mode = ti_thermal_set_mode,
300	.get_trip_type = ti_thermal_get_trip_type,
301	.get_trip_temp = ti_thermal_get_trip_temp,
302	.get_crit_temp = ti_thermal_get_crit_temp,
303};
304
305static struct ti_thermal_data
306*ti_thermal_build_data(struct ti_bandgap *bgp, int id)
307{
308	struct ti_thermal_data *data;
309
310	data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL);
311	if (!data) {
312		dev_err(bgp->dev, "kzalloc fail\n");
313		return NULL;
314	}
315	data->sensor_id = id;
316	data->bgp = bgp;
317	data->mode = THERMAL_DEVICE_ENABLED;
318	/* pcb_tz will be either valid or PTR_ERR() */
319	data->pcb_tz = thermal_zone_get_zone_by_name("pcb");
320	INIT_WORK(&data->thermal_wq, ti_thermal_work);
321
322	return data;
323}
324
325int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
326			     char *domain)
327{
328	struct ti_thermal_data *data;
329
330	data = ti_bandgap_get_sensor_data(bgp, id);
331
332	if (!data || IS_ERR(data))
333		data = ti_thermal_build_data(bgp, id);
334
335	if (!data)
336		return -EINVAL;
337
338	/* in case this is specified by DT */
339	data->ti_thermal = thermal_zone_of_sensor_register(bgp->dev, id,
340					data, &ti_of_thermal_ops);
341	if (IS_ERR(data->ti_thermal)) {
342		/* Create thermal zone */
343		data->ti_thermal = thermal_zone_device_register(domain,
344				OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
345				NULL, FAST_TEMP_MONITORING_RATE,
346				FAST_TEMP_MONITORING_RATE);
347		if (IS_ERR(data->ti_thermal)) {
348			dev_err(bgp->dev, "thermal zone device is NULL\n");
349			return PTR_ERR(data->ti_thermal);
350		}
351		data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
352		data->our_zone = true;
353	}
354	ti_bandgap_set_sensor_data(bgp, id, data);
355	ti_bandgap_write_update_interval(bgp, data->sensor_id,
356					data->ti_thermal->polling_delay);
357
358	return 0;
359}
360
361int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
362{
363	struct ti_thermal_data *data;
364
365	data = ti_bandgap_get_sensor_data(bgp, id);
366
367	if (data && data->ti_thermal) {
368		if (data->our_zone)
369			thermal_zone_device_unregister(data->ti_thermal);
370		else
371			thermal_zone_of_sensor_unregister(bgp->dev,
372							  data->ti_thermal);
373	}
374
375	return 0;
376}
377
378int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
379{
380	struct ti_thermal_data *data;
381
382	data = ti_bandgap_get_sensor_data(bgp, id);
383
384	schedule_work(&data->thermal_wq);
385
386	return 0;
387}
388
389int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
390{
391	struct ti_thermal_data *data;
392	struct device_node *np = bgp->dev->of_node;
393
394	/*
395	 * We are assuming here that if one deploys the zone
396	 * using DT, then it must be aware that the cooling device
397	 * loading has to happen via cpufreq driver.
398	 */
399	if (of_find_property(np, "#thermal-sensor-cells", NULL))
400		return 0;
401
402	data = ti_bandgap_get_sensor_data(bgp, id);
403	if (!data || IS_ERR(data))
404		data = ti_thermal_build_data(bgp, id);
405
406	if (!data)
407		return -EINVAL;
408
409	/* Register cooling device */
410	data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
411	if (IS_ERR(data->cool_dev)) {
412		int ret = PTR_ERR(data->cool_dev);
413
414		if (ret != -EPROBE_DEFER)
415			dev_err(bgp->dev,
416				"Failed to register cpu cooling device %d\n",
417				ret);
418
419		return ret;
420	}
421	ti_bandgap_set_sensor_data(bgp, id, data);
422
423	return 0;
424}
425
426int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
427{
428	struct ti_thermal_data *data;
429
430	data = ti_bandgap_get_sensor_data(bgp, id);
431
432	if (data)
433		cpufreq_cooling_unregister(data->cool_dev);
434
435	return 0;
436}
437