前面讲过在thermal_init->of_parse_thermal_zones的时候已经从dts中建好了zone device,并绑定了cool device
int __init of_parse_thermal_zones(void)
{
struct device_node *np, *child;
struct __thermal_zone *tz;
struct thermal_zone_device_ops *ops;
//找到zone device
np = of_find_node_by_name(NULL, "thermal-zones");
if (!np) {
pr_debug("unable to find thermal zones\n");
return 0; /* Run successfully on systems without thermal DT */
}
for_each_available_child_of_node(np, child) {
struct thermal_zone_device *zone;
struct thermal_zone_params *tzp;
int i, mask = 0;
u32 prop;
//从dts中parse值后赋值给tzp
tz = thermal_of_build_thermal_zone(child);
if (IS_ERR(tz)) {
pr_err("failed to build thermal zone %s: %ld\n",
child->name,
PTR_ERR(tz));
continue;
}
ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
if (!ops)
goto exit_free;
tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
if (!tzp) {
kfree(ops);
goto exit_free;
}
/* No hwmon because there might be hwmon drivers registering */
tzp->no_hwmon = true;
if (!of_property_read_u32(child, "sustainable-power", &prop))
tzp->sustainable_power = prop;
for (i = 0; i < tz->ntrips; i++)
mask |= 1 << i;
/* these two are left for temperature drivers to use */
tzp->slope = tz->slope;
tzp->offset = tz->offset;
//注册zone device 并绑定cool device
zone = thermal_zone_device_register(child->name, tz->ntrips,
mask, tz,
ops, tzp,
tz->passive_delay,
tz->polling_delay);
if (IS_ERR(zone)) {
pr_err("Failed to build %s zone %ld\n", child->name,
PTR_ERR(zone));
kfree(tzp);
kfree(ops);
of_thermal_free_zone(tz);
/* attempting to build remaining zones still */
}
}
of_node_put(np);
return 0;
}
但是需要注意的是,这里并没有为zone device 添加sensor,也就是说zone device不能得到目前的温度,因此thermal driver主要责任就是给zone device添加sensor。
这里以下面的thermal 驱动为例
static int hisi_thermal_probe(struct platform_device *pdev)
{
struct hisi_thermal_data *data;
struct resource *res;
int i;
int ret;
//注册中断线程化
ret = devm_request_threaded_irq(&pdev->dev, data->irq,
hisi_thermal_alarm_irq,
hisi_thermal_alarm_irq_thread,
0, "hisi_thermal", data);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
return ret;
}
//调用hisi_thermal_register_sensor 为zone device添加sensor来获取温度
for (i = 0; i < HISI_MAX_SENSORS; ++i) {
ret = hisi_thermal_register_sensor(pdev, data,
&data->sensors[i], i);
if (ret)
dev_err(&pdev->dev,
"failed to register thermal sensor: %d\n", ret);
else
hisi_thermal_toggle_sensor(&data->sensors[i], true);
}
return 0;
}
继续看看hisi_thermal_register_sensor
static int hisi_thermal_register_sensor(struct platform_device *pdev,
struct hisi_thermal_data *data,
struct hisi_thermal_sensor *sensor,
int index)
{
//调用devm_thermal_zone_of_sensor_register->thermal_zone_of_sensor_register 来为已经存在的zone device添加sensor,这里的hisi_of_thermal_ops 就是sensor 获取温度的ops
sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
sensor->id, sensor, &hisi_of_thermal_ops);
if (IS_ERR(sensor->tzd)) {
ret = PTR_ERR(sensor->tzd);
sensor->tzd = NULL;
dev_err(&pdev->dev, "failed to register sensor id %d: %d\n",
sensor->id, ret);
return ret;
}
}
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);
//找到zone device在dts中的node
np = of_find_node_by_name(NULL, "thermal-zones");
if (!np)
return ERR_PTR(-ENODEV);
if (!dev || !dev->of_node) {
of_node_put(np);
return ERR_PTR(-EINVAL);
}
sensor_np = of_node_get(dev->of_node);
for_each_available_child_of_node(np, child) {
struct of_phandle_args sensor_specs;
int ret, id;
/* 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);
if (ret)
continue;
//每个zone 只能有一个sensor
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;
}
//找到目前sensor对应的zone device。找到后通过thermal_zone_of_add_sensor 给zone 添加sensor
if (sensor_specs.np == sensor_np && id == sensor_id) {
tzd = thermal_zone_of_add_sensor(child, sensor_np,
data, ops);
if (!IS_ERR(tzd))
tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
of_node_put(sensor_specs.np);
of_node_put(child);
goto exit;
}
of_node_put(sensor_specs.np);
}
}
static struct thermal_zone_device *
thermal_zone_of_add_sensor(struct device_node *zone,
struct device_node *sensor, void *data,
const struct thermal_zone_of_device_ops *ops)
{
struct thermal_zone_device *tzd;
struct __thermal_zone *tz;
//这部是关键,根据name找到zone device
tzd = thermal_zone_get_zone_by_name(zone->name);
if (IS_ERR(tzd))
return ERR_PTR(-EPROBE_DEFER);
tz = tzd->devdata;
if (!ops)
return ERR_PTR(-EINVAL);
mutex_lock(&tzd->lock);
tz->ops = ops;
tz->sensor_data = data;
//为zone device的赋值,后面就直接通过tzd->ops->get_temp 来获取温度
tzd->ops->get_temp = of_thermal_get_temp;
tzd->ops->get_trend = of_thermal_get_trend;
}
static int of_thermal_get_temp(struct thermal_zone_device *tz,
int *temp)
{
struct __thermal_zone *data = tz->devdata;
if (!data->ops->get_temp)
return -EINVAL;
//可见又是调用data->ops->get_temp,这里的data就是hisi_of_thermal_ops
return data->ops->get_temp(data->sensor_data, temp);
}
static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
.get_temp = hisi_thermal_get_temp,
};
hisi_thermal_get_temp->hisi_thermal_get_sensor_temp得到温度。查看hisi_thermal_get_sensor_temp的code会发现基本是在读取硬件寄存器