Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
[sfrench/cifs-2.6.git] / drivers / thermal / broadcom / bcm2835_thermal.c
1 /*
2  * Driver for Broadcom BCM2835 SoC temperature sensor
3  *
4  * Copyright (C) 2016 Martin Sperl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include <linux/clk.h>
18 #include <linux/debugfs.h>
19 #include <linux/device.h>
20 #include <linux/err.h>
21 #include <linux/io.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/of_address.h>
26 #include <linux/of_device.h>
27 #include <linux/platform_device.h>
28 #include <linux/thermal.h>
29
30 #define BCM2835_TS_TSENSCTL                     0x00
31 #define BCM2835_TS_TSENSSTAT                    0x04
32
33 #define BCM2835_TS_TSENSCTL_PRWDW               BIT(0)
34 #define BCM2835_TS_TSENSCTL_RSTB                BIT(1)
35
36 /*
37  * bandgap reference voltage in 6 mV increments
38  * 000b = 1178 mV, 001b = 1184 mV, ... 111b = 1220 mV
39  */
40 #define BCM2835_TS_TSENSCTL_CTRL_BITS           3
41 #define BCM2835_TS_TSENSCTL_CTRL_SHIFT          2
42 #define BCM2835_TS_TSENSCTL_CTRL_MASK               \
43         GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS +     \
44                 BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \
45                 BCM2835_TS_TSENSCTL_CTRL_SHIFT)
46 #define BCM2835_TS_TSENSCTL_CTRL_DEFAULT        1
47 #define BCM2835_TS_TSENSCTL_EN_INT              BIT(5)
48 #define BCM2835_TS_TSENSCTL_DIRECT              BIT(6)
49 #define BCM2835_TS_TSENSCTL_CLR_INT             BIT(7)
50 #define BCM2835_TS_TSENSCTL_THOLD_SHIFT         8
51 #define BCM2835_TS_TSENSCTL_THOLD_BITS          10
52 #define BCM2835_TS_TSENSCTL_THOLD_MASK               \
53         GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS +     \
54                 BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \
55                 BCM2835_TS_TSENSCTL_THOLD_SHIFT)
56 /*
57  * time how long the block to be asserted in reset
58  * which based on a clock counter (TSENS clock assumed)
59  */
60 #define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT      18
61 #define BCM2835_TS_TSENSCTL_RSTDELAY_BITS       8
62 #define BCM2835_TS_TSENSCTL_REGULEN             BIT(26)
63
64 #define BCM2835_TS_TSENSSTAT_DATA_BITS          10
65 #define BCM2835_TS_TSENSSTAT_DATA_SHIFT         0
66 #define BCM2835_TS_TSENSSTAT_DATA_MASK               \
67         GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS +     \
68                 BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \
69                 BCM2835_TS_TSENSSTAT_DATA_SHIFT)
70 #define BCM2835_TS_TSENSSTAT_VALID              BIT(10)
71 #define BCM2835_TS_TSENSSTAT_INTERRUPT          BIT(11)
72
73 struct bcm2835_thermal_data {
74         struct thermal_zone_device *tz;
75         void __iomem *regs;
76         struct clk *clk;
77         struct dentry *debugfsdir;
78 };
79
80 static int bcm2835_thermal_adc2temp(u32 adc, int offset, int slope)
81 {
82         return offset + slope * adc;
83 }
84
85 static int bcm2835_thermal_temp2adc(int temp, int offset, int slope)
86 {
87         temp -= offset;
88         temp /= slope;
89
90         if (temp < 0)
91                 temp = 0;
92         if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
93                 temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
94
95         return temp;
96 }
97
98 static int bcm2835_thermal_get_temp(void *d, int *temp)
99 {
100         struct bcm2835_thermal_data *data = d;
101         u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);
102
103         if (!(val & BCM2835_TS_TSENSSTAT_VALID))
104                 return -EIO;
105
106         val &= BCM2835_TS_TSENSSTAT_DATA_MASK;
107
108         *temp = bcm2835_thermal_adc2temp(
109                 val,
110                 thermal_zone_get_offset(data->tz),
111                 thermal_zone_get_slope(data->tz));
112
113         return 0;
114 }
115
116 static const struct debugfs_reg32 bcm2835_thermal_regs[] = {
117         {
118                 .name = "ctl",
119                 .offset = 0
120         },
121         {
122                 .name = "stat",
123                 .offset = 4
124         }
125 };
126
127 static void bcm2835_thermal_debugfs(struct platform_device *pdev)
128 {
129         struct thermal_zone_device *tz = platform_get_drvdata(pdev);
130         struct bcm2835_thermal_data *data = tz->devdata;
131         struct debugfs_regset32 *regset;
132
133         data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
134         if (!data->debugfsdir)
135                 return;
136
137         regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
138         if (!regset)
139                 return;
140
141         regset->regs = bcm2835_thermal_regs;
142         regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);
143         regset->base = data->regs;
144
145         debugfs_create_regset32("regset", 0444, data->debugfsdir, regset);
146 }
147
148 static const struct thermal_zone_of_device_ops bcm2835_thermal_ops = {
149         .get_temp = bcm2835_thermal_get_temp,
150 };
151
152 /*
153  * Note: as per Raspberry Foundation FAQ
154  * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature)
155  * the recommended temperature range for the SoC -40C to +85C
156  * so the trip limit is set to 80C.
157  * this applies to all the BCM283X SoC
158  */
159
160 static const struct of_device_id bcm2835_thermal_of_match_table[] = {
161         {
162                 .compatible = "brcm,bcm2835-thermal",
163         },
164         {
165                 .compatible = "brcm,bcm2836-thermal",
166         },
167         {
168                 .compatible = "brcm,bcm2837-thermal",
169         },
170         {},
171 };
172 MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
173
174 static int bcm2835_thermal_probe(struct platform_device *pdev)
175 {
176         const struct of_device_id *match;
177         struct thermal_zone_device *tz;
178         struct bcm2835_thermal_data *data;
179         struct resource *res;
180         int err = 0;
181         u32 val;
182         unsigned long rate;
183
184         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
185         if (!data)
186                 return -ENOMEM;
187
188         match = of_match_device(bcm2835_thermal_of_match_table,
189                                 &pdev->dev);
190         if (!match)
191                 return -EINVAL;
192
193         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
194         data->regs = devm_ioremap_resource(&pdev->dev, res);
195         if (IS_ERR(data->regs)) {
196                 err = PTR_ERR(data->regs);
197                 dev_err(&pdev->dev, "Could not get registers: %d\n", err);
198                 return err;
199         }
200
201         data->clk = devm_clk_get(&pdev->dev, NULL);
202         if (IS_ERR(data->clk)) {
203                 err = PTR_ERR(data->clk);
204                 if (err != -EPROBE_DEFER)
205                         dev_err(&pdev->dev, "Could not get clk: %d\n", err);
206                 return err;
207         }
208
209         err = clk_prepare_enable(data->clk);
210         if (err)
211                 return err;
212
213         rate = clk_get_rate(data->clk);
214         if ((rate < 1920000) || (rate > 5000000))
215                 dev_warn(&pdev->dev,
216                          "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n",
217                          data->clk, data->clk);
218
219         /* register of thermal sensor and get info from DT */
220         tz = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
221                                              &bcm2835_thermal_ops);
222         if (IS_ERR(tz)) {
223                 err = PTR_ERR(tz);
224                 dev_err(&pdev->dev,
225                         "Failed to register the thermal device: %d\n",
226                         err);
227                 goto err_clk;
228         }
229
230         /*
231          * right now the FW does set up the HW-block, so we are not
232          * touching the configuration registers.
233          * But if the HW is not enabled, then set it up
234          * using "sane" values used by the firmware right now.
235          */
236         val = readl(data->regs + BCM2835_TS_TSENSCTL);
237         if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
238                 int trip_temp, offset, slope;
239
240                 slope = thermal_zone_get_slope(tz);
241                 offset = thermal_zone_get_offset(tz);
242                 /*
243                  * For now we deal only with critical, otherwise
244                  * would need to iterate
245                  */
246                 err = tz->ops->get_trip_temp(tz, 0, &trip_temp);
247                 if (err < 0) {
248                         dev_err(&pdev->dev,
249                                 "Not able to read trip_temp: %d\n",
250                                 err);
251                         goto err_tz;
252                 }
253
254                 /* set bandgap reference voltage and enable voltage regulator */
255                 val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<
256                        BCM2835_TS_TSENSCTL_CTRL_SHIFT) |
257                       BCM2835_TS_TSENSCTL_REGULEN;
258
259                 /* use the recommended reset duration */
260                 val |= (0xFE << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
261
262                 /*  trip_adc value from info */
263                 val |= bcm2835_thermal_temp2adc(trip_temp,
264                                                 offset,
265                                                 slope)
266                         << BCM2835_TS_TSENSCTL_THOLD_SHIFT;
267
268                 /* write the value back to the register as 2 steps */
269                 writel(val, data->regs + BCM2835_TS_TSENSCTL);
270                 val |= BCM2835_TS_TSENSCTL_RSTB;
271                 writel(val, data->regs + BCM2835_TS_TSENSCTL);
272         }
273
274         data->tz = tz;
275
276         platform_set_drvdata(pdev, tz);
277
278         bcm2835_thermal_debugfs(pdev);
279
280         return 0;
281 err_tz:
282         thermal_zone_of_sensor_unregister(&pdev->dev, tz);
283 err_clk:
284         clk_disable_unprepare(data->clk);
285
286         return err;
287 }
288
289 static int bcm2835_thermal_remove(struct platform_device *pdev)
290 {
291         struct thermal_zone_device *tz = platform_get_drvdata(pdev);
292         struct bcm2835_thermal_data *data = tz->devdata;
293
294         debugfs_remove_recursive(data->debugfsdir);
295         thermal_zone_of_sensor_unregister(&pdev->dev, tz);
296         clk_disable_unprepare(data->clk);
297
298         return 0;
299 }
300
301 static struct platform_driver bcm2835_thermal_driver = {
302         .probe = bcm2835_thermal_probe,
303         .remove = bcm2835_thermal_remove,
304         .driver = {
305                 .name = "bcm2835_thermal",
306                 .of_match_table = bcm2835_thermal_of_match_table,
307         },
308 };
309 module_platform_driver(bcm2835_thermal_driver);
310
311 MODULE_AUTHOR("Martin Sperl");
312 MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
313 MODULE_LICENSE("GPL");