瀏覽代碼

完善batteryled驱动

liu qidong [url ssh://qidong.liu@10.2.90.253:29418/] 3 周之前
父節點
當前提交
c269bb45ff
共有 1 個文件被更改,包括 266 次插入8 次删除
  1. 266 8
      batteryled.c

+ 266 - 8
batteryled.c

@@ -15,7 +15,24 @@
 #include <linux/poll.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
-#include "light_ring.h"
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+
+#include "gpioregs.h"
+
+// blue is charge
+// white is health
+// 因为我们的LED没有蓝色和白色。只有红色和绿色。所以用红色表示充电,绿色表示健康
+enum battery_led_color
+{
+ BATTERY_LED_OFF = 0x00,
+ BATTERY_LED_WHITE = 0x01,
+ BATTERY_LED_BLUE = 0x02,
+ BATTERY_LED_WHITE_BLINK = 0x03,
+ BATTERY_LED_BLUE_BLINK = 0x04
+};
 
 
 extern struct kobject *vfiec_kobj;
@@ -23,14 +40,164 @@ static struct kobject *batteryled_kobj;
 
 static unsigned int led_charge_val = 0;
 static unsigned int led_health_val = 0;
+static struct delayed_work delay_work1;
+
+
+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;
+}
 
 /* ==================== max_fade_brightness ==================== */
 static ssize_t led_health_show(struct kobject *kobj,
                                         struct kobj_attribute *attr,
                                         char *buf)
 {
-    return sprintf(buf, "%u\n", led_health_val);
+    uint8_t data = 0;
+    int ret = 0;
+
+    ret = oem_ec_read_ram(2, 0x31, &data);
+
+    return sprintf(buf, "%02x\n", data);
 }
 
 static ssize_t led_health_store(struct kobject *kobj,
@@ -39,13 +206,21 @@ static ssize_t led_health_store(struct kobject *kobj,
 {
     u32 val;
     int ret;
+    printk("%s: %s\n", __func__, buf);
 
     ret = kstrtou32(buf, 10, &val);
     if (ret < 0)
         return ret;
 
-    led_health_val = val;
-    pr_info("batteryled: led_health_val %u\n", led_health_val);
+    if(val == 0x0 || val == 0x1 || val == 0x3)
+    {
+        led_health_val = val;
+    }
+    else
+    {
+        return -EINVAL;
+    }
+    schedule_delayed_work(&delay_work1, msecs_to_jiffies(10));
 
     return count;
 }
@@ -57,9 +232,12 @@ static struct kobj_attribute led_health =
 static ssize_t led_charge_show(struct kobject *kobj, struct kobj_attribute *attr,
                          char *buf)
 {
-    const char *mode_str;
+    uint8_t data = 0;
+    int ret = 0;
 
-    return sprintf(buf, "%u\n", led_charge_val);
+    ret = oem_ec_read_ram(2, 0x31, &data);
+
+    return sprintf(buf, "%02x\n", data);
 }
 
 static ssize_t led_charge_store(struct kobject *kobj, struct kobj_attribute *attr,
@@ -67,13 +245,21 @@ static ssize_t led_charge_store(struct kobject *kobj, struct kobj_attribute *att
 {
     u32 val;
     int ret;
+    printk("%s: %s\n", __func__, buf);
 
     ret = kstrtou32(buf, 10, &val);
     if (ret < 0)
         return ret;
 
-    led_charge_val = val;
-    pr_info("batteryled: led_charge_val %u\n", led_charge_val);
+    if(val == 0x0 || val == 0x2 || val == 0x4)
+    {
+        led_charge_val = val;
+    }
+    else
+    {
+        return -EINVAL;
+    }
+    schedule_delayed_work(&delay_work1, msecs_to_jiffies(10));
 
     return count;
 }
@@ -92,9 +278,81 @@ static struct attribute_group batteryled_attr_group = {
     .attrs = batteryled_attrs,
 };
 
+static void delay_work_func(struct work_struct *work)
+{
+    static uint8_t blink_flag = 0;
+    uint8_t data = 0;
+
+    if(blink_flag == 0)
+    {
+        //闪烁的时候灭
+        blink_flag = 1;
+        if(led_health_val == 0x0)
+        {
+            data = data & 0xf3;//灭
+        }
+        else if(led_health_val == 0x1)
+        {
+            data = data | 0x04;//亮
+        }
+        else if(led_health_val == 0x3)
+        {
+            data = data & 0xf3;//灭
+        }
+        
+        if(led_charge_val == 0x0)
+        {
+            data = data & 0xcf;
+        }
+        else if(led_charge_val == 0x2)
+        {
+            data = data | 0x20;
+        }
+        else if(led_charge_val == 0x4)
+        {
+            data = data & 0xcf;
+        }
+
+    }
+    else if(blink_flag == 1)
+    {
+        // 闪烁的时候亮
+        blink_flag = 0;
+        if(led_health_val == 0x0)
+        {
+            data = data & 0xf3;//灭
+        }
+        else if(led_health_val == 0x1)
+        {
+            data = data | 0x04;//亮
+        }
+        else if(led_health_val == 0x3)
+        {
+            data = data | 0x04;//亮
+        }
+        
+        if(led_charge_val == 0x0)
+        {
+            data = data & 0xcf;
+        }
+        else if(led_charge_val == 0x2)
+        {
+            data = data | 0x20;
+        }
+        else if(led_charge_val == 0x4)
+        {
+            data = data | 0x20;
+        }
+    }
+    oem_ec_write_ram(2, 0x31, data);
+    oem_ec_write_ram(2, 0x21, 0x3C);
+    schedule_delayed_work(&delay_work1, msecs_to_jiffies(500));
+}
+
 int batteryled_init(void)
 {
     int ret;
+    INIT_DELAYED_WORK(&delay_work1, delay_work_func);
 
         /* 创建 /sys/kernel/vfiec/batteryled */
     batteryled_kobj = kobject_create_and_add("batteryled", vfiec_kobj);