From: 张晴 Date: Tue, 23 Jul 2013 03:04:22 +0000 (+0800) Subject: rk3188:pmu:rt5025:modify some bug for pmu charger & irq & guage X-Git-Tag: firefly_0821_release~6857^2~2 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=8f3906c52e28b9804d08fbdeb2c81e116c81585c;p=firefly-linux-kernel-4.4.55.git rk3188:pmu:rt5025:modify some bug for pmu charger & irq & guage --- diff --git a/arch/arm/mach-rk30/board-pmu-rt5025.c b/arch/arm/mach-rk30/board-pmu-rt5025.c old mode 100755 new mode 100644 index f0f0fc567118..4cb462ba3002 --- a/arch/arm/mach-rk30/board-pmu-rt5025.c +++ b/arch/arm/mach-rk30/board-pmu-rt5025.c @@ -37,10 +37,6 @@ static int rt5025_pre_init(struct rt5025_chip *rt5025_chip){ ret |= (1<<3); //enable DC4 boost rt5025_reg_write(rt5025_chip->i2c, 0x17,ret); /***********************************************/ - ret = rt5025_reg_read(rt5025_chip->i2c, 0x07); - ret |= (1<<5); // - rt5025_reg_write(rt5025_chip->i2c, 0x07,ret); - /************************************************/ return 0; } @@ -283,13 +279,14 @@ static struct rt5025_power_data rt5025_power_data = { }, .CHGControl4 = { .bitfield = { + .AICR_CON = 1, .AICR = RT5025_AICR_500MA, - .ICC = RT5025_ICC_1P8A, + .ICC = RT5025_ICC_0P5A, }, }, .CHGControl5 = { .bitfield = { - .DPM = RT5025_DPM_DIS, + .DPM = RT5025_DPM_4P5V, }, }, .CHGControl6 = { @@ -302,10 +299,11 @@ static struct rt5025_power_data rt5025_power_data = { .CHGControl7 = { .bitfield = { .CHGC_EN = 1, - .CHG_DCDC_MODE = 1, + .CHG_DCDC_MODE = 0, .BATD_EN = 0, }, }, + .fcc = 6200, //6200 mAh }; static struct rt5025_gpio_data rt5025_gpio_data = { @@ -323,7 +321,7 @@ static struct rt5025_misc_data rt5025_misc_data = { }, .VSYSCtrl = { .bitfield = { - .VOFF = RT5025_VOFF_3P1V, + .VOFF = RT5025_VOFF_3P4V, }, }, .PwrOnCfg = { @@ -386,7 +384,7 @@ static struct rt5025_irq_data rt5025_irq_data = { }, .irq_enable4 = { .bitfield = { - .SYSLV = 0, + .SYSLV = 1, .DCDC4LVHV = 1, .PWRONLP = 0, .PWRONSP = 0, @@ -412,11 +410,19 @@ static struct rt5025_irq_data rt5025_irq_data = { static void rt5025_charger_event_callback(uint32_t detected) { RTINFO("event detected = 0x%08x\n", detected); + if (detected & CHG_EVENT_CHTERMI) + { + pr_info("charger termination OK\n"); + } } static void rt5025_power_event_callback(uint32_t detected) { RTINFO("event detected = 0x%08x\n", detected); + if (detected & PWR_EVENT_SYSLV) + { + pr_info("sys voltage low\n"); + } } static struct rt5025_event_callback rt5025_event_callback = { diff --git a/arch/arm/mach-rk30/board-rk3168-tb.c b/arch/arm/mach-rk30/board-rk3168-tb.c old mode 100755 new mode 100644 index 2d2e39232f8b..79dd15fa761d --- a/arch/arm/mach-rk30/board-rk3168-tb.c +++ b/arch/arm/mach-rk30/board-rk3168-tb.c @@ -2118,8 +2118,8 @@ static struct pmu_info rt5025_ldo_info[] = { }, { .name = "rt5025-ldo3", //vdd10 - .min_uv = 1200000, - .max_uv = 1200000, + .min_uv = 1000000, + .max_uv = 1000000, }, { .name = "rt5025-ldo4", //vccjetta diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index cb39666a85b3..a384a7beb57c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -865,6 +865,12 @@ config MFD_RT5025_DEBUG help Enable RT5025 core debug driver. +config MFD_RT_SHOW_INFO + bool "RT5025 debug message" + depends on MFD_RT5025 + default n + help + Eneable RT5025 debug message config MFD_RK610 bool "RK610(Jetta) Multimedia support" diff --git a/drivers/mfd/rt5025-core.c b/drivers/mfd/rt5025-core.c old mode 100755 new mode 100644 index 51e59e1687c7..164f193cc694 --- a/drivers/mfd/rt5025-core.c +++ b/drivers/mfd/rt5025-core.c @@ -193,7 +193,7 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ } } #endif /* CONFIG_MFD_RT5025_IRQ */ -#if 0 +#if 1 #ifdef CONFIG_MFD_RT5025_DEBUG RTINFO("mfd add debug dev\n"); printk("%s,line=%d\n", __func__,__LINE__); @@ -219,7 +219,7 @@ out_dev: mfd_remove_devices(chip->dev); return ret; } -subsys_initcall_sync(rt5025_core_init); +EXPORT_SYMBOL(rt5025_core_init); int __devexit rt5025_core_deinit(struct rt5025_chip *chip) { diff --git a/drivers/mfd/rt5025-debug.c b/drivers/mfd/rt5025-debug.c old mode 100755 new mode 100644 index bec09d68c25f..71dce8ad7f9f --- a/drivers/mfd/rt5025-debug.c +++ b/drivers/mfd/rt5025-debug.c @@ -177,7 +177,7 @@ static int __init rt5025_debug_init(void) { return platform_driver_register(&rt5025_debug_driver); } -subsys_initcall_sync(rt5025_debug_init); +module_init(rt5025_debug_init); static void __exit rt5025_debug_exit(void) { diff --git a/drivers/mfd/rt5025-i2c.c b/drivers/mfd/rt5025-i2c.c old mode 100755 new mode 100644 index 29961de04e7b..b44a20dc1689 --- a/drivers/mfd/rt5025-i2c.c +++ b/drivers/mfd/rt5025-i2c.c @@ -16,9 +16,27 @@ #include #include +#define ROCKCHIP_I2C_RATE (200*1000) + static inline int rt5025_read_device(struct i2c_client *i2c, int reg, int bytes, void *dest) { + #if 1 + int ret; + unsigned char reg_addr = reg; + struct i2c_msg i2c_msg[2]; + i2c_msg[0].addr = i2c->addr; + i2c_msg[0].flags = i2c->flags; + i2c_msg[0].len = 1; + i2c_msg[0].buf = ®_addr; + i2c_msg[0].scl_rate = ROCKCHIP_I2C_RATE; + i2c_msg[1].addr = i2c->addr; + i2c_msg[1].flags = i2c->flags | I2C_M_RD; + i2c_msg[1].len = bytes; + i2c_msg[1].buf = dest; + i2c_msg[1].scl_rate = ROCKCHIP_I2C_RATE; + ret = i2c_transfer(i2c->adapter, i2c_msg, 2); + #else int ret; if (bytes > 1) ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest); @@ -28,7 +46,7 @@ static inline int rt5025_read_device(struct i2c_client *i2c, return ret; *(unsigned char *)dest = (unsigned char)ret; } - + #endif return ret; } @@ -38,17 +56,75 @@ int rt5025_reg_block_read(struct i2c_client *i2c, \ return rt5025_read_device(i2c, reg, bytes, dest); } EXPORT_SYMBOL(rt5025_reg_block_read); -#if 0 + +static inline int rt5025_write_device(struct i2c_client *i2c, + int reg, int bytes, void *dest) +{ + #if 1 + int ret; + struct i2c_msg i2c_msg; + char *tx_buf = (char*)kmalloc(bytes+1, GFP_KERNEL); + tx_buf[0] = reg; + memcpy(tx_buf+1, dest, bytes); + i2c_msg.addr = i2c->addr; + i2c_msg.flags = i2c->flags; + i2c_msg.len = bytes + 1; + i2c_msg.buf = tx_buf; + i2c_msg.scl_rate = ROCKCHIP_I2C_RATE; + ret = i2c_transfer(i2c->adapter, &i2c_msg, 1); + kfree(tx_buf); + #else + int ret; + if (bytes > 1) + ret = i2c_smbus_write_i2c_block_data(i2c, reg, bytes, dest); + else { + ret = i2c_smbus_write_byte_data(i2c, reg, dest); + if (ret < 0) + return ret; + *(unsigned char *)dest = (unsigned char)ret; + } + #endif + return ret; +} + +int rt5025_reg_block_write(struct i2c_client *i2c, \ + int reg, int bytes, void *dest) +{ + return rt5025_write_device(i2c, reg, bytes, dest); +} +EXPORT_SYMBOL(rt5025_reg_block_write); + int rt5025_reg_read(struct i2c_client *i2c, int reg) { struct rt5025_chip* chip = i2c_get_clientdata(i2c); int ret; + #if 1 + unsigned char reg_addr = reg; + unsigned char reg_data = 0; + struct i2c_msg i2c_msg[2]; + RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n", + (unsigned int)i2c,(unsigned int)reg); + mutex_lock(&chip->io_lock); + i2c_msg[0].addr = i2c->addr; + i2c_msg[0].flags = i2c->flags; + i2c_msg[0].len = 1; + i2c_msg[0].buf = ®_addr; + i2c_msg[0].scl_rate = ROCKCHIP_I2C_RATE; + i2c_msg[1].addr = i2c->addr; + i2c_msg[1].flags = i2c->flags | I2C_M_RD; + i2c_msg[1].len = 1; + i2c_msg[1].buf = ®_data; + i2c_msg[1].scl_rate = ROCKCHIP_I2C_RATE; + ret = i2c_transfer(i2c->adapter, i2c_msg, 2); + mutex_unlock(&chip->io_lock); + #else RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n", (unsigned int)i2c,(unsigned int)reg); mutex_lock(&chip->io_lock); ret = i2c_smbus_read_byte_data(i2c, reg); mutex_unlock(&chip->io_lock); - return ret; + #endif + return reg_data; } EXPORT_SYMBOL(rt5025_reg_read); @@ -56,88 +132,58 @@ int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { struct rt5025_chip* chip = i2c_get_clientdata(i2c); int ret; - printk("%s,line=%d\n", __func__,__LINE__); - -// RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n", - // (unsigned int)i2c,(unsigned int)reg,(unsigned int)data); + #if 1 + unsigned char xfer_data[2]; + struct i2c_msg i2c_msg; + RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n", + (unsigned int)i2c,(unsigned int)reg,(unsigned int)data); + xfer_data[0] = reg; + xfer_data[1] = data; + mutex_lock(&chip->io_lock); + i2c_msg.addr = i2c->addr; + i2c_msg.flags = i2c->flags; + i2c_msg.len = 2; + i2c_msg.buf = xfer_data; + i2c_msg.scl_rate = ROCKCHIP_I2C_RATE; + ret = i2c_transfer(i2c->adapter, &i2c_msg, 1); + mutex_unlock(&chip->io_lock); + #else + RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n", + (unsigned int)i2c,(unsigned int)reg,(unsigned int)data); mutex_lock(&chip->io_lock); -printk("%s,line=%d \n", __func__,__LINE__); - ret = i2c_smbus_write_byte_data(i2c, reg, data); mutex_unlock(&chip->io_lock); - printk("%s,line=%d %d \n", __func__,__LINE__,ret); + #endif return ret; } EXPORT_SYMBOL(rt5025_reg_write); -#else -int rt5025_reg_read(struct i2c_client *i2c, int reg) -{ - struct i2c_adapter *adap; - struct i2c_msg msgs[2]; - int ret; - unsigned char *dest; - u8 val; - - dest = &val; - - if(!i2c) - return ret; - - adap = i2c->adapter; - - msgs[0].addr = i2c->addr; - msgs[0].buf = ® - msgs[0].flags = i2c->flags; - msgs[0].len = 1; - msgs[0].scl_rate = 200*1000; - - msgs[1].buf = dest; - msgs[1].addr = i2c->addr; - msgs[1].flags = i2c->flags | I2C_M_RD; - msgs[1].len = 1; - msgs[1].scl_rate = 200*1000; - ret = i2c_transfer(adap, msgs, 2); - -// printk("***run in %s %d msgs[1].buf = %d\n",__FUNCTION__,__LINE__,*(msgs[1].buf)); - - return val; -} -EXPORT_SYMBOL(rt5025_reg_read); -int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data) -{ - - int ret=-1; - - struct i2c_adapter *adap; - struct i2c_msg msg; - char tx_buf[2]; - - if(!i2c) - return ret; - - adap = i2c->adapter; - tx_buf[0] = reg; - tx_buf[1] = data; - - msg.addr = i2c->addr; - msg.buf = &tx_buf[0]; - msg.len = 1 +1; - msg.flags = i2c->flags; - msg.scl_rate = 200*1000; - - ret = i2c_transfer(adap, &msg, 1); - return ret; -} -EXPORT_SYMBOL(rt5025_reg_write); -#endif int rt5025_assign_bits(struct i2c_client *i2c, int reg, unsigned char mask, unsigned char data) { struct rt5025_chip *chip = i2c_get_clientdata(i2c); unsigned char value; int ret; + #if 1 + struct i2c_msg i2c_msg; + u8 xfer_data[2] = {0}; + mutex_lock(&chip->io_lock); + ret = rt5025_read_device(i2c, reg, 1, &value); + if (ret < 0) + goto out; + + value &= ~mask; + value |= (data&mask); + xfer_data[0] = reg; + xfer_data[1] = value; + i2c_msg.addr = i2c->addr; + i2c_msg.flags = i2c->flags; + i2c_msg.len = 2; + i2c_msg.buf = xfer_data; + i2c_msg.scl_rate = ROCKCHIP_I2C_RATE; + ret = i2c_transfer(i2c->adapter, &i2c_msg, 1); + #else mutex_lock(&chip->io_lock); ret = rt5025_read_device(i2c, reg, 1, &value); @@ -146,7 +192,8 @@ int rt5025_assign_bits(struct i2c_client *i2c, int reg, goto out; value &= ~mask; value |= (data&mask); - ret = rt5025_reg_write(i2c,reg,value); + ret = i2c_smbus_write_byte_data(i2c,reg,value); + #endif out: mutex_unlock(&chip->io_lock); return ret; @@ -198,8 +245,8 @@ static int __devinit rt5025_i2c_probe(struct i2c_client *client, const struct i2 rt5025_read_device(client,0x00,1,&val); if (val != 0x81){ - printk("The PMIC is not RT5025\n"); - return 0; + printk("The PMIC is not RT5025\n"); + return -ENODEV; } ret = rt5025_core_init(chip, pdata); if (ret < 0) @@ -231,7 +278,7 @@ static int __devexit rt5025_i2c_remove(struct i2c_client *client) rt5025_core_deinit(chip); #if 0 if (chip->event_callback) - kfree(chip->event_callback);a + kfree(chip->event_callback); #endif kfree(chip); return 0; diff --git a/drivers/mfd/rt5025-irq.c b/drivers/mfd/rt5025-irq.c old mode 100755 new mode 100644 index 82535e9f2b01..1c1198705c1d --- a/drivers/mfd/rt5025-irq.c +++ b/drivers/mfd/rt5025-irq.c @@ -43,8 +43,21 @@ static void rt5025_work_func(struct work_struct *work) unsigned char irq_stat[10] = {0}; uint32_t chg_event = 0, pwr_event = 0; - if (rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 10, irq_stat) >= 0) + #ifdef CONFIG_POWER_RT5025 + if (!ii->chip->power_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) + { + 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]); RTINFO("stat value = %02x\n", rt5025_reg_read(ii->i2c, RT5025_REG_CHGSTAT)); @@ -63,33 +76,37 @@ static void rt5025_work_func(struct work_struct *work) 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); #endif /* CONFIG_POWER_RT5025 */ - enable_irq(ii->irq); + //enable_irq(ii->irq); } static irqreturn_t rt5025_interrupt(int irqno, void *param) { struct rt5025_irq_info *ii = (struct rt5025_irq_info *)param; - disable_irq_nosync(ii->irq); + //disable_irq_nosync(ii->irq); queue_delayed_work(ii->wq, &ii->delayed_work, 0); return IRQ_HANDLED; } static int __devinit rt5025_interrupt_init(struct rt5025_irq_info* ii) { - int ret; + int ret = 0; RTINFO("\n"); ii->wq = create_workqueue("rt5025_wq"); INIT_DELAYED_WORK(&ii->delayed_work, rt5025_work_func); + #if 0 if (gpio_is_valid(ii->intr_pin)) { ret = gpio_request(ii->intr_pin, "rt5025_interrupt"); @@ -99,6 +116,7 @@ static int __devinit rt5025_interrupt_init(struct rt5025_irq_info* ii) ret = gpio_direction_input(ii->intr_pin); if (ret) return ret; + #endif if (request_irq(ii->irq, rt5025_interrupt, IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED, "RT5025_IRQ", ii)) { @@ -106,17 +124,20 @@ static int __devinit rt5025_interrupt_init(struct rt5025_irq_info* ii) return -EINVAL; } enable_irq_wake(ii->irq); + queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(100)); + #if 0 if (!gpio_get_value(ii->intr_pin)) { - disable_irq_nosync(ii->irq); + //disable_irq_nosync(ii->irq); queue_delayed_work(ii->wq, &ii->delayed_work, 0); } } else return -EINVAL; + #endif - return 0; + return ret; } static void __devexit rt5025_interrupt_deinit(struct rt5025_irq_info* ii) @@ -160,7 +181,7 @@ static int __devinit rt5025_irq_probe(struct platform_device *pdev) ii->dev = &pdev->dev; ii->chip = chip; ii->intr_pin = pdata->intr_pin; - ii->irq = gpio_to_irq(pdata->intr_pin); + ii->irq = chip->irq;//gpio_to_irq(pdata->intr_pin); if (pdata->cb) ii->event_cb = pdata->cb; diff --git a/drivers/power/rt5025-gauge.c b/drivers/power/rt5025-gauge.c old mode 100755 new mode 100644 index 34d181e1718a..e4dd00dfb724 --- a/drivers/power/rt5025-gauge.c +++ b/drivers/power/rt5025-gauge.c @@ -116,11 +116,23 @@ struct rt5025_gauge_chip { /* 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; @@ -147,6 +159,9 @@ struct rt5025_gauge_chip { 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]; @@ -155,13 +170,95 @@ 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; @@ -173,37 +270,46 @@ static int rt5025_read_reg(struct i2c_client *client, 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) + 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; + 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); } @@ -371,13 +477,26 @@ static void rt5025_get_chg_cc(struct i2c_client *client) } 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){ @@ -386,18 +505,28 @@ static void rt5025_get_chg_cc(struct i2c_client *client) }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); } @@ -413,13 +542,26 @@ static void rt5025_get_dchg_cc(struct i2c_client *client) } 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){ @@ -428,18 +570,28 @@ static void rt5025_get_dchg_cc(struct i2c_client *client) }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); } @@ -475,9 +627,95 @@ static void rt5025_get_timer(struct i2c_client *client) 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) { - chip->soc = 50; + //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) @@ -775,7 +1013,13 @@ int rt5025_gauge_init(struct rt5025_power_info *info) 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; @@ -798,6 +1042,7 @@ int rt5025_gauge_init(struct rt5025_power_info *info) "rt-battery-monitor"); /* enable channel */ rt5025_register_init(info->i2c); + rt5025_gauge_init_soc(info->i2c); /* enable gauge IRQ */ rt5025_alert_init(info->i2c); diff --git a/drivers/power/rt5025-power.c b/drivers/power/rt5025-power.c old mode 100755 new mode 100644 index d37232f9abc3..b99a79d32fc7 --- a/drivers/power/rt5025-power.c +++ b/drivers/power/rt5025-power.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ static char *rt5025_supply_list[] = { "rt5025-battery", }; +#if 0 static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff) { int ret; @@ -52,6 +54,34 @@ static int rt5025_set_charging_buck(struct i2c_client *i2c, int onoff) ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL2, RT5025_CHGBUCKEN_MASK); return ret; } +#endif + +static int rt5025_set_charging_current(struct i2c_client *i2c, int cur_value) +{ + int ret = 0; + u8 data = 0; + + //ICC Setting + if (cur_value > 2000) + data |= 0x0f<<3; + else if (cur_value >= 500 && cur_value <= 2000) + { + data = (cur_value-500)/100; + data<<=3; + } + + + //AICR Setting + if (cur_value > 1000) + data |= 0x03<<1; + else if (cur_value > 500 && cur_value <= 1000) + data |= 0x02<<1; + else if (cur_value > 100 && cur_value >= 500) + data |= 0x01<<1; + + rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGCC_MASK, data); + return ret; +} static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_val) { @@ -59,8 +89,10 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v switch (new_val) { case 0x00: + #if 0 rt5025_set_charging_current_switch(info->i2c, 1); rt5025_set_charging_buck(info->i2c, 1); + #endif info->chg_stat = 0x00; if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING); @@ -72,14 +104,18 @@ static int rt5025_chgstat_changed(struct rt5025_power_info *info, unsigned new_v info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_CHARGING); break; case 0x02: + #if 0 rt5025_set_charging_current_switch(info->i2c, 0); + #endif info->chg_stat = 0x02; if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_FULL); break; case 0x03: + #if 0 rt5025_set_charging_buck(info->i2c, 0); rt5025_set_charging_current_switch(info->i2c, 0); + #endif info->chg_stat = 0x03; if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_DISCHARGING); @@ -129,6 +165,9 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info) power_supply_changed(&info->usb); } + if (old_acval != new_acval || old_usbval != new_usbval) + schedule_delayed_work(&info->usb_detect_work, 0); //no delay + new_chgval = (chgstatval&RT5025_CHGSTAT_MASK)>>RT5025_CHGSTAT_SHIFT; if (new_acval || new_usbval) { @@ -139,8 +178,10 @@ int rt5025_power_charge_detect(struct rt5025_power_info *info) } else { + #if 0 rt5025_set_charging_buck(info->i2c, 0); rt5025_set_charging_current_switch(info->i2c, 0); + #endif info->chg_stat = RT5025_CHGSTAT_UNKNOWN; if (info->event_callback) info->event_callback->rt5025_gauge_set_status(POWER_SUPPLY_STATUS_NOT_CHARGING); @@ -171,8 +212,54 @@ 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); + struct rt5025_power_info *pi = (struct rt5025_power_info *)container_of(delayed_work, struct rt5025_power_info, usb_detect_work); + + pr_info("rt5025: %s ++", __func__); + + mutex_lock(&pi->var_lock); + if (pi->ac_online) + { + rt5025_set_charging_current(pi->i2c, 1000); + pi->usb_cnt = 0; + } + else if (pi->usb_online) + { + pr_info("%s: usb_cnt %d\n", __func__, pi->usb_cnt); + switch(dwc_vbus_status()) + { + case 2: // USB Wall charger + rt5025_set_charging_current(pi->i2c, 1000); + pr_info("rt5025: detect usb wall charger\n"); + break; + case 1: //normal USB + default: + rt5025_set_charging_current(pi->i2c, 500); + pr_info("rt5025: detect normal usb\n"); + break; + } + if (pi->usb_cnt++ < 60) + schedule_delayed_work(&pi->usb_detect_work, 1*HZ); + } + else + { + //default to prevent over current charging + rt5025_set_charging_current(pi->i2c, 500); + //reset usb_cnt; + pi->usb_cnt = 0; + } + mutex_unlock(&pi->var_lock); + + pr_info("rt5025: %s --", __func__); +} + 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 @@ -191,6 +278,7 @@ static int __devinit rt5025_init_charger(struct rt5025_power_info *info, struct rt5025_power_charge_detect(info); + RTINFO("--\n"); return 0; } @@ -208,6 +296,9 @@ static int __devinit rt5025_power_probe(struct platform_device *pdev) pi->i2c = chip->i2c; pi->dev = &pdev->dev; + pi->fcc = pdata->power_data->fcc; + mutex_init(&pi->var_lock); + INIT_DELAYED_WORK(&pi->usb_detect_work, usb_detect_work_func); ret = rt5025_gauge_init(pi); if (ret) diff --git a/include/linux/mfd/rt5025.h b/include/linux/mfd/rt5025.h index 77e76a43ff9f..e83c60d59b90 100755 --- a/include/linux/mfd/rt5025.h +++ b/include/linux/mfd/rt5025.h @@ -181,7 +181,7 @@ struct rt5025_power_data { }CHGControl3; union { struct { - unsigned char Resv:1; + unsigned char AICR_CON:1; unsigned char AICR:2; unsigned char ICC:4; unsigned char CHG_RST:1; @@ -215,6 +215,7 @@ struct rt5025_power_data { }bitfield; unsigned char val; }CHGControl7; + u32 fcc; }; struct rt5025_gpio_data { @@ -398,6 +399,10 @@ struct rt5025_power_info { 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; unsigned ac_online:1; unsigned usb_online:1; unsigned chg_stat:3; @@ -438,6 +443,7 @@ extern int rt5025_power_charge_detect(struct rt5025_power_info *); #endif /* CONFIG_POEWR_RT5025 */ extern int rt5025_reg_block_read(struct i2c_client *, int, int, void *); +extern int rt5025_reg_block_write(struct i2c_client *, int, int, void *); extern int rt5025_reg_read(struct i2c_client *, int); extern int rt5025_reg_write(struct i2c_client *, int, unsigned char); extern int rt5025_assign_bits(struct i2c_client *, int, unsigned char, unsigned char); diff --git a/include/linux/power/rt5025-power.h b/include/linux/power/rt5025-power.h index 1700ec7415d6..3f700c6bbf66 100755 --- a/include/linux/power/rt5025-power.h +++ b/include/linux/power/rt5025-power.h @@ -25,6 +25,7 @@ #define RT5025_CHGBUCKEN_MASK 0x02 #define RT5025_CHGCEN_MASK 0x10 +#define RT5025_CHGCC_MASK 0x7E #define RT5025_CHGSTAT_MASK 0x30 #define RT5025_CHGSTAT_SHIFT 4