blob: 7e17377b6962512ab2aef6e913b51ed372d27086 [file] [log] [blame]
Peng Fan5ef5b6d2019-05-05 13:23:54 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 NXP
4 */
5
6#include <config.h>
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
10#include <thermal.h>
11#include <dm/device-internal.h>
12#include <dm/device.h>
13#include <asm/arch/sci/sci.h>
14
15DECLARE_GLOBAL_DATA_PTR;
16
17struct imx_sc_thermal_plat {
18 int critical;
19 int alert;
20 int polling_delay;
21 int id;
22 bool zone_node;
23};
24
25static int read_temperature(struct udevice *dev, int *temp)
26{
27 s16 celsius;
28 s8 tenths;
29 int ret;
30
31 sc_rsrc_t *sensor_rsrc = (sc_rsrc_t *)dev_get_driver_data(dev);
32
33 struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
34
35 if (!temp)
36 return -EINVAL;
37
38 ret = sc_misc_get_temp(-1, sensor_rsrc[pdata->id], SC_C_TEMP,
39 &celsius, &tenths);
40 if (ret) {
41 printf("Error: get temperature failed! (error = %d)\n", ret);
42 return ret;
43 }
44
45 *temp = celsius * 1000 + tenths * 100;
46
47 return 0;
48}
49
50int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
51{
52 struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
53 int cpu_temp = 0;
54 int ret;
55
56 ret = read_temperature(dev, &cpu_temp);
57 if (ret)
58 return ret;
59
60 while (cpu_temp >= pdata->alert) {
61 printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)",
62 cpu_temp, pdata->alert, pdata->critical);
63 puts(" waiting...\n");
64 mdelay(pdata->polling_delay);
65 ret = read_temperature(dev, &cpu_temp);
66 if (ret)
67 return ret;
68 }
69
70 *temp = cpu_temp / 1000;
71
72 return 0;
73}
74
75static const struct dm_thermal_ops imx_sc_thermal_ops = {
76 .get_temp = imx_sc_thermal_get_temp,
77};
78
79static int imx_sc_thermal_probe(struct udevice *dev)
80{
81 debug("%s dev name %s\n", __func__, dev->name);
82 return 0;
83}
84
85static int imx_sc_thermal_bind(struct udevice *dev)
86{
87 struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
88 int reg, ret;
89 int offset;
90 const char *name;
91 const void *prop;
92
93 debug("%s dev name %s\n", __func__, dev->name);
94
95 prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible",
96 NULL);
97 if (!prop)
98 return 0;
99
100 pdata->zone_node = 1;
101
102 reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "tsens-num", 0);
103 if (reg == 0) {
104 printf("%s: no temp sensor number provided!\n", __func__);
105 return -EINVAL;
106 }
107
108 offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
109 fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
110 /* Bind the subnode to this driver */
111 name = fdt_get_name(gd->fdt_blob, offset, NULL);
112
113 ret = device_bind_with_driver_data(dev, dev->driver, name,
114 dev->driver_data,
115 offset_to_ofnode(offset),
116 NULL);
117 if (ret)
118 printf("Error binding driver '%s': %d\n",
119 dev->driver->name, ret);
120 }
121 return 0;
122}
123
124static int imx_sc_thermal_ofdata_to_platdata(struct udevice *dev)
125{
126 struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
127 struct fdtdec_phandle_args args;
128 const char *type;
129 int ret;
130 int trips_np;
131
132 debug("%s dev name %s\n", __func__, dev->name);
133
134 if (pdata->zone_node)
135 return 0;
136
137 ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
138 "thermal-sensors",
139 "#thermal-sensor-cells",
140 0, 0, &args);
141 if (ret)
142 return ret;
143
144 if (args.node != dev_of_offset(dev->parent))
145 return -EFAULT;
146
147 if (args.args_count >= 1)
148 pdata->id = args.args[0];
149 else
150 pdata->id = 0;
151
152 debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
153
154 pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
155 "polling-delay", 1000);
156
157 trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
158 "trips");
159 fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
160 type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
161 if (type) {
162 if (strcmp(type, "critical") == 0) {
163 pdata->critical = fdtdec_get_int(gd->fdt_blob,
164 trips_np,
165 "temperature",
166 85);
167 } else if (strcmp(type, "passive") == 0) {
168 pdata->alert = fdtdec_get_int(gd->fdt_blob,
169 trips_np,
170 "temperature",
171 80);
172 }
173 }
174 }
175
176 debug("id %d polling_delay %d, critical %d, alert %d\n", pdata->id,
177 pdata->polling_delay, pdata->critical, pdata->alert);
178
179 return 0;
180}
181
182static const sc_rsrc_t imx8qxp_sensor_rsrc[] = {
183 SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
184 SC_R_PMIC_1, SC_R_PMIC_2,
185};
186
187static const struct udevice_id imx_sc_thermal_ids[] = {
188 { .compatible = "nxp,imx8qxp-sc-tsens", .data =
189 (ulong)&imx8qxp_sensor_rsrc, },
190 { }
191};
192
193U_BOOT_DRIVER(imx_sc_thermal) = {
194 .name = "imx_sc_thermal",
195 .id = UCLASS_THERMAL,
196 .ops = &imx_sc_thermal_ops,
197 .of_match = imx_sc_thermal_ids,
198 .bind = imx_sc_thermal_bind,
199 .probe = imx_sc_thermal_probe,
200 .ofdata_to_platdata = imx_sc_thermal_ofdata_to_platdata,
201 .platdata_auto_alloc_size = sizeof(struct imx_sc_thermal_plat),
202 .flags = DM_FLAG_PRE_RELOC,
203};