Android PowerSupply (四)ChargeIC SGM41511 IC driver调试

本文深入探讨了Android系统中针对SGM41511充电IC的电源管理驱动,包括i2c设备注册、probe过程、power_supply的注册以及中断处理。详细解析了电源状态的获取、中断触发的uevent上报,展示了如何监控和管理电池和USB电源状态。
摘要由CSDN通过智能技术生成

目录

Android PowerSupply (一)总概

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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值