rk3188:pmu:rt5025:modify some bug for pmu charger & irq & guage
author张晴 <zhangqing@rock-chips.com>
Tue, 23 Jul 2013 03:04:22 +0000 (11:04 +0800)
committer张晴 <zhangqing@rock-chips.com>
Tue, 23 Jul 2013 03:04:22 +0000 (11:04 +0800)
arch/arm/mach-rk30/board-pmu-rt5025.c [changed mode: 0755->0644]
arch/arm/mach-rk30/board-rk3168-tb.c [changed mode: 0755->0644]
drivers/mfd/Kconfig
drivers/mfd/rt5025-core.c [changed mode: 0755->0644]
drivers/mfd/rt5025-debug.c [changed mode: 0755->0644]
drivers/mfd/rt5025-i2c.c [changed mode: 0755->0644]
drivers/mfd/rt5025-irq.c [changed mode: 0755->0644]
drivers/power/rt5025-gauge.c [changed mode: 0755->0644]
drivers/power/rt5025-power.c [changed mode: 0755->0644]
include/linux/mfd/rt5025.h
include/linux/power/rt5025-power.h

old mode 100755 (executable)
new mode 100644 (file)
index f0f0fc5..4cb462b
@@ -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 = {
old mode 100755 (executable)
new mode 100644 (file)
index 2d2e392..79dd15f
@@ -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
index cb39666a85b342d1cf811420f7a425e4cb3e053c..a384a7beb57cd88eedc9e683650385b78851e888 100644 (file)
@@ -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"
old mode 100755 (executable)
new mode 100644 (file)
index 51e59e1..164f193
@@ -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)
 {
old mode 100755 (executable)
new mode 100644 (file)
index bec09d6..71dce8a
@@ -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)
 {
old mode 100755 (executable)
new mode 100644 (file)
index 29961de..b44a20d
 #include <linux/slab.h>
 #include <linux/mfd/rt5025.h>
 
+#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 = &reg_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 = &reg_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 = &reg_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 = &reg;
-    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;
old mode 100755 (executable)
new mode 100644 (file)
index 82535e9..1c11987
@@ -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;
 
old mode 100755 (executable)
new mode 100644 (file)
index 34d181e..e4dd00d
@@ -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; i++)
+       {
+               if (x<=*(pX+i))
+                       break;
+       }
+       #if 0 // for linear interpolation
+       #else
+       if (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)
+       chartx_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);
old mode 100755 (executable)
new mode 100644 (file)
index d37232f..b99a79d
@@ -19,6 +19,7 @@
 #include <linux/err.h>
 #include <linux/version.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include <linux/mfd/rt5025.h>
 #include <linux/power/rt5025-power.h>
 #include <linux/power/rt5025-gauge.h>
@@ -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)
index 77e76a43ff9f95804bbf14c93bf9f48204fe8204..e83c60d59b9007950f84d8084db0fd21ab8184e9 100755 (executable)
@@ -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);
index 1700ec7415d6a7146fba953dd3c49551909ee296..3f700c6bbf66580e01ae3d5241f2172fc6479c21 100755 (executable)
@@ -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