目录
Android PowerSupply (二)power_supply_core
Android PowerSupply (三)power_supply_sys
Android PowerSupply (四)ChargeIC SGM41511 IC driver调试
Android PowerSupply (五)ChargeIC SGM41511 IC简介
Android Healthd BartteryMonitor
以下是 power supply driver 编写的简要过程
注册i2c 设备
static struct of_device_id sgm41511_charger_match_table[] = {
{ .compatible = "sgm41511", },
{ },
};
static const struct i2c_device_id sgm41511_charger_id[] = {
{ "sgm41511", 0x00 },
{ },
};
static struct i2c_driver sgm41511_charger_driver = {
.driver = {
.name = "sgm41511",
.of_match_table = sgm41511_charger_match_table,
},
.probe = sgm41511_charger_probe,
.remove = sgm41511_charger_remove,
.id_table = sgm41511_charger_id,
};
static int sgm41511_init(void)
{
printk(KERN_ERR"sgm41511_init\n");
return i2c_add_driver(&sgm41511_charger_driver);
}
probe过程
static int sgm41511_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct sgm41511 *sgm;
sgm = kzalloc(sizeof(struct sgm41511), GFP_KERNEL);
g_sgm = sgm;
sgm->dev = &client->dev;
sgm->client = client;
mutex_init(&sgm->i2c_rw_lock);
i2c_set_clientdata(client, sgm);
ret = sgm41511_detect_device(sgm);
//!< 读id判断ic类型 By: jixuan 2021年6月15日
ret = sgm41511_init_device(sgm);
//!< 通过ic给ic传入初始化参数 By: jixuan 2021年6月15日
/*
sgm41511_reset_watchdog_timer(sgm);
sgm41511_disable_watchdog_timer(sgm);
sgm41511_use_absolute_iindpm(sgm, true);
sgm41511_set_input_volt_limit(sgm, 4500);
sgm41511_set_input_current_limit(sgm, 2400);
sgm41511_set_term_current(sgm, 180);
sgm41511_set_chargevoltage(sgm, 4400);
sgm41511_set_chargecurrent(sgm, 2040);
sgm41511_set_otg_volt(sgm, 5150);
sgm41511_enable_charger(sgm);
*/
ret = sgm41511_init_usb_psy(sgm);
//!< 注册类型为usb 的power supply,后面做详细解析 By: jixuan 2021年6月15日
ret = sgm41511_init_main_psy(sgm);
//!< 注册类型为main 的power supply,后面做详细解析 By: jixuan 2021年6月15日
sgm->usb_vbus_gpio = of_get_named_gpio(sgm->dev->of_node,"sgm,interrupt-gpio", 0);
sgm->usb_vbus_irq = gpio_to_irq(sgm->usb_vbus_gpio);
if (sgm->usb_vbus_irq) {
ret = request_threaded_irq(sgm->usb_vbus_irq,
sgm41511_charger_interrupt, NULL,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"sgm41511_charger_irq", sgm);
enable_irq_wake(sgm->usb_vbus_irq);
}
//!< 申请gpio中断,用于ic有状态更新 ic发出的中断信号的识别 By: jixuan 2021年6月15日
ret = sgm41511_register_extcon_notifier(sgm);
//!< 注册extcon_notifier 用于监听 usb mode的变化,当usb处于host模式时 为otg输出 vbus电压 By: jixuan 2021年6月15日
INIT_DELAYED_WORK(&sgm->otg_work, sgm41511_otg_work_start);
INIT_DELAYED_WORK(&sgm->irq_work, sgm41511_irq_work_start);
ret = sysfs_create_group(&sgm->dev->kobj, &sgm41511_attr_group);
//!< 初始化otg处理,中断处理工作对了,创建设备节点 By: jixuan 2021年6月15日
}
power_supply的注册
static char *sgm41511_usb_supplied_to[] = { "battery", };
static const struct power_supply_desc sgm41511_usb_psy_desc = {
.name = "usb",
.type = POWER_SUPPLY_TYPE_USB,
.properties = sgm41511_usb_props,
.num_properties = ARRAY_SIZE(sgm41511_usb_props),
.get_property = sgm41511_usb_get_prop,
};
static const struct power_supply_desc sgm41511_power_supply_desc = {
.name = "main",
.type = POWER_SUPPLY_TYPE_MAIN,
.properties = sgm41511_main_props,
.num_properties = ARRAY_SIZE(sgm41511_main_props),
.get_property = sgm41511_get_main_property,
};
static int sgm41511_init_usb_psy(struct sgm41511 *sgm)
{
struct power_supply_config usb_cfg = { };
usb_cfg.drv_data = sgm;
usb_cfg.of_node = sgm->dev->of_node;
usb_cfg.supplied_to = sgm41511_usb_supplied_to;
usb_cfg.num_supplicants = ARRAY_SIZE(sgm41511_usb_supplied_to);
sgm->usb_psy = devm_power_supply_register(sgm->dev,
&sgm41511_usb_psy_desc,
&usb_cfg);
if (IS_ERR(sgm->usb_psy)) {
pr_err("Couldn't register USB main power supply\n");
return PTR_ERR(sgm->usb_psy);
}
return 0;
}
static int sgm41511_init_main_psy(struct sgm41511 *sgm)
{
struct power_supply_config main_cfg = { };
main_cfg.drv_data = sgm;
main_cfg.of_node = sgm->dev->of_node;
// main_cfg.supplied_to = sgm41511_main_supplied_to;
// main_cfg.num_supplicants = ARRAY_SIZE(sgm41511_main_supplied_to);
sgm->main_psy = devm_power_supply_register(sgm->dev,
&sgm41511_power_supply_desc,
&main_cfg);
if (IS_ERR(sgm->main_psy)) {
pr_err("Couldn't register main power supply\n");
return PTR_ERR(sgm->main_psy);
}
return 0;
}
get_property的实现
//!< 这里以 main powersupply为例 By: jixuan 2021年6月15日
static enum power_supply_property sgm41511_main_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_ONLINE,
};
static int sgm41511_get_main_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct sgm41511 *sgm = power_supply_get_drvdata(psy);
struct sgm41511_state state;
state = sgm->state;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
if (!state.vbus_stat) //no input
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else if (!state.chrg_stat) //charger disable
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else if (state.chrg_stat == 1 || state.chrg_stat == 2)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (state.chrg_stat == 3)
val->intval = POWER_SUPPLY_STATUS_FULL;
else
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
case POWER_SUPPLY_PROP_ONLINE:
if(state.vbus_stat == 1 || state.vbus_stat == 2)
val->intval = 1;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
if (state.chrg_stat == 1)
val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; //Vbat < Vbatlow
else if (state.chrg_stat == 2)
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
else
val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
break;
default:
return -EINVAL;
}
return 0;
}
通过回调 get_property 会对传入的属性进行解析,需要注意,注册的类型必须实现其处理,否则容易照成非法访问程序跑飞
这里拿POWER_SUPPLY_PROP_STATUS 为例; 返回当前的status,根据记录的寄存器的值(寄存器的更新通过中断实现)
前面提到的 status的枚举;而这些枚举在上报uevent时又会被对应解析成相应的字符串信息、
中断处理
static void sgm41511_irq_work_start(struct work_struct *work)
{
int ret = 0;
struct delayed_work *dw = to_delayed_work(work);
struct sgm41511 *sgm = container_of(dw, struct sgm41511, irq_work);
struct sgm41511_state state;
state = sgm->state;
ret = sgm41511_get_chip_state(sgm);
//!< 结合寄存器信息,获取对应位的bit值,来确定其状态、 By: jixuan 2021年6月15日
/*
ret = sgm41511_read_byte(g_sgm, &status, 0x08);
if(!ret){
g_sgm->state.vsys_stat = status & 0x01;
g_sgm->state.chrg_stat = (status & 0x18) >> 3;
g_sgm->state.vbus_stat = (status & 0xE0) >> 5;
}
*/
if(!ret){
if ((state.vbus_stat != sgm->state.vbus_stat ) ||
(state.chrg_stat != sgm->state.vbus_stat ) )
{
power_supply_changed(sgm->usb_psy);
power_supply_changed(sgm->main_psy);
//!< 上报uevent By: jixuan 2021年6月15日
}
}
enable_irq(sgm->usb_vbus_irq);
}
调用power_supply_changed 将当前的状态通过uevent