diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 15:50:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 15:50:54 -0400 |
commit | bfaf245022b4b8661af2e35f467cf0e91943c24c (patch) | |
tree | b5a6ee49a047557a791eb897c8c9545a155e36b7 /drivers/platform/mips/cpu_hwmon.c | |
parent | 96d928ed75c4ba4253e82910a697ec7b06ace8b4 (diff) | |
parent | 3e20a26b02bd4f24945c87407df51948dd488620 (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"This is the main pull request for MIPS for Linux 4.1. Most
noteworthy:
- Add more Octeon-optimized crypto functions
- Octeon crypto preemption and locking fixes
- Little endian support for Octeon
- Use correct CSR to soft reset Octeons
- Support LEDs on the Octeon-based DSR-1000N
- Fix PCI interrupt mapping for the Octeon-based DSR-1000N
- Mark prom_free_prom_memory() as __init for a number of systems
- Support for Imagination's Pistachio SOC. This includes arch and
CLK bits. I'd like to merge pinctrl bits later
- Improve parallelism of csum_partial for certain pipelines
- Organize DTB files in subdirs like other architectures
- Implement read_sched_clock for all MIPS platforms other than
Octeon
- Massive series of 38 fixes and cleanups for the FPU emulator /
kernel
- Further FPU remulator work to support new features. This sits on a
separate branch which also has been pulled into the 4.1 KVM branch
- Clean up and fixes for the SEAD3 eval board; remove unused file
- Various updates for Netlogic platforms
- A number of small updates for Loongson 3 platforms
- Increase the memory limit for ATH79 platforms to 256MB
- A fair number of fixes and updates for BCM47xx platforms
- Finish the implementation of XPA support
- MIPS FDC support. No, not floppy controller but Fast Debug Channel :)
- Detect the R16000 used in SGI legacy platforms
- Fix Kconfig dependencies for the SSB bus support"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (265 commits)
MIPS: Makefile: Fix MIPS ASE detection code
MIPS: asm: elf: Set O32 default FPU flags
MIPS: BCM47XX: Fix detecting Microsoft MN-700 & Asus WL500G
MIPS: Kconfig: Disable SMP/CPS for 64-bit
MIPS: Hibernate: flush TLB entries earlier
MIPS: smp-cps: cpu_set FPU mask if FPU present
MIPS: lose_fpu(): Disable FPU when MSA enabled
MIPS: ralink: add missing symbol for RALINK_ILL_ACC
MIPS: ralink: Fix bad config symbol in PCI makefile.
SSB: fix Kconfig dependencies
MIPS: Malta: Detect and fix bad memsize values
Revert "MIPS: Avoid pipeline stalls on some MIPS32R2 cores."
MIPS: Octeon: Delete override of cpu_has_mips_r2_exec_hazard.
MIPS: Fix cpu_has_mips_r2_exec_hazard.
MIPS: kernel: entry.S: Set correct ISA level for mips_ihb
MIPS: asm: spinlock: Fix addiu instruction for R10000_LLSC_WAR case
MIPS: r4kcache: Use correct base register for MIPS R6 cache flushes
MIPS: Kconfig: Fix typo for the r2-to-r6 emulator kernel parameter
MIPS: unaligned: Fix regular load/store instruction emulation for EVA
MIPS: unaligned: Surround load/store macros in do {} while statements
...
Diffstat (limited to 'drivers/platform/mips/cpu_hwmon.c')
-rw-r--r-- | drivers/platform/mips/cpu_hwmon.c | 207 |
1 files changed, 207 insertions, 0 deletions
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 | */ | ||
18 | int 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 | |||
31 | static struct device *cpu_hwmon_dev; | ||
32 | |||
33 | static ssize_t get_hwmon_name(struct device *dev, | ||
34 | struct device_attribute *attr, char *buf); | ||
35 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, get_hwmon_name, NULL, 0); | ||
36 | |||
37 | static struct attribute *cpu_hwmon_attributes[] = { | ||
38 | &sensor_dev_attr_name.dev_attr.attr, | ||
39 | NULL | ||
40 | }; | ||
41 | |||
42 | /* Hwmon device attribute group */ | ||
43 | static struct attribute_group cpu_hwmon_attribute_group = { | ||
44 | .attrs = cpu_hwmon_attributes, | ||
45 | }; | ||
46 | |||
47 | /* Hwmon device get name */ | ||
48 | static 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 | |||
54 | static ssize_t get_cpu0_temp(struct device *dev, | ||
55 | struct device_attribute *attr, char *buf); | ||
56 | static ssize_t get_cpu1_temp(struct device *dev, | ||
57 | struct device_attribute *attr, char *buf); | ||
58 | static ssize_t cpu0_temp_label(struct device *dev, | ||
59 | struct device_attribute *attr, char *buf); | ||
60 | static ssize_t cpu1_temp_label(struct device *dev, | ||
61 | struct device_attribute *attr, char *buf); | ||
62 | |||
63 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu0_temp, NULL, 1); | ||
64 | static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu0_temp_label, NULL, 1); | ||
65 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu1_temp, NULL, 2); | ||
66 | static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu1_temp_label, NULL, 2); | ||
67 | |||
68 | static 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 | |||
74 | static 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 | |||
80 | static 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 | |||
86 | static 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 | |||
92 | static 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 | |||
99 | static 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 | |||
106 | static 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 | |||
123 | sysfs_create_temp2_fail: | ||
124 | sysfs_remove_files(kobj, hwmon_cputemp1); | ||
125 | |||
126 | sysfs_create_temp1_fail: | ||
127 | return -1; | ||
128 | } | ||
129 | |||
130 | static 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 | ||
139 | static struct delayed_work thermal_work; | ||
140 | |||
141 | static 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 | |||
150 | static 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 | |||
181 | fail_create_sysfs_cputemp_files: | ||
182 | sysfs_remove_group(&cpu_hwmon_dev->kobj, | ||
183 | &cpu_hwmon_attribute_group); | ||
184 | |||
185 | fail_sysfs_create_group_hwmon: | ||
186 | hwmon_device_unregister(cpu_hwmon_dev); | ||
187 | |||
188 | fail_hwmon_device_register: | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static 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 | |||
201 | module_init(loongson_hwmon_init); | ||
202 | module_exit(loongson_hwmon_exit); | ||
203 | |||
204 | MODULE_AUTHOR("Yu Xiang <xiangy@lemote.com>"); | ||
205 | MODULE_AUTHOR("Huacai Chen <chenhc@lemote.com>"); | ||
206 | MODULE_DESCRIPTION("Loongson CPU Hwmon driver"); | ||
207 | MODULE_LICENSE("GPL"); | ||