root/drivers/platform/mips/cpu_hwmon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. loongson3_cpu_temp
  2. get_hwmon_name
  3. cpu_temp_label
  4. get_cpu_temp
  5. create_sysfs_cputemp_files
  6. remove_sysfs_cputemp_files
  7. do_thermal_timer
  8. loongson_hwmon_init
  9. loongson_hwmon_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 #include <linux/err.h>
   3 #include <linux/module.h>
   4 #include <linux/reboot.h>
   5 #include <linux/jiffies.h>
   6 #include <linux/hwmon.h>
   7 #include <linux/hwmon-sysfs.h>
   8 
   9 #include <loongson.h>
  10 #include <boot_param.h>
  11 #include <loongson_hwmon.h>
  12 
  13 /*
  14  * Loongson-3 series cpu has two sensors inside,
  15  * each of them from 0 to 255,
  16  * if more than 127, that is dangerous.
  17  * here only provide sensor1 data, because it always hot than sensor0
  18  */
  19 int loongson3_cpu_temp(int cpu)
  20 {
  21         u32 reg, prid_rev;
  22 
  23         reg = LOONGSON_CHIPTEMP(cpu);
  24         prid_rev = read_c0_prid() & PRID_REV_MASK;
  25         switch (prid_rev) {
  26         case PRID_REV_LOONGSON3A_R1:
  27                 reg = (reg >> 8) & 0xff;
  28                 break;
  29         case PRID_REV_LOONGSON3B_R1:
  30         case PRID_REV_LOONGSON3B_R2:
  31         case PRID_REV_LOONGSON3A_R2_0:
  32         case PRID_REV_LOONGSON3A_R2_1:
  33                 reg = ((reg >> 8) & 0xff) - 100;
  34                 break;
  35         case PRID_REV_LOONGSON3A_R3_0:
  36         case PRID_REV_LOONGSON3A_R3_1:
  37                 reg = (reg & 0xffff)*731/0x4000 - 273;
  38                 break;
  39         }
  40         return (int)reg * 1000;
  41 }
  42 
  43 static int nr_packages;
  44 static struct device *cpu_hwmon_dev;
  45 
  46 static ssize_t get_hwmon_name(struct device *dev,
  47                         struct device_attribute *attr, char *buf);
  48 static SENSOR_DEVICE_ATTR(name, S_IRUGO, get_hwmon_name, NULL, 0);
  49 
  50 static struct attribute *cpu_hwmon_attributes[] = {
  51         &sensor_dev_attr_name.dev_attr.attr,
  52         NULL
  53 };
  54 
  55 /* Hwmon device attribute group */
  56 static struct attribute_group cpu_hwmon_attribute_group = {
  57         .attrs = cpu_hwmon_attributes,
  58 };
  59 
  60 /* Hwmon device get name */
  61 static ssize_t get_hwmon_name(struct device *dev,
  62                         struct device_attribute *attr, char *buf)
  63 {
  64         return sprintf(buf, "cpu-hwmon\n");
  65 }
  66 
  67 static ssize_t get_cpu_temp(struct device *dev,
  68                         struct device_attribute *attr, char *buf);
  69 static ssize_t cpu_temp_label(struct device *dev,
  70                         struct device_attribute *attr, char *buf);
  71 
  72 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL, 1);
  73 static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu_temp_label, NULL, 1);
  74 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu_temp, NULL, 2);
  75 static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu_temp_label, NULL, 2);
  76 static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, get_cpu_temp, NULL, 3);
  77 static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, cpu_temp_label, NULL, 3);
  78 static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, get_cpu_temp, NULL, 4);
  79 static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, cpu_temp_label, NULL, 4);
  80 
  81 static const struct attribute *hwmon_cputemp[4][3] = {
  82         {
  83                 &sensor_dev_attr_temp1_input.dev_attr.attr,
  84                 &sensor_dev_attr_temp1_label.dev_attr.attr,
  85                 NULL
  86         },
  87         {
  88                 &sensor_dev_attr_temp2_input.dev_attr.attr,
  89                 &sensor_dev_attr_temp2_label.dev_attr.attr,
  90                 NULL
  91         },
  92         {
  93                 &sensor_dev_attr_temp3_input.dev_attr.attr,
  94                 &sensor_dev_attr_temp3_label.dev_attr.attr,
  95                 NULL
  96         },
  97         {
  98                 &sensor_dev_attr_temp4_input.dev_attr.attr,
  99                 &sensor_dev_attr_temp4_label.dev_attr.attr,
 100                 NULL
 101         }
 102 };
 103 
 104 static ssize_t cpu_temp_label(struct device *dev,
 105                         struct device_attribute *attr, char *buf)
 106 {
 107         int id = (to_sensor_dev_attr(attr))->index - 1;
 108         return sprintf(buf, "CPU %d Temperature\n", id);
 109 }
 110 
 111 static ssize_t get_cpu_temp(struct device *dev,
 112                         struct device_attribute *attr, char *buf)
 113 {
 114         int id = (to_sensor_dev_attr(attr))->index - 1;
 115         int value = loongson3_cpu_temp(id);
 116         return sprintf(buf, "%d\n", value);
 117 }
 118 
 119 static int create_sysfs_cputemp_files(struct kobject *kobj)
 120 {
 121         int i, ret = 0;
 122 
 123         for (i=0; i<nr_packages; i++)
 124                 ret = sysfs_create_files(kobj, hwmon_cputemp[i]);
 125 
 126         return ret;
 127 }
 128 
 129 static void remove_sysfs_cputemp_files(struct kobject *kobj)
 130 {
 131         int i;
 132 
 133         for (i=0; i<nr_packages; i++)
 134                 sysfs_remove_files(kobj, hwmon_cputemp[i]);
 135 }
 136 
 137 #define CPU_THERMAL_THRESHOLD 90000
 138 static struct delayed_work thermal_work;
 139 
 140 static void do_thermal_timer(struct work_struct *work)
 141 {
 142         int i, value, temp_max = 0;
 143 
 144         for (i=0; i<nr_packages; i++) {
 145                 value = loongson3_cpu_temp(i);
 146                 if (value > temp_max)
 147                         temp_max = value;
 148         }
 149 
 150         if (temp_max <= CPU_THERMAL_THRESHOLD)
 151                 schedule_delayed_work(&thermal_work, msecs_to_jiffies(5000));
 152         else
 153                 orderly_poweroff(true);
 154 }
 155 
 156 static int __init loongson_hwmon_init(void)
 157 {
 158         int ret;
 159 
 160         pr_info("Loongson Hwmon Enter...\n");
 161 
 162         cpu_hwmon_dev = hwmon_device_register(NULL);
 163         if (IS_ERR(cpu_hwmon_dev)) {
 164                 ret = PTR_ERR(cpu_hwmon_dev);
 165                 pr_err("hwmon_device_register fail!\n");
 166                 goto fail_hwmon_device_register;
 167         }
 168 
 169         nr_packages = loongson_sysconf.nr_cpus /
 170                 loongson_sysconf.cores_per_package;
 171 
 172         ret = sysfs_create_group(&cpu_hwmon_dev->kobj,
 173                                 &cpu_hwmon_attribute_group);
 174         if (ret) {
 175                 pr_err("fail to create loongson hwmon!\n");
 176                 goto fail_sysfs_create_group_hwmon;
 177         }
 178 
 179         ret = create_sysfs_cputemp_files(&cpu_hwmon_dev->kobj);
 180         if (ret) {
 181                 pr_err("fail to create cpu temperature interface!\n");
 182                 goto fail_create_sysfs_cputemp_files;
 183         }
 184 
 185         INIT_DEFERRABLE_WORK(&thermal_work, do_thermal_timer);
 186         schedule_delayed_work(&thermal_work, msecs_to_jiffies(20000));
 187 
 188         return ret;
 189 
 190 fail_create_sysfs_cputemp_files:
 191         sysfs_remove_group(&cpu_hwmon_dev->kobj,
 192                                 &cpu_hwmon_attribute_group);
 193 
 194 fail_sysfs_create_group_hwmon:
 195         hwmon_device_unregister(cpu_hwmon_dev);
 196 
 197 fail_hwmon_device_register:
 198         return ret;
 199 }
 200 
 201 static void __exit loongson_hwmon_exit(void)
 202 {
 203         cancel_delayed_work_sync(&thermal_work);
 204         remove_sysfs_cputemp_files(&cpu_hwmon_dev->kobj);
 205         sysfs_remove_group(&cpu_hwmon_dev->kobj,
 206                                 &cpu_hwmon_attribute_group);
 207         hwmon_device_unregister(cpu_hwmon_dev);
 208 }
 209 
 210 module_init(loongson_hwmon_init);
 211 module_exit(loongson_hwmon_exit);
 212 
 213 MODULE_AUTHOR("Yu Xiang <xiangy@lemote.com>");
 214 MODULE_AUTHOR("Huacai Chen <chenhc@lemote.com>");
 215 MODULE_DESCRIPTION("Loongson CPU Hwmon driver");
 216 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */