temperature_sysfs.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/kobject.h>
  5. #include <linux/sysfs.h>
  6. #include <linux/acpi.h>
  7. #include <linux/io.h>
  8. #include <linux/ioport.h>
  9. #include <linux/delay.h>
  10. #include "gpioregs.h"
  11. #define IT87_REG_TEMP(nr) (0x29 + (nr))
  12. #define DEV 0x07
  13. #define PME 0x04
  14. #define REG_2E 0x2e
  15. #define REG_4E 0x4e
  16. #define DEVID 0x20
  17. #define IT87_ACT_REG 0x30
  18. #define IT87_BASE_REG 0x60
  19. #define IT8786E_DEVID 0x8786
  20. #define DRIVER_NAME "tempperature_sysfs"
  21. struct temp_data {
  22. unsigned short addr;
  23. struct mutex lock;
  24. };
  25. static struct temp_data *g_data = NULL;
  26. extern struct kobject *hwmon_kobj;
  27. static int ec_read_reg(struct temp_data *data, u8 reg)
  28. {
  29. outb_p(reg, data->addr + 0);
  30. return inb_p(data->addr + 1);
  31. }
  32. static ssize_t temp1_input_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
  33. {
  34. struct temp_data *data = g_data;
  35. int val;
  36. mutex_lock(&data->lock);
  37. val = ((s8)ec_read_reg(data, IT87_REG_TEMP(0)));
  38. mutex_unlock(&data->lock);
  39. return sprintf(buf, "%d\n", val);
  40. }
  41. static ssize_t temp2_input_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
  42. {
  43. struct temp_data *data = g_data;
  44. int val;
  45. mutex_lock(&data->lock);
  46. val = ((s8)ec_read_reg(data, IT87_REG_TEMP(1)));
  47. mutex_unlock(&data->lock);
  48. return sprintf(buf, "%d\n", val);
  49. }
  50. static struct kobj_attribute temp1_input_attr =
  51. __ATTR(temp1_input, 0444, temp1_input_show, NULL);
  52. static struct kobj_attribute temp2_input_attr =
  53. __ATTR(temp2_input, 0444, temp2_input_show, NULL);
  54. static struct attribute *temperature_sysfs_attrs[] = {
  55. &temp1_input_attr.attr,
  56. &temp2_input_attr.attr,
  57. NULL,
  58. };
  59. static struct attribute_group temperature_sysfs_attr_group = {
  60. .attrs = temperature_sysfs_attrs,
  61. };
  62. static inline int superio_inw(int ioreg, int reg)
  63. {
  64. int val;
  65. outb(reg++, ioreg);
  66. val = inb(ioreg + 1) << 8;
  67. outb(reg, ioreg);
  68. val |= inb(ioreg + 1);
  69. return val;
  70. }
  71. static inline int superio_inb(int ioreg, int reg)
  72. {
  73. outb(reg, ioreg);
  74. return inb(ioreg + 1);
  75. }
  76. static inline void superio_outb(int ioreg, int reg, int val)
  77. {
  78. outb(reg, ioreg);
  79. outb(val, ioreg + 1);
  80. }
  81. static inline void superio_select(int ioreg, int ldn)
  82. {
  83. outb(DEV, ioreg);
  84. outb(ldn, ioreg + 1);
  85. }
  86. static inline int superio_enter(int ioreg)
  87. {
  88. if (!request_muxed_region(ioreg, 2, DRIVER_NAME))
  89. return -EBUSY;
  90. outb(0x87, ioreg);
  91. outb(0x01, ioreg);
  92. outb(0x55, ioreg);
  93. outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
  94. return 0;
  95. }
  96. static inline void superio_exit(int ioreg)
  97. {
  98. outb(0x02, ioreg);
  99. outb(0x02, ioreg + 1);
  100. release_region(ioreg, 2);
  101. }
  102. static int vfiec_find(int sioaddr, unsigned short *address)
  103. {
  104. int err;
  105. u16 chip_type;
  106. err = superio_enter(sioaddr);
  107. if (err)
  108. return err;
  109. chip_type = superio_inw(sioaddr, DEVID);
  110. if (chip_type != IT8786E_DEVID) {
  111. superio_exit(sioaddr);
  112. return -ENODEV;
  113. }
  114. superio_select(sioaddr, PME);
  115. if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
  116. pr_info("Device not activated\n");
  117. superio_exit(sioaddr);
  118. return -ENODEV;
  119. }
  120. *address = superio_inw(sioaddr, IT87_BASE_REG) & ~0x07;
  121. if (*address == 0) {
  122. pr_info("Base address not set\n");
  123. superio_exit(sioaddr);
  124. return -ENODEV;
  125. }
  126. pr_info("Found IT8786E chip at 0x%x\n", *address);
  127. superio_exit(sioaddr);
  128. return 0;
  129. }
  130. int temperature_sysfs_init(void)
  131. {
  132. int ret = 0;
  133. int err;
  134. unsigned short address = 0;
  135. struct temp_data *data;
  136. /* 探测SuperIO */
  137. err = vfiec_find(0x2e, &address);
  138. if (err) {
  139. err = vfiec_find(0x4e, &address);
  140. if (err) {
  141. pr_err("IT8786E not found\n");
  142. return -ENODEV;
  143. }
  144. }
  145. /* 分配数据结构 */
  146. data = kzalloc(sizeof(*data), GFP_KERNEL);
  147. if (!data)
  148. return -ENOMEM;
  149. data->addr = address + 5;
  150. mutex_init(&data->lock);
  151. g_data = data;
  152. ret = sysfs_create_group(hwmon_kobj, &temperature_sysfs_attr_group);
  153. return ret;
  154. }
  155. void temperature_sysfs_exit(void)
  156. {
  157. sysfs_remove_group(hwmon_kobj, &temperature_sysfs_attr_group);
  158. }