1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-3-08 GuEe-GUI the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#define DBG_TAG "thermal.bcm2711"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#define AVS_RO_TEMP_STATUS 0x200
#define AVS_RO_TEMP_STATUS_VALID_MSK (RT_BIT(16) | RT_BIT(10))
#define AVS_RO_TEMP_STATUS_DATA_MSK RT_GENMASK(9, 0)
struct bcm2711_thermal
{
struct rt_thermal_zone_device parent;
struct rt_syscon *regmap;
};
#define raw_to_bcm2711_thermal(raw) rt_container_of(raw, struct bcm2711_thermal, parent)
static rt_err_t bcm2711_thermal_zone_get_temp(struct rt_thermal_zone_device *zdev,
int *out_temp)
{
rt_err_t err;
rt_uint32_t val;
struct rt_thermal_zone_params *tz_params;
struct bcm2711_thermal *btz = raw_to_bcm2711_thermal(zdev);
if ((err = rt_syscon_read(btz->regmap, AVS_RO_TEMP_STATUS, &val)))
{
return err;
}
if (!(val & AVS_RO_TEMP_STATUS_VALID_MSK))
{
return -RT_EIO;
}
val &= AVS_RO_TEMP_STATUS_DATA_MSK;
tz_params = &btz->parent.params;
/* Convert a HW code to a temperature reading (millidegree celsius) */
*out_temp = tz_params->slope * val + tz_params->offset;
return RT_EOK;
}
const static struct rt_thermal_zone_ops bcm2711_thermal_zone_ops =
{
.get_temp = bcm2711_thermal_zone_get_temp,
};
static rt_err_t bcm2711_thermal_probe(struct rt_platform_device *pdev)
{
rt_err_t err;
struct rt_ofw_node *pnp;
struct rt_device *dev = &pdev->parent;
struct bcm2711_thermal *btz = rt_calloc(1, sizeof(*btz));
if (!btz)
{
return -RT_ENOMEM;
}
pnp = rt_ofw_get_parent(dev->ofw_node);
if (!pnp)
{
err = -RT_EINVAL;
goto _fail;
}
btz->regmap = rt_syscon_find_by_ofw_node(pnp);
rt_ofw_node_put(pnp);
if (!btz->regmap)
{
err = -RT_EINVAL;
goto _fail;
}
btz->parent.parent.ofw_node = dev->ofw_node;
btz->parent.ops = &bcm2711_thermal_zone_ops;
rt_dm_dev_set_name(&btz->parent.parent, "bcm2711");
if ((err = rt_thermal_zone_device_register(&btz->parent)))
{
goto _fail;
}
dev->user_data = btz;
return RT_EOK;
_fail:
rt_free(btz);
return err;
}
static rt_err_t bcm2711_thermal_remove(struct rt_platform_device *pdev)
{
struct bcm2711_thermal *btz = pdev->parent.user_data;
rt_thermal_zone_device_unregister(&btz->parent);
rt_free(btz);
return RT_EOK;
}
static const struct rt_ofw_node_id bcm2711_thermal_ofw_ids[] =
{
{ .compatible = "brcm,bcm2711-thermal" },
{ /* sentinel */ }
};
static struct rt_platform_driver bcm2711_thermal_driver =
{
.name = "bcm2711-thermal",
.ids = bcm2711_thermal_ofw_ids,
.probe = bcm2711_thermal_probe,
.remove = bcm2711_thermal_remove,
};
RT_PLATFORM_DRIVER_EXPORT(bcm2711_thermal_driver);
|