Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.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         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");