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;
}
},
.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 = {
.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 = {
},
.VSYSCtrl = {
.bitfield = {
- .VOFF = RT5025_VOFF_3P1V,
+ .VOFF = RT5025_VOFF_3P4V,
},
},
.PwrOnCfg = {
},
.irq_enable4 = {
.bitfield = {
- .SYSLV = 0,
+ .SYSLV = 1,
.DCDC4LVHV = 1,
.PWRONLP = 0,
.PWRONSP = 0,
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 = {
},
{
.name = "rt5025-ldo3", //vdd10
- .min_uv = 1200000,
- .max_uv = 1200000,
+ .min_uv = 1000000,
+ .max_uv = 1000000,
},
{
.name = "rt5025-ldo4", //vccjetta
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"
}
}
#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__);
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)
{
{
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)
{
#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 = ®_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);
return ret;
*(unsigned char *)dest = (unsigned char)ret;
}
-
+ #endif
return ret;
}
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);
{
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);
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;
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)
rt5025_core_deinit(chip);
#if 0
if (chip->event_callback)
- kfree(chip->event_callback);a
+ kfree(chip->event_callback);
#endif
kfree(chip);
return 0;
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));
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");
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))
{
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)
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;
/* 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 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];
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;
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);
}
}
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){
}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);
}
}
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){
}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);
}
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)
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;
"rt-battery-monitor");
/* enable channel */
rt5025_register_init(info->i2c);
+ rt5025_gauge_init_soc(info->i2c);
/* enable gauge IRQ */
rt5025_alert_init(info->i2c);
#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>
"rt5025-battery",
};
+#if 0
static int rt5025_set_charging_current_switch (struct i2c_client *i2c, int onoff)
{
int ret;
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)
{
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);
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);
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)
{
}
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);
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
rt5025_power_charge_detect(info);
+ RTINFO("--\n");
return 0;
}
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)
}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;
}bitfield;
unsigned char val;
}CHGControl7;
+ u32 fcc;
};
struct rt5025_gpio_data {
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;
#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);
#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