| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/kobject.h>
- #include <linux/sysfs.h>
- #include <linux/acpi.h>
- #include <linux/io.h>
- #include <linux/ioport.h>
- #include <linux/delay.h>
- #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);
- }
|