rk3188:pmu:rt5025:modify some bug for pmu charger & irq & guage

This commit is contained in:
张晴
2013-07-23 11:04:22 +08:00
parent 539ef9e47d
commit 8f3906c52e
11 changed files with 533 additions and 110 deletions

24
arch/arm/mach-rk30/board-pmu-rt5025.c Executable file → Normal file
View File

@@ -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 = {

4
arch/arm/mach-rk30/board-rk3168-tb.c Executable file → Normal file
View File

@@ -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

View 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"

4
drivers/mfd/rt5025-core.c Executable file → Normal file
View File

@@ -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)
{

2
drivers/mfd/rt5025-debug.c Executable file → Normal file
View File

@@ -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)
{

197
drivers/mfd/rt5025-i2c.c Executable file → Normal file
View File

@@ -16,9 +16,27 @@
#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;

35
drivers/mfd/rt5025-irq.c Executable file → Normal file
View File

@@ -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;

271
drivers/power/rt5025-gauge.c Executable file → Normal file
View File

@@ -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)
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);

91
drivers/power/rt5025-power.c Executable file → Normal file
View File

@@ -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)

View File

@@ -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);

View File

@@ -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