bq24735是TI推出的一款充电芯片,工作中刚好,使用该芯片进行设计工作。
首先简单了解一下bq24735的寄存器介绍
bq24735寄存器比较简单,程序编写过程中,都会用到这些寄存器。
首先驱动使用i2c_driver类型,驱动采用传统的模式,在board中注册,这里需要注意的是bq24735地址
{
.type = "bq24735",
.platform_data= &bq24735_exchg_data,
.addr = 0x09,
},
这里bq24735_exchg_data可以定义一些私有数据,一般把bq24735初始化设置充电电压、充电电流、输入电流配置放进去,根据个人偏好处理吧,我个人基本上会把这个参数置空,因为不想每次都改动board文件了,有需求的话就直接修改bq24735驱动。
bq24735的驱动文件也很简单了,主要步骤就是
1.进入probe
2.读取bq24735 ID
ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
ret);
return ret;
} else if (ret != 0x0040) {
dev_err(&client->dev,
"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
return -ENODEV;
}
/* Sleep at least 525ns to allow the reset to complete */
msleep(500);
ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read device id : %d\n", ret);
return ret;
} else if (ret != 0x000B) {
dev_err(&client->dev,
"device id mismatch. 0x000b != 0x%04x\n", ret);
return -ENODEV;
}
3.配置bq24735的充电电压、充电电流、输入电流。这里需要注意的是,配置的值不是随便写的,需要到bq24735手册上查询,确定每个bit的配置含义,然后计算出自己想要配置的数值,然后写入对应的寄存器。
ret = bq24735_write_word(charger->client,
BQ24735_CHARGE_CURRENT, value);
if (ret < 0) {
dev_err(&charger->client->dev,
"Failed to write charger current : %d\n",ret);
return ret;
}
ret = bq24735_write_word(charger->client,
BQ24735_CHARGE_VOLTAGE, value);
if (ret < 0) {
dev_err(&charger->client->dev,
"Failed to write charger voltage : %d\n",ret);
return ret;
}
ret = bq24735_write_word(charger->client,
BQ24735_INPUT_CURRENT, value);
if (ret < 0) {
dev_err(&charger->client->dev,
"Failed to write input current : %d\n",ret);
return ret;
}
4.关于AC插入检测
bq24735是可以检测是否有外部适配器插入检测,然后通过进行是否充电控制。检测的方法最好通过bq24735的ACDET管教进行,那要在驱动中实现一个GPIO的中断检测,这里我没有那样处理,而是在内核开启一个定时器,每秒钟读取bq24735的状态寄存器,查看是否有AC插入,如果有就使能充电,如果没有就关闭充电。
init_timer(&bq24735_timer);
bq24735_timer.function = bq24735_scan;
bq24735_timer.data = 0;
bq24735_timer.expires = jiffies + HZ;
add_timer(&bq24735_timer);
void bq24735_scan()
{
if (bq24735_charger_is_present(charger))
bq24735_enable_charging(charger);
else
bq24735_disable_charging(charger);
bq24735_timer.expires = jiffies + HZ;
add_timer(&bq24735_timer);
}
这样处理响应的实时性虽说差不多(凑合能用),但是比较占用CPU资源,最好还是采用GPIO中断的方式,来进行AC插入检测。等我调试了GPIO中断方式,再写一篇帖子来细说吧,当前任务先把项目交付。
5.使用到的一些关键宏函数,手动做了一点改动,基本上意思能表示清楚了,要借鉴的话,还是需要自己做点处理。
#define BQ24735_CHG_OPT 0x12
#define BQ24735_CHG_OPT_CHARGE_DISABLE (1 << 0)
#define BQ24735_CHG_OPT_AC_PRESENT (1 << 4)
#define BQ24735_CHARGE_CURRENT 0x14
#define BQ24735_CHARGE_CURRENT_MASK 0x1fc0
#define BQ24735_CHARGE_VOLTAGE 0x15
#define BQ24735_CHARGE_VOLTAGE_MASK 0x7ff0
#define BQ24735_INPUT_CURRENT 0x3f
#define BQ24735_INPUT_CURRENT_MASK 0x1f80
#define BQ24735_MANUFACTURER_ID 0xfe
#define BQ24735_DEVICE_ID 0xff
static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
u16 value)
{
return i2c_smbus_write_word_data(client, reg, le16_to_cpu(value));
}
static inline int bq24735_read_word(struct i2c_client *client, u8 reg)
{
s32 ret = i2c_smbus_read_word_data(client, reg);
return ret < 0 ? ret : le16_to_cpu(ret);
}
static int bq24735_update_word(struct i2c_client *client, u8 reg,
u16 mask, u16 value)
{
unsigned int tmp;
int ret;
ret = bq24735_read_word(client, reg);
if (ret < 0)
return ret;
tmp = ret & ~mask;
tmp |= value & mask;
return bq24735_write_word(client, reg, tmp);
}
static inline int bq24735_enable_charging(struct bq24735 *charger)
{
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
~BQ24735_CHG_OPT_CHARGE_DISABLE);
}
static inline int bq24735_disable_charging(struct bq24735 *charger)
{
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
BQ24735_CHG_OPT_CHARGE_DISABLE);
}
static bool bq24735_charger_is_present(struct bq24735 *charger)
{
int ac = 0;
ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
if (ac < 0) {
dev_err(&charger->client->dev,
"Failed to read charger options : %d\n",ac);
return false;
}
bq24735_write_word(charger->client,
BQ24735_CHG_OPT, /*0xf912*/0x9912);
return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false;
}
针对上述表述上传一个参考代码