From 704a6374570ff4ddc1cdd42838d4a750056aa11b Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BC=A0=E6=99=B4?= Date: Sat, 10 Aug 2013 10:28:23 +0800 Subject: [PATCH] rk3188:pmu_rt5025:updata rt5025 drivers,modify some bug --- arch/arm/mach-rk30/board-pmu-rt5025.c | 26 +- drivers/mfd/ricoh619.c | 2 +- drivers/mfd/rt5025-core.c | 21 +- drivers/mfd/rt5025-debug.c | 45 +- drivers/mfd/rt5025-irq.c | 54 +- drivers/mfd/rt5025-misc.c | 1 - drivers/power/Makefile | 2 +- drivers/power/rt5025-battery.c | 1658 ++++++++++++++++++++ drivers/power/rt5025-gauge.c | 1070 ------------- drivers/power/rt5025-power.c | 86 +- drivers/power/rt5025-swjeita.c | 397 +++++ drivers/regulator/rt5025-regulator.c | 138 +- include/linux/mfd/rt5025-irq.h | 9 + include/linux/mfd/rt5025.h | 213 ++- include/linux/power/rockchip-6200ma-bat.h | 26 + include/linux/power/rt5025-battery.h | 125 ++ include/linux/power/rt5025-gauge.h | 37 - include/linux/power/rt5025-power.h | 2 +- include/linux/power/rt5025-swjeita.h | 35 + include/linux/regulator/rt5025-regulator.h | 13 + 20 files changed, 2706 insertions(+), 1254 deletions(-) mode change 100644 => 100755 drivers/mfd/ricoh619.c mode change 100755 => 100644 drivers/mfd/rt5025-misc.c mode change 100755 => 100644 drivers/power/Makefile create mode 100755 drivers/power/rt5025-battery.c delete mode 100644 drivers/power/rt5025-gauge.c create mode 100755 drivers/power/rt5025-swjeita.c mode change 100755 => 100644 include/linux/mfd/rt5025-irq.h mode change 100755 => 100644 include/linux/mfd/rt5025.h create mode 100755 include/linux/power/rockchip-6200ma-bat.h create mode 100755 include/linux/power/rt5025-battery.h delete mode 100755 include/linux/power/rt5025-gauge.h create mode 100755 include/linux/power/rt5025-swjeita.h mode change 100755 => 100644 include/linux/regulator/rt5025-regulator.h diff --git a/arch/arm/mach-rk30/board-pmu-rt5025.c b/arch/arm/mach-rk30/board-pmu-rt5025.c index 4cb462ba3002..17b99fa43dbd 100644 --- a/arch/arm/mach-rk30/board-pmu-rt5025.c +++ b/arch/arm/mach-rk30/board-pmu-rt5025.c @@ -303,7 +303,7 @@ static struct rt5025_power_data rt5025_power_data = { .BATD_EN = 0, }, }, - .fcc = 6200, //6200 mAh +// .fcc = 6200, //6200 mAh }; static struct rt5025_gpio_data rt5025_gpio_data = { @@ -379,7 +379,7 @@ static struct rt5025_irq_data rt5025_irq_data = { .TIMEOUT_PC = 1, .CHVSREGI = 0, .CHTREGI = 0, - .CHRCHGI = 0, + .CHRCHGI = 1, }, }, .irq_enable4 = { @@ -407,6 +407,27 @@ static struct rt5025_irq_data rt5025_irq_data = { }, }; +//temp unit: 'c*10 degree +static int jeita_temp[4] = { 0, 150, 500, 600}; +static u8 jeita_scalar[4] = { 0x2d, 0x25, 0x12, 0x0e}; +//cc unit: xxx mA +static int jeita_temp_cc[][5] = {{ 500, 500, 500, 500, 500}, // not plugin + { 0 , 250, 500, 250, 0}, // normal USB + { 0, 500, 1000, 500, 0}, // USB charger + { 0, 500, 1000, 500, 0}}; // AC Adapter +//cv unit: xxx mV +static int jeita_temp_cv[][5] = {{ 4200, 4200, 4200, 4200, 4200}, // not plugin + { 4200, 4200, 4200, 4200, 4200}, // normal USB + { 4200, 4200, 4200, 4200, 4200}, // USB charger + { 4200, 4200, 4200, 4200, 4200}}; // AC Adapter + +static struct rt5025_jeita_data rt5025_jeita_data = { + .temp = jeita_temp, + .temp_scalar = jeita_scalar, + .temp_cc = jeita_temp_cc, + .temp_cv = jeita_temp_cv, +}; + static void rt5025_charger_event_callback(uint32_t detected) { RTINFO("event detected = 0x%08x\n", detected); @@ -449,6 +470,7 @@ static struct rt5025_platform_data rt5025_data = { .gpio_data = &rt5025_gpio_data, .misc_data = &rt5025_misc_data, .irq_data = &rt5025_irq_data, + .jeita_data = &rt5025_jeita_data, .cb = &rt5025_event_callback, .intr_pin = 81, //GPIO81 }; diff --git a/drivers/mfd/ricoh619.c b/drivers/mfd/ricoh619.c old mode 100644 new mode 100755 index d5b816255796..bdceb2ccd1c4 --- a/drivers/mfd/ricoh619.c +++ b/drivers/mfd/ricoh619.c @@ -715,7 +715,7 @@ static int ricoh619_i2c_probe(struct i2c_client *client, mutex_init(&ricoh619->io_lock); ret = ricoh619_read(ricoh619->dev, 0x36, &control); - if ((control < 0) || (control == 0xff)) { + if ((control < 0) || (control == 0xff) || (control == 0)) { printk(KERN_INFO "The device is not ricoh619\n"); return 0; } diff --git a/drivers/mfd/rt5025-core.c b/drivers/mfd/rt5025-core.c index 164f193cc694..245c1c0c9f63 100644 --- a/drivers/mfd/rt5025-core.c +++ b/drivers/mfd/rt5025-core.c @@ -47,6 +47,16 @@ static struct mfd_cell power_devs[] = { .id = -1, .num_resources = 0, }, +{ + .name = RT5025_DEVICE_NAME "-swjeita", + .id = -1, + .num_resources = 0, +}, +{ + .name = RT5025_DEVICE_NAME "-battery", + .id = -1, + .num_resources = 0, +}, }; #endif /* CONFIG_POWER_RT5025 */ @@ -95,7 +105,6 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ int ret = 0; RTINFO("Start to initialize all device\n"); - printk("%s,line=%d\n", __func__,__LINE__); #ifdef CONFIG_REGULATOR_RT5025 if (pdata && pdata->regulator[0]) { @@ -117,7 +126,7 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ #endif /* CONFIG_REGULATOR_RT5025 */ #ifdef CONFIG_POWER_RT5025 - if (pdata && pdata->power_data) { + if (pdata && pdata->power_data && pdata->jeita_data) { RTINFO("mfd add power dev\n"); #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) ret = mfd_add_devices(chip->dev, 0, &power_devs[0], @@ -155,7 +164,7 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ } } #endif /* CONFIG_GPIO_RT5025 */ -\ + #ifdef CONFIG_MFD_RT5025_MISC if (pdata && pdata->misc_data) { RTINFO("mfd add misc dev\n"); @@ -193,10 +202,9 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ } } #endif /* CONFIG_MFD_RT5025_IRQ */ -#if 1 + #ifdef CONFIG_MFD_RT5025_DEBUG RTINFO("mfd add debug dev\n"); - printk("%s,line=%d\n", __func__,__LINE__); #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) ret = mfd_add_devices(chip->dev, 0, &debug_devs[0], ARRAY_SIZE(debug_devs), @@ -211,8 +219,7 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ goto out_dev; } #endif /* CONFIG_MFD_RT5025_DEBUG */ -#endif - + RTINFO("Initialize all device successfully\n"); return ret; out_dev: diff --git a/drivers/mfd/rt5025-debug.c b/drivers/mfd/rt5025-debug.c index 71dce8ad7f9f..b50c70990d53 100644 --- a/drivers/mfd/rt5025-debug.c +++ b/drivers/mfd/rt5025-debug.c @@ -31,8 +31,9 @@ static struct i2c_client *client; static struct dentry *debugfs_rt_dent; static struct dentry *debugfs_peek; static struct dentry *debugfs_poke; +static struct dentry *debugfs_regs; -static unsigned char read_data; +static unsigned char read_data[10]; static int reg_debug_open(struct inode *inode, struct file *file) { @@ -65,12 +66,23 @@ static int get_parameters(char *buf, long int *param1, int num_of_par) return 0; } +#define LOG_FORMAT "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n" + static ssize_t reg_debug_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) { - char lbuf[8]; - - snprintf(lbuf, sizeof(lbuf), "0x%x\n", read_data); + char *access_str = filp->private_data; + char lbuf[150]; + if (!strcmp(access_str, "regs")) + { + RTINFO("read regs file\n"); + /* read regs */ + snprintf(lbuf, sizeof(lbuf), LOG_FORMAT LOG_FORMAT, read_data[0], \ + read_data[1], read_data[2], read_data[3], read_data[4], read_data[5], \ + read_data[6], read_data[7], read_data[8], read_data[9]); + } + else + snprintf(lbuf, sizeof(lbuf), "0x%02x\n", read_data[0]); return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf)); } @@ -105,7 +117,26 @@ static ssize_t reg_debug_write(struct file *filp, rc = get_parameters(lbuf, param, 1); if ((param[0] <= 0xFF) && (rc == 0)) { - read_data = rt5025_reg_read(client, param[0]); + read_data[0] = rt5025_reg_read(client, param[0]); + } + else + rc = -EINVAL; + } else if (!strcmp(access_str, "regs")) { + /* read */ + rc = get_parameters(lbuf, param, 1); + if ((param[0] <= 0xFF) && (rc == 0)) + { + rt5025_reg_block_read(client, param[0], 10, read_data); + RTINFO("regs 0 = 0x%02x\n", read_data[0]); + RTINFO("regs 1 = 0x%02x\n", read_data[1]); + RTINFO("regs 2 = 0x%02x\n", read_data[2]); + RTINFO("regs 3 = 0x%02x\n", read_data[3]); + RTINFO("regs 4 = 0x%02x\n", read_data[4]); + RTINFO("regs 5 = 0x%02x\n", read_data[5]); + RTINFO("regs 6 = 0x%02x\n", read_data[6]); + RTINFO("regs 7 = 0x%02x\n", read_data[7]); + RTINFO("regs 8 = 0x%02x\n", read_data[8]); + RTINFO("regs 9 = 0x%02x\n", read_data[9]); } else rc = -EINVAL; @@ -145,6 +176,10 @@ static int __devinit rt5025_debug_probe(struct platform_device *pdev) debugfs_poke = debugfs_create_file("poke", S_IFREG | S_IRUGO, debugfs_rt_dent, (void *) "poke", ®_debug_ops); + + debugfs_regs = debugfs_create_file("regs", + S_IFREG | S_IRUGO, debugfs_rt_dent, + (void *) "regs", ®_debug_ops); } platform_set_drvdata(pdev, di); diff --git a/drivers/mfd/rt5025-irq.c b/drivers/mfd/rt5025-irq.c index 1c1198705c1d..dcb15ecaf4de 100644 --- a/drivers/mfd/rt5025-irq.c +++ b/drivers/mfd/rt5025-irq.c @@ -40,33 +40,40 @@ static void rt5025_work_func(struct work_struct *work) { struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work); struct rt5025_irq_info *ii = (struct rt5025_irq_info *)container_of(delayed_work, struct rt5025_irq_info, delayed_work); - unsigned char irq_stat[10] = {0}; + unsigned char irq_stat[6] = {0}; uint32_t chg_event = 0, pwr_event = 0; #ifdef CONFIG_POWER_RT5025 - if (!ii->chip->power_info) + if (!ii->chip->power_info || !ii->chip->jeita_info || !ii->chip->battery_info) { queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(1)); return; } #endif - //if (rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 10, irq_stat) >= 0) + #if 0 + if (rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 10, irq_stat) >= 0) { - irq_stat[1] = rt5025_reg_read(ii->i2c, 0x31); - irq_stat[3] = rt5025_reg_read(ii->i2c, 0x33); - irq_stat[5] = rt5025_reg_read(ii->i2c, 0x35); - irq_stat[7] = rt5025_reg_read(ii->i2c, 0x37); - irq_stat[9] = rt5025_reg_read(ii->i2c, 0x39); - RTINFO("irq1->%02x, irq2->%02x, irq3->%02x\n", irq_stat[1], irq_stat[3], irq_stat[5]); - RTINFO("irq4->%02x, irq5->%02x\n", irq_stat[7], irq_stat[9]); + #endif + irq_stat[0] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS1); + irq_stat[1] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS2); + irq_stat[2] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS3); + irq_stat[3] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS4); + irq_stat[4] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS5); + irq_stat[5] = rt5025_reg_read(ii->i2c, RT5025_REG_GAUGEIRQFLG); + RTINFO("irq1->0x%02x, irq2->0x%02x, irq3->0x%02x\n", irq_stat[0], irq_stat[1], irq_stat[2]); + RTINFO("irq4->0x%02x, irq5->0x%02x, irq6->0x%02x\n", irq_stat[3], irq_stat[4], irq_stat[5]); RTINFO("stat value = %02x\n", rt5025_reg_read(ii->i2c, RT5025_REG_CHGSTAT)); - chg_event = irq_stat[1]<<16 | irq_stat[3]<<8 | irq_stat[5]; - pwr_event = irq_stat[7]<<8 | irq_stat[9]; + chg_event = irq_stat[0]<<16 | irq_stat[1]<<8 | irq_stat[2]; + pwr_event = irq_stat[3]<<8 | irq_stat[4]; #ifdef CONFIG_POWER_RT5025 if (chg_event & CHARGER_DETECT_MASK) + { + if (chg_event & CHG_EVENT_CHTERMI) + ii->chip->power_info->chg_term++; rt5025_power_charge_detect(ii->chip->power_info); + } #endif /* CONFIG_POWER_RT5025 */ if (ii->event_cb) { @@ -75,15 +82,18 @@ static void rt5025_work_func(struct work_struct *work) if (pwr_event) ii->event_cb->power_event_callkback(pwr_event); } - } #if 0 + } else dev_err(ii->dev, "read irq stat io fail\n"); #endif #ifdef CONFIG_POWER_RT5025 - rt5025_power_passirq_to_gauge(ii->chip->power_info); + if (irq_stat[5] & RT5025_FLG_TEMP) + rt5025_swjeita_irq_handler(ii->chip->jeita_info, irq_stat[5] & RT5025_FLG_TEMP); + if (irq_stat[5] & RT5025_FLG_VOLT) + rt5025_gauge_irq_handler(ii->chip->battery_info, irq_stat[5] & RT5025_FLG_VOLT); #endif /* CONFIG_POWER_RT5025 */ //enable_irq(ii->irq); @@ -170,7 +180,6 @@ static int __devinit rt5025_irq_probe(struct platform_device *pdev) struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); struct rt5025_platform_data *pdata = chip->dev->platform_data; struct rt5025_irq_info *ii; - printk("%s,line=%d\n", __func__,__LINE__); RTINFO("\n"); ii = kzalloc(sizeof(*ii), GFP_KERNEL); @@ -201,6 +210,20 @@ static int __devexit rt5025_irq_remove(struct platform_device *pdev) return 0; } +static void rt5025_irq_shutdown(struct platform_device *pdev) +{ + struct rt5025_irq_info *ii = platform_get_drvdata(pdev); + + if (ii->irq) + free_irq(ii->irq, ii); + + if (ii->wq) + { + cancel_delayed_work_sync(&ii->delayed_work); + flush_workqueue(ii->wq); + } +} + static struct platform_driver rt5025_irq_driver = { .driver = { @@ -209,6 +232,7 @@ static struct platform_driver rt5025_irq_driver = }, .probe = rt5025_irq_probe, .remove = __devexit_p(rt5025_irq_remove), + .shutdown = rt5025_irq_shutdown, }; static int __init rt5025_irq_init(void) diff --git a/drivers/mfd/rt5025-misc.c b/drivers/mfd/rt5025-misc.c old mode 100755 new mode 100644 index 83be67c79d1a..e47b1d62a941 --- a/drivers/mfd/rt5025-misc.c +++ b/drivers/mfd/rt5025-misc.c @@ -49,7 +49,6 @@ static int __devinit rt5025_misc_probe(struct platform_device *pdev) struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); struct rt5025_platform_data *pdata = chip->dev->platform_data; struct rt5025_misc_info *mi; - printk("%s,line=%d\n", __func__,__LINE__); mi = kzalloc(sizeof(*mi), GFP_KERNEL); if (!mi) diff --git a/drivers/power/Makefile b/drivers/power/Makefile old mode 100755 new mode 100644 index 2513b80b7da9..8ab4962c12a9 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -49,4 +49,4 @@ obj-$(CONFIG_PLAT_RK) += rk29_charger_display.o obj-$(CONFIG_BATTERY_RK30_ADC_FAC) += rk30_factory_adc_battery.o obj-$(CONFIG_CW2015_BATTERY) += cw2015_battery.o obj-$(CONFIG_BATTERY_RICOH619) += ricoh619-battery.o -obj-$(CONFIG_POWER_RT5025) += rt5025-power.o rt5025-gauge.o \ No newline at end of file +obj-$(CONFIG_POWER_RT5025) += rt5025-power.o rt5025-battery.o rt5025-swjeita.o diff --git a/drivers/power/rt5025-battery.c b/drivers/power/rt5025-battery.c new file mode 100755 index 000000000000..83b458a5aa02 --- /dev/null +++ b/drivers/power/rt5025-battery.c @@ -0,0 +1,1658 @@ +/* drivers/power/rt5025-battery.c + * I2C Driver for Richtek RT5025 PMIC + * Multi function device - multi functional baseband PMIC Battery part + * + * Copyright (C) 2013 + * Author: Nick Hung + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VOLTAGE_ALERT 1 +#define TEMPERATURE_ALERT 0 + +#define RT5025_CSV 0 +#define RT5025_B 1 +#define RT5025_TEST_WAKE_LOCK 1 + +u8 irq_thres[LAST_TYPE]; + +void rt5025_gauge_set_status(struct rt5025_battery_info *bi, int status) +{ + bi->status = status; + if (status == POWER_SUPPLY_STATUS_FULL) + bi->tp_flag = true; +} +EXPORT_SYMBOL(rt5025_gauge_set_status); + +void rt5025_gauge_set_online(struct rt5025_battery_info *bi, bool present) +{ + bi->online = present; +} +EXPORT_SYMBOL(rt5025_gauge_set_online); + +static int rt5025_read_reg(struct i2c_client *client, + u8 reg, u8 *data, u8 len) +{ + #if 1 + return rt5025_reg_block_read(client, reg, len, data); + #else + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msgs[2]; + int ret; + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; + msgs[0].len = 1; + msgs[0].buf = ® + + msgs[1].addr = client->addr; + msgs[1].flags = client->flags | I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = data; + + ret = i2c_transfer(adap, msgs, 2); + + return (ret == 2)? len : ret; + #endif +} + +static int rt5025_write_reg(struct i2c_client *client, + u8 reg, u8 *data, u8 len) +{ + #if 1 + return rt5025_reg_block_write(client, reg, len, data); + #else + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg; + int ret; + char *tx_buf = (char *)kmalloc(len + 1, GFP_KERNEL); + + if(!tx_buf) + return -ENOMEM; + tx_buf[0] = reg; + memcpy(tx_buf+1, data, len); + + msg.addr = client->addr; + msg.flags = client->flags; + msg.len = len + 1; + msg.buf = (char *)tx_buf; + + ret = i2c_transfer(adap, &msg, 1); + kfree(tx_buf); + return (ret == 1) ? len : ret; + #endif +} + +static void rt5025_gauge_alarm(struct alarm *alarm) +{ + struct rt5025_battery_info *bi = (struct rt5025_battery_info *)container_of(alarm, struct rt5025_battery_info, wakeup_alarm); + + wake_lock(&bi->monitor_wake_lock); + schedule_delayed_work(&bi->monitor_work, 0); +} + +static void rt5025_program_alarm(struct rt5025_battery_info *bi) +{ + ktime_t low_interval = ktime_set(bi->update_time, 0); + ktime_t slack = ktime_set(20, 0); + ktime_t next; + + next = ktime_add(bi->last_poll, low_interval); + alarm_start_range(&bi->wakeup_alarm, next, ktime_add(next, slack)); +} + +#if 0 +static void rt5025_run_time(struct rt5025_battery_info *bi) +{ + if(bi->curr <= 0) + { + bi->time_to_empty = bi->rm / (bi->curr*(-1)); + } + else + { + bi->time_to_full = (bi->fcc * 3600 - bi->rm) / bi->curr; + } + RTINFO("RTTF = %d\n",bi->time_to_full); + RTINFO("RTTE = %d\n",bi->time_to_empty); +} +#endif + +static int rt5025_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct rt5025_battery_info *bi = dev_get_drvdata(psy->dev->parent); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = bi->status; + //val->intval = POWER_SUPPLY_STATUS_CHARGING; + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = bi->health; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = bi->present; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = bi->ext_temp; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = bi->online; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = bi->vcell * 1000; //uV + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = bi->curr * 1000; //uA + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = bi->soc; + //val->intval = 50; + if (val->intval > 100) + val->intval = 100; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + #if 0 + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: + val->intval = bi->time_to_empty; + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + val->intval = bi->time_to_full; + #endif + break; + default: + return -EINVAL; + } + return 0; +} + +static void rt5025_get_vcell(struct rt5025_battery_info *bi) +{ + u8 data[2]; + + if (rt5025_read_reg(bi->client, RT5025_REG_VCELL_MSB, data, 2) < 0){ + printk(KERN_ERR "%s: Failed to read Voltage\n", __func__); + } + + if (bi->avg_flag) + bi->vcell = ((data[0] << 8) + data[1]) * 61 / 100; + else + bi->vcell = (bi->vcell + ((data[0] << 8) + data[1]) * 61 / 100) / 2; +#if RT5025_B + bi->curr_offset = (15444 * bi->vcell - 27444000) / 10000; +#else + if (37 * bi->vcell > 92000) + bi->curr_offset = (37 * bi->vcell - 92000) / 1000; + else + bi->curr_offset = 0; +#endif + +#if RT5025_CSV + // if (!bi->avg_flag) + // pr_info("%d,%d,", bi->vcell, bi->curr_offset); +#else + if (bi->avg_flag) + RTINFO("vcell_pre: %d, offset: %d\n", bi->vcell, bi->curr_offset); + else + RTINFO("vcell_avg: %d, offset: %d\n", bi->vcell, bi->curr_offset); +#endif +} + +static void rt5025_get_current(struct rt5025_battery_info *bi) +{ + u8 data[2]; + s32 temp; + int sign = 0; + + if (rt5025_read_reg(bi->client, RT5025_REG_CURRENT_MSB, data, 2) < 0) { + printk(KERN_ERR "%s: Failed to read CURRENT\n", __func__); + } +#if RT5025_B + temp = (data[0]<<8) | data[1]; + bi->curr_raw = ((temp & 0x7FFF) * 3125) / 10000; + + if (data[0] & (1 << 7)) { + sign = 1; + temp = (((temp & 0x7FFF) * 3125) / 10 + bi->curr_offset) / 1000; + }else{ + if ((temp * 3125) / 10 > bi->curr_offset) + temp = ((temp * 3125) / 10 - bi->curr_offset) / 1000; + } + + if (temp < DEADBAND) + temp = 0; + + if (sign){ + temp *= -1; + bi->curr_raw *= -1; + } +#else + temp = (data[0]<<8) | data[1]; + if (data[0] & (1 << 7)) { + sign = 1; + temp = temp & 0x7FFF; + if(temp > bi->curr_offset) + temp = temp - bi->curr_offset; + }else { + temp = temp + bi->curr_offset; + } + + temp = (temp * 37375) / 100000; //Unit: 0.3125mA + if (temp < DEADBAND) + temp = 0; + + if (sign) + temp *= -1; +#endif + + if (bi->avg_flag) + bi->curr = temp; + else + bi->curr = (bi->curr + temp) / 2; + + if(bi->curr > 0) + bi->internal_status = POWER_SUPPLY_STATUS_CHARGING; + else + bi->internal_status = POWER_SUPPLY_STATUS_DISCHARGING; + RTINFO("current=%d, internal_status=%d\n", bi->curr, bi->internal_status); + +#if RT5025_CSV + // if (!bi->avg_flag) + // pr_info("%d,",bi->curr); +#else + if (bi->avg_flag) + RTINFO("current_pre: %d\n", bi->curr); + else + RTINFO("current_avg: %d\n", bi->curr); +#endif +} + +static void rt5025_get_external_temp(struct rt5025_battery_info *bi) +{ + u8 data[2]; + s32 temp; + + if (rt5025_read_reg(bi->client, RT5025_REG_EXT_TEMPERATUE_MSB, data, 2) < 0) { + printk(KERN_ERR "%s: Failed to read TEMPERATURE\n", __func__); + } + bi->ain_volt = (data[0] * 256 + data[1]) * 61 / 100; + if(bi->ain_volt < 1150) + { + bi->present = 1; + } + else + { + bi->present = 0; + } + + temp = (bi->ain_volt * (-91738) + 81521000) / 100000; + bi->ext_temp = (int)temp; + //test + //bi->ext_temp = 250; + + if (bi->ext_temp >= HIGH_TEMP_THRES) { + if (bi->health != POWER_SUPPLY_HEALTH_OVERHEAT) + bi->temp_high_cnt++; + } else if (bi->ext_temp <= HIGH_TEMP_RECOVER && bi->ext_temp >= LOW_TEMP_RECOVER) { + if (bi->health == POWER_SUPPLY_HEALTH_OVERHEAT || + bi->health == POWER_SUPPLY_HEALTH_COLD) + bi->temp_recover_cnt++; + } else if (bi->ext_temp <= LOW_TEMP_THRES) { + if (bi->health != POWER_SUPPLY_HEALTH_COLD) + bi->temp_low_cnt++; + }else { + bi->temp_high_cnt = 0; + bi->temp_low_cnt = 0; + bi->temp_recover_cnt = 0; + } + + if (bi->temp_high_cnt >= TEMP_ABNORMAL_COUNT) { + bi->health = POWER_SUPPLY_HEALTH_OVERHEAT; + bi->temp_high_cnt = 0; + } else if (bi->temp_low_cnt >= TEMP_ABNORMAL_COUNT) { + bi->health = POWER_SUPPLY_HEALTH_COLD; + bi->temp_low_cnt = 0; + } else if (bi->temp_recover_cnt >= TEMP_ABNORMAL_COUNT) { + bi->health = POWER_SUPPLY_HEALTH_GOOD; + bi->temp_recover_cnt = 0; + } + //RTINFO("external temperature: %d\n", bi->ext_temp); +} + +static void rt5025_clear_cc(struct rt5025_battery_info *bi, operation_mode mode) +{ + u8 data[2]; + + if (rt5025_read_reg(bi->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){ + pr_err("%s: failed to read channel\n", __func__); + } + + if (mode == CHG) + data[0] = data[0] | CHANNEL_H_BIT_CLRQCHG; + else + data[0] = data[0] | CHANNEL_H_BIT_CLRQDCHG; + + if (rt5025_write_reg(bi->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){ + pr_err("%s: failed to write channel\n", __func__); + } +} + +static void rt5025_get_chg_cc(struct rt5025_battery_info *bi) +{ + u8 data[4]; + u32 qh_old,ql_old,qh_new,ql_new; + u32 cc_masec,offset; + + if (rt5025_read_reg(bi->client, RT5025_REG_QCHGH_MSB, data, 4) < 0){ + pr_err("%s: Failed to read QCHG\n", __func__); + } + qh_old = (data[0]<<8) + data[1]; + ql_old = (data[2]<<8) + data[3]; + + if (rt5025_read_reg(bi->client, RT5025_REG_QCHGH_MSB, data, 4) < 0){ + pr_err("%s: Failed to read QCHG\n", __func__); + } + qh_new = (data[0]<<8) + data[1]; + ql_new = (data[2]<<8) + data[3]; + +#if RT5025_B + if (qh_new > qh_old){ + cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; + }else if (qh_new == qh_old){ + if (ql_new >= ql_old){ + cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; + }else { + cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10; + } + } + + offset = bi->curr_offset * bi->time_interval; + + if (cc_masec > offset){ + cc_masec = (cc_masec - offset) / 1000; + } +#else + if (qh_new > qh_old){ + cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; + }else if (qh_new == qh_old){ + if (ql_new >= ql_old){ + cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; + }else { + cc_masec = (((qh_old<<16) + ql_old) * 5996) / 1000; + } + } + + offset = (bi->curr_offset * bi->time_interval * 37375) / 100000; + + if (cc_masec != 0){ + cc_masec = cc_masec - offset; + } +#endif + if (cc_masec < (DEADBAND * bi->time_interval)) + cc_masec = 0; + +#if RT5025_CSV + //pr_info("%d,\n", cc_masec); +#else + RTINFO("chg_cc_mAsec: %d\n", cc_masec); +#endif + + bi->chg_cc = cc_masec; + //bi->chg_cc = (cc_masec + bi->chg_cc_unuse) / 3600; + //bi->chg_cc_unuse = (cc_masec + bi->chg_cc_unuse) % 3600; + rt5025_clear_cc(bi, CHG); +} + +static void rt5025_get_dchg_cc(struct rt5025_battery_info *bi) +{ + u8 data[4]; + u32 qh_old,ql_old,qh_new,ql_new; + u32 cc_masec,offset; + + if (rt5025_read_reg(bi->client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){ + printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__); + } + qh_old = (data[0]<<8) + data[1]; + ql_old = (data[2]<<8) + data[3]; + + if (rt5025_read_reg(bi->client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){ + printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__); + } + qh_new = (data[0]<<8) + data[1]; + ql_new = (data[2]<<8) + data[3]; + +#if RT5025_B + if (qh_new > qh_old){ + cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; + }else if (qh_new == qh_old){ + if (ql_new >= ql_old){ + cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; + }else { + cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10; + } + } + + offset = bi->curr_offset * bi->time_interval; + + if (cc_masec != 0){ + cc_masec = (cc_masec + offset) / 1000; + } +#else + if (qh_new > qh_old){ + cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; + }else if (qh_new == qh_old){ + if (ql_new >= ql_old){ + cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; + }else { + cc_masec = (((qh_old<<16) + ql_old) * 5996) / 1000; + } + } + + offset = (bi->curr_offset * bi->time_interval * 37375) / 100000; + + if (cc_masec > offset){ + cc_masec = cc_masec - offset; + } +#endif + if (cc_masec < (DEADBAND * bi->time_interval)) + cc_masec = 0; + +#if RT5025_CSV + //pr_info("%d,", cc_masec); +#else + RTINFO("dchg_cc_mAsec: %d\n", cc_masec); +#endif + bi->dchg_cc = cc_masec; + //bi->dchg_cc = (cc_masec + bi->dchg_cc_unuse) / 3600; + //bi->dchg_cc_unuse = (cc_masec + bi->dchg_cc_unuse) % 3600; + rt5025_clear_cc(bi, DCHG); + +} + +static void rt5025_cycle_count(struct rt5025_battery_info *bi) +{ + bi->acc_dchg_cap += bi->dchg_cc; + if(bi->acc_dchg_cap >= (bi->dc * 3600)){ + bi->cycle_cnt++; + bi->acc_dchg_cap -= (bi->dc * 3600); + } +} + +static void rt5025_get_irq_flag(struct rt5025_battery_info *bi, u8 flag) +{ +#if 0 + u8 data[1]; + + if (rt5025_read_reg(bi->client, RT5025_REG_IRQ_FLAG, data, 1) < 0){ + pr_err("%s: Failed to read irq_flag\n", __func__); + } +#endif + + bi->irq_flag = flag; + //RTINFO("IRQ_FLG 0x%x\n", bi->irq_flag); +} + +static void rt5025_get_timer(struct rt5025_battery_info *bi) +{ + u8 data[2]; + //frankie + //u16 gauge_timer; + + if (rt5025_read_reg(bi->client, RT5025_REG_TIMER, data, 2) < 0){ + pr_err("%s: Failed to read Timer\n", __func__); + } + + bi->gauge_timer = (data[0] << 8) + data[1]; + if (!bi->device_suspend){ + if (bi->gauge_timer > bi->pre_gauge_timer) + bi->time_interval = bi->gauge_timer - bi->pre_gauge_timer; + else + bi->time_interval = 65536 - bi->pre_gauge_timer + bi->gauge_timer; + } + + bi->pre_gauge_timer = bi->gauge_timer; +#if RT5025_CSV + // pr_info("%d,%d,", bi->gauge_timer,bi->time_interval); +#else + RTINFO("timer %d , interval %d\n", bi->gauge_timer,bi->time_interval); +#endif +} + +static void rt5025_alert_setting(struct rt5025_battery_info *bi, alert_type type, bool enable) +{ + u8 data[1]; + + if (rt5025_read_reg(bi->client, RT5025_REG_IRQ_CTL, data, 1) < 0){ + printk(KERN_ERR "%s: Failed to read CONFIG\n", __func__); + } + + if(enable){ + switch(type){ + case MAXTEMP: + data[0] |= IRQ_CTL_BIT_TMX; //Enable max temperature alert + bi->max_temp_irq = true; + //RTDBG("Enable min temperature alert"); + break; + case MINTEMP: + data[0] |= IRQ_CTL_BIT_TMN; //Enable min temperature alert + bi->min_temp_irq = true; + //RTDBG("Enable max temperature alert"); + break; + case MAXVOLT: + data[0] |= IRQ_CTL_BIT_VMX; //Enable max voltage alert + bi->max_volt_irq = true; + //RTDBG("Enable max voltage alert"); + break; + case MINVOLT1: + data[0] |= IRQ_CTL_BIT_VMN1; //Enable min1 voltage alert + bi->min_volt1_irq = true; + //RTDBG("Enable min1 voltage alert"); + break; + case MINVOLT2: + data[0] |= IRQ_CTL_BIT_VMN2; //Enable min2 voltage alert + bi->min_volt2_irq = true; + //RTDBG("Enable min2 voltage alert"); + break; + default: + break; + } + }else{ + switch(type){ + case MAXTEMP: + data[0] = data[0] &~ IRQ_CTL_BIT_TMX; //Disable max temperature alert + bi->max_temp_irq = false; + //RTDBG("Disable min temperature alert"); + break; + case MINTEMP: + data[0] = data[0] &~ IRQ_CTL_BIT_TMN; //Disable min temperature alert + bi->min_temp_irq = false; + //RTDBG("Disable max temperature alert"); + break; + case MAXVOLT: + data[0] = data[0] &~ IRQ_CTL_BIT_VMX; //Disable max voltage alert + bi->max_volt_irq = false; + //RTDBG("Disable max voltage alert"); + break; + case MINVOLT1: + data[0] = data[0] &~ IRQ_CTL_BIT_VMN1; //Disable min1 voltage alert + bi->min_volt1_irq = false; + //RTDBG("Disable min1 voltage alert"); + break; + case MINVOLT2: + data[0] = data[0] &~ IRQ_CTL_BIT_VMN2; //Disable min2 voltage alert + bi->min_volt2_irq = false; + //RTDBG("Disable min2 voltage alert"); + break; + default: + break; + } + } + if (rt5025_write_reg(bi->client, RT5025_REG_IRQ_CTL, data, 1) < 0) + pr_err("%s: failed to write IRQ control\n", __func__); +} + +static void rt5025_alert_threshold_init(struct i2c_client *client) +{ + u8 data[1]; + + #if 0 //change the operating right to jeita driver + /* TALRT MAX threshold setting */ + data[0] = irq_thres[MAXTEMP]; + if (rt5025_write_reg(client, RT5025_REG_TALRT_MAXTH, data, 1) < 0) + printk(KERN_ERR "%s: failed to write TALRT MAX threshold\n", __func__); + /* TALRT MIN threshold setting */ + data[0] = irq_thres[MINTEMP]; + if (rt5025_write_reg(client, RT5025_REG_TALRT_MINTH, data, 1) < 0) + printk(KERN_ERR "%s: failed to write TALRT MIN threshold\n", __func__); + #endif + /* VALRT MAX threshold setting */ + data[0] = irq_thres[MAXVOLT]; + if (rt5025_write_reg(client, RT5025_REG_VALRT_MAXTH, data, 1) < 0) + printk(KERN_ERR "%s: failed to write VALRT MAX threshold\n", __func__); + /* VALRT MIN1 threshold setting */ + data[0] = irq_thres[MINVOLT1]; + if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN1TH, data, 1) < 0) + printk(KERN_ERR "%s: failed to write VALRT MIN1 threshold\n", __func__); + /* VALRT MIN2 threshold setting */ + data[0] = irq_thres[MINVOLT2]; + if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN2TH, data, 1) < 0) + printk(KERN_ERR "%s: failed to write VALRT MIN2 threshold\n", __func__); +} + +static void rt5025_alert_init(struct rt5025_battery_info *bi) +{ + + /* Set RT5025 gauge alert configuration */ + rt5025_alert_threshold_init(bi->client); + /* Enable gauge alert function */ + rt5025_alert_setting(bi, MINVOLT2,VOLTAGE_ALERT); +} + +void rt5025_gauge_irq_handler(struct rt5025_battery_info *bi, u8 irq_flag) +{ + rt5025_get_irq_flag(bi, irq_flag); + + if ((bi->irq_flag) & IRQ_FLG_BIT_TMX){ + //printk(KERN_INFO "[RT5025]: Min temperature IRQ received\n"); + rt5025_alert_setting(bi,MAXTEMP,false); + bi->max_temp_irq = false; + } + if ((bi->irq_flag) & IRQ_FLG_BIT_TMN){ + //printk(KERN_INFO "[RT5025]: Max temperature IRQ received\n"); + rt5025_alert_setting(bi,MINTEMP,false); + bi->min_temp_irq = false; + } + if ((bi->irq_flag) & IRQ_FLG_BIT_VMX){ + //printk(KERN_INFO "[RT5025]: Max voltage IRQ received\n"); + rt5025_alert_setting(bi,MAXVOLT,false); + bi->max_volt_irq = false; + } + if ((bi->irq_flag) & IRQ_FLG_BIT_VMN1){ + //printk(KERN_INFO "[RT5025]: Min voltage1 IRQ received\n"); + rt5025_alert_setting(bi,MINVOLT1,false); + bi->min_volt1_irq = false; + } + if ((bi->irq_flag) & IRQ_FLG_BIT_VMN2){ + //printk(KERN_INFO "[RT5025]: Min voltage2 IRQ received\n"); + rt5025_alert_setting(bi,MINVOLT2,false); + bi->min_volt2_irq = false; + bi->min_volt2_alert = true; + wake_lock_timeout(&bi->low_battery_wake_lock, msecs_to_jiffies(LOW_BAT_WAKE_LOK_TIME*MSEC_PER_SEC)); + } + + wake_lock(&bi->monitor_wake_lock); + schedule_delayed_work(&bi->monitor_work, 0); +} +EXPORT_SYMBOL(rt5025_gauge_irq_handler); + +static void rt5025_convert_masec_to_permille(struct rt5025_battery_info *bi) +{ + bi->permille = bi->rm / 3600 * 1000 / bi->fcc; + RTINFO("permille=%d\n", bi->permille); + return; +} + +static void rt5025_convert_permille_to_masec(struct rt5025_battery_info *bi) +{ + bi->rm = bi->permille * bi->fcc / 1000 * 3600; + return; +} + +static void rt5025_init_capacity(struct rt5025_battery_info *bi) +{ + int i = 1; + int size; + int slope, const_term; + int delta_y, delta_x; + + size = ARRAY_SIZE(rt5025_battery_param1); + while((bi->vcell < rt5025_battery_param1[i].x) && + (i < (size - 1))){ + i++; + } + + delta_x = rt5025_battery_param1[i-1].x - rt5025_battery_param1[i].x; + delta_y = (rt5025_battery_param1[i-1].y - rt5025_battery_param1[i].y); + + slope = delta_y * 1000 / delta_x; + + const_term = (rt5025_battery_param1[i].y) - ((rt5025_battery_param1[i].x * slope) / 1000); + + if (bi->vcell >= rt5025_battery_param1[0].x) + bi->permille = rt5025_battery_param1[0].y; + else if (bi->vcell <= rt5025_battery_param1[size-1].x) + bi->permille = rt5025_battery_param1[size-1].y; + else + bi->permille = (bi->vcell * slope) / 1000 + const_term; + rt5025_convert_permille_to_masec(bi); + bi->soc = bi->rm /36/bi->fcc_aging; + bi->init_cap = false; + + //pr_err("[rt5025] i=%d, delta_x=%d, delta_y=%d, slope=%d, const_term=%d\n", i, delta_x, delta_y, slope, const_term); + RTINFO("voltage=%d, permille=%d, soc=%d, rm=%d\n", bi->vcell, bi->permille, bi->soc, bi->rm); + return; +} + +static void rt5025_smooth_soc(struct rt5025_battery_info *bi) +{ + if ((bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) && + (bi->soc < 100)){ + bi->soc++; + }else if ((bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && + (bi->soc > 0)){ + bi->soc--; + }else{ + bi->smooth_flag = false; + bi->update_time = NORMAL_POLL; + } +} + + +static void rt5025_soc_irreversible(struct rt5025_battery_info *bi) +{ + // Prevent inverse + //if (!bi->init_cap){ + if (!bi->init_once){ + if (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING){ + if (bi->soc < bi->pre_soc) + bi->soc = bi->pre_soc; + }else if (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING){ + if (bi->soc > bi->pre_soc) + bi->soc = bi->pre_soc; + } + } + else + bi->init_once = false; + + bi->pre_soc = bi->soc; +} + +static void rt5025_soc_lock(struct rt5025_battery_info *bi) +{ + // lock 99% + RTINFO("internal status=%d, tp_flag=%d, soc=%d\n", bi->internal_status, bi->tp_flag, bi->soc); + if ((bi->soc >= 99) && (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING)) + { + if (bi->tp_flag) + bi->soc = 100; + else + { + if (bi->status == POWER_SUPPLY_STATUS_FULL) + bi->soc = 100; + else + bi->soc = 99; + } + } + else if ((bi->soc < 99) && (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) && \ + (bi->tp_flag)) + { + bi->update_time = SMOOTH_POLL; + bi->smooth_flag = true; + rt5025_smooth_soc(bi); + }else + { + bi->tp_flag = false; + } + + // lock 1% + if ((bi->soc <= 1) && + (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING)){ + if (bi->edv_flag) + bi->soc = 0; + else + bi->soc = 1; + }else if ((bi->soc > 1) && + (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && + (bi->edv_flag)){ + bi->update_time = SMOOTH_POLL; + bi->smooth_flag = true; + rt5025_smooth_soc(bi); + }else{ + bi->edv_flag = false; + } +} + +static void rt5025_get_soc(struct rt5025_battery_info *bi) +{ + if (bi->smooth_flag){ + bi->smooth_flag = false; + bi->update_time = NORMAL_POLL; + } + RTINFO("before rm=%d\n", bi->rm); + if ((!bi->tp_flag) && + (!bi->edv_flag)){ + bi->rm = (bi->rm + bi->chg_cc) > bi->dchg_cc ? + bi->rm + bi->chg_cc - bi->dchg_cc : 0; + if (bi->rm > (bi->fcc * 3600)) + bi->rm = bi->fcc * 3600; + rt5025_convert_masec_to_permille(bi); + bi->soc = DIV_ROUND_UP(bi->permille, 10); +#if RT5025_CSV + bi->temp_soc = bi->soc; + //pr_info("%d", bi->soc); +#else + RTINFO("after rm=%d\n", bi->rm); + RTINFO("temp_soc=%d\n", bi->soc); +#endif + } +#if RT5025_CSV + // pr_info("%d,%d,%d,%d,%d", bi->soc,bi->permille,bi->rm,bi->fcc,bi->smooth_flag); +#else + RTINFO("soc=%d, permille=%d, rm=%d, fcc=%d, smooth_flag=%d\n", bi->soc,bi->permille,bi->rm,bi->fcc,bi->smooth_flag); +#endif + return; +} + +static void rt5025_soc_relearn_check(struct rt5025_battery_info *bi) +{ + // TP relearn +/* if ((bi->vcell >= TP_VOLT) && + (bi->curr <= TP_CURR) && + (bi->status == POWER_SUPPLY_STATUS_CHARGING) && + (!bi->tp_flag)){ + bi->tp_cnt++; + bi->update_time = TP_POLL; + }else { + bi->tp_cnt = 0; + bi->update_time = NORMAL_POLL; + } + + if (bi->tp_cnt == TP_TOTAL_COUNT){ + bi->tp_cnt = 0; + bi->tp_flag = true; + bi->rm = bi->fcc * 3600; + rt5025_convert_masec_to_permille(); + bi->update_time = NORMAL_POLL; + }*/ + + // if EOC happened, the tp_flag should be set 1. + if(bi->tp_flag == true) + { + bi->rm = bi->fcc * 3600; + rt5025_convert_masec_to_permille(bi); + bi->update_time = NORMAL_POLL; + } + + if(rt5025_battery_param2[4].x < bi->vcell && bi->vcell <= rt5025_battery_param2[4].x+300) + { + bi->update_time = EDV_POLL; + bi->edv_detection = true; + } + else if((bi->vcell >= rt5025_battery_param2[4].x + 300 +EDV_HYS) && (bi->edv_detection == true)) + { + bi->update_time = NORMAL_POLL; + bi->edv_detection = false; + } + else if((bi->vcell <= rt5025_battery_param2[4].x) && (bi->min_volt2_alert == true)) + { + bi->edv_flag = true; + bi->rm = 0; + rt5025_convert_masec_to_permille(bi); + bi->edv_detection = false; + bi->update_time = NORMAL_POLL; + } + else if((bi->vcell > rt5025_battery_param2[4].x + EDV_HYS) && (bi->min_volt2_alert == true)) + { + bi->min_volt2_alert = false; + } + + /*// EDV relearn + if (bi->vcell <= EDV_VOLT){ + if ((bi->curr <= EDV_CURR) || + (bi->vcell <= rt5025_battery_param2[4].x)) + bi->edv_cnt++; + else + { + bi->edv_cnt = 0; + } + bi->edv_detection = true; + bi->update_time = EDV_POLL; + }else if ((bi->vcell > (EDV_VOLT + EDV_HYS)) && + (bi->edv_detection)) { + bi->edv_cnt = 0; + bi->edv_detection = false; + bi->edv_flag = false; + bi->update_time = NORMAL_POLL; + } + else + { + bi->edv_cnt = 0; + } + + if (bi->edv_cnt == EDV_TOTAL_COUNT){ + bi->edv_cnt = 0; + bi->edv_flag = true; + bi->rm = 0; + rt5025_convert_masec_to_permille(); + bi->edv_detection = false; + bi->update_time = NORMAL_POLL; + } + if(bi->edv_detection) + { + bi->update_time = EDV_POLL; + }*/ + if (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) + bi->edv_flag = false; + else if (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) + bi->tp_flag = false; + +#if RT5025_CSV + //pr_err("%d,%d,%d,%d,%d", + // bi->tp_cnt,bi->tp_flag,bi->edv_detection,bi->edv_cnt,bi->edv_flag); +#else + RTINFO("tp_cnt=%d, tp_flag=%d, edv_detection=%d, edv_cnt=%d, edv_flag=%d\n", + bi->tp_cnt,bi->tp_flag,bi->edv_detection,bi->edv_cnt,bi->edv_flag); +#endif + + return; +} + +static void rt5025_channel_cc(struct rt5025_battery_info *bi, bool enable) +{ + u8 data[1]; + + if (rt5025_read_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ + printk(KERN_INFO "%s: failed to read channel\n", __func__); + } + + if (enable){ + data[0] = data[0] | 0x80; + }else { + data[0] = data[0] & 0x7F; + } + + if (rt5025_write_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ + printk(KERN_INFO "%s: failed to write channel\n", __func__); + } +} + +#if 0 +static void rt5025_pretrim(struct rt5025_battery_info *bi) +{ + u8 data0[2]; + u8 data1[1]; + + data0[0] = 0x55; + data0[1] = 0xAA; + if (rt5025_write_reg(bi->client, 0xF0, data0, 2) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } + data0[0] = 0x07; + if (rt5025_write_reg(bi->client, 0xF1, data0, 1) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } + // write trim data D0 + data0[0] = 0xDE; + if (rt5025_write_reg(bi->client, 0xD0, data0, 1) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } + // Read back to verify + if (rt5025_read_reg(bi->client, 0xD0, data1, 1) < 0){ + printk(KERN_ERR "%s: failed to read channel\n", __func__); + } + if (data1[0] != data0[0]) + printk(KERN_ERR "%s: 0xD0 write fail\n", __func__); + // write trim data D1 + data0[0] = 0x01; + if (rt5025_write_reg(bi->client, 0xD1, data0, 1) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } + // Read back to verify + if (rt5025_read_reg(bi->client, 0xD1, data1, 1) < 0){ + printk(KERN_ERR "%s: failed to read channel\n", __func__); + } + if (data1[0] != data0[0]) + printk(KERN_ERR "%s: 0xD1 write fail\n", __func__); + // write trim data D2 + data0[0] = 0x10; + if (rt5025_write_reg(bi->client, 0xD2, data0, 1) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } + // Read back to verify + if (rt5025_read_reg(bi->client, 0xD2, data1, 1) < 0){ + printk(KERN_ERR "%s: failed to read channel\n", __func__); + } + if(data1[0] != data0[0]) + printk(KERN_ERR "%s: 0xD2 write fail\n", __func__); + // write trim data D3 + data0[0] = 0x89; + if (rt5025_write_reg(bi->client, 0xD3, data0, 1) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } + // Read back to verify + if (rt5025_read_reg(bi->client, 0xD3, data1, 1) < 0){ + printk(KERN_ERR "%s: failed to read channel\n", __func__); + } + if(data1[0] != data0[0]) + printk(KERN_ERR "%s: 0xD3 write fail\n", __func__); + // write trim data D4 + data0[0] = 0xF2; + if (rt5025_write_reg(bi->client, 0xD4, data0, 1) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } + // Read back to verify + if (rt5025_read_reg(bi->client, 0xD4, data1, 1) < 0){ + printk(KERN_ERR "%s: failed to read channel\n", __func__); + } + if (data1[0] != data0[0]) + printk(KERN_ERR "%s: 0xD4 write fail\n", __func__); + + data0[0] = 0x55; + data0[1] = 0x55; + if (rt5025_write_reg(bi->client, 0xF0, data0, 2) < 0){ + printk(KERN_ERR "%s: failed to write channel\n", __func__); + } +} +#endif + +static int rt5025_battery_parameter_backup(struct rt5025_battery_info *bi) +{ + u8 data[4]; + RTINFO("\n"); + //backup fcc_aging, rm, cycle_count, acc_dchg_cap + //fcc_aging + data[0] = (bi->fcc_aging>>8)&0xff; + data[1] = (bi->fcc_aging)&0xff; + rt5025_write_reg(bi->client, 0x21, data, 2); + //rm + data[0] = (bi->rm>>24)&0xff; + data[1] = (bi->rm>>16)&0xff; + data[2] = (bi->rm>>8)&0xff; + data[3] = (bi->rm)&0xff; + rt5025_write_reg(bi->client, 0x23, data, 4); + //acc_dchg_cap + data[0] = (bi->acc_dchg_cap>>24)&0xff; + data[1] = (bi->acc_dchg_cap>>16)&0xff; + data[2] = (bi->acc_dchg_cap>>8)&0xff; + data[3] = (bi->acc_dchg_cap)&0xff; + rt5025_write_reg(bi->client, 0x27, data, 4); + //cycle_count + data[0] = (bi->cycle_cnt)&0xff; + rt5025_write_reg(bi->client, 0x2B, data, 1); + return 0; +} + +static int rt5025_battery_parameter_restore(struct rt5025_battery_info *bi) +{ + u8 data[4]; + RTINFO("\n"); + //restore fcc_aging, rm ,cycle_count, acc_dchg_cap + //fcc_aging + rt5025_read_reg(bi->client, 0x21, data, 2); + bi->fcc = bi->fcc_aging = data[0]<<8 | data[1]; + //rm + rt5025_read_reg(bi->client, 0x23, data, 4); + bi->rm = data[0]<<24 | data[1]<<16 | data[2]<<8 | data[3]; + //acc_dchg_cap + rt5025_read_reg(bi->client, 0x27, data, 4); + bi->acc_dchg_cap = data[0]<<24 | data[1]<<16 | data[2]<<8 | data[3]; + //cycle_count + rt5025_read_reg(bi->client, 0x2B, data, 1); + bi->cycle_cnt = data[0]; + + return 0; +} + + +// return value; 1-> initialized, 0-> no initial value +static int rt5025_battery_parameter_initcheck(struct rt5025_battery_info *bi) +{ + u8 data[2]; + u16 value; + int ret = 0; + + if (rt5025_read_reg(bi->client, 0x21, data, 2) < 0) + { + pr_err("%s: check initial value error\n", __func__); + } + else + { + value = data[1]<<8 | data[0]; + if (value) + ret = 1; + } + RTINFO("initial check = %d\n", ret); + + return ret; +} + +static void rt5025_register_init(struct rt5025_battery_info *bi) +{ + u8 data[1]; + + /* enable the channel of current,qc,ain,vbat and vadc */ + if (rt5025_read_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ + pr_err("%s: failed to read channel\n", __func__); + } + data[0] = data[0] | CHANNEL_L_BIT_CADC_EN | CHANNEL_L_BIT_AINCH | \ + CHANNEL_L_BIT_VBATSCH | CHANNEL_L_BIT_VADC_EN; + if (rt5025_write_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ + pr_err("%s: failed to write channel\n", __func__); + } + /* set the alert threshold value */ + irq_thres[MINVOLT2] = VALRTMIN2_VALUE; + irq_thres[VOLT_RLS] = VRLS_VALUE; + + bi->chg_cc_unuse = 0; + bi->dchg_cc_unuse = 0; + bi->pre_gauge_timer = 0; + bi->online = 1; + bi->status = bi->internal_status = POWER_SUPPLY_STATUS_DISCHARGING; + bi->health = POWER_SUPPLY_HEALTH_GOOD; + + bi->init_cap = true; + bi->avg_flag = true; + + bi->fcc_aging = rt5025_battery_param2[4].y; + bi->fcc = rt5025_battery_param2[4].y; + bi->dc = rt5025_battery_param2[4].y; + bi->rm = 0; + + bi->edv_cnt = 0; + bi->edv_flag = false; + bi->edv_detection = false; + bi->init_once = true; + + bi->tp_cnt = 0; + bi->tp_flag = false; + + bi->acc_dchg_cap = 0; + bi->cycle_cnt = 0; + + // if has initial data, rewrite to the stored data + if (rt5025_battery_parameter_initcheck(bi)) + { + bi->init_cap = false; + rt5025_battery_parameter_restore(bi); + bi->soc = bi->rm/36/bi->fcc_aging; + } + + bi->update_time = NORMAL_POLL; + bi->device_suspend = false; + RTINFO("register initialized\n"); +} + +static void rt5025_soc_aging(struct rt5025_battery_info *bi) +{ + if (bi->cycle_cnt >= rt5025_battery_param2[3].x) + { + bi->fcc_aging = bi->fcc_aging*(1000-rt5025_battery_param2[3].y)/1000; + bi->rm = bi->rm*(1000-rt5025_battery_param2[3].y)/1000; + bi->cycle_cnt -= rt5025_battery_param2[3].x; + } + RTINFO("fcc_aging=%d, rm=%d, cycle_cnt=%d\n", bi->fcc_aging, bi->rm, bi->cycle_cnt); +} + +static void rt5025_temp_comp(struct rt5025_battery_info *bi) +{ + int i = 1; + int size; + int slope, const_term; + int delta_y, delta_x; + + size = 3; + while((bi->ext_temp < rt5025_battery_param2[i].x) && + (i < (size - 1))){ + i++; + } + + delta_x = rt5025_battery_param2[i-1].x - rt5025_battery_param2[i].x; + delta_y = (rt5025_battery_param2[i-1].y - rt5025_battery_param2[i].y); + + slope = delta_y * 1000 / delta_x; + + const_term = (rt5025_battery_param2[i].y) - ((rt5025_battery_param2[i].x * slope) / 1000); + + if (bi->ext_temp >= rt5025_battery_param2[0].x) + bi->tempcmp = rt5025_battery_param2[0].y; + else if (bi->ext_temp <= rt5025_battery_param2[size-1].x) + bi->tempcmp = rt5025_battery_param2[size-1].y; + else + bi->tempcmp = (bi->ext_temp * slope) / 1000 + const_term; + + bi->fcc = bi->fcc_aging + bi->fcc_aging * bi->tempcmp /1000; + if (bi->fcc >= (bi->dc*3>>1)) + bi->fcc = bi->dc*3>>1; + if (bi->fcc <= (bi->dc>>1)) + bi->fcc = bi->dc>>1; + bi->rm = bi->fcc * bi->soc * 36; + //pr_err("[rt5025] i=%d, delta_x=%d, delta_y=%d, slope=%d, const_term=%d\n", i, delta_x, delta_y, slope, const_term); + RTINFO("tempcmp=%d, ext_temp=%d, fcc=%d, rm=%d\n", bi->tempcmp, bi->ext_temp, bi->fcc, bi->rm); + return; +} + +static void rt5025_soc_temp_comp(struct rt5025_battery_info *bi) +{ + RTINFO("soc->%d++\n", bi->soc); + bi->temp_range_0_5 = false; + bi->temp_range_5_10 = false; + bi->temp_range_10_15 = false; + bi->temp_range_15_20 = false; + bi->temp_range_20_30 = false; + bi->temp_range_30_35 = false; + bi->temp_range_35_40 = false; + bi->temp_range_40_45 = false; + bi->temp_range_45_50 = false; + + if (bi->ext_temp < 50) + bi->temp_range_0_5 = true; + else if (50 <= bi->ext_temp && bi->ext_temp < 100) + bi->temp_range_5_10 = true; + else if (100 <= bi->ext_temp && bi->ext_temp < 150) + bi->temp_range_10_15 = true; + else if (150 <= bi->ext_temp && bi->ext_temp < 200) + bi->temp_range_15_20 = true; + else if (200 <= bi->ext_temp && bi->ext_temp <= 300) + bi->temp_range_20_30 = true; + else if (300 < bi->ext_temp && bi->ext_temp <= 350) + bi->temp_range_30_35 = true; + else if (350 < bi->ext_temp && bi->ext_temp <= 400) + bi->temp_range_35_40 = true; + else if (400 < bi->ext_temp && bi->ext_temp <= 450) + bi->temp_range_40_45 = true; + else if (450 < bi->ext_temp) + bi->temp_range_45_50 = true; + + if((bi->temp_range_0_5 == true) && (bi->range_0_5_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = true; + bi->range_5_10_done = false; + bi->range_10_15_done = false; + bi->range_15_20_done = false; + bi->range_20_30_done = false; + bi->range_30_35_done = false; + bi->range_35_40_done = false; + bi->range_40_45_done = false; + bi->range_45_50_done = false; + } + else if((bi->temp_range_5_10 == true) && (bi->range_5_10_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = false; + bi->range_5_10_done = true; + bi->range_10_15_done = false; + bi->range_15_20_done = false; + bi->range_20_30_done = false; + bi->range_30_35_done = false; + bi->range_35_40_done = false; + bi->range_40_45_done = false; + bi->range_45_50_done = false; + } + else if((bi->temp_range_10_15 == true) && (bi->range_10_15_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = false; + bi->range_5_10_done = false; + bi->range_10_15_done = true; + bi->range_15_20_done = false; + bi->range_20_30_done = false; + bi->range_30_35_done = false; + bi->range_35_40_done = false; + bi->range_40_45_done = false; + bi->range_45_50_done = false; + } + else if((bi->temp_range_15_20 == true) && (bi->range_15_20_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = false; + bi->range_5_10_done = false; + bi->range_10_15_done = false; + bi->range_15_20_done = true; + bi->range_20_30_done = false; + bi->range_30_35_done = false; + bi->range_35_40_done = false; + bi->range_40_45_done = false; + bi->range_45_50_done = false; + } + else if((bi->temp_range_20_30 == true) && (bi->range_20_30_done == false)) + { + bi->fcc = bi->fcc_aging; + bi->rm = bi->fcc*bi->soc*36; + bi->range_0_5_done = false; + bi->range_5_10_done = false; + bi->range_10_15_done = false; + bi->range_15_20_done = false; + bi->range_20_30_done = true; + bi->range_30_35_done = false; + bi->range_35_40_done = false; + bi->range_40_45_done = false; + bi->range_45_50_done = false; + } + else if((bi->temp_range_30_35 == true) && (bi->range_30_35_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = false; + bi->range_5_10_done = false; + bi->range_10_15_done = false; + bi->range_15_20_done = false; + bi->range_20_30_done = false; + bi->range_30_35_done = true; + bi->range_35_40_done = false; + bi->range_40_45_done = false; + bi->range_45_50_done = false; + } + else if((bi->temp_range_35_40 == true) && (bi->range_35_40_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = false; + bi->range_5_10_done = false; + bi->range_10_15_done = false; + bi->range_15_20_done = false; + bi->range_20_30_done = false; + bi->range_30_35_done = false; + bi->range_35_40_done = true; + bi->range_40_45_done = false; + bi->range_45_50_done = false; + } + else if((bi->temp_range_40_45 == true) && (bi->range_40_45_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = false; + bi->range_5_10_done = false; + bi->range_10_15_done = false; + bi->range_15_20_done = false; + bi->range_20_30_done = false; + bi->range_30_35_done = false; + bi->range_35_40_done = false; + bi->range_40_45_done = true; + bi->range_45_50_done = false; + } + else if((bi->temp_range_45_50 == true) && (bi->range_45_50_done == false)) + { + rt5025_temp_comp(bi); + bi->range_0_5_done = false; + bi->range_5_10_done = false; + bi->range_10_15_done = false; + bi->range_15_20_done = false; + bi->range_20_30_done = false; + bi->range_30_35_done = false; + bi->range_35_40_done = false; + bi->range_40_45_done = false; + bi->range_45_50_done = true; + } + RTINFO("soc->%d--\n", bi->soc); +} + +static void rt5025_update(struct rt5025_battery_info *bi) +{ + /* Update voltage */ + rt5025_get_vcell(bi); + /* Update current */ + rt5025_get_current(bi); + + /* Update external temperature */ + rt5025_get_external_temp(bi); + /* Read timer */ + rt5025_get_timer(bi); + /* Update chg cc */ + rt5025_get_chg_cc(bi); + /* Update dchg cc */ + rt5025_get_dchg_cc(bi); + /* Update cycle count check */ + rt5025_cycle_count(bi); + /* Calculate cycle count */ + rt5025_soc_aging(bi); + /* calculate initial soc */ + if (bi->init_cap){ + rt5025_init_capacity(bi); +#if RT5025_CSV + pr_info("vcell,offset,current,timer,interval,QCHG,QDCHG,tp_cnt,tp_flag,edv_det,edv_cnt,edv_flag,soc,permille,RM,FCC,smooth_flag,acc_QD,cycle,update_time\n"); +#endif + } + + /* Relearn SOC */ + rt5025_soc_relearn_check(bi); + /* SOC_Temp_Comp*/ + rt5025_soc_temp_comp(bi); + /* Update SOC */ + rt5025_get_soc(bi); + + /* SOC Control Process */ + rt5025_soc_lock(bi); + rt5025_soc_irreversible(bi); + + /* Update RTTF or RTTE */ + //rt5025_run_time(bi); + +#if TEMPERATURE_ALERT + if ((bi->max_temp_irq == false) && + (((irq_thres[MAXTEMP] * IRQ_THRES_UNIT) / 100 - bi->ain_volt) > irq_thres[TEMP_RLS])){ + rt5025_alert_setting(bi,MAXTEMP,true); + }else if ((bi->min_temp_irq == false) && + ((bi->ain_volt - (irq_thres[MINTEMP] * IRQ_THRES_UNIT) / 100) > irq_thres[TEMP_RLS])){ + rt5025_alert_setting(bi,MINTEMP,true); + } +#endif +#if 0 + }else if ((bi->min_volt1_irq == false) && + ((bi->vcell - ((irq_thres[MINVOLT1] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){ + rt5025_alert_setting(bi,MINVOLT1,true); + }else if ((bi->min_volt2_irq == false) && + ((bi->vcell - ((irq_thres[MINVOLT2] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){ + rt5025_alert_setting(bi,MINVOLT2,true); + } +#endif + +#if VOLTAGE_ALERT + if ((bi->min_volt2_irq == false) && + (bi->vcell > (rt5025_battery_param2[4].x + EDV_HYS))){ + rt5025_alert_setting(bi,MINVOLT2,true); + } +#endif +#if RT5025_CSV + printk(KERN_INFO "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",bi->vcell,bi->curr_offset,bi->curr,bi->gauge_timer,bi->time_interval,bi->chg_cc, + bi->dchg_cc,bi->tp_cnt,bi->tp_flag,bi->edv_detection,bi->edv_cnt,bi->edv_flag,bi->soc, + bi->permille,bi->rm,bi->fcc,bi->smooth_flag,bi->acc_dchg_cap,bi->cycle_cnt,bi->update_time); +#else + pr_info("[RT5025] update_time=%d\n",bi->update_time); + pr_info("\n"); +#endif +} + +static void rt5025_update_work(struct work_struct *work) +{ + struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work); + struct rt5025_battery_info *bi = (struct rt5025_battery_info *)container_of(delayed_work, struct rt5025_battery_info, monitor_work); + unsigned long flags; + + rt5025_update(bi); + + /* prevent suspend before starting the alarm */ + local_irq_save(flags); + bi->last_poll = alarm_get_elapsed_realtime(); + rt5025_program_alarm(bi); + local_irq_restore(flags); + + wake_unlock(&bi->monitor_wake_lock); +} + +static enum power_supply_property rt5025_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_TECHNOLOGY, + #if 0 + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + #endif +}; + +static int rt5025_battery_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct rt5025_battery_info *bi = platform_get_drvdata(pdev); + //bi->last_event = ktime_get(); + bi->last_event = current_kernel_time(); + + //cy add for battery parameter backup + rt5025_battery_parameter_backup(bi); + + rt5025_channel_cc(bi, false); + cancel_delayed_work(&bi->monitor_work); + rt5025_get_timer(bi); + bi->device_suspend = true; + //bi->update_time = SUSPEND_POLL; + RTINFO("RM=%d\n",bi->rm); + return 0; +} + +static int rt5025_battery_resume(struct platform_device *pdev) +{ + struct rt5025_battery_info *bi = platform_get_drvdata(pdev); + //ktime_t now; + //struct timespec now = current_kernel_time(); + //struct timeval tv; + //long time_interval; + + //now = ktime_get(); + //tv = ktime_to_timeval(ktime_sub(now, bi->last_event)); + //RTINFO("Sleep time = %d\n",(u32)tv.tv_sec); + //bi->rm = bi->rm - ((u32)tv.tv_sec * SLEEP_CURRENT); + + //time_interval = now.tv_sec - bi->last_event.tv_sec; + //bi->rm = bi->rm - (time_interval * SLEEP_CURRENT); + //RTINFO("Sleep time=%d, RM=%d",(int)time_interval,bi->rm); + + rt5025_channel_cc(bi, true); + wake_lock(&bi->monitor_wake_lock); + schedule_delayed_work(&bi->monitor_work, 0); + bi->device_suspend = false; + //RTINFO("\n"); + return 0; +} + +static int rt5025_battery_remove(struct platform_device *pdev) +{ + struct rt5025_battery_info *bi = platform_get_drvdata(pdev); + + power_supply_unregister(&bi->battery); + cancel_delayed_work(&bi->monitor_work); + wake_lock_destroy(&bi->monitor_wake_lock); + kfree(bi); + return 0; +} + +static int rt5025_battery_probe(struct platform_device *pdev) +{ + struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct rt5025_battery_info *bi; + int ret; + + bi = kzalloc(sizeof(*bi), GFP_KERNEL); + if (!bi) + return -ENOMEM; + + bi->client = chip->i2c; + bi->chip = chip; + + + bi->last_poll = alarm_get_elapsed_realtime(); + alarm_init(&bi->wakeup_alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + rt5025_gauge_alarm); + + INIT_DELAYED_WORK(&bi->monitor_work, rt5025_update_work); + + wake_lock_init(&bi->monitor_wake_lock, WAKE_LOCK_SUSPEND, "rt-battery-monitor"); + wake_lock_init(&bi->low_battery_wake_lock, WAKE_LOCK_SUSPEND, "low_battery_wake_lock"); +#if RT5025_TEST_WAKE_LOCK + wake_lock_init(&bi->test_wake_lock, WAKE_LOCK_SUSPEND, "rt-test"); +#endif + /* Write trimed data */ + //rt5025_pretrim(client); + /* enable channel */ + rt5025_register_init(bi); + /* enable gauge IRQ */ + rt5025_alert_init(bi); + + /* register callback functions */ + /* + chip->cb.rt5025_gauge_irq_handler = rt5025_irq_handler; + chip->cb.rt5025_gauge_set_status = rt5025_set_status; + chip->cb.rt5025_gauge_set_online = rt5025_set_online; + chip->cb.rt5025_gauge_suspend = rt5025_gauge_suspend; + chip->cb.rt5025_gauge_resume = rt5025_gauge_resume; + chip->cb.rt5025_gauge_remove = rt5025_gauge_remove; + + rt5025_register_gauge_callbacks(&chip->cb); + */ + + platform_set_drvdata(pdev, bi); + + bi->battery.name = "rt5025-battery"; + bi->battery.type = POWER_SUPPLY_TYPE_BATTERY; + bi->battery.get_property = rt5025_get_property; + bi->battery.properties = rt5025_battery_props; + bi->battery.num_properties = ARRAY_SIZE(rt5025_battery_props); + + ret = power_supply_register(&pdev->dev, &bi->battery); + if (ret) { + printk(KERN_ERR "[RT5025] power supply register failed\n"); + goto err_wake_lock; + } + + + wake_lock(&bi->monitor_wake_lock); +#if RT5025_TEST_WAKE_LOCK + wake_lock(&bi->test_wake_lock); +#endif + schedule_delayed_work(&bi->monitor_work, msecs_to_jiffies(INIT_POLL*MSEC_PER_SEC)); + chip->battery_info = bi; + + pr_info("rt5025-battery driver is successfully loaded\n"); + + return 0; + +err_wake_lock: + wake_lock_destroy(&bi->monitor_wake_lock); + kfree(bi); + + return ret; +} + +static void rt5025_battery_shutdown(struct platform_device *pdev) +{ + struct rt5025_battery_info *bi = platform_get_drvdata(pdev); + + RTINFO("\n"); + rt5025_battery_parameter_backup(bi); +} + +static struct platform_driver rt5025_battery_driver = +{ + .driver = { + .name = RT5025_DEVICE_NAME "-battery", + .owner = THIS_MODULE, + }, + .probe = rt5025_battery_probe, + .remove = __devexit_p(rt5025_battery_remove), + .shutdown = rt5025_battery_shutdown, + .suspend = rt5025_battery_suspend, + .resume = rt5025_battery_resume, +}; + +static int __init rt5025_battery_init(void) +{ + return platform_driver_register(&rt5025_battery_driver); +} +module_init(rt5025_battery_init); + +static void __exit rt5025_battery_exit(void) +{ + platform_driver_unregister(&rt5025_battery_driver); +} +module_exit(rt5025_battery_exit); + + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Nick Hung -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RT5025_REG_IRQ_CTL 0x50 -#define RT5025_REG_IRQ_FLAG 0x51 -#define RT5025_REG_VALRT_MAXTH 0x53 -#define RT5025_REG_VALRT_MIN1TH 0x54 -#define RT5025_REG_VALRT_MIN2TH 0x55 -#define RT5025_REG_TALRT_MAXTH 0x56 -#define RT5025_REG_TALRT_MINTH 0x57 -#define RT5025_REG_VCELL_MSB 0x58 -#define RT5025_REG_VCELL_LSB 0x59 -#define RT5025_REG_INT_TEMPERATUE_MSB 0x5B -#define RT5025_REG_INT_TEMPERATUE_LSB 0x5C -#define RT5025_REG_EXT_TEMPERATUE_MSB 0x5E -#define RT5025_REG_EXT_TEMPERATUE_LSB 0x5F -#define RT5025_REG_TIMER 0x60 -#define RT5025_REG_CHANNEL_MSB 0x62 -#define RT5025_REG_CHANNEL_LSB 0x63 -#define RT5025_REG_CURRENT_MSB 0x76 -#define RT5025_REG_CURRENT_LSB 0x77 -#define RT5025_REG_QCHGH_MSB 0x78 -#define RT5025_REG_QCHGH_LSB 0x79 -#define RT5025_REG_QCHGL_MSB 0x7A -#define RT5025_REG_QCHGL_LSB 0x7B -#define RT5025_REG_QDCHGH_MSB 0x7C -#define RT5025_REG_QDCHGH_LSB 0x7D -#define RT5025_REG_QDCHGL_MSB 0x7E -#define RT5025_REG_QDCHGL_LSB 0x7F - -#define IRQ_CTL_BIT_TMX (1 << 5) -#define IRQ_CTL_BIT_TMN (1 << 4) -#define IRQ_CTL_BIT_VMX (1 << 2) -#define IRQ_CTL_BIT_VMN1 (1 << 1) -#define IRQ_CTL_BIT_VMN2 (1 << 0) - -#define IRQ_FLG_BIT_TMX (1 << 5) -#define IRQ_FLG_BIT_TMN (1 << 4) -#define IRQ_FLG_BIT_VMX (1 << 2) -#define IRQ_FLG_BIT_VMN1 (1 << 1) -#define IRQ_FLG_BIT_VMN2 (1 << 0) - -#define CHANNEL_H_BIT_CLRQDCHG (1 << 7) -#define CHANNEL_H_BIT_CLRQCHG (1 << 6) - -#define CHANNEL_L_BIT_CADC_EN (1 << 7) -#define CHANNEL_L_BIT_INTEMPCH (1 << 6) -#define CHANNEL_L_BIT_AINCH (1 << 2) -#define CHANNEL_L_BIT_VBATSCH (1 << 1) -#define CHANNEL_L_BIT_VADC_EN (1 << 0) - -#define NORMAL_POLL 10 /* 10 sec */ -#define SUSPEND_POLL (30*60) /* 30 min */ - -#define HIGH_TEMP_THRES 650 -#define HIGH_TEMP_RECOVER 430 -#define LOW_TEMP_THRES (-30) -#define LOW_TEMP_RECOVER 0 -#define TEMP_ABNORMAL_COUNT 3 - -#define TALRTMAX_VALUE 0x38 //65.39'C 0x9 -#define TALRTMIN_VALUE 0x11 //-18.75'C 0x17 -#define VALRTMAX_VALUE 0xDC //4297mV -#define VALRTMIN1_VALUE 0xB8 //3600mV -#define VALRTMIN2_VALUE 0x99 //3000mV -#define TRLS_VALUE 55 //5'C -#define VRLS_VALUE 100 //100mV - -#define IRQ_THRES_UNIT 1953 - -struct rt5025_gauge_chip { - struct i2c_client *client; - struct rt5025_power_info *info; - struct rt5025_gauge_callbacks cb; - - struct power_supply battery; - - struct delayed_work monitor_work; - struct wake_lock monitor_wake_lock; - struct alarm wakeup_alarm; - - bool suspend_poll; - ktime_t last_poll; - - /* battery voltage */ - u16 vcell; - /* battery current */ - s16 curr; - /* battery current offset */ - u8 curr_offset; - /* AIN voltage */ - u16 ain_volt; - /* battery external temperature */ - s16 ext_temp; - /* charge coulomb counter */ - u32 chg_cc; - u32 chg_cc_unuse; - //u32 chg_cc_raw; // JY: May not necessary - /* discharge coulomb counter */ - u32 dchg_cc; - u32 dchg_cc_unuse; - //u32 dchg_cc_raw; // JY: May not necessary - - // JY add variable - bool soc_init; - u32 rm; - u32 rm_old; - u8 soc_old; - // --------------- - - u32 fcc; - /* battery capacity */ - u8 soc; - u32 soc_precise; - u16 time_interval; - u16 pre_gauge_timer; - - u8 online; - u8 status; - u8 health; - - /* IRQ flag */ - u8 irq_flag; - - /* max voltage IRQ flag */ - bool max_volt_irq; - /* min voltage1 IRQ flag */ - bool min_volt1_irq; - /* min voltage2 IRQ flag */ - bool min_volt2_irq; - /* max temperature IRQ flag */ - bool max_temp_irq; - /* min temperature IRQ flag */ - bool min_temp_irq; - - u8 temp_high_cnt; - u8 temp_low_cnt; - u8 temp_recover_cnt; -}; - -static u32 battery_vcell_table[] = {3000, 3418, 3598, 3650, 3679, 3722, 3766, 3790, 3826, 3914, 3973, 4046, 4130, 4190}; -static u32 battery_soc_table[] = {0, 2, 5, 7, 14, 24, 40, 49, 58, 71, 80, 89, 98, 100}; - -struct rt5025_gauge_chip *chip; -u8 irq_thres[LAST_TYPE]; - -void rt5025_set_status(int status) -{ - chip->status = status; -} - -static int get_vcell_segment_index(u32* pX, size_t size, u32 x) -{ - unsigned int i; - if (x <= *pX) - return 0; - for (i=0; i=(size-2)) - return size-3; - #endif - return i; -} - -static u32 rt5025_vcell2soc(u32* pX, u32* pY, size_t size, u32 _x) -{ - #if 0 // Linear interpolation - int index; - int x1, x2; - int y, y1, y2; - index = get_vcell_segment_index(pX, size, _x); - if (_x<*pX) - return 0; - if (_x>=*(pX+size-1)) - return 100; - if (_x == *(pX+index)) - return *(pY+index); - x1 = *(pX+index-1); - x2 = *(pX+index); - y1 = *(pY+index-1); - y2 = *(pY+index); - - y = (_x-x1)*(y2-y1)*100/(x2-x1); - y /= 100; - y += y1; - - return y; - #else // Lagrange interpolation - int index; - int32_t x1, x2, x3; - int32_t y1, y2, y3; - int32_t a1, a2, a3, b1, b2, b3; - int32_t x = _x; - if (_x<*pX) - return 0; - if (_x>=*(pX+size-1)) - return 100; - index = get_vcell_segment_index(pX, size, _x); - pX+=index; - pY+=index; - x1 = *pX; - x2 = *(pX+1); - x3 = *(pX+2); - y1 = *pY; - y2 = *(pY+1); - y3 = *(pY+2); - if (x == x1) - return y1; - if (x == x2) - return y2; - if (x == x3) - return y3; - a1 = y1*(x-x2)*(x-x3); - a2 = y2*(x-x1)*(x-x3); - a3 = y3*(x-x1)*(x-x2); - b1 = (x1-x2)*(x1-x3); - b2 = (x2-x1)*(x2-x3); - b3 = (x3-x1)*(x3-x2); - - return (100*a1/b1+100*a2/b2+100*a3/b3)/100; - #endif -} - -static int rt5025_read_reg(struct i2c_client *client, - u8 reg, u8 *data, u8 len) -{ - #if 1 - int ret; - - ret = rt5025_reg_block_read(client, reg, len, data); - #else - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msgs[2]; - int ret; - - msgs[0].addr = client->addr; - msgs[0].flags = client->flags; - msgs[0].len = 1; - msgs[0].buf = ® - msgs[0].scl_rate = 200*1000; - - msgs[1].addr = client->addr; - msgs[1].flags = client->flags | I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = data; - msgs[1].scl_rate = 200*1000; - - ret = i2c_transfer(adap, msgs, 2); - #endif - return (ret == 2)? len : ret; -} - -static int rt5025_write_reg(struct i2c_client *client, - u8 reg, u8 *data, u8 len) -{ - #if 1 - int ret; - - ret = rt5025_reg_block_write(client, reg, len, data); - #else - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - - int ret; - char* tx_buf = (char *)kmalloc(len + 1, GFP_KERNEL); - - if (!tx_buf) - return -ENOMEM; - tx_buf[0] = reg; - memcpy(tx_buf+1, data, len); - - msg.addr = client->addr; - msg.flags = client->flags; - msg.len = len + 1; - msg.buf = (char *)tx_buf; - msg.scl_rate = 200*1000; - ret = i2c_transfer(adap, &msg, 1); - kfree(tx_buf); - - #endif - return (ret == 1) ? len : ret; -} - -static void rt5025_gauge_alarm(struct alarm *alarm) -{ - pr_info("%s: alarmed \n", __func__); - wake_lock(&chip->monitor_wake_lock); - schedule_delayed_work(&chip->monitor_work, 0); -} - -static void rt5025_program_alarm(int seconds) -{ - ktime_t low_interval = ktime_set(seconds, 0); - ktime_t slack = ktime_set(20, 0); - ktime_t next; - - next = ktime_add(chip->last_poll, low_interval); - alarm_start_range(&chip->wakeup_alarm, next, ktime_add(next, slack)); -} - -static int rt5025_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = chip->status; - break; - case POWER_SUPPLY_PROP_HEALTH: - val->intval = chip->health; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = chip->online; - break; - case POWER_SUPPLY_PROP_TEMP: - val->intval = chip->ext_temp; - break; - case POWER_SUPPLY_PROP_ONLINE: - val->intval = 1; - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = chip->vcell * 1000; //uV - break; - case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = chip->curr * 1000; //uA - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = chip->soc; - if (val->intval > 100) - val->intval = 100; - break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = POWER_SUPPLY_TECHNOLOGY_LION; - break; - default: - return -EINVAL; - } - return 0; -} - -static void rt5025_get_vcell(struct i2c_client *client) -{ - u8 data[2]; - - if (rt5025_read_reg(client, RT5025_REG_VCELL_MSB, data, 2) < 0){ - printk(KERN_ERR "%s: Failed to read Voltage\n", __func__); - } - - chip->vcell = ((data[0] << 8) + data[1]) * 61 / 100; - chip->curr_offset = (15444 * chip->vcell - 27444000) / 10000; - - RTINFO("[RT5025] vcell: %d, offset: %d\n", chip->vcell, chip->curr_offset); -} - -static void rt5025_get_current(struct i2c_client *client) -{ - u8 data[2]; - u16 temp; - int sign = 0; - - if (rt5025_read_reg(client, RT5025_REG_CURRENT_MSB, data, 2) < 0) { - printk(KERN_ERR "%s: Failed to read CURRENT\n", __func__); - } - - temp = (data[0]<<8) | data[1]; - if (data[0] & (1 << 7)) { - sign = 1; - temp = (((temp & 0x7FFF) * 3125) / 10 + chip->curr_offset) / 1000; - }else - temp = ((temp * 3125) / 10 - chip->curr_offset) / 1000; - - if (sign) - temp *= -1; - - chip->curr = temp; - RTINFO("[RT5025] current: %d\n", chip->curr); -} - -static void rt5025_get_external_temp(struct i2c_client *client) -{ - u8 data[2]; - long int temp; - - if (rt5025_read_reg(client, RT5025_REG_EXT_TEMPERATUE_MSB, data, 2) < 0) { - printk(KERN_ERR "%s: Failed to read TEMPERATURE\n", __func__); - } - chip->ain_volt = (data[0] * 256 + data[1]) * 61 / 100; - /// Check battery present - if (chip->ain_volt < 1150) - chip->online = true; - else - chip->online = false; - temp = (chip->ain_volt * (-91738) + 81521000) / 100000; - chip->ext_temp = (int)temp; - - if (chip->ext_temp >= HIGH_TEMP_THRES) { - if (chip->health != POWER_SUPPLY_HEALTH_OVERHEAT) - chip->temp_high_cnt++; - } else if (chip->ext_temp <= HIGH_TEMP_RECOVER && chip->ext_temp >= LOW_TEMP_RECOVER) { - if (chip->health == POWER_SUPPLY_HEALTH_OVERHEAT || - chip->health == POWER_SUPPLY_HEALTH_COLD) - chip->temp_recover_cnt++; - } else if (chip->ext_temp <= LOW_TEMP_THRES) { - if (chip->health != POWER_SUPPLY_HEALTH_COLD) - chip->temp_low_cnt++; - } else { - chip->temp_high_cnt = 0; - chip->temp_low_cnt = 0; - chip->temp_recover_cnt = 0; - } - - if (chip->temp_high_cnt >= TEMP_ABNORMAL_COUNT) { - chip->health = POWER_SUPPLY_HEALTH_OVERHEAT; - chip->temp_high_cnt = 0; - } else if (chip->temp_low_cnt >= TEMP_ABNORMAL_COUNT) { - chip->health = POWER_SUPPLY_HEALTH_COLD; - chip->temp_low_cnt = 0; - } else if (chip->temp_recover_cnt >= TEMP_ABNORMAL_COUNT) { - chip->health = POWER_SUPPLY_HEALTH_GOOD; - chip->temp_recover_cnt = 0; - } - RTINFO("[RT5025] external temperature: %d\n", chip->ext_temp); -} - -static void rt5025_clear_cc(operation_mode mode) -{ - u8 data[2]; - - if (rt5025_read_reg(chip->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){ - printk(KERN_ERR "%s: failed to read channel\n", __func__); - } - - if (mode == CHG) - data[0] = data[0] | CHANNEL_H_BIT_CLRQCHG; - else - data[0] = data[0] | CHANNEL_H_BIT_CLRQDCHG; - - if (rt5025_write_reg(chip->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } -} - -static void rt5025_get_chg_cc(struct i2c_client *client) -{ - u8 data[4]; - u32 qh_old,ql_old,qh_new,ql_new; - u32 cc_masec,offset; - - if (rt5025_read_reg(client, RT5025_REG_QCHGH_MSB, data, 4) < 0){ - printk(KERN_ERR "%s: Failed to read QCHG\n", __func__); - } - qh_old = (data[0]<<8) + data[1]; - ql_old = (data[2]<<8) + data[3]; - //pr_info("%s qh_old %04x ql_old %04x\n", __func__, qh_old, ql_old); - - if (rt5025_read_reg(client, RT5025_REG_QCHGH_MSB, data, 4) < 0){ - printk(KERN_ERR "%s: Failed to read QCHG\n", __func__); - } - qh_new = (data[0]<<8) + data[1]; - ql_new = (data[2]<<8) + data[3]; - //pr_info("%s qh_new %04x ql_new %04x\n", __func__, qh_new, ql_new); - - #if 0 - if (qh_new > qh_old){ - cc_masec = qh_new*91266 + ((ql_new*22)>>4); - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - cc_masec = qh_new*91266 + ((ql_new*22)>>4); - }else { - cc_masec = qh_old*91266 + ((ql_old*22)>>4); - } - } - #else - if (qh_new > qh_old){ - cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - }else { - cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10; - } - } - #endif - - offset = chip->curr_offset * chip->time_interval; - - if (cc_masec != 0){ - #if 0 - cc_masec /= 1000; - #else - cc_masec = (cc_masec - offset) / 1000; - #endif - } - - RTINFO("[RT5025] chg_cc_mAsec: %d\n", cc_masec); - - #if 0 - chip->chg_cc = cc_masec; - chip->chg_cc_unuse = 0; - #else - chip->chg_cc = (cc_masec + chip->chg_cc_unuse) / 3600; - chip->chg_cc_unuse = (cc_masec + chip->chg_cc_unuse) % 3600; - #endif - RTINFO("[RT5025] chg_cc_mAH: %d\n", chip->chg_cc); - rt5025_clear_cc(CHG); -} - -static void rt5025_get_dchg_cc(struct i2c_client *client) -{ - u8 data[4]; - u32 qh_old,ql_old,qh_new,ql_new; - u32 cc_masec,offset; - - if (rt5025_read_reg(client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){ - printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__); - } - qh_old = (data[0]<<8) + data[1]; - ql_old = (data[2]<<8) + data[3]; - //pr_info("%s qh_old %04x ql_old %04x\n", __func__, qh_old, ql_old); - - if (rt5025_read_reg(client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){ - printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__); - } - qh_new = (data[0]<<8) + data[1]; - ql_new = (data[2]<<8) + data[3]; - // pr_info("%s qh_new %04x ql_new %04x\n", __func__, qh_new, ql_new); - -#if 0 - if (qh_new > qh_old){ - cc_masec = qh_new*91266 + ((ql_new*22)>>4); - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - cc_masec = qh_new*91266 + ((ql_new*22)>>4); - }else { - cc_masec = qh_old*91266 + ((ql_old*22)>>4); - } - } -#else - if (qh_new > qh_old){ - cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - }else { - cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10; - } - } -#endif - - offset = chip->curr_offset * chip->time_interval; - - if (cc_masec != 0){ - #if 0 - cc_masec /= 1000; - #else - cc_masec = (cc_masec - offset) / 1000; - #endif - } - - RTINFO("[RT5025] dchg_cc_mAsec: %d\n", cc_masec); - - #if 0 - chip->dchg_cc = cc_masec; - chip->dchg_cc_unuse = 0; - #else - chip->dchg_cc = (cc_masec + chip->dchg_cc_unuse) / 3600; - chip->dchg_cc_unuse = (cc_masec + chip->dchg_cc_unuse) % 3600; - #endif - RTINFO("[RT5025] dchg_cc_mAH: %d\n", chip->dchg_cc); - rt5025_clear_cc(DCHG); -} - -static void rt5025_get_irq_flag(struct i2c_client *client) -{ - u8 data[1]; - - if (rt5025_read_reg(client, RT5025_REG_IRQ_FLAG, data, 1) < 0){ - printk(KERN_ERR "%s: Failed to read irq_flag\n", __func__); - } - - chip->irq_flag = data[0]; - RTINFO("[RT5025] IRQ_FLG 0x%x\n", chip->irq_flag); -} - -static void rt5025_get_timer(struct i2c_client *client) -{ - u8 data[2]; - u16 gauge_timer; - - if (rt5025_read_reg(client, RT5025_REG_TIMER, data, 2) < 0){ - printk(KERN_ERR "%s: Failed to read Timer\n", __func__); - } - - gauge_timer = (data[0] << 8) + data[1]; - if (gauge_timer > chip->pre_gauge_timer) - chip->time_interval = gauge_timer - chip->pre_gauge_timer; - else - chip->time_interval = 65536 - chip->pre_gauge_timer + gauge_timer; - - chip->pre_gauge_timer = gauge_timer; - RTINFO("[RT5025] timer %d , interval %d\n", gauge_timer,chip->time_interval); -} - -static void rt5025_gauge_init_soc(struct i2c_client *client) -{ - /* Update voltage */ - rt5025_get_vcell(client); - /* Update current */ - rt5025_get_current(client); - /* Update external temperature */ - rt5025_get_external_temp(client); - // JY add - if (chip->soc_init) - { - chip->soc = chip->soc_old; - chip->rm = chip->rm_old; - } - else - { - chip->soc = rt5025_vcell2soc(battery_vcell_table, battery_soc_table, ARRAY_SIZE(battery_vcell_table), chip->vcell); - chip->soc_precise = (u32)(chip->soc); - chip->soc_init = true; - chip->soc_old = chip->soc; - chip->rm = (chip->soc *chip->fcc)/100; - chip->rm_old = chip->rm; - } - // ---------------- - /* - chip->soc = rt5025_vcell2soc(battery_vcell_table, battery_soc_table, ARRAY_SIZE(battery_vcell_table), chip->vcell); - chip->soc_precise = (u32)(chip->soc); - */ - pr_info("%s: vcell = %d, soc = %d\n", __func__, chip->vcell, chip->soc); - /* upsampling (extend more 12 bits)*/ -} - -static void rt5025_get_soc(struct i2c_client *client) -{ - //fcc = full charged capacity (battery capacity) - int chg_cc = chip->chg_cc; - int dchg_cc = chip->dchg_cc; - - // JY new implement - chip->rm = chip->rm_old + (chg_cc - dchg_cc); - if (chip->rm < 0) - { - chip->rm = 0; - chip->chg_cc = 0; - chip->dchg_cc = 0; - } - else if (chip->rm > chip->fcc) - { - chip->rm = chip->fcc; - chip->chg_cc = chip->fcc; - chip->dchg_cc = 0; - } - - chip->soc_precise = (chip->rm *100)/chip->fcc; - - chip->soc = (chip->soc_precise); - - if (chip->soc > chip->soc_old+1) - { - chip->soc = chip->soc_old + 1; - } - else if (chip->soc < chip->soc_old-1) - { - chip->soc = chip->soc_old -1; - } - - if (chip->soc < 0) - chip->soc = 0; - else if (chip->soc > 100) - chip->soc = 100; - - chip->rm_old = chip->rm; - chip->soc_old = chip->soc; - // -------------------- - - /* JY mark it - - chip->soc_precise = chip->soc_precise + ((chg_cc-dchg_cc)*100)/chip->fcc; - - pr_info("%s chg_cc = %d\n", __func__, chg_cc); - pr_info("%s dchg_cc = %d\n", __func__, dchg_cc); - pr_info("%s soc_precise = %d\n", __func__, chip->soc_precise); - chip->soc = (chip->soc_precise); - if (chip->soc < 0) - chip->soc = 0; - else if (chip->soc > 100) - chip->soc = 100; - */ - //chip->soc = 50; -} - -static void rt5025_channel_cc(bool enable) -{ - u8 data[1]; - - if (rt5025_read_reg(chip->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ - printk(KERN_ERR "%s: failed to read channel\n", __func__); - } - - if (enable){ - data[0] = data[0] | 0x80; - }else { - data[0] = data[0] & 0x7F; - } - - if (rt5025_write_reg(chip->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } -} - -static void rt5025_register_init(struct i2c_client *client) -{ - u8 data[1]; - - /* enable the channel of current,qc,ain,vbat and vadc */ - if (rt5025_read_reg(client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ - printk("%s: failed to read channel\n", __func__); - } - data[0] = data[0] | - CHANNEL_L_BIT_CADC_EN | - CHANNEL_L_BIT_AINCH | - CHANNEL_L_BIT_VBATSCH | - CHANNEL_L_BIT_VADC_EN; - if (rt5025_write_reg(client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ - printk("%s: failed to write channel\n", __func__); - } - /* set the alert threshold value */ - irq_thres[MAXTEMP] = TALRTMAX_VALUE; - irq_thres[MINTEMP] = TALRTMIN_VALUE; - irq_thres[MAXVOLT] = VALRTMAX_VALUE; - irq_thres[MINVOLT1] = VALRTMIN1_VALUE; - irq_thres[MINVOLT2] = VALRTMIN2_VALUE; - irq_thres[TEMP_RLS] = TRLS_VALUE; - irq_thres[VOLT_RLS] = VRLS_VALUE; - - chip->chg_cc_unuse = 0; - chip->dchg_cc_unuse = 0; - chip->pre_gauge_timer = 0; - chip->online = 1; - chip->status = POWER_SUPPLY_STATUS_DISCHARGING; - chip->health = POWER_SUPPLY_HEALTH_GOOD; - RTINFO("[RT5025] register initialized\n"); -} - -static void rt5025_alert_setting(alert_type type, bool enable) -{ - u8 data[1]; - - if (rt5025_read_reg(chip->client, RT5025_REG_IRQ_CTL, data, 1) < 0){ - printk(KERN_ERR "%s: Failed to read CONFIG\n", __func__); - } - - if(enable){ - switch(type){ - case MAXTEMP: - data[0] |= IRQ_CTL_BIT_TMX; //Enable max temperature alert - chip->max_temp_irq = true; - RTINFO("Enable min temperature alert"); - break; - case MINTEMP: - data[0] |= IRQ_CTL_BIT_TMN; //Enable min temperature alert - chip->min_temp_irq = true; - RTINFO("Enable max temperature alert"); - break; - case MAXVOLT: - data[0] |= IRQ_CTL_BIT_VMX; //Enable max voltage alert - chip->max_volt_irq = true; - RTINFO("Enable max voltage alert"); - break; - case MINVOLT1: - data[0] |= IRQ_CTL_BIT_VMN1; //Enable min1 voltage alert - chip->min_volt1_irq = true; - RTINFO("Enable min1 voltage alert"); - break; - case MINVOLT2: - data[0] |= IRQ_CTL_BIT_VMN2; //Enable min2 voltage alert - chip->min_volt2_irq = true; - RTINFO("Enable min2 voltage alert"); - break; - default: - break; - } - }else{ - switch(type){ - case MAXTEMP: - data[0] = data[0] &~ IRQ_CTL_BIT_TMX; //Disable max temperature alert - chip->max_temp_irq = false; - RTINFO("Disable min temperature alert"); - break; - case MINTEMP: - data[0] = data[0] &~ IRQ_CTL_BIT_TMN; //Disable min temperature alert - chip->min_temp_irq = false; - RTINFO("Disable max temperature alert"); - break; - case MAXVOLT: - data[0] = data[0] &~ IRQ_CTL_BIT_VMX; //Disable max voltage alert - chip->max_volt_irq = false; - RTINFO("Disable max voltage alert"); - break; - case MINVOLT1: - data[0] = data[0] &~ IRQ_CTL_BIT_VMN1; //Disable min1 voltage alert - chip->min_volt1_irq = false; - RTINFO("Disable min1 voltage alert"); - break; - case MINVOLT2: - data[0] = data[0] &~ IRQ_CTL_BIT_VMN2; //Disable min2 voltage alert - chip->min_volt2_irq = false; - RTINFO("Disable min2 voltage alert"); - break; - default: - break; - } - } - if (rt5025_write_reg(chip->client, RT5025_REG_IRQ_CTL, data, 1) < 0) - printk(KERN_ERR "%s: failed to write IRQ control\n", __func__); -} -static void rt5025_alert_threshold_init(struct i2c_client *client) -{ - u8 data[1]; - - /* TALRT MAX threshold setting */ - data[0] = irq_thres[MAXTEMP]; - if (rt5025_write_reg(client, RT5025_REG_TALRT_MAXTH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write TALRT MAX threshold\n", __func__); - /* TALRT MIN threshold setting */ - data[0] = irq_thres[MINTEMP]; - if (rt5025_write_reg(client, RT5025_REG_TALRT_MINTH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write TALRT MIN threshold\n", __func__); - /* VALRT MAX threshold setting */ - data[0] = irq_thres[MAXVOLT]; - if (rt5025_write_reg(client, RT5025_REG_VALRT_MAXTH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write VALRT MAX threshold\n", __func__); - /* VALRT MIN1 threshold setting */ - data[0] = irq_thres[MINVOLT1]; - if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN1TH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write VALRT MIN1 threshold\n", __func__); - /* VALRT MIN2 threshold setting */ - data[0] = irq_thres[MINVOLT2]; - if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN2TH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write VALRT MIN2 threshold\n", __func__); -} - -static void rt5025_alert_init(struct i2c_client *client) -{ - /* Set RT5025 gauge alert configuration */ - rt5025_alert_threshold_init(client); - /* Enable gauge alert function */ - rt5025_alert_setting(MAXTEMP,true); - rt5025_alert_setting(MINTEMP,true); - rt5025_alert_setting(MAXVOLT,true); - rt5025_alert_setting(MINVOLT1,true); - rt5025_alert_setting(MINVOLT2,true); -} - -void rt5025_irq_handler(void) -{ - rt5025_get_irq_flag(chip->client); - - if ((chip->irq_flag) & IRQ_FLG_BIT_TMX){ - printk(KERN_INFO "[RT5025]: Min temperature IRQ received\n"); - rt5025_alert_setting(MAXTEMP,false); - chip->max_temp_irq = false; - } - if ((chip->irq_flag) & IRQ_FLG_BIT_TMN){ - printk(KERN_INFO "[RT5025]: Max temperature IRQ received\n"); - rt5025_alert_setting(MINTEMP,false); - chip->min_temp_irq = false; - } - if ((chip->irq_flag) & IRQ_FLG_BIT_VMX){ - printk(KERN_INFO "[RT5025]: Max voltage IRQ received\n"); - rt5025_alert_setting(MAXVOLT,false); - chip->max_volt_irq = false; - } - if ((chip->irq_flag) & IRQ_FLG_BIT_VMN1){ - printk(KERN_INFO "[RT5025]: Min voltage1 IRQ received\n"); - rt5025_alert_setting(MINVOLT1,false); - chip->min_volt1_irq = false; - } - if ((chip->irq_flag) & IRQ_FLG_BIT_VMN2){ - printk(KERN_INFO "[RT5025]: Min voltage2 IRQ received\n"); - rt5025_alert_setting(MINVOLT2,false); - chip->min_volt2_irq = false; - } - - wake_lock(&chip->monitor_wake_lock); - schedule_delayed_work(&chip->monitor_work, 0); -} - -static void rt5025_update(struct i2c_client *client) -{ - /* Update voltage */ - rt5025_get_vcell(client); - /* Update current */ - rt5025_get_current(client); - /* Update external temperature */ - rt5025_get_external_temp(client); - /* Read timer */ - rt5025_get_timer(client); - /* Update chg cc */ - rt5025_get_chg_cc(client); - /* Update dchg cc */ - rt5025_get_dchg_cc(client); - /* Update SOC */ - rt5025_get_soc(client); - - if ((chip->max_temp_irq == false) && - (((irq_thres[MAXTEMP] * IRQ_THRES_UNIT) / 100 - chip->ain_volt) > irq_thres[TEMP_RLS])){ - rt5025_alert_setting(MAXTEMP,true); - }else if ((chip->min_temp_irq == false) && - ((chip->ain_volt - (irq_thres[MINTEMP] * IRQ_THRES_UNIT) / 100) > irq_thres[TEMP_RLS])){ - rt5025_alert_setting(MINTEMP,true); - }else if ((chip->max_volt_irq == false) && - ((((irq_thres[MAXVOLT] * IRQ_THRES_UNIT) / 100) - chip->vcell) > irq_thres[VOLT_RLS])){ - rt5025_alert_setting(MAXVOLT,true); - }else if ((chip->min_volt1_irq == false) && - ((chip->vcell - ((irq_thres[MINVOLT1] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){ - rt5025_alert_setting(MINVOLT1,true); - }else if ((chip->min_volt2_irq == false) && - ((chip->vcell - ((irq_thres[MINVOLT2] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){ - rt5025_alert_setting(MINVOLT2,true); - } -} - -static void rt5025_update_work(struct work_struct *work) -{ - unsigned long flags; - - rt5025_update(chip->client); - - /* Update data to framework */ - power_supply_changed(&chip->battery); - - /* prevent suspend before starting the alarm */ - local_irq_save(flags); - chip->last_poll = alarm_get_elapsed_realtime(); - rt5025_program_alarm(NORMAL_POLL); - local_irq_restore(flags); - - wake_unlock(&chip->monitor_wake_lock); -} - -static enum power_supply_property rt5025_battery_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_TEMP, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_NOW, - POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_TECHNOLOGY, -}; - -void rt5025_gauge_suspend(void) -{ - rt5025_channel_cc(false); - cancel_delayed_work(&chip->monitor_work); - - RTINFO("\n"); -} - -void rt5025_gauge_resume(void) -{ - rt5025_channel_cc(true); - wake_lock(&chip->monitor_wake_lock); - schedule_delayed_work(&chip->monitor_work, 0); - RTINFO("\n"); -} - -void rt5025_gauge_remove(void) -{ - chip->info->event_callback = NULL; - power_supply_unregister(&chip->battery); - cancel_delayed_work(&chip->monitor_work); - wake_lock_destroy(&chip->monitor_wake_lock); - kfree(chip); -} - -int rt5025_gauge_init(struct rt5025_power_info *info) -{ - int ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->client = info->i2c; - chip->fcc = info->fcc; - chip->info = info; - // JY add - chip->soc_init = false; - chip->rm = chip->fcc/2; - chip->rm_old = chip->rm; - // ------------ - chip->battery.name = "rt5025-battery"; - chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; - chip->battery.get_property = rt5025_get_property; - chip->battery.properties = rt5025_battery_props; - chip->battery.num_properties = ARRAY_SIZE(rt5025_battery_props); - - ret = power_supply_register(info->dev, &chip->battery); - if (ret) { - printk(KERN_ERR "[RT5025] power supply register failed\n"); - goto err_wake_lock; - } - - chip->last_poll = alarm_get_elapsed_realtime(); - alarm_init(&chip->wakeup_alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, - rt5025_gauge_alarm); - - INIT_DELAYED_WORK(&chip->monitor_work, rt5025_update_work); - - wake_lock_init(&chip->monitor_wake_lock, WAKE_LOCK_SUSPEND, - "rt-battery-monitor"); - /* enable channel */ - rt5025_register_init(info->i2c); - rt5025_gauge_init_soc(info->i2c); - - /* enable gauge IRQ */ - rt5025_alert_init(info->i2c); - - /* register callback functions */ - chip->cb.rt5025_gauge_irq_handler = rt5025_irq_handler; - chip->cb.rt5025_gauge_set_status = rt5025_set_status; - chip->cb.rt5025_gauge_suspend = rt5025_gauge_suspend; - chip->cb.rt5025_gauge_resume = rt5025_gauge_resume; - chip->cb.rt5025_gauge_remove = rt5025_gauge_remove; - info->event_callback=&chip->cb; - - //rt_register_gauge_callbacks(info->i2c, &chip->cb); - - wake_lock(&chip->monitor_wake_lock); - schedule_delayed_work(&chip->monitor_work, msecs_to_jiffies(1000)); - - return 0; - -err_wake_lock: - wake_lock_destroy(&chip->monitor_wake_lock); - kfree(chip); - - return ret; -} diff --git a/drivers/power/rt5025-power.c b/drivers/power/rt5025-power.c index b99a79d32fc7..037be178ecca 100644 --- a/drivers/power/rt5025-power.c +++ b/drivers/power/rt5025-power.c @@ -22,7 +22,6 @@ #include #include #include -#include #include @@ -34,6 +33,7 @@ static char *rt5025_supply_list[] = { "rt5025-battery", }; + #if 0 static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff) { @@ -62,6 +62,7 @@ static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value) u8 data = 0; //ICC Setting + #if 0 if (cur_value > 2000) data |= 0x0f<<3; else if (cur_value >= 500 && cur_value <= 2000) @@ -69,7 +70,7 @@ static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value) data = (cur_value-500)/100; data<<=3; } - + #endif //AICR Setting if (cur_value > 1000) @@ -79,7 +80,7 @@ static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value) else if (cur_value > 100 && cur_value >= 500) data |= 0x01<<1; - rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGCC_MASK, data); + rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGAICR_MASK, data); return ret; } @@ -94,22 +95,52 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v rt5025_set_charging_buck(info->i2c, 1); #endif info->chg_stat = 0x00; + #if 1 + if (info->chip->battery_info) + { + if (info->chg_term == 0) + rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_DISCHARGING); + else if (info->chg_term > 0) + { + rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_FULL); + info->chg_term = 0; + } + + } + #else if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING); + #endif break; case 0x01: //rt5025_set_charging_current_switch(info->i2c, 1); info->chg_stat = 0x01; + #if 1 + if (info->chip->battery_info) + { + rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_CHARGING); + info->chg_term = 0; + } + #else if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING); + #endif break; case 0x02: #if 0 rt5025_set_charging_current_switch(info->i2c, 0); #endif info->chg_stat = 0x02; + #if 1 + if (info->chip->battery_info) + { + rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_FULL); + info->chg_term = 0; + } + #else if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL); + #endif break; case 0x03: #if 0 @@ -117,8 +148,21 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v rt5025_set_charging_current_switch(info->i2c, 0); #endif info->chg_stat = 0x03; + #if 1 + if (info->chip->battery_info) + { + if (info->chg_term == 0) + rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_CHARGING); + else if (info->chg_term > 1) + { + rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_FULL); + info->chg_term = 0; + } + } + #else if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING); + #endif break; default: break; @@ -126,6 +170,7 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v return ret; } +#if 0 int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info) { if (info->event_callback) @@ -133,6 +178,7 @@ int rt5025_power_passirq_to_gauge(struct rt5025_power_info *info) return 0; } EXPORT_SYMBOL(rt5025_power_passirq_to_gauge); +#endif int rt5025_power_charge_detect(struct rt5025_power_info *info) { @@ -169,6 +215,7 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info) schedule_delayed_work(&info->usb_detect_work, 0); //no delay new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT; + if (new_acval || new_usbval) { if (old_chgval != new_chgval) @@ -183,8 +230,15 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info) rt5025_set_charging_current_switch(info->i2c, 0); #endif info->chg_stat = RT5025_CHGSTAT_UNKNOWN; + if (info->chip->jeita_info) + rt5025_notify_charging_cable(info->chip->jeita_info, JEITA_NO_CHARGE); + #if 1 + if (info->chip->battery_info) + rt5025_gauge_set_status(info->chip->battery_info, POWER_SUPPLY_STATUS_NOT_CHARGING); + #else if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_NOT_CHARGING); + #endif } return ret; @@ -212,8 +266,10 @@ static int rt5025_adap_get_props(struct power_supply *psy, return 0; } + extern int dwc_vbus_status(void); + static void usb_detect_work_func(struct work_struct *work) { struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work); @@ -225,6 +281,7 @@ static void usb_detect_work_func(struct work_struct *work) if (pi->ac_online) { rt5025_set_charging_current(pi->i2c, 1000); + rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_AC_ADAPTER); pi->usb_cnt = 0; } else if (pi->usb_online) @@ -234,11 +291,13 @@ static void usb_detect_work_func(struct work_struct *work) { case 2: // USB Wall charger rt5025_set_charging_current(pi->i2c, 1000); + rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_USB_TA); pr_info("rt5025: detect usb wall charger\n"); break; case 1: //normal USB default: rt5025_set_charging_current(pi->i2c, 500); + rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_NORMAL_USB); pr_info("rt5025: detect normal usb\n"); break; } @@ -249,6 +308,7 @@ static void usb_detect_work_func(struct work_struct *work) { //default to prevent over current charging rt5025_set_charging_current(pi->i2c, 500); + rt5025_notify_charging_cable(pi->chip->jeita_info, JEITA_NO_CHARGE); //reset usb_cnt; pi->usb_cnt = 0; } @@ -259,13 +319,14 @@ static void usb_detect_work_func(struct work_struct *work) static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_data* pd) { - RTINFO("++\n"); info->ac_online = 0; info->usb_online =0; //init charger buckck & charger current en to disable stat info->chg_stat = RT5025_CHGSTAT_UNKNOWN; + #if 0 if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING); + #endif rt5025_set_bits(info->i2c, RT5025_REG_CHGCTL4, RT5025_CHGRST_MASK); udelay(200); //init register setting @@ -278,7 +339,6 @@ static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_charge_detect(info); - RTINFO("--\n"); return 0; } @@ -288,25 +348,26 @@ static int __devinit rt5025_power_probe(struct platform_device *pdev) struct rt5025_platform_data *pdata = chip->dev->platform_data; struct rt5025_power_info *pi; int ret = 0; - printk("%s,line=%d\n", __func__,__LINE__); - + pi = kzalloc(sizeof(*pi), GFP_KERNEL); if (!pi) return -ENOMEM; pi->i2c = chip->i2c; pi->dev = &pdev->dev; - pi->fcc = pdata->power_data->fcc; + pi->chip = chip; mutex_init(&pi->var_lock); INIT_DELAYED_WORK(&pi->usb_detect_work, usb_detect_work_func); + #if 0 ret = rt5025_gauge_init(pi); if (ret) goto out; + #endif platform_set_drvdata(pdev, pi); - pi->ac.name = "rt5025-ac"; + pi->ac.name = "rt5025-dc"; pi->ac.type = POWER_SUPPLY_TYPE_MAINS; pi->ac.supplied_to = rt5025_supply_list; pi->ac.properties = rt5025_adap_props; @@ -340,18 +401,23 @@ out: static int rt5025_power_suspend(struct platform_device *pdev, pm_message_t state) { + #if 0 struct rt5025_power_info *pi = platform_get_drvdata(pdev); if (pi->event_callback) pi->event_callback->rt5025_gauge_suspend(); + #endif return 0; } static int rt5025_power_resume(struct platform_device *pdev) { + #if 0 struct rt5025_power_info *pi = platform_get_drvdata(pdev); + if (pi->event_callback) pi->event_callback->rt5025_gauge_resume(); + #endif return 0; } @@ -360,8 +426,10 @@ static int __devexit rt5025_power_remove(struct platform_device *pdev) struct rt5025_power_info *pi = platform_get_drvdata(pdev); struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); + #if 0 if (pi->event_callback) pi->event_callback->rt5025_gauge_remove(); + #endif power_supply_unregister(&pi->usb); power_supply_unregister(&pi->ac); chip->power_info = NULL; diff --git a/drivers/power/rt5025-swjeita.c b/drivers/power/rt5025-swjeita.c new file mode 100755 index 000000000000..5df1a363cfaf --- /dev/null +++ b/drivers/power/rt5025-swjeita.c @@ -0,0 +1,397 @@ +/* drivers/power/rt5025-swjeita.c + * swjeita Driver for Richtek RT5025 PMIC + * Multi function device - multi functional baseband PMIC swjeita part + * + * Copyright (C) 2013 + * Author: CY Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TEMP_TOLERANCE 10 // 'c*10 gap for tolerance + +static int rt5025_set_charging_cc_switch (struct i2c_client *i2c, int onoff) +{ + int ret; + RTINFO("onoff = %d\n", onoff); + if (onoff) + ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCCEN_MASK); + else + ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCCEN_MASK); + return ret; +} + +static int rt5025_set_charging_cc(struct i2c_client *i2c, int cur_value) +{ + int ret; + u8 data; + + RTINFO("current value = %d\n", cur_value); + if (cur_value < 500) + data = 0; + else if (cur_value > 2000) + data = 0xf< 4440) + data = 0x2f<cur_temp; + int sect_index; + + RTINFO("\n"); + if (temp < swji->temp[0]) + sect_index = 0; + else if (temp >= swji->temp[0] && temp < swji->temp[1]) + sect_index = 1; + else if (temp >= swji->temp[1] && temp < swji->temp[2]) + sect_index = 2; + else if (temp >= swji->temp[2] && temp < swji->temp[3]) + sect_index = 3; + else if (temp >= swji->temp[3]) + sect_index = 4; + + RTINFO("sect_index = %d\n", sect_index); + return sect_index; +} + +static int rt5025_get_external_temp_index(struct rt5025_swjeita_info *swji) +{ + u8 data[2]; + long int temp; + int sect_index; + + RTINFO("\n"); + if (rt5025_reg_block_read(swji->i2c, RT5025_REG_AINH, 2, data) < 0) + pr_err("%s: failed to read ext_temp register\n", __func__); + + temp = (data[0]*256+data[1])*61/100; + temp = (temp * (-91738) +81521000)/100000; + + swji->cur_temp = temp; + + RTINFO("cur_section = %d, cur_temp = %d\n", swji->cur_section, swji->cur_temp); + + switch (swji->cur_section) + { + case 0: + if (temp < swji->temp[0]+TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 1: + if (temp <= swji->temp[0]-TEMP_TOLERANCE || temp >= swji->temp[1]+TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 2: + if (temp <= swji->temp[1]-TEMP_TOLERANCE || temp >= swji->temp[2]+TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 3: + if (temp <= swji->temp[2]-TEMP_TOLERANCE || temp >= swji->temp[3]+TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 4: + if (temp <= swji->temp[3]-TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + default: + sect_index = swji->cur_section; + break; + } + RTINFO("sect_index = %d\n", sect_index); + return sect_index; +} + +static inline int rt5025_set_ainadc_onoff(struct rt5025_swjeita_info *swji, int enable) +{ + int ret; + + RTINFO("enable = %d\n", enable); + if (enable) + ret = rt5025_set_bits(swji->i2c, RT5025_REG_CHANNELL, RT5025_AINEN_MASK); + else + ret = rt5025_clr_bits(swji->i2c, RT5025_REG_CHANNELL, RT5025_AINEN_MASK); + + return ret; +} + +static int rt5025_set_exttemp_alert(struct rt5025_swjeita_info *swji, int index) +{ + int ret = 0; + + RTINFO("index = %d\n", index); + + switch (index) + { + case 0: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[0]); + break; + case 1: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[0]); + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[1]); + break; + case 2: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[1]); + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[2]); + break; + case 3: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[2]); + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[3]); + break; + case 4: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[3]); + break; + } + + return ret; +} + +static int rt5025_exttemp_alert_switch(struct rt5025_swjeita_info *swji, int onoff) +{ + if (!onoff) + { + rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); + } + else + { + switch (swji->cur_section) + { + case 0: + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); + break; + case 1: + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); + break; + case 2: + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); + break; + case 3: + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); + break; + case 4: + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + break; + } + } + + RTINFO("index=%d, onoff=%d\n", swji->cur_section, onoff); + return 0; +} + +int rt5025_notify_charging_cable(struct rt5025_swjeita_info *swji, int cable_type) +{ + int sect_index; + int ret = 0; + + RTINFO("cable_type = %d\n", cable_type); + + rt5025_exttemp_alert_switch(swji, 0); + + sect_index = rt5025_get_external_temp_index(swji); + if (swji->cur_section != sect_index || swji->init_once == 0) + { + rt5025_set_exttemp_alert(swji, sect_index); + swji->cur_section = sect_index; + swji->init_once = 1; + } + + switch (cable_type) + { + case JEITA_NORMAL_USB: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; + case JEITA_USB_TA: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; + case JEITA_AC_ADAPTER: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; + case JEITA_NO_CHARGE: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; + } + swji->cur_cable = cable_type; + + rt5025_exttemp_alert_switch(swji, 1); + + return ret; +} +EXPORT_SYMBOL(rt5025_notify_charging_cable); + +int rt5025_swjeita_irq_handler(struct rt5025_swjeita_info *swji, unsigned char event) +{ + int ret = 0; + RTINFO("event = 0x%02x\n", event); + + if (event&(RT5025_TMXEN_MASK|RT5025_TMNEN_MASK)) + rt5025_notify_charging_cable(swji, swji->cur_cable); + + return ret; +} +EXPORT_SYMBOL(rt5025_swjeita_irq_handler); + +static int __devinit rt5025_swjeita_probe(struct platform_device *pdev) +{ + struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct rt5025_platform_data *pdata = chip->dev->platform_data; + struct rt5025_swjeita_info *swji; + int ret = 0; + + swji = kzalloc(sizeof(*swji), GFP_KERNEL); + if (!swji) + return -ENOMEM; + + #if 0 // for debug pdata->jeita_data + for (ret=0; ret<4; ret++) + RTINFO("jeita temp value %d\n", pdata->jeita_data->temp[ret]); + for (ret=0; ret<4; ret++) + { + RTINFO("jeita temp_cc value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cc[ret][0], \ + pdata->jeita_data->temp_cc[ret][1], pdata->jeita_data->temp_cc[ret][2], \ + pdata->jeita_data->temp_cc[ret][3], pdata->jeita_data->temp_cc[ret][4]); + } + for (ret=0; ret<4; ret++) + { + RTINFO("jeita temp_cv value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cv[ret][0], \ + pdata->jeita_data->temp_cv[ret][1], pdata->jeita_data->temp_cv[ret][2], \ + pdata->jeita_data->temp_cv[ret][3], pdata->jeita_data->temp_cv[ret][4]); + } + for (ret=0; ret<4; ret++) + { + RTINFO("temp_scalar[%d] = 0x%02x\n", ret, pdata->jeita_data->temp_scalar[ret]); + } + ret = 0; + #endif /* #if 0 */ + + swji->i2c = chip->i2c; + swji->chip = chip; + swji->cur_section = 2; //initial as the normal temperature + swji->cur_cable = JEITA_NO_CHARGE; + swji->temp = pdata->jeita_data->temp; + swji->temp_scalar = pdata->jeita_data->temp_scalar; + swji->temp_cc = pdata->jeita_data->temp_cc; + swji->temp_cv = pdata->jeita_data->temp_cv; + platform_set_drvdata(pdev, swji); + + rt5025_set_ainadc_onoff(swji, 1); + mdelay(100); + rt5025_notify_charging_cable(swji, swji->cur_cable); + + chip->jeita_info = swji; + RTINFO("rt5025-swjeita driver is successfully loaded\n"); + return ret; +} + +static int __devexit rt5025_swjeita_remove(struct platform_device *pdev) +{ + struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); + + swji->chip->jeita_info = NULL; + kfree(swji); + return 0; +} + +static int rt5025_swjeita_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); + + swji->suspend = 1; + return 0; +} + +static int rt5025_swjeita_resume(struct platform_device *pdev) +{ + struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); + + swji->suspend = 0; + return 0; +} + +static struct platform_driver rt5025_swjeita_driver = +{ + .driver = { + .name = RT5025_DEVICE_NAME "-swjeita", + .owner = THIS_MODULE, + }, + .probe = rt5025_swjeita_probe, + .remove = __devexit_p(rt5025_swjeita_remove), + .suspend = rt5025_swjeita_suspend, + .resume = rt5025_swjeita_resume, +}; + +static int __init rt5025_swjeita_init(void) +{ + return platform_driver_register(&rt5025_swjeita_driver); +} +module_init(rt5025_swjeita_init); + +static void __exit rt5025_swjeita_exit(void) +{ + platform_driver_unregister(&rt5025_swjeita_driver); +} +module_exit(rt5025_swjeita_exit); + + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("CY Huang =info->vol_output_size)? \ -EINVAL: \ - info->vol_output_list[index ]; + info->vol_output_list[index]; } -//#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38)) +#if 0 //(LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38)) static int rt5025_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); @@ -147,7 +149,7 @@ static int rt5025_get_voltage_sel(struct regulator_dev *rdev) return ret; return (ret & info->vol_mask) >> info->vol_shift; } -//#else +#else static int rt5025_find_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { @@ -169,6 +171,7 @@ static int rt5025_set_voltage(struct regulator_dev *rdev, { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data; + if (check_range(info, min_uV, max_uV)) { dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n", min_uV, max_uV); @@ -176,20 +179,22 @@ static int rt5025_set_voltage(struct regulator_dev *rdev, } data = rt5025_find_voltage(rdev,min_uV,max_uV); data <<= info->vol_shift; + return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data); } static int rt5025_get_voltage(struct regulator_dev *rdev) { + struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); int ret; - ret = rt5025_get_voltage_sel(rdev); + ret = rt5025_reg_read(info->i2c, info->vol_reg); if (ret < 0) return ret; - return rt5025_list_voltage(rdev, ret ); - + ret = (ret & info->vol_mask) >> info->vol_shift; + return rt5025_list_voltage(rdev, ret); } -//#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */ +#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */ static int rt5025_enable(struct regulator_dev *rdev) { @@ -218,102 +223,61 @@ static int rt5025_is_enabled(struct regulator_dev *rdev) return (ret & (info->enable_bit))?1:0; } -static int rt5025_dcdc_get_mode(struct regulator_dev *rdev) + +static int rt5025_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); - int buck = rdev_get_id(rdev) - 0; int ret; - uint8_t control; - - ret = rt5025_reg_read(info->i2c, 0x0c); - if (ret < 0) { - return ret; - } - if (buck ==0){ - control =(ret & 0x80)>>7; - } - else if (buck ==1){ - control =(ret & 0x40)>>6; - } - else if (buck ==2){ - control =(ret & 0x20)>>5; - } - else{ - return -1; - } - switch (control) { - case 0: - return REGULATOR_MODE_FAST; - case 1: - return REGULATOR_MODE_NORMAL; - default: - return -1; + if (!info->mode_bit) + ret = 0; + else + { + switch (mode) + { + case REGULATOR_MODE_NORMAL: + ret = rt5025_set_bits(info->i2c, info->mode_reg, info->mode_bit); + break; + case REGULATOR_MODE_FAST: + ret = rt5025_clr_bits(info->i2c, info->mode_reg, info->mode_bit); + break; + default: + ret = -EINVAL; + break; + } } - + return ret; } -static int rt5025_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode) + +static unsigned int rt5025_get_mode(struct regulator_dev *rdev) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); - int buck = rdev_get_id(rdev) - 0; - int ret; - uint8_t control; - - ret = rt5025_reg_read(info->i2c, 0x0c); - if (buck ==0){ - control =ret &(~ (1 <<7)); - } - else if (buck ==1){ - control =ret &(~ (1 <<6)); - } - else if (buck ==2){ - control =ret &(~ (1 <<5)); - } - else{ - return -1; - } - - switch(mode) + unsigned int mode; + int data; + + if (!info->mode_bit) + mode = REGULATOR_MODE_NORMAL; + else { - case REGULATOR_MODE_FAST: - return rt5025_reg_write(info->i2c, 0x0c,control); - case REGULATOR_MODE_NORMAL: - return rt5025_reg_write(info->i2c, 0x0c,(control | (1 <<(7-buck)))); - default: - printk("error:pmu_rt5025 only powersave pwm & auto mode\n"); - return -EINVAL; + data = rt5025_reg_read(info->i2c, info->mode_reg); + mode = (data & info->mode_bit)?REGULATOR_MODE_NORMAL:REGULATOR_MODE_FAST; } -} -static int rt5025_dcdc_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector, - unsigned int new_selector) -{ - int old_volt, new_volt; - - old_volt = rt5025_list_voltage(rdev, old_selector); - if (old_volt < 0) - return old_volt; - - new_volt = rt5025_list_voltage(rdev, new_selector); - if (new_volt < 0) - return new_volt; - - return DIV_ROUND_UP(abs(old_volt - new_volt), 25000); + return mode; } static struct regulator_ops rt5025_regulator_ops = { .list_voltage = rt5025_list_voltage, -//#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38)) -// .get_voltage_sel = rt5025_get_voltage_sel, -// .set_voltage_sel = rt5025_set_voltage_sel, -//#else +#if 0 //(LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38)) + .get_voltage_sel = rt5025_get_voltage_sel, + .set_voltage_sel = rt5025_set_voltage_sel, +#else .set_voltage = rt5025_set_voltage, .get_voltage = rt5025_get_voltage, -//#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */ +#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */ .enable = rt5025_enable, .disable = rt5025_disable, .is_enabled = rt5025_is_enabled, - .get_mode = rt5025_dcdc_get_mode, - .set_mode = rt5025_dcdc_set_mode, - .set_voltage_time_sel = rt5025_dcdc_set_voltage_time_sel, + .set_mode = rt5025_set_mode, + .get_mode = rt5025_get_mode, }; #define RT5025_DCDCVOUT_LIST1 rt5025_vol_output_list1 @@ -358,6 +322,8 @@ static struct regulator_ops rt5025_regulator_ops = { .vol_mask = RT5025_DCDCVOUT_MASK##_id, \ .enable_reg = RT5025_DCDC_OUTPUT_EN, \ .enable_bit = RT5025_DCDCEN_MASK##_id, \ + .mode_reg = RT5025_REG_DCDCVRC, \ + .mode_bit = RT5025_DCDCMODE_MASK##_id \ } #define RT5025_LDO(_id, min, max) \ @@ -379,6 +345,8 @@ static struct regulator_ops rt5025_regulator_ops = { .vol_mask = RT5025_LDOVOUT_MASK##_id, \ .enable_reg = RT5025_LDO_OUTPUT_EN, \ .enable_bit = RT5025_LDOEN_MASK##_id, \ + .mode_reg = RT5025_REG_LDOVRC, \ + .mode_bit = RT5025_LDOMODE_MASK##_id, \ } static struct rt5025_regulator_info rt5025_regulator_info[] = diff --git a/include/linux/mfd/rt5025-irq.h b/include/linux/mfd/rt5025-irq.h old mode 100755 new mode 100644 index 96efd61ce45b..2355d8cb0738 --- a/include/linux/mfd/rt5025-irq.h +++ b/include/linux/mfd/rt5025-irq.h @@ -16,9 +16,18 @@ #define RT5025_REG_CHGSTAT 0x01 #define RT5025_REG_IRQEN1 0x30 +#define RT5025_REG_IRQSTATUS1 0x31 #define RT5025_REG_IRQEN2 0x32 +#define RT5025_REG_IRQSTATUS2 0x33 #define RT5025_REG_IRQEN3 0x34 +#define RT5025_REG_IRQSTATUS3 0x35 #define RT5025_REG_IRQEN4 0x36 +#define RT5025_REG_IRQSTATUS4 0x37 #define RT5025_REG_IRQEN5 0x38 +#define RT5025_REG_IRQSTATUS5 0x39 + +#define RT5025_REG_GAUGEIRQFLG 0x51 +#define RT5025_FLG_TEMP 0x30 +#define RT5025_FLG_VOLT 0x07 #endif /* #ifndef __LINUX_RT5025_IRQ_H */ diff --git a/include/linux/mfd/rt5025.h b/include/linux/mfd/rt5025.h old mode 100755 new mode 100644 index e83c60d59b90..d3b790becfa7 --- a/include/linux/mfd/rt5025.h +++ b/include/linux/mfd/rt5025.h @@ -14,6 +14,7 @@ #define __LINUX_MFD_RT5025_H #include +#include #define RT5025_DEVICE_NAME "RT5025" @@ -215,7 +216,6 @@ struct rt5025_power_data { }bitfield; unsigned char val; }CHGControl7; - u32 fcc; }; struct rt5025_gpio_data { @@ -337,6 +337,21 @@ struct rt5025_irq_data { }irq_enable5; }; +enum { + JEITA_NO_CHARGE, + JEITA_NORMAL_USB, + JEITA_USB_TA, + JEITA_AC_ADAPTER, + JEITA_CHARGER_MAX, +}; + +struct rt5025_jeita_data { + int* temp; + u8* temp_scalar; + int (*temp_cc)[5]; + int (*temp_cv)[5]; +}; + #define CHG_EVENT_INACOVP (0x80<<16) #define CHG_EVENT_INAC_PLUGIN (0x40<<16) #define CHG_EVENT_INUSBOVP (0x10<<16) @@ -360,7 +375,9 @@ struct rt5025_irq_data { #define CHARGER_DETECT_MASK (CHG_EVENT_INAC_PLUGIN | CHG_EVENT_INUSB_PLUGIN | \ CHG_EVENT_CHSLPI_INAC | CHG_EVENT_CHSLPI_INUSB | \ - CHG_EVENT_CHBADI_INAC | CHG_EVENT_CHBADI_INUSB) + CHG_EVENT_CHBADI_INAC | CHG_EVENT_CHBADI_INUSB | \ + CHG_EVENT_CHTERMI | CHG_EVENT_CHRCHGI) + #define PWR_EVENT_OTIQ (0x80<<8) #define PWR_EVENT_DCDC1LV (0x40<<8) @@ -374,7 +391,7 @@ struct rt5025_irq_data { #define PWR_EVENT_KPSHDN (0x80<<0) #define PWR_EVNET_PWRONR (0x40<<0) #define PWR_EVENT_PWRONF (0x20<<0) -#define PWR_EVENT_RESETB (0x10<<0) +#define PWR_EVENT_RESETB (0x10<<0) #define PWR_EVENT_GPIO2IE (0x08<<0) #define PWR_EVENT_GPIO1IE (0x04<<0) #define PWR_EVENT_GPIO0IE (0x02<<0) @@ -393,53 +410,209 @@ struct rt5025_event_callback { #endif }; +struct rt5025_platform_data { + struct regulator_init_data* regulator[RT5025_MAX_REGULATOR]; + struct rt5025_power_data* power_data; + struct rt5025_gpio_data* gpio_data; + struct rt5025_misc_data* misc_data; + struct rt5025_irq_data* irq_data; + struct rt5025_jeita_data* jeita_data; + struct rt5025_event_callback *cb; + int (*pre_init)(struct rt5025_chip *rt5025_chip); + /** Called after subdevices are set up */ + int (*post_init)(void); + int intr_pin; +}; + struct rt5025_power_info { struct i2c_client *i2c; struct device *dev; - struct rt5025_gauge_callbacks *event_callback; + struct rt5025_chip *chip; + //struct rt5025_gauge_callbacks *event_callback; struct power_supply ac; struct power_supply usb; struct mutex var_lock; struct delayed_work usb_detect_work; int usb_cnt; - u32 fcc; + int chg_term; unsigned ac_online:1; unsigned usb_online:1; unsigned chg_stat:3; }; +struct rt5025_swjeita_info { + struct i2c_client *i2c; + struct rt5025_chip *chip; + int *temp; + u8 *temp_scalar; + int (*temp_cc)[5]; + int (*temp_cv)[5]; + int cur_section; + int cur_cable; + int cur_temp; + int init_once; + int suspend; +}; + +struct rt5025_battery_info { + struct i2c_client *client; + struct rt5025_chip *chip; + //struct rt5025_gauge_callbacks cb; + + struct power_supply battery; + + struct delayed_work monitor_work; + struct wake_lock monitor_wake_lock; + struct wake_lock low_battery_wake_lock; +//#if RT5025_TEST_WAKE_LOCK + struct wake_lock test_wake_lock; +//#endif + struct alarm wakeup_alarm; + + bool temp_range_0_5; + bool temp_range_5_10; + bool temp_range_10_15; + bool temp_range_15_20; + bool temp_range_20_30; + bool temp_range_30_35; + bool temp_range_35_40; + bool temp_range_40_45; + bool temp_range_45_50; + + bool range_0_5_done; + bool range_5_10_done; + bool range_10_15_done; + bool range_15_20_done; + bool range_20_30_done; + bool range_30_35_done; + bool range_35_40_done; + bool range_40_45_done; + bool range_45_50_done; + + + + bool suspend_poll; + ktime_t last_poll; +// ktime_t last_event; + struct timespec last_event; + + u16 update_time; + + /* previous battery voltage */ + u16 pre_vcell; + /* previous battery current */ + s16 pre_curr; + /* battery voltage */ + u16 vcell; + /* battery current */ + s16 curr; + /* battery current offset */ + u16 curr_offset; + /* AIN voltage */ + u16 ain_volt; + /* battery external temperature */ + s16 ext_temp; + /* charge coulomb counter */ + u32 chg_cc; + u32 chg_cc_unuse; + /* discharge coulomb counter */ + u32 dchg_cc; + u32 dchg_cc_unuse; + /* battery capacity */ + u16 soc; + u16 temp_soc; + u16 pre_soc; + + u16 time_interval; + u16 pre_gauge_timer; + + u8 online; + u8 status; + u8 internal_status; + u8 health; + u8 present; + + /* IRQ flag */ + u8 irq_flag; + + /* max voltage IRQ flag */ + bool max_volt_irq; + /* min voltage1 IRQ flag */ + bool min_volt1_irq; + /* min voltage2 IRQ flag */ + bool min_volt2_irq; + /* max temperature IRQ flag */ + bool max_temp_irq; + /* min temperature IRQ flag */ + bool min_temp_irq; + + bool min_volt2_alert; + + u8 temp_high_cnt; + u8 temp_low_cnt; + u8 temp_recover_cnt; + + bool init_cap; + bool avg_flag; + + /* remain capacity */ + u32 rm; + /* SOC permille */ + u16 permille; + /* full capccity */ + u16 fcc_aging; + u16 fcc; + u16 dc; + s16 tempcmp; + #if 0 + u32 time_to_empty; + u32 time_to_full; + #endif + + bool edv_flag; + bool edv_detection; + u8 edv_cnt; + + bool tp_flag; + u8 tp_cnt; + + u8 cycle_cnt; + u32 acc_dchg_cap; + + bool smooth_flag; + + u16 gauge_timer; + s16 curr_raw; + + bool init_once; + bool device_suspend; + u8 test_temp; +}; + struct rt5025_chip { struct i2c_client *i2c; struct workqueue_struct *wq; struct device *dev; struct rt5025_power_info *power_info; + struct rt5025_swjeita_info *jeita_info; + struct rt5025_battery_info *battery_info; int suspend; int irq; struct delayed_work delayed_work; struct mutex io_lock; }; -struct rt5025_platform_data { - struct regulator_init_data* regulator[RT5025_MAX_REGULATOR]; - struct rt5025_power_data* power_data; - struct rt5025_gpio_data* gpio_data; - struct rt5025_misc_data* misc_data; - struct rt5025_irq_data* irq_data; - struct rt5025_event_callback *cb; - int (*pre_init)(struct rt5025_chip *rt5025_chip); - /** Called after subdevices are set up */ - int (*post_init)(void); - int intr_pin; -}; - #ifdef CONFIG_MFD_RT5025_MISC extern void rt5025_power_off(void); #endif /* CONFIG_MFD_RT5025_MISC */ #ifdef CONFIG_POWER_RT5025 -extern int rt5025_gauge_init(struct rt5025_power_info *); -extern int rt5025_power_passirq_to_gauge(struct rt5025_power_info *); +extern void rt5025_gauge_set_status(struct rt5025_battery_info *, int); +extern void rt5025_gauge_set_online(struct rt5025_battery_info *, bool); +extern void rt5025_gauge_irq_handler(struct rt5025_battery_info *, u8); extern int rt5025_power_charge_detect(struct rt5025_power_info *); +extern int rt5025_notify_charging_cable(struct rt5025_swjeita_info *, int); +extern int rt5025_swjeita_irq_handler(struct rt5025_swjeita_info *, unsigned char); #endif /* CONFIG_POEWR_RT5025 */ extern int rt5025_reg_block_read(struct i2c_client *, int, int, void *); diff --git a/include/linux/power/rockchip-6200ma-bat.h b/include/linux/power/rockchip-6200ma-bat.h new file mode 100755 index 000000000000..8cfc32aafd54 --- /dev/null +++ b/include/linux/power/rockchip-6200ma-bat.h @@ -0,0 +1,26 @@ +battery_graph_prop rt5025_battery_param1[] = +{ + {4190, 1000}, + {4153, 980}, + {4067, 890}, + {3991, 800}, + {3931, 710}, + {3845, 580}, + {3799, 490}, + {3776, 400}, + {3743, 240}, + {3695, 140}, + {3660, 70}, + {3642, 50}, + {3509, 20}, + {3300, 0}, +}; + +battery_graph_prop rt5025_battery_param2[] = +{ + {450,30}, + {250, 0}, + {50,-90}, + {50, 10}, + {3400, 6900}, +}; diff --git a/include/linux/power/rt5025-battery.h b/include/linux/power/rt5025-battery.h new file mode 100755 index 000000000000..cbb92ac32e7d --- /dev/null +++ b/include/linux/power/rt5025-battery.h @@ -0,0 +1,125 @@ +/* + * include/linux/power/rt5025-battery.h + * Include header file for Richtek RT5025 battery Driver + * + * Copyright (C) 2013 Richtek Electronics + * cy_huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_RT5025_BATTERY_H +#define __LINUX_RT5025_BATTERY_H + +#define ROCKCHIP_BATTERY_6200MAH +#undef ROCKCHIP_BATTERY_2100MAH + +#define RT5025_REG_IRQ_CTL 0x50 +#define RT5025_REG_IRQ_FLAG 0x51 +#define RT5025_REG_VALRT_MAXTH 0x53 +#define RT5025_REG_VALRT_MIN1TH 0x54 +#define RT5025_REG_VALRT_MIN2TH 0x55 +#define RT5025_REG_TALRT_MAXTH 0x56 +#define RT5025_REG_TALRT_MINTH 0x57 +#define RT5025_REG_VCELL_MSB 0x58 +#define RT5025_REG_VCELL_LSB 0x59 +#define RT5025_REG_INT_TEMPERATUE_MSB 0x5B +#define RT5025_REG_INT_TEMPERATUE_LSB 0x5C +#define RT5025_REG_EXT_TEMPERATUE_MSB 0x5E +#define RT5025_REG_EXT_TEMPERATUE_LSB 0x5F +#define RT5025_REG_TIMER 0x60 +#define RT5025_REG_CHANNEL_MSB 0x62 +#define RT5025_REG_CHANNEL_LSB 0x63 +#define RT5025_REG_CURRENT_MSB 0x76 +#define RT5025_REG_CURRENT_LSB 0x77 +#define RT5025_REG_QCHGH_MSB 0x78 +#define RT5025_REG_QCHGH_LSB 0x79 +#define RT5025_REG_QCHGL_MSB 0x7A +#define RT5025_REG_QCHGL_LSB 0x7B +#define RT5025_REG_QDCHGH_MSB 0x7C +#define RT5025_REG_QDCHGH_LSB 0x7D +#define RT5025_REG_QDCHGL_MSB 0x7E +#define RT5025_REG_QDCHGL_LSB 0x7F + +#define IRQ_CTL_BIT_TMX (1 << 5) +#define IRQ_CTL_BIT_TMN (1 << 4) +#define IRQ_CTL_BIT_VMX (1 << 2) +#define IRQ_CTL_BIT_VMN1 (1 << 1) +#define IRQ_CTL_BIT_VMN2 (1 << 0) + +#define IRQ_FLG_BIT_TMX (1 << 5) +#define IRQ_FLG_BIT_TMN (1 << 4) +#define IRQ_FLG_BIT_VMX (1 << 2) +#define IRQ_FLG_BIT_VMN1 (1 << 1) +#define IRQ_FLG_BIT_VMN2 (1 << 0) + +#define CHANNEL_H_BIT_CLRQDCHG (1 << 7) +#define CHANNEL_H_BIT_CLRQCHG (1 << 6) + +#define CHANNEL_L_BIT_CADC_EN (1 << 7) +#define CHANNEL_L_BIT_INTEMPCH (1 << 6) +#define CHANNEL_L_BIT_AINCH (1 << 2) +#define CHANNEL_L_BIT_VBATSCH (1 << 1) +#define CHANNEL_L_BIT_VADC_EN (1 << 0) + +#define NORMAL_POLL 30 /* 30 sec */ +#define TP_POLL 5 /* 5 sec */ +#define EDV_POLL 1 /* 1 sec */ +#define SMOOTH_POLL 5 /* 5 sec */ +#define SUSPEND_POLL (30*60) /* 30 min */ +#define INIT_POLL 1 +#define LOW_BAT_WAKE_LOK_TIME 120 + +#define HIGH_TEMP_THRES 650 +#define HIGH_TEMP_RECOVER 430 +#define LOW_TEMP_THRES (-30) +#define LOW_TEMP_RECOVER 0 +#define TEMP_ABNORMAL_COUNT 3 + +#define EDV_HYS 100 +#define IRQ_THRES_UNIT 1953 + +#define TALRTMAX_VALUE 0x38 //65.39'C +#define TALRTMIN_VALUE 0x9 //-18.75'C +#define TRLS_VALUE 55 //5'C ; unit:mV +#define VRLS_VALUE 100 //100mV + + +#define DEADBAND 10 + +//#define SLEEP_CURRENT 3 //mA + +typedef enum{ + CHG, + DCHG +}operation_mode; + +typedef struct{ + int x; + int y; +}battery_graph_prop; + +typedef enum { + MAXTEMP, + MINTEMP, + MAXVOLT, + MINVOLT1, + MINVOLT2, + TEMP_RLS, + VOLT_RLS, + LAST_TYPE, +}alert_type; + +#if defined(ROCKCHIP_BATTERY_6200MAH) +#include +#elif defined(ROCKCHIP_BATTERY_2100MAH) +#include +#else +#include +#endif + +#define VALRTMIN2_VALUE (rt5025_battery_param2[4].x * 100 / IRQ_THRES_UNIT + 1) //EDV0 voltage + +#endif /* #ifndef __LINUX_RT5025_BATTERY_H */ diff --git a/include/linux/power/rt5025-gauge.h b/include/linux/power/rt5025-gauge.h deleted file mode 100755 index 4ca38cbfa6a1..000000000000 --- a/include/linux/power/rt5025-gauge.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * rt5025_gauge.h - * fuel-gauge driver - * revision 0.1 - */ - -#ifndef __LINUX_RT5025_GAUGE_H_ -#define __LINUX_RT5025_GAUGE_H_ - -#define GPIO_GAUGE_ALERT 4 - -struct rt5025_gauge_callbacks { - void (*rt5025_gauge_irq_handler)(void); - void (*rt5025_gauge_set_status)(int status); - void (*rt5025_gauge_suspend)(void); - void (*rt5025_gauge_resume)(void); - void (*rt5025_gauge_remove)(void); -}; - - -typedef enum{ - CHG, - DCHG -}operation_mode; - -typedef enum{ - MAXTEMP, - MINTEMP, - MAXVOLT, - MINVOLT1, - MINVOLT2, - TEMP_RLS, - VOLT_RLS, - LAST_TYPE -}alert_type; - -#endif /* #ifndef __LINUX_RT5025_GAUGE_H_ */ diff --git a/include/linux/power/rt5025-power.h b/include/linux/power/rt5025-power.h index 3f700c6bbf66..0f6d2470e2dc 100755 --- a/include/linux/power/rt5025-power.h +++ b/include/linux/power/rt5025-power.h @@ -25,7 +25,7 @@ #define RT5025_CHGBUCKEN_MASK 0x02 #define RT5025_CHGCEN_MASK 0x10 -#define RT5025_CHGCC_MASK 0x7E +#define RT5025_CHGAICR_MASK 0x06 #define RT5025_CHGSTAT_MASK 0x30 #define RT5025_CHGSTAT_SHIFT 4 diff --git a/include/linux/power/rt5025-swjeita.h b/include/linux/power/rt5025-swjeita.h new file mode 100755 index 000000000000..e2e432cf9d8e --- /dev/null +++ b/include/linux/power/rt5025-swjeita.h @@ -0,0 +1,35 @@ +/* + * include/linux/power/rt5025-swjeita.h + * Include header file for Richtek RT5025 Core Jeita Driver + * + * Copyright (C) 2013 Richtek Electronics + * cy_huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_RT5025_SWJEITA_H +#define __LINUX_RT5025_SWJEITA_H + +#define RT5025_REG_CHGCTL3 0x03 +#define RT5025_REG_CHGCTL4 0x04 +#define RT5025_REG_CHGCTL7 0x07 +#define RT5025_REG_AINH 0x5E +#define RT5025_REG_CHANNELL 0x63 +#define RT5025_REG_IRQCTL 0x50 +#define RT5025_REG_TALRTMAX 0x56 +#define RT5025_REG_TALRTMIN 0x57 + +#define RT5025_CHGCCEN_MASK 0x10 +#define RT5025_CHGICC_SHIFT 3 +#define RT5025_CHGICC_MASK 0x78 +#define RT5025_CHGCV_SHIFT 2 +#define RT5025_CHGCV_MASK 0xFC +#define RT5025_AINEN_MASK 0x04 +#define RT5025_TMXEN_MASK 0x20 +#define RT5025_TMNEN_MASK 0x10 + + +#endif /* #ifndef __LINUX_RT5025_SWJEITA_H */ diff --git a/include/linux/regulator/rt5025-regulator.h b/include/linux/regulator/rt5025-regulator.h old mode 100755 new mode 100644 index 317e3f6a1dc8..f9467830ef11 --- a/include/linux/regulator/rt5025-regulator.h +++ b/include/linux/regulator/rt5025-regulator.h @@ -25,6 +25,8 @@ #define RT5025_REG_LDOCTRL6 0x12 #define RT5025_REG_DCDCEN 0x17 #define RT5025_REG_LDOEN 0x18 +#define RT5025_REG_DCDCVRC 0x0B +#define RT5025_REG_LDOVRC 0x00 #define RT5025_DCDCVOUT1 RT5025_REG_DCDCCTRL1 #define RT5025_DCDCVOUT2 RT5025_REG_DCDCCTRL2 @@ -73,4 +75,15 @@ #define RT5025_LDOEN_MASK5 0x10 #define RT5025_LDOEN_MASK6 0x20 +#define RT5025_DCDCMODE_MASK1 0x40 +#define RT5025_DCDCMODE_MASK2 0x20 +#define RT5025_DCDCMODE_MASK3 0x10 +#define RT5025_DCDCMODE_MASK4 0x00 +#define RT5025_LDOMODE_MASK1 0x00 +#define RT5025_LDOMODE_MASK2 0x00 +#define RT5025_LDOMODE_MASK3 0x00 +#define RT5025_LDOMODE_MASK4 0x00 +#define RT5025_LDOMODE_MASK5 0x00 +#define RT5025_LDOMODE_MASK6 0x00 + #endif /* __LINUX_RT5025_REGULATOR_H */ -- 2.34.1