aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuacai Chen <chenhc@lemote.com>2015-03-28 22:54:09 -0400
committerRalf Baechle <ralf@linux-mips.org>2015-04-01 11:22:17 -0400
commit64f09aa967e1a6effdffcbf14c912ec5f9e3715e (patch)
tree3c776ec46700b0de7bcbcb38dd2d3f2a0d3726c7
parentf14ceff75545f9a1e62430fe9cc796208569b972 (diff)
MIPS: Loongson-3: Add CPU Hwmon platform driver
This add CPU Hwmon (temperature sensor) platform driver for Loongson-3. Signed-off-by: Huacai Chen <chenhc@lemote.com> Cc: Steven J. Hill <Steven.Hill@imgtec.com> Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang <zhangfx@lemote.com> Cc: Zhangjin Wu <wuzhangjin@gmail.com> Patchwork: https://patchwork.linux-mips.org/patch/9617/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/include/asm/mach-loongson/loongson.h4
-rw-r--r--arch/mips/loongson/common/env.c9
-rw-r--r--drivers/platform/Kconfig3
-rw-r--r--drivers/platform/Makefile1
-rw-r--r--drivers/platform/mips/Kconfig26
-rw-r--r--drivers/platform/mips/Makefile1
-rw-r--r--drivers/platform/mips/cpu_hwmon.c207
7 files changed, 251 insertions, 0 deletions
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index 5459ac09679f..9783103fd6f6 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -255,6 +255,10 @@ static inline void do_perfcnt_IRQ(void)
255extern u64 loongson_chipcfg[MAX_PACKAGES]; 255extern u64 loongson_chipcfg[MAX_PACKAGES];
256#define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id])) 256#define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id]))
257 257
258/* Chip Temperature registor of each physical cpu package, PRid >= Loongson-3A */
259extern u64 loongson_chiptemp[MAX_PACKAGES];
260#define LOONGSON_CHIPTEMP(id) (*(volatile u32 *)(loongson_chiptemp[id]))
261
258/* Freq Control register of each physical cpu package, PRid >= Loongson-3B */ 262/* Freq Control register of each physical cpu package, PRid >= Loongson-3B */
259extern u64 loongson_freqctrl[MAX_PACKAGES]; 263extern u64 loongson_freqctrl[MAX_PACKAGES];
260#define LOONGSON_FREQCTRL(id) (*(volatile u32 *)(loongson_freqctrl[id])) 264#define LOONGSON_FREQCTRL(id) (*(volatile u32 *)(loongson_freqctrl[id]))
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
index 045ea3d47c87..22f04ca2ff3e 100644
--- a/arch/mips/loongson/common/env.c
+++ b/arch/mips/loongson/common/env.c
@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap;
29struct loongson_system_configuration loongson_sysconf; 29struct loongson_system_configuration loongson_sysconf;
30 30
31u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; 31u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
32u64 loongson_chiptemp[MAX_PACKAGES];
32u64 loongson_freqctrl[MAX_PACKAGES]; 33u64 loongson_freqctrl[MAX_PACKAGES];
33 34
34unsigned long long smp_group[4]; 35unsigned long long smp_group[4];
@@ -97,6 +98,10 @@ void __init prom_init_env(void)
97 loongson_chipcfg[1] = 0x900010001fe00180; 98 loongson_chipcfg[1] = 0x900010001fe00180;
98 loongson_chipcfg[2] = 0x900020001fe00180; 99 loongson_chipcfg[2] = 0x900020001fe00180;
99 loongson_chipcfg[3] = 0x900030001fe00180; 100 loongson_chipcfg[3] = 0x900030001fe00180;
101 loongson_chiptemp[0] = 0x900000001fe0019c;
102 loongson_chiptemp[1] = 0x900010001fe0019c;
103 loongson_chiptemp[2] = 0x900020001fe0019c;
104 loongson_chiptemp[3] = 0x900030001fe0019c;
100 loongson_sysconf.ht_control_base = 0x90000EFDFB000000; 105 loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
101 loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; 106 loongson_sysconf.workarounds = WORKAROUND_CPUFREQ;
102 } else if (ecpu->cputype == Loongson_3B) { 107 } else if (ecpu->cputype == Loongson_3B) {
@@ -110,6 +115,10 @@ void __init prom_init_env(void)
110 loongson_chipcfg[1] = 0x900020001fe00180; 115 loongson_chipcfg[1] = 0x900020001fe00180;
111 loongson_chipcfg[2] = 0x900040001fe00180; 116 loongson_chipcfg[2] = 0x900040001fe00180;
112 loongson_chipcfg[3] = 0x900060001fe00180; 117 loongson_chipcfg[3] = 0x900060001fe00180;
118 loongson_chiptemp[0] = 0x900000001fe0019c;
119 loongson_chiptemp[1] = 0x900020001fe0019c;
120 loongson_chiptemp[2] = 0x900040001fe0019c;
121 loongson_chiptemp[3] = 0x900060001fe0019c;
113 loongson_freqctrl[0] = 0x900000001fe001d0; 122 loongson_freqctrl[0] = 0x900000001fe001d0;
114 loongson_freqctrl[1] = 0x900020001fe001d0; 123 loongson_freqctrl[1] = 0x900020001fe001d0;
115 loongson_freqctrl[2] = 0x900040001fe001d0; 124 loongson_freqctrl[2] = 0x900040001fe001d0;
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 09fde58b12e0..0adccbf5c83f 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,6 +1,9 @@
1if X86 1if X86
2source "drivers/platform/x86/Kconfig" 2source "drivers/platform/x86/Kconfig"
3endif 3endif
4if MIPS
5source "drivers/platform/mips/Kconfig"
6endif
4if GOLDFISH 7if GOLDFISH
5source "drivers/platform/goldfish/Kconfig" 8source "drivers/platform/goldfish/Kconfig"
6endif 9endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 3656b7b17b99..ca2692510733 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5obj-$(CONFIG_X86) += x86/ 5obj-$(CONFIG_X86) += x86/
6obj-$(CONFIG_MIPS) += mips/
6obj-$(CONFIG_OLPC) += olpc/ 7obj-$(CONFIG_OLPC) += olpc/
7obj-$(CONFIG_GOLDFISH) += goldfish/ 8obj-$(CONFIG_GOLDFISH) += goldfish/
8obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ 9obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
new file mode 100644
index 000000000000..b3ae30a4c67b
--- /dev/null
+++ b/drivers/platform/mips/Kconfig
@@ -0,0 +1,26 @@
1#
2# MIPS Platform Specific Drivers
3#
4
5menuconfig MIPS_PLATFORM_DEVICES
6 bool "MIPS Platform Specific Device Drivers"
7 default y
8 help
9 Say Y here to get to see options for device drivers of various
10 MIPS platforms, including vendor-specific netbook/laptop/desktop
11 extension and hardware monitor drivers. This option itself does
12 not add any kernel code.
13
14 If you say N, all options in this submenu will be skipped and disabled.
15
16if MIPS_PLATFORM_DEVICES
17
18config CPU_HWMON
19 tristate "Loongson CPU HWMon Driver"
20 depends on LOONGSON_MACH3X
21 select HWMON
22 default y
23 help
24 Loongson-3A/3B CPU Hwmon (temperature sensor) driver.
25
26endif # MIPS_PLATFORM_DEVICES
diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile
new file mode 100644
index 000000000000..8dfd03924c37
--- /dev/null
+++ b/drivers/platform/mips/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o
diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c
new file mode 100644
index 000000000000..0f6c63e17049
--- /dev/null
+++ b/drivers/platform/mips/cpu_hwmon.c
@@ -0,0 +1,207 @@
1#include <linux/err.h>
2#include <linux/module.h>
3#include <linux/reboot.h>
4#include <linux/jiffies.h>
5#include <linux/hwmon.h>
6#include <linux/hwmon-sysfs.h>
7
8#include <loongson.h>
9#include <boot_param.h>
10#include <loongson_hwmon.h>
11
12/*
13 * Loongson-3 series cpu has two sensors inside,
14 * each of them from 0 to 255,
15 * if more than 127, that is dangerous.
16 * here only provide sensor1 data, because it always hot than sensor0
17 */
18int loongson3_cpu_temp(int cpu)
19{
20 u32 reg;
21
22 reg = LOONGSON_CHIPTEMP(cpu);
23 if (loongson_sysconf.cputype == Loongson_3A)
24 reg = (reg >> 8) & 0xff;
25 else if (loongson_sysconf.cputype == Loongson_3B)
26 reg = ((reg >> 8) & 0xff) - 100;
27
28 return (int)reg * 1000;
29}
30
31static struct device *cpu_hwmon_dev;
32
33static ssize_t get_hwmon_name(struct device *dev,
34 struct device_attribute *attr, char *buf);
35static SENSOR_DEVICE_ATTR(name, S_IRUGO, get_hwmon_name, NULL, 0);
36
37static struct attribute *cpu_hwmon_attributes[] = {
38 &sensor_dev_attr_name.dev_attr.attr,
39 NULL
40};
41
42/* Hwmon device attribute group */
43static struct attribute_group cpu_hwmon_attribute_group = {
44 .attrs = cpu_hwmon_attributes,
45};
46
47/* Hwmon device get name */
48static ssize_t get_hwmon_name(struct device *dev,
49 struct device_attribute *attr, char *buf)
50{
51 return sprintf(buf, "cpu-hwmon\n");
52}
53
54static ssize_t get_cpu0_temp(struct device *dev,
55 struct device_attribute *attr, char *buf);
56static ssize_t get_cpu1_temp(struct device *dev,
57 struct device_attribute *attr, char *buf);
58static ssize_t cpu0_temp_label(struct device *dev,
59 struct device_attribute *attr, char *buf);
60static ssize_t cpu1_temp_label(struct device *dev,
61 struct device_attribute *attr, char *buf);
62
63static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu0_temp, NULL, 1);
64static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu0_temp_label, NULL, 1);
65static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu1_temp, NULL, 2);
66static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu1_temp_label, NULL, 2);
67
68static const struct attribute *hwmon_cputemp1[] = {
69 &sensor_dev_attr_temp1_input.dev_attr.attr,
70 &sensor_dev_attr_temp1_label.dev_attr.attr,
71 NULL
72};
73
74static const struct attribute *hwmon_cputemp2[] = {
75 &sensor_dev_attr_temp2_input.dev_attr.attr,
76 &sensor_dev_attr_temp2_label.dev_attr.attr,
77 NULL
78};
79
80static ssize_t cpu0_temp_label(struct device *dev,
81 struct device_attribute *attr, char *buf)
82{
83 return sprintf(buf, "CPU 0 Temprature\n");
84}
85
86static ssize_t cpu1_temp_label(struct device *dev,
87 struct device_attribute *attr, char *buf)
88{
89 return sprintf(buf, "CPU 1 Temprature\n");
90}
91
92static ssize_t get_cpu0_temp(struct device *dev,
93 struct device_attribute *attr, char *buf)
94{
95 int value = loongson3_cpu_temp(0);
96 return sprintf(buf, "%d\n", value);
97}
98
99static ssize_t get_cpu1_temp(struct device *dev,
100 struct device_attribute *attr, char *buf)
101{
102 int value = loongson3_cpu_temp(1);
103 return sprintf(buf, "%d\n", value);
104}
105
106static int create_sysfs_cputemp_files(struct kobject *kobj)
107{
108 int ret;
109
110 ret = sysfs_create_files(kobj, hwmon_cputemp1);
111 if (ret)
112 goto sysfs_create_temp1_fail;
113
114 if (loongson_sysconf.nr_cpus <= loongson_sysconf.cores_per_package)
115 return 0;
116
117 ret = sysfs_create_files(kobj, hwmon_cputemp2);
118 if (ret)
119 goto sysfs_create_temp2_fail;
120
121 return 0;
122
123sysfs_create_temp2_fail:
124 sysfs_remove_files(kobj, hwmon_cputemp1);
125
126sysfs_create_temp1_fail:
127 return -1;
128}
129
130static void remove_sysfs_cputemp_files(struct kobject *kobj)
131{
132 sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp1);
133
134 if (loongson_sysconf.nr_cpus > loongson_sysconf.cores_per_package)
135 sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp2);
136}
137
138#define CPU_THERMAL_THRESHOLD 90000
139static struct delayed_work thermal_work;
140
141static void do_thermal_timer(struct work_struct *work)
142{
143 int value = loongson3_cpu_temp(0);
144 if (value <= CPU_THERMAL_THRESHOLD)
145 schedule_delayed_work(&thermal_work, msecs_to_jiffies(5000));
146 else
147 orderly_poweroff(true);
148}
149
150static int __init loongson_hwmon_init(void)
151{
152 int ret;
153
154 pr_info("Loongson Hwmon Enter...\n");
155
156 cpu_hwmon_dev = hwmon_device_register(NULL);
157 if (IS_ERR(cpu_hwmon_dev)) {
158 ret = -ENOMEM;
159 pr_err("hwmon_device_register fail!\n");
160 goto fail_hwmon_device_register;
161 }
162
163 ret = sysfs_create_group(&cpu_hwmon_dev->kobj,
164 &cpu_hwmon_attribute_group);
165 if (ret) {
166 pr_err("fail to create loongson hwmon!\n");
167 goto fail_sysfs_create_group_hwmon;
168 }
169
170 ret = create_sysfs_cputemp_files(&cpu_hwmon_dev->kobj);
171 if (ret) {
172 pr_err("fail to create cpu temprature interface!\n");
173 goto fail_create_sysfs_cputemp_files;
174 }
175
176 INIT_DEFERRABLE_WORK(&thermal_work, do_thermal_timer);
177 schedule_delayed_work(&thermal_work, msecs_to_jiffies(20000));
178
179 return ret;
180
181fail_create_sysfs_cputemp_files:
182 sysfs_remove_group(&cpu_hwmon_dev->kobj,
183 &cpu_hwmon_attribute_group);
184
185fail_sysfs_create_group_hwmon:
186 hwmon_device_unregister(cpu_hwmon_dev);
187
188fail_hwmon_device_register:
189 return ret;
190}
191
192static void __exit loongson_hwmon_exit(void)
193{
194 cancel_delayed_work_sync(&thermal_work);
195 remove_sysfs_cputemp_files(&cpu_hwmon_dev->kobj);
196 sysfs_remove_group(&cpu_hwmon_dev->kobj,
197 &cpu_hwmon_attribute_group);
198 hwmon_device_unregister(cpu_hwmon_dev);
199}
200
201module_init(loongson_hwmon_init);
202module_exit(loongson_hwmon_exit);
203
204MODULE_AUTHOR("Yu Xiang <xiangy@lemote.com>");
205MODULE_AUTHOR("Huacai Chen <chenhc@lemote.com>");
206MODULE_DESCRIPTION("Loongson CPU Hwmon driver");
207MODULE_LICENSE("GPL");