]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/thermal/qoriq_thermal.c
Merge branch 'next' into for-linus
[linux.git] / drivers / thermal / qoriq_thermal.c
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         if (!np) {
197                 dev_err(&pdev->dev, "Device OF-Node is NULL");
198                 return -ENODEV;
199         }
200
201         data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data),
202                             GFP_KERNEL);
203         if (!data)
204                 return -ENOMEM;
205
206         platform_set_drvdata(pdev, data);
207
208         data->little_endian = of_property_read_bool(np, "little-endian");
209
210         data->regs = of_iomap(np, 0);
211         if (!data->regs) {
212                 dev_err(&pdev->dev, "Failed to get memory region\n");
213                 ret = -ENODEV;
214                 goto err_iomap;
215         }
216
217         qoriq_tmu_init_device(data);    /* TMU initialization */
218
219         ret = qoriq_tmu_calibration(pdev);      /* TMU calibration */
220         if (ret < 0)
221                 goto err_tmu;
222
223         ret = qoriq_tmu_register_tmu_zone(pdev);
224         if (ret < 0) {
225                 dev_err(&pdev->dev, "Failed to register sensors\n");
226                 ret = -ENODEV;
227                 goto err_iomap;
228         }
229
230         return 0;
231
232 err_tmu:
233         iounmap(data->regs);
234
235 err_iomap:
236         platform_set_drvdata(pdev, NULL);
237
238         return ret;
239 }
240
241 static int qoriq_tmu_remove(struct platform_device *pdev)
242 {
243         struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
244
245         /* Disable monitoring */
246         tmu_write(data, TMR_DISABLE, &data->regs->tmr);
247
248         iounmap(data->regs);
249         platform_set_drvdata(pdev, NULL);
250
251         return 0;
252 }
253
254 #ifdef CONFIG_PM_SLEEP
255 static int qoriq_tmu_suspend(struct device *dev)
256 {
257         u32 tmr;
258         struct qoriq_tmu_data *data = dev_get_drvdata(dev);
259
260         /* Disable monitoring */
261         tmr = tmu_read(data, &data->regs->tmr);
262         tmr &= ~TMR_ME;
263         tmu_write(data, tmr, &data->regs->tmr);
264
265         return 0;
266 }
267
268 static int qoriq_tmu_resume(struct device *dev)
269 {
270         u32 tmr;
271         struct qoriq_tmu_data *data = dev_get_drvdata(dev);
272
273         /* Enable monitoring */
274         tmr = tmu_read(data, &data->regs->tmr);
275         tmr |= TMR_ME;
276         tmu_write(data, tmr, &data->regs->tmr);
277
278         return 0;
279 }
280 #endif
281
282 static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
283                          qoriq_tmu_suspend, qoriq_tmu_resume);
284
285 static const struct of_device_id qoriq_tmu_match[] = {
286         { .compatible = "fsl,qoriq-tmu", },
287         { .compatible = "fsl,imx8mq-tmu", },
288         {},
289 };
290 MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
291
292 static struct platform_driver qoriq_tmu = {
293         .driver = {
294                 .name           = "qoriq_thermal",
295                 .pm             = &qoriq_tmu_pm_ops,
296                 .of_match_table = qoriq_tmu_match,
297         },
298         .probe  = qoriq_tmu_probe,
299         .remove = qoriq_tmu_remove,
300 };
301 module_platform_driver(qoriq_tmu);
302
303 MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>");
304 MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver");
305 MODULE_LICENSE("GPL v2");