cpu_hwmon.c 5.4 KB

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