starfive: refresh patches
[openwrt/staging/981213.git] / target / linux / starfive / patches-6.1 / 0110-hwmon-sfctemp-Add-StarFive-JH71x0-temperature-sensor.patch
1 From 3f68f5d0a8c598a09d26a3908cbbff7312b31487 Mon Sep 17 00:00:00 2001
2 From: Emil Renner Berthing <kernel@esmil.dk>
3 Date: Tue, 21 Mar 2023 10:26:44 +0800
4 Subject: [PATCH 110/122] hwmon: (sfctemp) Add StarFive JH71x0 temperature
5 sensor
6
7 Add driver for the StarFive JH71x0 temperature sensor. You
8 can enable/disable it and read temperature in milli Celcius
9 through sysfs.
10
11 Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
12 Co-developed-by: Samin Guo <samin.guo@starfivetech.com>
13 Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
14 Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
15 ---
16 Documentation/hwmon/index.rst | 1 +
17 Documentation/hwmon/sfctemp.rst | 33 ++++
18 MAINTAINERS | 8 +
19 drivers/hwmon/Kconfig | 10 +
20 drivers/hwmon/Makefile | 1 +
21 drivers/hwmon/sfctemp.c | 331 ++++++++++++++++++++++++++++++++
22 6 files changed, 384 insertions(+)
23 create mode 100644 Documentation/hwmon/sfctemp.rst
24 create mode 100644 drivers/hwmon/sfctemp.c
25
26 --- a/Documentation/hwmon/index.rst
27 +++ b/Documentation/hwmon/index.rst
28 @@ -179,6 +179,7 @@ Hardware Monitoring Kernel Drivers
29 sch5627
30 sch5636
31 scpi-hwmon
32 + sfctemp
33 sht15
34 sht21
35 sht3x
36 --- /dev/null
37 +++ b/Documentation/hwmon/sfctemp.rst
38 @@ -0,0 +1,33 @@
39 +.. SPDX-License-Identifier: GPL-2.0
40 +
41 +Kernel driver sfctemp
42 +=====================
43 +
44 +Supported chips:
45 + - StarFive JH7100
46 + - StarFive JH7110
47 +
48 +Authors:
49 + - Emil Renner Berthing <kernel@esmil.dk>
50 +
51 +Description
52 +-----------
53 +
54 +This driver adds support for reading the built-in temperature sensor on the
55 +JH7100 and JH7110 RISC-V SoCs by StarFive Technology Co. Ltd.
56 +
57 +``sysfs`` interface
58 +-------------------
59 +
60 +The temperature sensor can be enabled, disabled and queried via the standard
61 +hwmon interface in sysfs under ``/sys/class/hwmon/hwmonX`` for some value of
62 +``X``:
63 +
64 +================ ==== =============================================
65 +Name Perm Description
66 +================ ==== =============================================
67 +temp1_enable RW Enable or disable temperature sensor.
68 + Automatically enabled by the driver,
69 + but may be disabled to save power.
70 +temp1_input RO Temperature reading in milli-degrees Celsius.
71 +================ ==== =============================================
72 --- a/MAINTAINERS
73 +++ b/MAINTAINERS
74 @@ -18686,6 +18686,14 @@ L: netdev@vger.kernel.org
75 S: Supported
76 F: drivers/net/ethernet/sfc/
77
78 +SFCTEMP HWMON DRIVER
79 +M: Emil Renner Berthing <kernel@esmil.dk>
80 +L: linux-hwmon@vger.kernel.org
81 +S: Maintained
82 +F: Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml
83 +F: Documentation/hwmon/sfctemp.rst
84 +F: drivers/hwmon/sfctemp.c
85 +
86 SFF/SFP/SFP+ MODULE SUPPORT
87 M: Russell King <linux@armlinux.org.uk>
88 L: netdev@vger.kernel.org
89 --- a/drivers/hwmon/Kconfig
90 +++ b/drivers/hwmon/Kconfig
91 @@ -1911,6 +1911,16 @@ config SENSORS_STTS751
92 This driver can also be built as a module. If so, the module
93 will be called stts751.
94
95 +config SENSORS_SFCTEMP
96 + tristate "Starfive JH71x0 temperature sensor"
97 + depends on ARCH_STARFIVE || COMPILE_TEST
98 + help
99 + If you say yes here you get support for temperature sensor
100 + on the Starfive JH71x0 SoCs.
101 +
102 + This driver can also be built as a module. If so, the module
103 + will be called sfctemp.
104 +
105 config SENSORS_SMM665
106 tristate "Summit Microelectronics SMM665"
107 depends on I2C
108 --- a/drivers/hwmon/Makefile
109 +++ b/drivers/hwmon/Makefile
110 @@ -179,6 +179,7 @@ obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
111 obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
112 obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
113 obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o
114 +obj-$(CONFIG_SENSORS_SFCTEMP) += sfctemp.o
115 obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o
116 obj-$(CONFIG_SENSORS_SHT15) += sht15.o
117 obj-$(CONFIG_SENSORS_SHT21) += sht21.o
118 --- /dev/null
119 +++ b/drivers/hwmon/sfctemp.c
120 @@ -0,0 +1,331 @@
121 +// SPDX-License-Identifier: GPL-2.0
122 +/*
123 + * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
124 + * Copyright (C) 2021 Samin Guo <samin.guo@starfivetech.com>
125 + */
126 +
127 +#include <linux/bits.h>
128 +#include <linux/clk.h>
129 +#include <linux/delay.h>
130 +#include <linux/hwmon.h>
131 +#include <linux/io.h>
132 +#include <linux/module.h>
133 +#include <linux/mutex.h>
134 +#include <linux/of.h>
135 +#include <linux/platform_device.h>
136 +#include <linux/reset.h>
137 +
138 +/*
139 + * TempSensor reset. The RSTN can be de-asserted once the analog core has
140 + * powered up. Trst(min 100ns)
141 + * 0:reset 1:de-assert
142 + */
143 +#define SFCTEMP_RSTN BIT(0)
144 +
145 +/*
146 + * TempSensor analog core power down. The analog core will be powered up
147 + * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the
148 + * analog core is powered up.
149 + * 0:power up 1:power down
150 + */
151 +#define SFCTEMP_PD BIT(1)
152 +
153 +/*
154 + * TempSensor start conversion enable.
155 + * 0:disable 1:enable
156 + */
157 +#define SFCTEMP_RUN BIT(2)
158 +
159 +/*
160 + * TempSensor conversion value output.
161 + * Temp(C)=DOUT*Y/4094 - K
162 + */
163 +#define SFCTEMP_DOUT_POS 16
164 +#define SFCTEMP_DOUT_MSK GENMASK(27, 16)
165 +
166 +/* DOUT to Celcius conversion constants */
167 +#define SFCTEMP_Y1000 237500L
168 +#define SFCTEMP_Z 4094L
169 +#define SFCTEMP_K1000 81100L
170 +
171 +struct sfctemp {
172 + /* serialize access to hardware register and enabled below */
173 + struct mutex lock;
174 + void __iomem *regs;
175 + struct clk *clk_sense;
176 + struct clk *clk_bus;
177 + struct reset_control *rst_sense;
178 + struct reset_control *rst_bus;
179 + bool enabled;
180 +};
181 +
182 +static void sfctemp_power_up(struct sfctemp *sfctemp)
183 +{
184 + /* make sure we're powered down first */
185 + writel(SFCTEMP_PD, sfctemp->regs);
186 + udelay(1);
187 +
188 + writel(0, sfctemp->regs);
189 + /* wait t_pu(50us) + t_rst(100ns) */
190 + usleep_range(60, 200);
191 +
192 + /* de-assert reset */
193 + writel(SFCTEMP_RSTN, sfctemp->regs);
194 + udelay(1); /* wait t_su(500ps) */
195 +}
196 +
197 +static void sfctemp_power_down(struct sfctemp *sfctemp)
198 +{
199 + writel(SFCTEMP_PD, sfctemp->regs);
200 +}
201 +
202 +static void sfctemp_run(struct sfctemp *sfctemp)
203 +{
204 + writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);
205 + udelay(1);
206 +}
207 +
208 +static void sfctemp_stop(struct sfctemp *sfctemp)
209 +{
210 + writel(SFCTEMP_RSTN, sfctemp->regs);
211 +}
212 +
213 +static int sfctemp_enable(struct sfctemp *sfctemp)
214 +{
215 + int ret = 0;
216 +
217 + mutex_lock(&sfctemp->lock);
218 + if (sfctemp->enabled)
219 + goto done;
220 +
221 + ret = clk_prepare_enable(sfctemp->clk_bus);
222 + if (ret)
223 + goto err;
224 + ret = reset_control_deassert(sfctemp->rst_bus);
225 + if (ret)
226 + goto err_disable_bus;
227 +
228 + ret = clk_prepare_enable(sfctemp->clk_sense);
229 + if (ret)
230 + goto err_assert_bus;
231 + ret = reset_control_deassert(sfctemp->rst_sense);
232 + if (ret)
233 + goto err_disable_sense;
234 +
235 + sfctemp_power_up(sfctemp);
236 + sfctemp_run(sfctemp);
237 + sfctemp->enabled = true;
238 +done:
239 + mutex_unlock(&sfctemp->lock);
240 + return ret;
241 +
242 +err_disable_sense:
243 + clk_disable_unprepare(sfctemp->clk_sense);
244 +err_assert_bus:
245 + reset_control_assert(sfctemp->rst_bus);
246 +err_disable_bus:
247 + clk_disable_unprepare(sfctemp->clk_bus);
248 +err:
249 + mutex_unlock(&sfctemp->lock);
250 + return ret;
251 +}
252 +
253 +static int sfctemp_disable(struct sfctemp *sfctemp)
254 +{
255 + mutex_lock(&sfctemp->lock);
256 + if (!sfctemp->enabled)
257 + goto done;
258 +
259 + sfctemp_stop(sfctemp);
260 + sfctemp_power_down(sfctemp);
261 + reset_control_assert(sfctemp->rst_sense);
262 + clk_disable_unprepare(sfctemp->clk_sense);
263 + reset_control_assert(sfctemp->rst_bus);
264 + clk_disable_unprepare(sfctemp->clk_bus);
265 + sfctemp->enabled = false;
266 +done:
267 + mutex_unlock(&sfctemp->lock);
268 + return 0;
269 +}
270 +
271 +static void sfctemp_disable_action(void *data)
272 +{
273 + sfctemp_disable(data);
274 +}
275 +
276 +static int sfctemp_convert(struct sfctemp *sfctemp, long *val)
277 +{
278 + int ret;
279 +
280 + mutex_lock(&sfctemp->lock);
281 + if (!sfctemp->enabled) {
282 + ret = -ENODATA;
283 + goto out;
284 + }
285 +
286 + /* calculate temperature in milli Celcius */
287 + *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS)
288 + * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000;
289 +
290 + ret = 0;
291 +out:
292 + mutex_unlock(&sfctemp->lock);
293 + return ret;
294 +}
295 +
296 +static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type,
297 + u32 attr, int channel)
298 +{
299 + switch (type) {
300 + case hwmon_temp:
301 + switch (attr) {
302 + case hwmon_temp_enable:
303 + return 0644;
304 + case hwmon_temp_input:
305 + return 0444;
306 + default:
307 + return 0;
308 + }
309 + default:
310 + return 0;
311 + }
312 +}
313 +
314 +static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type,
315 + u32 attr, int channel, long *val)
316 +{
317 + struct sfctemp *sfctemp = dev_get_drvdata(dev);
318 +
319 + switch (type) {
320 + case hwmon_temp:
321 + switch (attr) {
322 + case hwmon_temp_enable:
323 + *val = sfctemp->enabled;
324 + return 0;
325 + case hwmon_temp_input:
326 + return sfctemp_convert(sfctemp, val);
327 + default:
328 + return -EINVAL;
329 + }
330 + default:
331 + return -EINVAL;
332 + }
333 +}
334 +
335 +static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type,
336 + u32 attr, int channel, long val)
337 +{
338 + struct sfctemp *sfctemp = dev_get_drvdata(dev);
339 +
340 + switch (type) {
341 + case hwmon_temp:
342 + switch (attr) {
343 + case hwmon_temp_enable:
344 + if (val == 0)
345 + return sfctemp_disable(sfctemp);
346 + if (val == 1)
347 + return sfctemp_enable(sfctemp);
348 + return -EINVAL;
349 + default:
350 + return -EINVAL;
351 + }
352 + default:
353 + return -EINVAL;
354 + }
355 +}
356 +
357 +static const struct hwmon_channel_info *sfctemp_info[] = {
358 + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
359 + HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT),
360 + NULL
361 +};
362 +
363 +static const struct hwmon_ops sfctemp_hwmon_ops = {
364 + .is_visible = sfctemp_is_visible,
365 + .read = sfctemp_read,
366 + .write = sfctemp_write,
367 +};
368 +
369 +static const struct hwmon_chip_info sfctemp_chip_info = {
370 + .ops = &sfctemp_hwmon_ops,
371 + .info = sfctemp_info,
372 +};
373 +
374 +static int sfctemp_probe(struct platform_device *pdev)
375 +{
376 + struct device *dev = &pdev->dev;
377 + struct device *hwmon_dev;
378 + struct sfctemp *sfctemp;
379 + int ret;
380 +
381 + sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL);
382 + if (!sfctemp)
383 + return -ENOMEM;
384 +
385 + dev_set_drvdata(dev, sfctemp);
386 + mutex_init(&sfctemp->lock);
387 +
388 + sfctemp->regs = devm_platform_ioremap_resource(pdev, 0);
389 + if (IS_ERR(sfctemp->regs))
390 + return PTR_ERR(sfctemp->regs);
391 +
392 + sfctemp->clk_sense = devm_clk_get(dev, "sense");
393 + if (IS_ERR(sfctemp->clk_sense))
394 + return dev_err_probe(dev, PTR_ERR(sfctemp->clk_sense),
395 + "error getting sense clock\n");
396 +
397 + sfctemp->clk_bus = devm_clk_get(dev, "bus");
398 + if (IS_ERR(sfctemp->clk_bus))
399 + return dev_err_probe(dev, PTR_ERR(sfctemp->clk_bus),
400 + "error getting bus clock\n");
401 +
402 + sfctemp->rst_sense = devm_reset_control_get_exclusive(dev, "sense");
403 + if (IS_ERR(sfctemp->rst_sense))
404 + return dev_err_probe(dev, PTR_ERR(sfctemp->rst_sense),
405 + "error getting sense reset\n");
406 +
407 + sfctemp->rst_bus = devm_reset_control_get_exclusive(dev, "bus");
408 + if (IS_ERR(sfctemp->rst_bus))
409 + return dev_err_probe(dev, PTR_ERR(sfctemp->rst_bus),
410 + "error getting busreset\n");
411 +
412 + ret = reset_control_assert(sfctemp->rst_sense);
413 + if (ret)
414 + return dev_err_probe(dev, ret, "error asserting sense reset\n");
415 +
416 + ret = reset_control_assert(sfctemp->rst_bus);
417 + if (ret)
418 + return dev_err_probe(dev, ret, "error asserting bus reset\n");
419 +
420 + ret = devm_add_action(dev, sfctemp_disable_action, sfctemp);
421 + if (ret)
422 + return ret;
423 +
424 + ret = sfctemp_enable(sfctemp);
425 + if (ret)
426 + return dev_err_probe(dev, ret, "error enabling temperature sensor: %d\n", ret);
427 +
428 + hwmon_dev = devm_hwmon_device_register_with_info(dev, "sfctemp", sfctemp,
429 + &sfctemp_chip_info, NULL);
430 + return PTR_ERR_OR_ZERO(hwmon_dev);
431 +}
432 +
433 +static const struct of_device_id sfctemp_of_match[] = {
434 + { .compatible = "starfive,jh7100-temp" },
435 + { .compatible = "starfive,jh7110-temp" },
436 + { /* sentinel */ }
437 +};
438 +MODULE_DEVICE_TABLE(of, sfctemp_of_match);
439 +
440 +static struct platform_driver sfctemp_driver = {
441 + .probe = sfctemp_probe,
442 + .driver = {
443 + .name = "sfctemp",
444 + .of_match_table = sfctemp_of_match,
445 + },
446 +};
447 +module_platform_driver(sfctemp_driver);
448 +
449 +MODULE_AUTHOR("Emil Renner Berthing");
450 +MODULE_DESCRIPTION("StarFive JH71x0 temperature sensor driver");
451 +MODULE_LICENSE("GPL");