xref: /linux/drivers/thermal/qoriq_thermal.c (revision d2912cb15bdda8ba4a5dd73396ad62641af2f520)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright 2016 Freescale Semiconductor, Inc.
4 
5 #include <linux/module.h>
6 #include <linux/platform_device.h>
7 #include <linux/err.h>
8 #include <linux/io.h>
9 #include <linux/of.h>
10 #include <linux/of_address.h>
11 #include <linux/thermal.h>
12 
13 #include "thermal_core.h"
14 
15 #define SITES_MAX	16
16 
17 /*
18  * QorIQ TMU Registers
19  */
20 struct qoriq_tmu_site_regs {
21 	u32 tritsr;		/* Immediate Temperature Site Register */
22 	u32 tratsr;		/* Average Temperature Site Register */
23 	u8 res0[0x8];
24 };
25 
26 struct qoriq_tmu_regs {
27 	u32 tmr;		/* Mode Register */
28 #define TMR_DISABLE	0x0
29 #define TMR_ME		0x80000000
30 #define TMR_ALPF	0x0c000000
31 	u32 tsr;		/* Status Register */
32 	u32 tmtmir;		/* Temperature measurement interval Register */
33 #define TMTMIR_DEFAULT	0x0000000f
34 	u8 res0[0x14];
35 	u32 tier;		/* Interrupt Enable Register */
36 #define TIER_DISABLE	0x0
37 	u32 tidr;		/* Interrupt Detect Register */
38 	u32 tiscr;		/* Interrupt Site Capture Register */
39 	u32 ticscr;		/* Interrupt Critical Site Capture Register */
40 	u8 res1[0x10];
41 	u32 tmhtcrh;		/* High Temperature Capture Register */
42 	u32 tmhtcrl;		/* Low Temperature Capture Register */
43 	u8 res2[0x8];
44 	u32 tmhtitr;		/* High Temperature Immediate Threshold */
45 	u32 tmhtatr;		/* High Temperature Average Threshold */
46 	u32 tmhtactr;	/* High Temperature Average Crit Threshold */
47 	u8 res3[0x24];
48 	u32 ttcfgr;		/* Temperature Configuration Register */
49 	u32 tscfgr;		/* Sensor Configuration Register */
50 	u8 res4[0x78];
51 	struct qoriq_tmu_site_regs site[SITES_MAX];
52 	u8 res5[0x9f8];
53 	u32 ipbrr0;		/* IP Block Revision Register 0 */
54 	u32 ipbrr1;		/* IP Block Revision Register 1 */
55 	u8 res6[0x310];
56 	u32 ttr0cr;		/* Temperature Range 0 Control Register */
57 	u32 ttr1cr;		/* Temperature Range 1 Control Register */
58 	u32 ttr2cr;		/* Temperature Range 2 Control Register */
59 	u32 ttr3cr;		/* Temperature Range 3 Control Register */
60 };
61 
62 struct qoriq_tmu_data;
63 
64 /*
65  * Thermal zone data
66  */
67 struct qoriq_sensor {
68 	struct thermal_zone_device	*tzd;
69 	struct qoriq_tmu_data		*qdata;
70 	int				id;
71 };
72 
73 struct qoriq_tmu_data {
74 	struct qoriq_tmu_regs __iomem *regs;
75 	bool little_endian;
76 	struct qoriq_sensor	*sensor[SITES_MAX];
77 };
78 
79 static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr)
80 {
81 	if (p->little_endian)
82 		iowrite32(val, addr);
83 	else
84 		iowrite32be(val, addr);
85 }
86 
87 static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr)
88 {
89 	if (p->little_endian)
90 		return ioread32(addr);
91 	else
92 		return ioread32be(addr);
93 }
94 
95 static int tmu_get_temp(void *p, int *temp)
96 {
97 	struct qoriq_sensor *qsensor = p;
98 	struct qoriq_tmu_data *qdata = qsensor->qdata;
99 	u32 val;
100 
101 	val = tmu_read(qdata, &qdata->regs->site[qsensor->id].tritsr);
102 	*temp = (val & 0xff) * 1000;
103 
104 	return 0;
105 }
106 
107 static const struct thermal_zone_of_device_ops tmu_tz_ops = {
108 	.get_temp = tmu_get_temp,
109 };
110 
111 static int qoriq_tmu_register_tmu_zone(struct platform_device *pdev)
112 {
113 	struct qoriq_tmu_data *qdata = platform_get_drvdata(pdev);
114 	int id, sites = 0;
115 
116 	for (id = 0; id < SITES_MAX; id++) {
117 		qdata->sensor[id] = devm_kzalloc(&pdev->dev,
118 				sizeof(struct qoriq_sensor), GFP_KERNEL);
119 		if (!qdata->sensor[id])
120 			return -ENOMEM;
121 
122 		qdata->sensor[id]->id = id;
123 		qdata->sensor[id]->qdata = qdata;
124 		qdata->sensor[id]->tzd = devm_thermal_zone_of_sensor_register(
125 				&pdev->dev, id, qdata->sensor[id], &tmu_tz_ops);
126 		if (IS_ERR(qdata->sensor[id]->tzd)) {
127 			if (PTR_ERR(qdata->sensor[id]->tzd) == -ENODEV)
128 				continue;
129 			else
130 				return PTR_ERR(qdata->sensor[id]->tzd);
131 		}
132 
133 		sites |= 0x1 << (15 - id);
134 	}
135 
136 	/* Enable monitoring */
137 	if (sites != 0)
138 		tmu_write(qdata, sites | TMR_ME | TMR_ALPF, &qdata->regs->tmr);
139 
140 	return 0;
141 }
142 
143 static int qoriq_tmu_calibration(struct platform_device *pdev)
144 {
145 	int i, val, len;
146 	u32 range[4];
147 	const u32 *calibration;
148 	struct device_node *np = pdev->dev.of_node;
149 	struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
150 
151 	if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) {
152 		dev_err(&pdev->dev, "missing calibration range.\n");
153 		return -ENODEV;
154 	}
155 
156 	/* Init temperature range registers */
157 	tmu_write(data, range[0], &data->regs->ttr0cr);
158 	tmu_write(data, range[1], &data->regs->ttr1cr);
159 	tmu_write(data, range[2], &data->regs->ttr2cr);
160 	tmu_write(data, range[3], &data->regs->ttr3cr);
161 
162 	calibration = of_get_property(np, "fsl,tmu-calibration", &len);
163 	if (calibration == NULL || len % 8) {
164 		dev_err(&pdev->dev, "invalid calibration data.\n");
165 		return -ENODEV;
166 	}
167 
168 	for (i = 0; i < len; i += 8, calibration += 2) {
169 		val = of_read_number(calibration, 1);
170 		tmu_write(data, val, &data->regs->ttcfgr);
171 		val = of_read_number(calibration + 1, 1);
172 		tmu_write(data, val, &data->regs->tscfgr);
173 	}
174 
175 	return 0;
176 }
177 
178 static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
179 {
180 	/* Disable interrupt, using polling instead */
181 	tmu_write(data, TIER_DISABLE, &data->regs->tier);
182 
183 	/* Set update_interval */
184 	tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir);
185 
186 	/* Disable monitoring */
187 	tmu_write(data, TMR_DISABLE, &data->regs->tmr);
188 }
189 
190 static int qoriq_tmu_probe(struct platform_device *pdev)
191 {
192 	int ret;
193 	struct qoriq_tmu_data *data;
194 	struct device_node *np = pdev->dev.of_node;
195 
196 	data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data),
197 			    GFP_KERNEL);
198 	if (!data)
199 		return -ENOMEM;
200 
201 	platform_set_drvdata(pdev, data);
202 
203 	data->little_endian = of_property_read_bool(np, "little-endian");
204 
205 	data->regs = of_iomap(np, 0);
206 	if (!data->regs) {
207 		dev_err(&pdev->dev, "Failed to get memory region\n");
208 		ret = -ENODEV;
209 		goto err_iomap;
210 	}
211 
212 	qoriq_tmu_init_device(data);	/* TMU initialization */
213 
214 	ret = qoriq_tmu_calibration(pdev);	/* TMU calibration */
215 	if (ret < 0)
216 		goto err_tmu;
217 
218 	ret = qoriq_tmu_register_tmu_zone(pdev);
219 	if (ret < 0) {
220 		dev_err(&pdev->dev, "Failed to register sensors\n");
221 		ret = -ENODEV;
222 		goto err_iomap;
223 	}
224 
225 	return 0;
226 
227 err_tmu:
228 	iounmap(data->regs);
229 
230 err_iomap:
231 	platform_set_drvdata(pdev, NULL);
232 
233 	return ret;
234 }
235 
236 static int qoriq_tmu_remove(struct platform_device *pdev)
237 {
238 	struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
239 
240 	/* Disable monitoring */
241 	tmu_write(data, TMR_DISABLE, &data->regs->tmr);
242 
243 	iounmap(data->regs);
244 	platform_set_drvdata(pdev, NULL);
245 
246 	return 0;
247 }
248 
249 #ifdef CONFIG_PM_SLEEP
250 static int qoriq_tmu_suspend(struct device *dev)
251 {
252 	u32 tmr;
253 	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
254 
255 	/* Disable monitoring */
256 	tmr = tmu_read(data, &data->regs->tmr);
257 	tmr &= ~TMR_ME;
258 	tmu_write(data, tmr, &data->regs->tmr);
259 
260 	return 0;
261 }
262 
263 static int qoriq_tmu_resume(struct device *dev)
264 {
265 	u32 tmr;
266 	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
267 
268 	/* Enable monitoring */
269 	tmr = tmu_read(data, &data->regs->tmr);
270 	tmr |= TMR_ME;
271 	tmu_write(data, tmr, &data->regs->tmr);
272 
273 	return 0;
274 }
275 #endif
276 
277 static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
278 			 qoriq_tmu_suspend, qoriq_tmu_resume);
279 
280 static const struct of_device_id qoriq_tmu_match[] = {
281 	{ .compatible = "fsl,qoriq-tmu", },
282 	{ .compatible = "fsl,imx8mq-tmu", },
283 	{},
284 };
285 MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
286 
287 static struct platform_driver qoriq_tmu = {
288 	.driver	= {
289 		.name		= "qoriq_thermal",
290 		.pm		= &qoriq_tmu_pm_ops,
291 		.of_match_table	= qoriq_tmu_match,
292 	},
293 	.probe	= qoriq_tmu_probe,
294 	.remove	= qoriq_tmu_remove,
295 };
296 module_platform_driver(qoriq_tmu);
297 
298 MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>");
299 MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver");
300 MODULE_LICENSE("GPL v2");
301