struct thermal_zone_device *
thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
?? ??? ??? ??? ?const struct thermal_zone_of_device_ops *ops)
{
?? ?struct device_node *np, *child, *sensor_np;
?? ?struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
?? ?struct thermal_zone_device *first_tzd = NULL;
?? ?struct __sensor_param *sens_param = NULL;
?? ?np = of_find_node_by_name(NULL, "thermal-zones");//获取thermal-zones设备节点
?? ?if (!np)
?? ??? ?return ERR_PTR(-ENODEV);
?? ?if (!dev || !dev->of_node) {
?? ??? ?of_node_put(np);
?? ??? ?return ERR_PTR(-EINVAL);
?? ?}
?? ?sens_param = kzalloc(sizeof(*sens_param), GFP_KERNEL);//分配sensors param 空间
?? ?if (!sens_param) {
?? ??? ?of_node_put(np);
?? ??? ?return ERR_PTR(-ENOMEM);
?? ?}
?? ?sens_param->sensor_data = data;//用于回调函数传递的参数
?? ?sens_param->ops = ops;//sensor回调
?? ?INIT_LIST_HEAD(&sens_param->first_tz);
?? ?sens_param->trip_high = INT_MAX;
?? ?sens_param->trip_low = INT_MIN;
?? ?mutex_init(&sens_param->lock);
?? ?sensor_np = of_node_get(dev->of_node);//从设备中获取设备节点
?? ?for_each_available_child_of_node(np, child) {//遍历thermal-zones设备节点中的每一个孩子节点
?? ??? ?struct of_phandle_args sensor_specs;
?? ??? ?int ret, id;
?? ??? ?struct __thermal_zone *tz;
?? ??? ?/* For now, thermal framework supports only 1 sensor per zone */
?? ??? ?ret = of_parse_phandle_with_args(child, "thermal-sensors",
?? ??? ??? ??? ??? ??? ? "#thermal-sensor-cells",
?? ??? ??? ??? ??? ??? ? 0, &sensor_specs);//从每一个孩子节点中获取thermal-sensors参数
?? ??? ?if (ret)
?? ??? ??? ?continue;
?? ??? ?if (sensor_specs.args_count >= 1) {
?? ??? ??? ?id = sensor_specs.args[0];
?? ??? ??? ?WARN(sensor_specs.args_count > 1,
?? ??? ??? ? ? ? "%s: too many cells in sensor specifier %d\n",
?? ??? ??? ? ? ? sensor_specs.np->name, sensor_specs.args_count);
?? ??? ?} else {
?? ??? ??? ?id = 0;
?? ??? ?}
?? ??? ?if (sensor_specs.np == sensor_np && id == sensor_id) {//设备树中参数和函数传进来的参数相同时添加sensor
?? ??? ??? ?tzd = thermal_zone_of_add_sensor(child, sensor_np,
?? ??? ??? ??? ??? ??? ??? ? sens_param);//添加sensor
?? ??? ??? ?if (!IS_ERR(tzd)) {
?? ??? ??? ??? ?if (!first_tzd)
?? ??? ??? ??? ??? ?first_tzd = tzd;
?? ??? ??? ??? ?tz = tzd->devdata;
?? ??? ??? ??? ?if (!tz->default_disable)
?? ??? ??? ??? ??? ?tzd->ops->set_mode(tzd,
?? ??? ??? ??? ??? ??? ?THERMAL_DEVICE_ENABLED);//使能
?? ??? ??? ?}
?? ??? ?}
?? ??? ?of_node_put(sensor_specs.np);
?? ?}
?? ?of_node_put(sensor_np);
?? ?of_node_put(np);
?? ?if (!first_tzd) {
?? ??? ?first_tzd = ERR_PTR(-ENODEV);
?? ??? ?kfree(sens_param);
?? ?}
?? ?return first_tzd;
}
static struct thermal_zone_device *
thermal_zone_of_add_sensor(struct device_node *zone,
?? ??? ??? ? ? struct device_node *sensor,
?? ??? ??? ? ? struct __sensor_param *sens_param)
{
?? ?struct thermal_zone_device *tzd;
?? ?struct __thermal_zone *tz;
?? ?tzd = thermal_zone_get_zone_by_name(zone->name);//通过设备节点的名字获取thermal zone设备
?? ?if (IS_ERR(tzd))
?? ??? ?return ERR_PTR(-EPROBE_DEFER);
?? ?tz = tzd->devdata;
?? ?if (!sens_param->ops)
?? ??? ?return ERR_PTR(-EINVAL);
?? ?mutex_lock(&tzd->lock);
?? ?tz->senps = sens_param;
?? ?tzd->ops->get_temp = of_thermal_get_temp;//获取温度回调,将通过此回调调用sensor回调
?? ?tzd->ops->get_trend = of_thermal_get_trend;//获取trend回调,将通过此回调调用sensor回调
?? ?/*
?? ? * The thermal zone core will calculate the window if they have set the
?? ? * optional set_trips pointer.
?? ? */
?? ?if (sens_param->ops->set_trips)//如果sensor回调存在
?? ??? ?tzd->ops->set_trips = of_thermal_set_trips;//设置触发点回调,将通过此回调调用sensor回调
?? ?if (sens_param->ops->set_emul_temp)
?? ??? ?tzd->ops->set_emul_temp = of_thermal_set_emul_temp;//将通过此回调调用sensor回调
?? ?list_add_tail(&tz->list, &sens_param->first_tz);//添加到链表中
?? ?mutex_unlock(&tzd->lock);
?? ?return tzd;
}
?
static int of_thermal_get_temp(struct thermal_zone_device *tz,
?? ??? ??? ? ? ? ? int *temp)
{
?? ?struct __thermal_zone *data = tz->devdata;
?? ?if (!data->senps || !data->senps->ops->get_temp)
?? ??? ?return -EINVAL;
?? ?if (data->mode == THERMAL_DEVICE_DISABLED) {//如果设备关闭,返回
?? ??? ?*temp = tz->tzp->tracks_low ?
?? ??? ??? ??? ?THERMAL_TEMP_INVALID_LOW :
?? ??? ??? ??? ?THERMAL_TEMP_INVALID;
?? ??? ?return 0;
?? ?}
?? ?return data->senps->ops->get_temp(data->senps->sensor_data, temp);//调用sensor回调
}
struct thermal_cooling_device *
thermal_of_cooling_device_register(struct device_node *np,
?? ??? ??? ??? ? ? char *type, void *devdata,
?? ??? ??? ??? ? ? const struct thermal_cooling_device_ops *ops)
{
?? ?return __thermal_cooling_device_register(np, type, devdata, ops);
}
static struct thermal_cooling_device *
__thermal_cooling_device_register(struct device_node *np,
?? ??? ??? ??? ? ?char *type, void *devdata,
?? ??? ??? ??? ? ?const struct thermal_cooling_device_ops *ops)
{
?? ?struct thermal_cooling_device *cdev;
?? ?struct thermal_zone_device *pos = NULL;
?? ?int result;
?? ?if (type && strlen(type) >= THERMAL_NAME_LENGTH)
?? ??? ?return ERR_PTR(-EINVAL);
?? ?if (!ops || !ops->get_max_state || !ops->get_cur_state ||
?? ? ? ?!ops->set_cur_state)
?? ??? ?return ERR_PTR(-EINVAL);
?? ?cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);//分配空间
?? ?if (!cdev)
?? ??? ?return ERR_PTR(-ENOMEM);
?? ?result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);//分配一个idr
?? ?if (result) {
?? ??? ?kfree(cdev);
?? ??? ?return ERR_PTR(result);
?? ?}
?? ?strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
?? ?mutex_init(&cdev->lock);
?? ?INIT_LIST_HEAD(&cdev->thermal_instances);//初始化cooling device 链表
?? ?cdev->np = np;
?? ?cdev->ops = ops;
?? ?cdev->updated = false;
?? ?cdev->device.class = &thermal_class;
?? ?cdev->device.groups = cooling_device_attr_groups;//用于创建相关的cool节点
?? ?cdev->devdata = devdata;
?? ?cdev->sysfs_cur_state_req = 0;
?? ?cdev->sysfs_min_state_req = ULONG_MAX;
?? ?dev_set_name(&cdev->device, "cooling_device%d", cdev->id);//设置cooling device name
?? ?result = device_register(&cdev->device);//注册设备
?? ?if (result) {
?? ??? ?release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
?? ??? ?kfree(cdev);
?? ??? ?return ERR_PTR(result);
?? ?}
?? ?/* Add 'this' new cdev to the global cdev list */
?? ?mutex_lock(&thermal_list_lock);
?? ?list_add(&cdev->node, &thermal_cdev_list);//添加到链表中
?? ?mutex_unlock(&thermal_list_lock);
?? ?/* Update binding information for 'this' new cdev */
?? ?bind_cdev(cdev);//绑定设备
?? ?mutex_lock(&thermal_list_lock);
?? ?list_for_each_entry(pos, &thermal_tz_list, node)
?? ??? ?if (atomic_cmpxchg(&pos->need_update, 1, 0))//此函数返回&tz->need_update的counter值来判断是否需要更新,如果&tz->need_update的counter值等于1,&tz->need_update的counter值将更新为0
?? ??? ??? ?thermal_zone_device_update(pos,
?? ??? ??? ??? ??? ??? ? ? THERMAL_EVENT_UNSPECIFIED);//thermal zone 设备更新,上一篇1.2.3.1有介绍,这里不多介绍了
?? ?mutex_unlock(&thermal_list_lock);//释放锁
?? ?return cdev;
}
static void bind_cdev(struct thermal_cooling_device *cdev)
{
?? ?int i, ret;
?? ?const struct thermal_zone_params *tzp;
?? ?struct thermal_zone_device *pos = NULL;
?? ?mutex_lock(&thermal_list_lock);
?? ?list_for_each_entry(pos, &thermal_tz_list, node) {//遍历每一个thermal_zone_device和此cooling device绑定
?? ??? ?if (!pos->tzp && !pos->ops->bind)
?? ??? ??? ?continue;
?? ??? ?if (pos->ops->bind) {//来自结构of_thermal_ops
?? ??? ??? ?ret = pos->ops->bind(pos, cdev);
?? ??? ??? ?if (ret)
?? ??? ??? ??? ?print_bind_err_msg(pos, cdev, ret);
?? ??? ??? ?continue;
?? ??? ?}
?? ??? ?tzp = pos->tzp;
?? ??? ?if (!tzp || !tzp->tbp)
?? ??? ??? ?continue;
?? ??? ?for (i = 0; i < tzp->num_tbps; i++) {
?? ??? ??? ?if (tzp->tbp[i].cdev || !tzp->tbp[i].match)//tzp->tbp[i].match
?? ??? ??? ??? ?continue;
?? ??? ??? ?if (tzp->tbp[i].match(pos, cdev))
?? ??? ??? ??? ?continue;
?? ??? ??? ?tzp->tbp[i].cdev = cdev;
?? ??? ??? ?__bind(pos, tzp->tbp[i].trip_mask, cdev,
?? ??? ??? ? ? ? ? tzp->tbp[i].binding_limits,
?? ??? ??? ? ? ? ? tzp->tbp[i].weight);
?? ??? ?}
?? ?}
?? ?mutex_unlock(&thermal_list_lock);
}
?
定义一个test_sensor的设备??
test_sensor: test_sensor@0 {
?? ??? ?compatible = "test,test_sensor";
?? ??? ?#thermal-sensor-cells = <0>;//代表是thermal sensor,0代表的是test_sensor带的参数个数
?? ?};
定义一个test_cool的设备??
test_cool: test_cool@0 {
?? ?compatible = "test,test_cool";
?? ?#cooling-cells = <2>;
};
&thermal_zones {
?? ?
?? ?test_step {
?? ??? ??? ?polling-delay-passive = <1000>;
?? ??? ??? ?polling-delay = <10000>;
?? ??? ??? ?thermal-sensors = <&test_sensor>;
?? ??? ??? ?wake-capable-sensor;
?? ??? ??? ?thermal-governor = "step_wise";
?? ??? ??? ?trips {
?? ??? ??? ??? ?test_config: test-config {
?? ??? ??? ??? ??? ?temperature = <65000>;
?? ??? ??? ??? ??? ?hysteresis = <10000>;
?? ??? ??? ??? ??? ?type = "passive";
?? ??? ??? ??? ?};
?? ??? ??? ??? ?test_config1: test-config1 {
?? ??? ??? ??? ??? ?temperature = <60000>;
?? ??? ??? ??? ??? ?hysteresis = <1000>;
?? ??? ??? ??? ??? ?type = "passive";
?? ??? ??? ??? ?};
?? ??? ??? ?};
?? ??? ??? ?cooling-maps {
?? ??? ??? ??? ?test_cdev {
?? ??? ??? ??? ??? ?trip = <&test_config>;
?? ??? ??? ??? ??? ?cooling-device =
?? ??? ??? ??? ??? ??? ?<&test_cool 0
?? ??? ??? ??? ??? ??? ??? ?THERMAL_MAX_LIMIT>;
?? ??? ??? ??? ?};
?? ??? ??? ??? ?test_cdev1 {
?? ??? ??? ??? ??? ?trip = <&test_config1>;
?? ??? ??? ??? ??? ?cooling-device =
?? ??? ??? ??? ??? ??? ?<&test_cool 0
?? ??? ??? ??? ??? ??? ??? ?THERMAL_MAX_LIMIT>;
?? ??? ??? ??? ?};
?? ??? ??? ?};
?? ??? ?};
?? ?
};
#include <linux/thermal.h>
struct test_tz_priv {
?? ?int val;
?? ?struct thermal_zone_device *tz_dev;
?? ?char name[32];
};
struct test_tz_priv tz_data0;
static ssize_t test_sensor_show(struct device *dev,
?? ??? ? ?struct device_attribute *attr,
?? ??? ? ?char *buf)
{
?? ?int count;
?? ?
?? ?count = sprintf(buf, "%d", tz_data0.val);
?? ?
?? ?return count;
}
static ssize_t test_sensor_store(struct device *dev,
?? ??? ??? ?struct device_attribute *attr,
?? ??? ??? ?const char *buf, size_t count)
{
?? ?int ret = -EINVAL;
?? ?int val;
???ret = sscanf(buf, "%d", &val);
?? ?if (ret <= 0) {
?? ??? ?return ret;
?? ?}
?? ?
?? ?tz_data0.val = val;
?? ?
?? ?return count;
}
static DEVICE_ATTR_RW(test_sensor);
/*
?* test_get_temp - get wsa temperature
?* @thermal: thermal zone device
?* @temp: temperature value
?*
?* Get the temperature of test.
?*
?* Return: 0 on success or negative error code on failure.
?*/
static int test_get_temp(void *data, int *val)
{
?? ?struct test_tz_priv *tz_pdata = data;
?? ?
?? ?*val = tz_pdata->val;
?? ?pr_info("%s %d\n", __func__, __LINE__);?? ?
?? ?return 0;
}
EXPORT_SYMBOL(test_get_temp);
static struct thermal_zone_of_device_ops test_thermal_ops = {
?? ?.get_temp = test_get_temp,
};
static int test_probe(struct platform_device *pdev)
{
?? ?struct device *dev = &pdev->dev;
?? ?int ret = 0;
?? ?
?? ?struct test_tz_priv *tz_pdata;
?? ?tz_pdata = &tz_data0;
?? ?
?? ?
?? ?tz_pdata->tz_dev = thermal_zone_of_sensor_register(dev, 0, tz_pdata,
?? ??? ??? ?&test_thermal_ops);
?? ?
?? ?if (IS_ERR(tz_pdata->tz_dev)) {
?? ??? ?pr_err("%s: thermal device register failed.\n", __func__);
?? ??? ?return -EINVAL;
?? ?}
?? ?
?? ?ret = device_create_file(dev, &dev_attr_test_sensor);
?? ?return ret;
}
static int test_remove(struct platform_device *pdev)
{
?? ?struct device *dev = &pdev->dev;
?? ?
?? ?pm_runtime_disable(dev);
?? ?pm_runtime_set_suspended(dev);
?? ?return 0;
}
static const struct of_device_id test_of_match[] = {
?? ?{.compatible = "test,test_sensor", },
?? ?{ }
};
static struct platform_driver test_sensor_driver = {
?? ?.driver = {
?? ??? ?.name = "test_sensor_driver",
?? ??? ?.owner = THIS_MODULE,
?? ??? ?.of_match_table = test_of_match,?? ?
?? ?},
?? ?.probe = test_probe,
?? ?.remove = test_remove,
};
/**************************************************************/
/*********************test cooling*****************************/
struct test_cooling_priv {
?? ?struct thermal_cooling_device *cdev;
?? ?unsigned long max_data;
?? ?unsigned long data;
};
struct test_cooling_priv cooling_data0;
static int test_cooling_get_max_xxx(struct thermal_cooling_device *cdev,
?? ??? ??? ??? ??? ?unsigned long *state)
{
?? ?struct test_cooling_priv *pdata = (struct test_cooling_priv *)cdev->devdata;
?? ?
?? ?*state = pdata->max_data;
?? ?
?? ?pr_info("%s %d\n", __func__, __LINE__);
?? ?return 0;
}
static int test_cooling_get_cur_xxx(struct thermal_cooling_device *cdev,
?? ??? ??? ??? ??? ?unsigned long *state)
{
?? ?struct test_cooling_priv *pdata = (struct test_cooling_priv *)cdev->devdata;
?? ?
?? ?*state = pdata->data;
?? ?
?? ?pr_info("%s %d\n", __func__, __LINE__);
?? ?return 0;
}
static int test_cooling_set_cur_xxx(struct thermal_cooling_device *cdev,
?? ??? ??? ??? ??? ?unsigned long state)
{
?? ?struct test_cooling_priv *pdata = (struct test_cooling_priv *)cdev->devdata;
?? ?
?? ?pdata->data = state;
?? ?pr_info("%s %d %d\n", __func__, __LINE__, state);
?? ?return 0;
}
static struct thermal_cooling_device_ops test_cooling_ops = {
?? ?.get_max_state = test_cooling_get_max_xxx,
?? ?.get_cur_state = test_cooling_get_cur_xxx,
?? ?.set_cur_state = test_cooling_set_cur_xxx,
};
static int test_cooling_probe(struct platform_device *pdev)
{
?? ?int ret = 0;
?? ?
?? ?cooling_data0.max_data = 8;
?? ?cooling_data0.cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
?? ??? ??? ??? ?(char *)dev_name(&pdev->dev), &cooling_data0, &test_cooling_ops);
?? ?if (unlikely(!cooling_data0.cdev))
?? ?{
?? ??? ?pr_err("Cooling device register failed\n");
?? ??? ?return -EINVAL;
?? ?}
?? ?return ret;
}
static int test_cooling_remove(struct platform_device *pdev)
{
?? ?return 0;
}
static const struct of_device_id test_cooling_of_match[] = {
?? ?{.compatible = "test,test_cool", },
?? ?{ }
};
static struct platform_driver test_cooling_driver = {
?? ?.driver = {
?? ??? ?.name = "test_cooling_driver",
?? ??? ?.owner = THIS_MODULE,
?? ??? ?.of_match_table = test_cooling_of_match,?? ?
?? ?},
?? ?.probe = test_cooling_probe,
?? ?.remove = test_cooling_remove,
};
/*******************************************************/
static int __init test_init(void)
{
?? ?int ret;
?? ?ret = platform_driver_register(&test_sensor_driver);
?? ?
?? ?ret = platform_driver_register(&test_cooling_driver);
?? ?
?? ?return ret;
}
static void __exit test_exit(void)
{
?? ?platform_driver_unregister(&test_sensor_driver);
?? ?platform_driver_unregister(&test_cooling_driver);
}
module_init(test_init);
module_exit(test_exit);
MODULE_DESCRIPTION("test driver");
MODULE_AUTHOR("xxxxxxxxxx");
MODULE_LICENSE("GPL");
?