thermal子系统之sensor &&cooling

2、sensor注册函数thermal_zone_of_sensor_register

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;
}

2.1 thermal_zone_of_add_sensor函数

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;
}
 

2.1.1 of_thermal_get_temp函数

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回调

}

3、cooling 设备注册函数thermal_of_cooling_device_register

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;
}


3.1 bind_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);
}
 

4. 例程:

4.1设备树

定义一个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>;
                };
            };
        };
    
};

4.2 例程代码部分:

#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");


 

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值