#include #include #include #include #include #include #include #include #include #include "gpioregs.h" #define IT87_REG_TEMP(nr) (0x29 + (nr)) #define DEV 0x07 #define PME 0x04 #define REG_2E 0x2e #define REG_4E 0x4e #define DEVID 0x20 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 #define IT8786E_DEVID 0x8786 #define DRIVER_NAME "tempperature_sysfs" struct temp_data { unsigned short addr; struct mutex lock; }; static struct temp_data *g_data = NULL; extern struct kobject *hwmon_kobj; static int ec_read_reg(struct temp_data *data, u8 reg) { outb_p(reg, data->addr + 0); return inb_p(data->addr + 1); } static ssize_t temp1_input_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct temp_data *data = g_data; int val; mutex_lock(&data->lock); val = ((s8)ec_read_reg(data, IT87_REG_TEMP(0))); mutex_unlock(&data->lock); return sprintf(buf, "%d\n", val); } static ssize_t temp2_input_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct temp_data *data = g_data; int val; mutex_lock(&data->lock); val = ((s8)ec_read_reg(data, IT87_REG_TEMP(1))); mutex_unlock(&data->lock); return sprintf(buf, "%d\n", val); } static struct kobj_attribute temp1_input_attr = __ATTR(temp1_input, 0444, temp1_input_show, NULL); static struct kobj_attribute temp2_input_attr = __ATTR(temp2_input, 0444, temp2_input_show, NULL); static struct attribute *temperature_sysfs_attrs[] = { &temp1_input_attr.attr, &temp2_input_attr.attr, NULL, }; static struct attribute_group temperature_sysfs_attr_group = { .attrs = temperature_sysfs_attrs, }; static inline int superio_inw(int ioreg, int reg) { int val; outb(reg++, ioreg); val = inb(ioreg + 1) << 8; outb(reg, ioreg); val |= inb(ioreg + 1); return val; } static inline int superio_inb(int ioreg, int reg) { outb(reg, ioreg); return inb(ioreg + 1); } static inline void superio_outb(int ioreg, int reg, int val) { outb(reg, ioreg); outb(val, ioreg + 1); } static inline void superio_select(int ioreg, int ldn) { outb(DEV, ioreg); outb(ldn, ioreg + 1); } static inline int superio_enter(int ioreg) { if (!request_muxed_region(ioreg, 2, DRIVER_NAME)) return -EBUSY; outb(0x87, ioreg); outb(0x01, ioreg); outb(0x55, ioreg); outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg); return 0; } static inline void superio_exit(int ioreg) { outb(0x02, ioreg); outb(0x02, ioreg + 1); release_region(ioreg, 2); } static int vfiec_find(int sioaddr, unsigned short *address) { int err; u16 chip_type; err = superio_enter(sioaddr); if (err) return err; chip_type = superio_inw(sioaddr, DEVID); if (chip_type != IT8786E_DEVID) { superio_exit(sioaddr); return -ENODEV; } superio_select(sioaddr, PME); if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) { pr_info("Device not activated\n"); superio_exit(sioaddr); return -ENODEV; } *address = superio_inw(sioaddr, IT87_BASE_REG) & ~0x07; if (*address == 0) { pr_info("Base address not set\n"); superio_exit(sioaddr); return -ENODEV; } pr_info("Found IT8786E chip at 0x%x\n", *address); superio_exit(sioaddr); return 0; } int temperature_sysfs_init(void) { int ret = 0; int err; unsigned short address = 0; struct temp_data *data; /* 探测SuperIO */ err = vfiec_find(0x2e, &address); if (err) { err = vfiec_find(0x4e, &address); if (err) { pr_err("IT8786E not found\n"); return -ENODEV; } } /* 分配数据结构 */ data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->addr = address + 5; mutex_init(&data->lock); g_data = data; ret = sysfs_create_group(hwmon_kobj, &temperature_sysfs_attr_group); return ret; } void temperature_sysfs_exit(void) { sysfs_remove_group(hwmon_kobj, &temperature_sysfs_attr_group); }