Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Huacai Chen and committed by
Ralf Baechle
64f09aa9 f14ceff7

+251
+4
arch/mips/include/asm/mach-loongson/loongson.h
··· 255 255 extern u64 loongson_chipcfg[MAX_PACKAGES]; 256 256 #define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id])) 257 257 258 + /* Chip Temperature registor of each physical cpu package, PRid >= Loongson-3A */ 259 + extern u64 loongson_chiptemp[MAX_PACKAGES]; 260 + #define LOONGSON_CHIPTEMP(id) (*(volatile u32 *)(loongson_chiptemp[id])) 261 + 258 262 /* Freq Control register of each physical cpu package, PRid >= Loongson-3B */ 259 263 extern u64 loongson_freqctrl[MAX_PACKAGES]; 260 264 #define LOONGSON_FREQCTRL(id) (*(volatile u32 *)(loongson_freqctrl[id]))
+9
arch/mips/loongson/common/env.c
··· 29 29 struct loongson_system_configuration loongson_sysconf; 30 30 31 31 u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; 32 + u64 loongson_chiptemp[MAX_PACKAGES]; 32 33 u64 loongson_freqctrl[MAX_PACKAGES]; 33 34 34 35 unsigned long long smp_group[4]; ··· 98 97 loongson_chipcfg[1] = 0x900010001fe00180; 99 98 loongson_chipcfg[2] = 0x900020001fe00180; 100 99 loongson_chipcfg[3] = 0x900030001fe00180; 100 + loongson_chiptemp[0] = 0x900000001fe0019c; 101 + loongson_chiptemp[1] = 0x900010001fe0019c; 102 + loongson_chiptemp[2] = 0x900020001fe0019c; 103 + loongson_chiptemp[3] = 0x900030001fe0019c; 101 104 loongson_sysconf.ht_control_base = 0x90000EFDFB000000; 102 105 loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; 103 106 } else if (ecpu->cputype == Loongson_3B) { ··· 115 110 loongson_chipcfg[1] = 0x900020001fe00180; 116 111 loongson_chipcfg[2] = 0x900040001fe00180; 117 112 loongson_chipcfg[3] = 0x900060001fe00180; 113 + loongson_chiptemp[0] = 0x900000001fe0019c; 114 + loongson_chiptemp[1] = 0x900020001fe0019c; 115 + loongson_chiptemp[2] = 0x900040001fe0019c; 116 + loongson_chiptemp[3] = 0x900060001fe0019c; 118 117 loongson_freqctrl[0] = 0x900000001fe001d0; 119 118 loongson_freqctrl[1] = 0x900020001fe001d0; 120 119 loongson_freqctrl[2] = 0x900040001fe001d0;
+3
drivers/platform/Kconfig
··· 1 1 if X86 2 2 source "drivers/platform/x86/Kconfig" 3 3 endif 4 + if MIPS 5 + source "drivers/platform/mips/Kconfig" 6 + endif 4 7 if GOLDFISH 5 8 source "drivers/platform/goldfish/Kconfig" 6 9 endif
+1
drivers/platform/Makefile
··· 3 3 # 4 4 5 5 obj-$(CONFIG_X86) += x86/ 6 + obj-$(CONFIG_MIPS) += mips/ 6 7 obj-$(CONFIG_OLPC) += olpc/ 7 8 obj-$(CONFIG_GOLDFISH) += goldfish/ 8 9 obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
+26
drivers/platform/mips/Kconfig
··· 1 + # 2 + # MIPS Platform Specific Drivers 3 + # 4 + 5 + menuconfig 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 + 16 + if MIPS_PLATFORM_DEVICES 17 + 18 + config 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 + 26 + endif # MIPS_PLATFORM_DEVICES
+1
drivers/platform/mips/Makefile
··· 1 + obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o
+207
drivers/platform/mips/cpu_hwmon.c
··· 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");