1 From 97abcfc5219149ff7d4883b295c80257f0315b5e Mon Sep 17 00:00:00 2001
2 From: Anson Huang <Anson.Huang@nxp.com>
3 Date: Wed, 7 Aug 2019 08:40:59 +0800
4 Subject: [PATCH] thermal: Add generic device cooling support
6 To compatible with previous implementation, add generic device
7 cooling support, each thermal zone will register a cooling
8 device, and when temperature exceed passive trip, the device
9 cooling driver will send out a system wide notification, each
10 device supporting cooling will need to register device cooling
11 and takes action when passive trip is exceeded;
13 Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
15 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
17 drivers/thermal/Kconfig | 7 ++
18 drivers/thermal/Makefile | 1 +
19 drivers/thermal/device_cooling.c | 152 +++++++++++++++++++++++++++++++++++++++
20 include/linux/device_cooling.h | 45 ++++++++++++
21 4 files changed, 205 insertions(+)
22 create mode 100644 drivers/thermal/device_cooling.c
23 create mode 100644 include/linux/device_cooling.h
25 --- a/drivers/thermal/Kconfig
26 +++ b/drivers/thermal/Kconfig
27 @@ -233,6 +233,13 @@ config IMX_THERMAL
28 cpufreq is used as the cooling device to throttle CPUs when the
29 passive trip is crossed.
31 +config DEVICE_THERMAL
32 + tristate "generic device cooling support"
34 + Support for device cooling.
35 + It supports notification of crossing passive trip for devices,
36 + devices need to do their own actions to cool down the SOC.
38 config MAX77620_THERMAL
39 tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
40 depends on MFD_MAX77620
41 --- a/drivers/thermal/Makefile
42 +++ b/drivers/thermal/Makefile
43 @@ -41,6 +41,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_t
44 obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
45 obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o
46 obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
47 +obj-$(CONFIG_DEVICE_THERMAL) += device_cooling.o
48 obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
49 obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
50 obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o
52 +++ b/drivers/thermal/device_cooling.c
55 + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
57 + * This program is free software; you can redistribute it and/or modify
58 + * it under the terms of the GNU General Public License version 2 as
59 + * published by the Free Software Foundation.
63 +#include <linux/module.h>
64 +#include <linux/thermal.h>
65 +#include <linux/err.h>
66 +#include <linux/slab.h>
68 +struct devfreq_cooling_device {
70 + struct thermal_cooling_device *cool_dev;
71 + unsigned int devfreq_state;
74 +static DEFINE_IDR(devfreq_idr);
75 +static DEFINE_MUTEX(devfreq_cooling_lock);
79 +static BLOCKING_NOTIFIER_HEAD(devfreq_cooling_chain_head);
81 +int register_devfreq_cooling_notifier(struct notifier_block *nb)
83 + return blocking_notifier_chain_register(
84 + &devfreq_cooling_chain_head, nb);
86 +EXPORT_SYMBOL_GPL(register_devfreq_cooling_notifier);
88 +int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
90 + return blocking_notifier_chain_unregister(
91 + &devfreq_cooling_chain_head, nb);
93 +EXPORT_SYMBOL_GPL(unregister_devfreq_cooling_notifier);
95 +static int devfreq_cooling_notifier_call_chain(unsigned long val)
97 + return (blocking_notifier_call_chain(
98 + &devfreq_cooling_chain_head, val, NULL)
99 + == NOTIFY_BAD) ? -EINVAL : 0;
102 +static int devfreq_set_cur_state(struct thermal_cooling_device *cdev,
103 + unsigned long state)
105 + struct devfreq_cooling_device *devfreq_device = cdev->devdata;
108 + ret = devfreq_cooling_notifier_call_chain(state);
112 + devfreq_device->devfreq_state = state;
117 +static int devfreq_get_max_state(struct thermal_cooling_device *cdev,
118 + unsigned long *state)
120 + *state = MAX_STATE;
125 +static int devfreq_get_cur_state(struct thermal_cooling_device *cdev,
126 + unsigned long *state)
128 + struct devfreq_cooling_device *devfreq_device = cdev->devdata;
130 + *state = devfreq_device->devfreq_state;
135 +static struct thermal_cooling_device_ops const devfreq_cooling_ops = {
136 + .get_max_state = devfreq_get_max_state,
137 + .get_cur_state = devfreq_get_cur_state,
138 + .set_cur_state = devfreq_set_cur_state,
141 +static int get_idr(struct idr *idr, int *id)
145 + mutex_lock(&devfreq_cooling_lock);
146 + ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
147 + mutex_unlock(&devfreq_cooling_lock);
148 + if (unlikely(ret < 0))
155 +static void release_idr(struct idr *idr, int id)
157 + mutex_lock(&devfreq_cooling_lock);
158 + idr_remove(idr, id);
159 + mutex_unlock(&devfreq_cooling_lock);
162 +struct thermal_cooling_device *devfreq_cooling_register(void)
164 + struct thermal_cooling_device *cool_dev;
165 + struct devfreq_cooling_device *devfreq_dev = NULL;
166 + char dev_name[THERMAL_NAME_LENGTH];
169 + devfreq_dev = kzalloc(sizeof(struct devfreq_cooling_device),
172 + return ERR_PTR(-ENOMEM);
174 + ret = get_idr(&devfreq_idr, &devfreq_dev->id);
176 + kfree(devfreq_dev);
177 + return ERR_PTR(-EINVAL);
180 + snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d",
183 + cool_dev = thermal_cooling_device_register(dev_name, devfreq_dev,
184 + &devfreq_cooling_ops);
186 + release_idr(&devfreq_idr, devfreq_dev->id);
187 + kfree(devfreq_dev);
188 + return ERR_PTR(-EINVAL);
190 + devfreq_dev->cool_dev = cool_dev;
191 + devfreq_dev->devfreq_state = 0;
195 +EXPORT_SYMBOL_GPL(devfreq_cooling_register);
197 +void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
199 + struct devfreq_cooling_device *devfreq_dev = cdev->devdata;
201 + thermal_cooling_device_unregister(devfreq_dev->cool_dev);
202 + release_idr(&devfreq_idr, devfreq_dev->id);
203 + kfree(devfreq_dev);
205 +EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
207 +++ b/include/linux/device_cooling.h
210 + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
212 + * This program is free software; you can redistribute it and/or modify
213 + * it under the terms of the GNU General Public License version 2 as
214 + * published by the Free Software Foundation.
218 +#ifndef __DEVICE_THERMAL_H__
219 +#define __DEVICE_THERMAL_H__
221 +#include <linux/thermal.h>
223 +#ifdef CONFIG_DEVICE_THERMAL
224 +int register_devfreq_cooling_notifier(struct notifier_block *nb);
225 +int unregister_devfreq_cooling_notifier(struct notifier_block *nb);
226 +struct thermal_cooling_device *devfreq_cooling_register(void);
227 +void devfreq_cooling_unregister(struct thermal_cooling_device *cdev);
230 +int register_devfreq_cooling_notifier(struct notifier_block *nb)
236 +int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
242 +struct thermal_cooling_device *devfreq_cooling_register(void)
248 +void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
253 +#endif /* __DEVICE_THERMAL_H__ */