|
@@ -15,7 +15,24 @@
|
|
|
#include <linux/poll.h>
|
|
#include <linux/poll.h>
|
|
|
#include <linux/mutex.h>
|
|
#include <linux/mutex.h>
|
|
|
#include <linux/delay.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;
|
|
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_charge_val = 0;
|
|
|
static unsigned int led_health_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 ==================== */
|
|
/* ==================== max_fade_brightness ==================== */
|
|
|
static ssize_t led_health_show(struct kobject *kobj,
|
|
static ssize_t led_health_show(struct kobject *kobj,
|
|
|
struct kobj_attribute *attr,
|
|
struct kobj_attribute *attr,
|
|
|
char *buf)
|
|
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,
|
|
static ssize_t led_health_store(struct kobject *kobj,
|
|
@@ -39,13 +206,21 @@ static ssize_t led_health_store(struct kobject *kobj,
|
|
|
{
|
|
{
|
|
|
u32 val;
|
|
u32 val;
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
+ printk("%s: %s\n", __func__, buf);
|
|
|
|
|
|
|
|
ret = kstrtou32(buf, 10, &val);
|
|
ret = kstrtou32(buf, 10, &val);
|
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
|
return ret;
|
|
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;
|
|
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,
|
|
static ssize_t led_charge_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
char *buf)
|
|
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,
|
|
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;
|
|
u32 val;
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
+ printk("%s: %s\n", __func__, buf);
|
|
|
|
|
|
|
|
ret = kstrtou32(buf, 10, &val);
|
|
ret = kstrtou32(buf, 10, &val);
|
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
|
return ret;
|
|
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;
|
|
return count;
|
|
|
}
|
|
}
|
|
@@ -92,9 +278,81 @@ static struct attribute_group batteryled_attr_group = {
|
|
|
.attrs = batteryled_attrs,
|
|
.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 batteryled_init(void)
|
|
|
{
|
|
{
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
+ INIT_DELAYED_WORK(&delay_work1, delay_work_func);
|
|
|
|
|
|
|
|
/* 创建 /sys/kernel/vfiec/batteryled */
|
|
/* 创建 /sys/kernel/vfiec/batteryled */
|
|
|
batteryled_kobj = kobject_create_and_add("batteryled", vfiec_kobj);
|
|
batteryled_kobj = kobject_create_and_add("batteryled", vfiec_kobj);
|