Merge tag 'i3c/for-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
[platform/kernel/linux-starfive.git] / drivers / hwmon / ltq-cputemp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Lantiq cpu temperature sensor driver
3  *
4  * Copyright (C) 2017 Florian Eckert <fe@dev.tdt.de>
5  */
6
7 #include <linux/bitops.h>
8 #include <linux/delay.h>
9 #include <linux/hwmon.h>
10 #include <linux/hwmon-sysfs.h>
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/of_device.h>
14
15 #include <lantiq_soc.h>
16
17 /* gphy1 configuration register contains cpu temperature */
18 #define CGU_GPHY1_CR   0x0040
19 #define CGU_TEMP_PD    BIT(19)
20
21 static void ltq_cputemp_enable(void)
22 {
23         ltq_cgu_w32(ltq_cgu_r32(CGU_GPHY1_CR) | CGU_TEMP_PD, CGU_GPHY1_CR);
24 }
25
26 static void ltq_cputemp_disable(void *data)
27 {
28         ltq_cgu_w32(ltq_cgu_r32(CGU_GPHY1_CR) & ~CGU_TEMP_PD, CGU_GPHY1_CR);
29 }
30
31 static int ltq_read(struct device *dev, enum hwmon_sensor_types type,
32                     u32 attr, int channel, long *temp)
33 {
34         int value;
35
36         switch (attr) {
37         case hwmon_temp_input:
38                 /* get the temperature including one decimal place */
39                 value = (ltq_cgu_r32(CGU_GPHY1_CR) >> 9) & 0x01FF;
40                 value = value * 5;
41                 /* range -38 to +154 °C, register value zero is -38.0 °C */
42                 value -= 380;
43                 /* scale temp to millidegree */
44                 value = value * 100;
45                 break;
46         default:
47                 return -EOPNOTSUPP;
48         }
49
50         *temp = value;
51         return 0;
52 }
53
54 static umode_t ltq_is_visible(const void *_data, enum hwmon_sensor_types type,
55                               u32 attr, int channel)
56 {
57         if (type != hwmon_temp)
58                 return 0;
59
60         switch (attr) {
61         case hwmon_temp_input:
62                 return 0444;
63         default:
64                 return 0;
65         }
66 }
67
68 static const struct hwmon_channel_info * const ltq_info[] = {
69         HWMON_CHANNEL_INFO(chip,
70                            HWMON_C_REGISTER_TZ),
71         HWMON_CHANNEL_INFO(temp,
72                            HWMON_T_INPUT),
73         NULL
74 };
75
76 static const struct hwmon_ops ltq_hwmon_ops = {
77         .is_visible = ltq_is_visible,
78         .read = ltq_read,
79 };
80
81 static const struct hwmon_chip_info ltq_chip_info = {
82         .ops = &ltq_hwmon_ops,
83         .info = ltq_info,
84 };
85
86 static int ltq_cputemp_probe(struct platform_device *pdev)
87 {
88         struct device *hwmon_dev;
89         int err = 0;
90
91         /* available on vr9 v1.2 SoCs only */
92         if (ltq_soc_type() != SOC_TYPE_VR9_2)
93                 return -ENODEV;
94
95         err = devm_add_action(&pdev->dev, ltq_cputemp_disable, NULL);
96         if (err)
97                 return err;
98
99         ltq_cputemp_enable();
100
101         hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
102                                                          "ltq_cputemp",
103                                                          NULL,
104                                                          &ltq_chip_info,
105                                                          NULL);
106
107         if (IS_ERR(hwmon_dev)) {
108                 dev_err(&pdev->dev, "Failed to register as hwmon device");
109                 return PTR_ERR(hwmon_dev);
110         }
111
112         return 0;
113 }
114
115 const struct of_device_id ltq_cputemp_match[] = {
116         { .compatible = "lantiq,cputemp" },
117         {},
118 };
119 MODULE_DEVICE_TABLE(of, ltq_cputemp_match);
120
121 static struct platform_driver ltq_cputemp_driver = {
122         .probe = ltq_cputemp_probe,
123         .driver = {
124                 .name = "ltq-cputemp",
125                 .of_match_table = ltq_cputemp_match,
126         },
127 };
128
129 module_platform_driver(ltq_cputemp_driver);
130
131 MODULE_AUTHOR("Florian Eckert <fe@dev.tdt.de>");
132 MODULE_DESCRIPTION("Lantiq cpu temperature sensor driver");
133 MODULE_LICENSE("GPL");