Ver código fonte

添加voltage sysfs驱动

2 arquivos alterados com 328 adições e 0 exclusões
  1. 321 0
      voltage_sysfs.c
  2. 7 0
      voltage_sysfs.h

+ 321 - 0
voltage_sysfs.c

@@ -0,0 +1,321 @@
+#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/delay.h>
+#include "gpioregs.h"
+
+extern struct kobject *hwmon_kobj;
+
+
+/* Helper functions for IO access */
+static uint8_t hwm_read_reg(uint16_t hwm_base, uint8_t reg)
+{
+    outb(reg, hwm_base + HWM_INDEX_OFFSET);
+    return inb(hwm_base + HWM_DATA_OFFSET);
+}
+
+static void hwm_write_reg(uint16_t hwm_base, uint8_t reg, uint8_t val)
+{
+    outb(reg, hwm_base + HWM_INDEX_OFFSET);
+    outb(val, hwm_base + HWM_DATA_OFFSET);
+}
+
+static uint8_t hwm_read_reg_retry(uint16_t hwm_base, uint8_t reg)
+{
+    uint8_t v = hwm_read_reg(hwm_base, reg);
+    if (v == 0xFF) {
+        v = hwm_read_reg(hwm_base, reg);
+    }
+    return v;
+}
+
+static int vin_raw_to_volt(uint8_t raw, int r_top_kohm, int r_bottom_kohm)
+{
+    int vm = raw * 11;
+    if (r_top_kohm > 0 && r_bottom_kohm > 0) {
+        vm = (vm * (r_top_kohm + r_bottom_kohm)) / r_bottom_kohm;
+    }
+    return vm;
+}
+
+static int ec_raw_to_volt(uint8_t raw, int r_top_kohm, int r_bottom_kohm)
+{
+    int vm = raw * 12; /* EC unit: 10mV */
+    vm = (vm * (r_top_kohm + r_bottom_kohm)) / r_bottom_kohm;
+    return vm ;
+}
+
+
+static int ec_wait_ibf(void)
+{
+    int i = 0;
+    while (inb(EC_CMD_PORT) & EC_IBF) {
+        if (++i > TIMEOUT_LOOPS) {
+            printk("Error: EC IBF Timeout!\n");
+            return -1;
+        }
+        udelay(1);
+    }
+    return 0;
+}
+
+static int ec_wait_obf(void)
+{
+    int i = 0;
+    while (!(inb(EC_CMD_PORT) & EC_OBF)) {
+        if (++i > TIMEOUT_LOOPS) {
+            printk("Error: EC OBF Timeout!\n");
+            return -1;
+        }
+        udelay(1);
+    }
+    return 0;
+}
+
+
+static int wait_ibf(void)
+{
+    int i = 0;
+    while (inb(EC_CMD_PORT) & EC_IBF)
+    {
+        if (++i > TIMEOUT_LOOPS)
+        {
+            return -1;
+        }
+        udelay(1);
+    }
+    return 0;
+}
+
+static int wait_obf(void)
+{
+    int i = 0;
+    while (!(inb(EC_CMD_PORT) & EC_OBF))
+    {
+        if (++i > TIMEOUT_LOOPS)
+        {
+            return -1;
+        }
+        udelay(1);
+    }
+    return 0;
+}
+
+static int ec_read_ram(uint8_t offset, uint8_t *data)
+{
+    if (wait_ibf() < 0)
+        return -1;
+    outb(CMD_READ_RAM, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_obf() < 0)
+        return -1;
+    *data = inb(EC_DATA_PORT);
+
+    return 0;
+}
+
+static int ec_write_ram(uint8_t offset, uint8_t data)
+{
+    if (wait_ibf() < 0)
+        return -1;
+    outb(CMD_WRITE_RAM, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(data, EC_DATA_PORT);
+
+    return 0;
+}
+
+static int oem_ec_read_ram(uint8_t page, uint8_t offset, uint8_t *data)
+{
+    unsigned char WEC, REC;
+    switch(page)
+    {
+        case 0:
+        {
+            WEC = 0x96;
+            REC = 0x95;
+            break;
+        }
+        
+        case 1:
+        {
+            WEC = 0x98;
+            REC = 0x97;
+            break;
+        }
+        
+        default:
+        {
+            WEC = 0x81;
+            REC = 0x80;
+            break;
+        }
+    }    
+    if (wait_ibf() < 0)
+        return -1;
+    outb(REC, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_obf() < 0)
+        return -1;
+    *data = inb(EC_DATA_PORT);
+
+    return 0;
+}
+
+static int oem_ec_write_ram(uint8_t page, uint8_t offset, uint8_t data)
+{
+    unsigned char WEC, REC;
+    switch(page)
+    {
+        case 0:
+        {
+            WEC = 0x96;
+            REC = 0x95;
+            break;
+        }
+        
+        case 1:
+        {
+            WEC = 0x98;
+            REC = 0x97;
+            break;
+        }
+        
+        default:
+        {
+            WEC = 0x81;
+            REC = 0x80;
+            break;
+        }
+    }
+    if (wait_ibf() < 0)
+        return -1;
+    outb(WEC, EC_CMD_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(offset, EC_DATA_PORT);
+
+    if (wait_ibf() < 0)
+        return -1;
+    outb(data, EC_DATA_PORT);
+
+    return 0;
+}
+
+
+
+
+static ssize_t voltage_5v_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buf)
+{
+	int vlotage = 0;
+    uint8_t raw;
+	raw = hwm_read_reg_retry(IT8786_HWM_BASE_DEFAULT, 0x22);
+
+	vlotage = vin_raw_to_volt(raw, 3, 2);
+
+	return sprintf(buf, "%d\n", vlotage);
+}
+
+static ssize_t voltage_5v_store(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t count)
+{
+    return -EINVAL;
+}
+
+
+static ssize_t voltage_vcore_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buf)
+{
+	int vlotage = 0;
+    uint8_t raw;
+	raw = hwm_read_reg_retry(IT8786_HWM_BASE_DEFAULT, 0x20);
+
+	vlotage = vin_raw_to_volt(raw, 0, 1);
+
+	return sprintf(buf, "%d\n", vlotage);
+}
+
+static ssize_t voltage_vcore_store(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t count)
+{
+    return -EINVAL;
+}
+
+
+
+static ssize_t voltage_12v_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buf)
+{
+	int vlotage = 0;
+    uint8_t raw;
+	if(oem_ec_read_ram(0x00, 0x6a, &raw) < 0)
+	{
+		return -1;
+	}
+	// raw = hwm_read_reg_retry(IT8786_HWM_BASE_DEFAULT, 0x6a);
+
+	vlotage = ec_raw_to_volt(raw, 10, 2);
+
+	return sprintf(buf, "%d\n", vlotage);
+}
+
+static ssize_t voltage_12v_store(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t count)
+{
+    return -EINVAL;
+}
+
+
+static struct kobj_attribute voltage_5v_attr =
+    __ATTR(voltage_5v, 0444, voltage_5v_show, voltage_5v_store);
+
+static struct kobj_attribute voltage_vcorev_attr =
+    __ATTR(voltage_vcore, 0444, voltage_vcore_show, voltage_vcore_store);
+
+static struct kobj_attribute voltage_12v_attr =
+    __ATTR(voltage_12v, 0444, voltage_12v_show, voltage_12v_store);
+
+static struct attribute *voltage_sysfs_attrs[] = {
+    &voltage_5v_attr.attr,
+    &voltage_vcorev_attr.attr,
+    &voltage_12v_attr.attr,
+    NULL,
+};
+
+static struct attribute_group voltage_sysfs_attr_group = {
+    .attrs = voltage_sysfs_attrs,
+};
+
+int voltage_sysfs_init(void)
+{
+    int ret = 0;
+
+    ret = sysfs_create_group(hwmon_kobj, &voltage_sysfs_attr_group);
+
+    return ret;
+}
+
+void voltage_sysfs_exit(void)
+{
+    sysfs_remove_group(hwmon_kobj, &voltage_sysfs_attr_group);
+}

+ 7 - 0
voltage_sysfs.h

@@ -0,0 +1,7 @@
+#ifndef __VOLTAGE_SYSFS_H__
+#define __VOLTAGE_SYSFS_H__
+
+int voltage_sysfs_init(void);
+void voltage_sysfs_exit(void);
+
+#endif