当前位置: 首页 > news >正文

10.MTK充电之mt6358-gauge驱动

1.概述

****mt6358-gauge电量计驱动,包括电量的运算、创建mt6358_sysfs_field_tbl文件节点、创建电池信息服务battery_update_routine实时更新电池状态。

2.分析mt6358_gauge_probe函数

static int mt6358_gauge_probe(struct platform_device *pdev)
{struct mtk_gauge *gauge;int ret;struct iio_channel *chan_bat_temp;/* 通过 IIO(Industrial I/O)子系统获取电池温度 ADC 通道 */chan_bat_temp = devm_iio_channel_get(&pdev->dev, "pmic_battery_temp");if (IS_ERR(chan_bat_temp)) {dev_err(&pdev->dev, "mt6358 requests probe deferral\n");return -EPROBE_DEFER;}/* 用于存储电量计状态和数据 */gauge = devm_kzalloc(&pdev->dev, sizeof(*gauge), GFP_KERNEL);if (!gauge)return -ENOMEM;gauge->chip = (struct mt6397_chip *)dev_get_drvdata(pdev->dev.parent);gauge->regmap = gauge->chip->regmap;gauge->regmap_type = REGMAP_TYPE_SPI;dev_set_drvdata(&pdev->dev, gauge);gauge->pdev = pdev;mutex_init(&gauge->ops_lock);/* 注册中断 - 通过名称获取中断号 */gauge->irq_no[COULOMB_H_IRQ] =platform_get_irq_byname(pdev, "COULOMB_H");gauge->irq_no[COULOMB_L_IRQ] =platform_get_irq_byname(pdev, "COULOMB_L");gauge->irq_no[VBAT_H_IRQ] = platform_get_irq_byname(pdev, "VBAT_H");gauge->irq_no[VBAT_L_IRQ] = platform_get_irq_byname(pdev, "VBAT_L");gauge->irq_no[NAFG_IRQ] = platform_get_irq_byname(pdev, "NAFG");gauge->irq_no[BAT_PLUGOUT_IRQ] =platform_get_irq_byname(pdev, "BAT_OUT");gauge->irq_no[ZCV_IRQ] = platform_get_irq_byname(pdev, "ZCV");gauge->irq_no[FG_N_CHARGE_L_IRQ] = platform_get_irq_byname(pdev,"FG_N_CHARGE_L");gauge->irq_no[FG_IAVG_H_IRQ] =platform_get_irq_byname(pdev, "FG_IAVG_H");gauge->irq_no[FG_IAVG_L_IRQ] =platform_get_irq_byname(pdev, "FG_IAVG_L");gauge->irq_no[BAT_TMP_H_IRQ] =platform_get_irq_byname(pdev, "BAT_TMP_H");gauge->irq_no[BAT_TMP_L_IRQ] =platform_get_irq_byname(pdev, "BAT_TMP_L");//获取电池温度gauge->chan_bat_temp = devm_iio_channel_get(&pdev->dev, "pmic_battery_temp");if (IS_ERR(gauge->chan_bat_temp)) {ret = PTR_ERR(gauge->chan_bat_temp);dev_err(&pdev->dev,  "pmic_battery_temp auxadc get fail, ret=%d\n", ret);}/* 获取电池电压 */gauge->chan_bat_voltage = devm_iio_channel_get(&pdev->dev, "pmic_battery_voltage");if (IS_ERR(gauge->chan_bat_voltage)) {ret = PTR_ERR(gauge->chan_bat_voltage);dev_err(&pdev->dev,  "chan_bat_voltage auxadc get fail, ret=%d\n", ret);}/* 获取电池接口电压(BIF) */gauge->chan_bif = devm_iio_channel_get(&pdev->dev, "pmic_bif_voltage");if (IS_ERR(gauge->chan_bif)) {ret = PTR_ERR(gauge->chan_bif);dev_err(&pdev->dev,  "pmic_bif_voltage auxadc get fail, ret=%d\n", ret);}/* 获取PTIM(动态电压测量)电压 */gauge->chan_ptim_bat_voltage = devm_iio_channel_get(&pdev->dev, "pmic_ptim_voltage");if (IS_ERR(gauge->chan_ptim_bat_voltage)) {ret = PTR_ERR(gauge->chan_ptim_bat_voltage);dev_err(&pdev->dev,  "chan_ptim_bat_voltage auxadc get fail, ret=%d\n",ret);}/* 获取 PTIM 电阻 */gauge->chan_ptim_r = devm_iio_channel_get(&pdev->dev, "pmic_ptim_r");if (IS_ERR(gauge->chan_ptim_r)) {ret = PTR_ERR(gauge->chan_ptim_r);dev_err(&pdev->dev,  "chan_ptim_r auxadc get fail, ret=%d\n",ret);}gauge->hw_status.car_tune_value = 1000;	/* 库仑计数器校准值    */gauge->hw_status.r_fg_value = 50;		/* 电量计内部电阻值 mΩ */gauge->attr = mt6358_sysfs_field_tbl;if (battery_psy_init(pdev)) {dev_err(&pdev->dev,  "battery_psy_init fail\n");return -ENOMEM;}gauge->name = "fgauge";gauge->psy_desc.name = "mtk-gauge";gauge->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;gauge->psy_desc.properties = gauge_properties;	/* 电量计属性 */gauge->psy_desc.num_properties = ARRAY_SIZE(gauge_properties);gauge->psy_desc.get_property = psy_gauge_get_property;gauge->psy_desc.set_property = psy_gauge_set_property;gauge->psy_cfg.drv_data = gauge;gauge->psy = power_supply_register(&pdev->dev, &gauge->psy_desc,&gauge->psy_cfg);mt6358_sysfs_create_group(gauge);initial_set(gauge, 0, 0);battery_init(pdev);adc_cali_cdev_init(gauge->gm, pdev);return 0;
}

2.分析gauge_properties电量计属性

****电量计的属性值,电池是否在位、充电器是否在线、最大充电电流、电池电量、电池温度、当前电流等。

static enum power_supply_property gauge_properties[] = {POWER_SUPPLY_PROP_PRESENT,			/* 电池是否在位(插入/移除)*/POWER_SUPPLY_PROP_ONLINE,			/* 充电器是否在线(是否供电)*/POWER_SUPPLY_PROP_CURRENT_MAX,		/* 最大允许电流(充电/放电)*/POWER_SUPPLY_PROP_ENERGY_EMPTY,		/* 电池是否完全耗尽(空电量)*/POWER_SUPPLY_PROP_CURRENT_NOW,		/* 当前电流(充电/放电)    */POWER_SUPPLY_PROP_TEMP,				/* 电池温度              */POWER_SUPPLY_PROP_VOLTAGE_NOW,		/* 当前电压              */
};static int psy_gauge_get_property(struct power_supply *psy,enum power_supply_property psp, union power_supply_propval *val)
{struct mtk_gauge *gauge;struct mtk_battery *gm;int ret = 0, value = 0;gauge = (struct mtk_gauge *)power_supply_get_drvdata(psy);switch (psp) {case POWER_SUPPLY_PROP_PRESENT:/* store disableGM30 status to mtk-gauge psy for DLPT */if (gauge == NULL || gauge->gm == NULL)val->intval = 0;elseval->intval = gauge->gm->disableGM30;break;case POWER_SUPPLY_PROP_ONLINE:if (gauge == NULL || gauge->gm == NULL)val->intval = 0;elseval->intval = gauge->gm->disableGM30;break;case POWER_SUPPLY_PROP_CURRENT_MAX:val->intval = get_ptim_current(gauge);break;case POWER_SUPPLY_PROP_ENERGY_EMPTY:
#ifdef POWER_MISC_OFFgm = gauge->gm;if (gm != NULL)val->intval = gm->sdc.shutdown_status.is_dlpt_shutdown;
#else	/* POWER_MISC_OFF */val->intval = 0;
#endif	/* POWER_MISC_OFF */break;case POWER_SUPPLY_PROP_CURRENT_NOW:ret = gauge_get_property(gauge->gm, GAUGE_PROP_BATTERY_CURRENT, &value);if (ret) {bm_err(gauge->gm, "%s, Failed to get CIC1, ret = %d\n", __func__, ret);value = gauge->gm->ibat;}val->intval = value * 100;return 0;case POWER_SUPPLY_PROP_TEMP:gm = gauge->gm;if (gm)val->intval = gm->battery_temp * 10;return 0;case POWER_SUPPLY_PROP_VOLTAGE_NOW:if (!gauge || !gauge->gm || gauge->gm->disableGM30)val->intval = 4000 * 1000;elseval->intval = gauge_get_int_property(gauge->gm,GAUGE_PROP_BATTERY_VOLTAGE) * 1000;return 0;default:return -EINVAL;}return 0;
}static int psy_gauge_set_property(struct power_supply *psy,enum power_supply_property psp,const union power_supply_propval *val)
{int ret = 0;struct mtk_gauge *gauge;struct mtk_battery *gm;gauge = (struct mtk_gauge *)power_supply_get_drvdata(psy);switch (psp) {case POWER_SUPPLY_PROP_ONLINE:pr_notice("%s: %d %d\n", __func__, psp, val->intval);break;case POWER_SUPPLY_PROP_ENERGY_EMPTY:gm = gauge->gm;if (gm != NULL && val->intval == 1)set_shutdown_cond(gm, DLPT_SHUTDOWN);break;case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN:gm = gauge->gm;if (gm != NULL && val->intval != 0) {gm->imix = val->intval;if (gm->imix > 5500) {gm->imix = 5500;pr_notice("imix check limit 5500:%d\n",val->intval);}}break;default:ret = -EINVAL;break;}return ret;}

3.分析mt6358_sysfs_create_group函数

实现初始化电量计、获取实时电池电流、获取累积充放电电量、设置库仑计数器高阈值中断、设置库仑计数器低阈值中断、检测电池是否在位、获取硬件版本、获取电池电压、获取电池温度文件节点等等,具体函数设计寄存器读写不在说明。
路径:/sys/devices/platform/1000d000.pwrap/1000d000.pwrap:mt6358-pmic/mt6358-gauge/power_supply/mtk-gauge/创建文件节点。


/* Must be in the same order as GAUGE_PROP_* */
static struct mtk_gauge_sysfs_field_info mt6358_sysfs_field_tbl[] = {GAUGE_SYSFS_FIELD_WO(initial_set,GAUGE_PROP_INITIAL),						/* 初始化电量计 */GAUGE_SYSFS_FIELD_RO(battery_current_get,			/* 获取实时电池电流 */GAUGE_PROP_BATTERY_CURRENT),GAUGE_SYSFS_FIELD_RO(coulomb_get,					/* 获取累积充放电电量 */GAUGE_PROP_COULOMB),GAUGE_SYSFS_FIELD_WO(coulomb_interrupt_ht_set,		/* 设置库仑计数器高阈值中断 */GAUGE_PROP_COULOMB_HT_INTERRUPT),GAUGE_SYSFS_FIELD_WO(coulomb_interrupt_lt_set,		/* 设置库仑计数器低阈值中断 */GAUGE_PROP_COULOMB_LT_INTERRUPT),GAUGE_SYSFS_FIELD_RO(battery_exist_get,				/* 检测电池是否在位 */GAUGE_PROP_BATTERY_EXIST),GAUGE_SYSFS_FIELD_RO(hw_version_get,				/* 获取硬件版本 */GAUGE_PROP_HW_VERSION),GAUGE_SYSFS_FIELD_RO(bat_vol_get,					/* 获取电池电压 */GAUGE_PROP_BATTERY_VOLTAGE),GAUGE_SYSFS_FIELD_RO(battery_temperature_adc_get,	/* 获取电池温度 */GAUGE_PROP_BATTERY_TEMPERATURE_ADC),GAUGE_SYSFS_FIELD_RO(bif_voltage_get,				GAUGE_PROP_BIF_VOLTAGE),					    /* 电池接口电压(BIF)*/GAUGE_SYSFS_FIELD_WO(en_h_vbat_set,					/* 启用高电压中断 */GAUGE_PROP_EN_HIGH_VBAT_INTERRUPT),GAUGE_SYSFS_FIELD_WO(en_l_vbat_set,					/* 启用低电压中断 */GAUGE_PROP_EN_LOW_VBAT_INTERRUPT),GAUGE_SYSFS_FIELD_WO(vbat_ht_set,					/* 设置电池高电压阈值 */GAUGE_PROP_VBAT_HT_INTR_THRESHOLD),GAUGE_SYSFS_FIELD_WO(vbat_lt_set,					/* 设置电池低电压阈值 */GAUGE_PROP_VBAT_LT_INTR_THRESHOLD),GAUGE_SYSFS_FIELD_RW(rtc_ui_soc, rtc_ui_soc_set, rtc_ui_soc_get,GAUGE_PROP_RTC_UI_SOC),						    /* RTC保存的电池百分比(0~100) */GAUGE_SYSFS_FIELD_RO(ptim_battery_voltage_get,		/* 获取PTIM模式下电池电压 */GAUGE_PROP_PTIM_BATTERY_VOLTAGE),GAUGE_SYSFS_FIELD_RO(ptim_resist_get,GAUGE_PROP_PTIM_RESIST),						/* 获取PTIM模式下电池内阻 */GAUGE_SYSFS_FIELD_WO(reset_set,GAUGE_PROP_RESET),								/* 重置电量计 */GAUGE_SYSFS_FIELD_RO(boot_zcv_get,GAUGE_PROP_BOOT_ZCV),							/* 获取开机时电池初始电压 */GAUGE_SYSFS_FIELD_RO(zcv_get,					GAUGE_PROP_ZCV),								/* 通过辅助adc读取电池电压 */GAUGE_SYSFS_FIELD_RO(zcv_current_get,GAUGE_PROP_ZCV_CURRENT),						/* 获取电池电流 */GAUGE_SYSFS_FIELD_RO(nafg_cnt_get,					/* 获取NAFG(电池未连接)计数 */GAUGE_PROP_NAFG_CNT),GAUGE_SYSFS_FIELD_RO(nafg_dltv_get,GAUGE_PROP_NAFG_DLTV),							/* NAFG电压下降阈值 */GAUGE_SYSFS_FIELD_RW(nafg_c_dltv, nafg_c_dltv_set, nafg_c_dltv_get,GAUGE_PROP_NAFG_C_DLTV),						/* 设置NAFG(Noise-Aware Fuel Gauge)模块的动态负载瞬态电压值 */GAUGE_SYSFS_FIELD_WO(nafg_en_set,GAUGE_PROP_NAFG_EN),							/* NAFG(Noise-Aware Fuel Gauge)模块功能启用 */GAUGE_SYSFS_FIELD_WO(nafg_zcv_set,GAUGE_PROP_NAFG_ZCV),							/* NAFG模式下的ZCV值 */GAUGE_SYSFS_FIELD_RO(nafg_vbat_get,					/* NAFG模式下的电池电压值 */GAUGE_PROP_NAFG_VBAT),GAUGE_SYSFS_FIELD_WO(reset_fg_rtc_set,GAUGE_PROP_RESET_FG_RTC),						/* 电量计重置RTC */GAUGE_SYSFS_FIELD_RW(gauge_initialized, gauge_initialized_set, gauge_initialized_get,GAUGE_PROP_GAUGE_INITIALIZED),					/* 电量计初始化获取设置 */ GAUGE_SYSFS_FIELD_RO(average_current_get,GAUGE_PROP_AVERAGE_CURRENT),					/* 读取平均电流:uA */GAUGE_SYSFS_FIELD_WO(bat_plugout_en_set,GAUGE_PROP_BAT_PLUGOUT_EN),						/* 电池拔出检测使能 */GAUGE_SYSFS_FIELD_WO(zcv_intr_threshold_set,GAUGE_PROP_ZCV_INTR_THRESHOLD),					/* zcv中断阈值 */GAUGE_SYSFS_FIELD_WO(zcv_intr_en_set,				/* 检测电池的零电流电压使能 */GAUGE_PROP_ZCV_INTR_EN),GAUGE_SYSFS_FIELD_WO(soff_reset_set,	GAUGE_PROP_SOFF_RESET),							/* SOFF(关机)状态重置 */GAUGE_SYSFS_FIELD_WO(ncar_reset_set,GAUGE_PROP_NCAR_RESET),							/* NCAR(噪声校准)重置 */GAUGE_SYSFS_FIELD_WO(bat_cycle_intr_threshold_set,GAUGE_PROP_BAT_CYCLE_INTR_THRESHOLD),GAUGE_SYSFS_FIELD_WO(hw_info_set,GAUGE_PROP_HW_INFO),							/* 硬件信息设置 */GAUGE_SYSFS_FIELD_WO(event_set,						/* 根据传入的事件执行不同事件处理 */GAUGE_PROP_EVENT),GAUGE_SYSFS_FIELD_WO(en_bat_tmp_ht_set,GAUGE_PROP_EN_BAT_TMP_HT),						/* 电池高温中断功能使能 */GAUGE_SYSFS_FIELD_WO(en_bat_tmp_lt_set,			GAUGE_PROP_EN_BAT_TMP_LT),						/* 电池低温中断功能使能 */GAUGE_SYSFS_FIELD_WO(bat_tmp_ht_threshold_set,			/* 设置电池高温阈值 */GAUGE_PROP_BAT_TMP_HT_THRESHOLD),GAUGE_SYSFS_FIELD_WO(bat_tmp_lt_threshold_set,			/* 设置电池低温阈值 */GAUGE_PROP_BAT_TMP_LT_THRESHOLD),GAUGE_SYSFS_INFO_FIELD_RW(info_2sec_reboot,GAUGE_PROP_2SEC_REBOOT),							/* 2s强制重启 */GAUGE_SYSFS_INFO_FIELD_RW(info_pl_charging_status,GAUGE_PROP_PL_CHARGING_STATUS),						/* 充电状态标志 */GAUGE_SYSFS_INFO_FIELD_RW(info_monitor_plchg_status,GAUGE_PROP_MONITER_PLCHG_STATUS),GAUGE_SYSFS_INFO_FIELD_RW(info_bat_plug_status,GAUGE_PROP_BAT_PLUG_STATUS),						/* 电池插入状态 */GAUGE_SYSFS_INFO_FIELD_RW(info_is_nvram_fail_mode,GAUGE_PROP_IS_NVRAM_FAIL_MODE),						GAUGE_SYSFS_INFO_FIELD_RW(info_monitor_soff_validtime,GAUGE_PROP_MONITOR_SOFF_VALIDTIME),					GAUGE_SYSFS_INFO_FIELD_RW(info_con0_soc, GAUGE_PROP_CON0_SOC),			/* 实时电池百分比(未校准)*/GAUGE_SYSFS_INFO_FIELD_RW(info_con1_uisoc, GAUGE_PROP_CON1_UISOC),	/* 用户界面显示的电池百分比 */GAUGE_SYSFS_INFO_FIELD_RW(info_con1_vaild, GAUGE_PROP_CON1_VAILD),	/* SOC数据有效性标志 */GAUGE_SYSFS_INFO_FIELD_RW(info_shutdown_car, GAUGE_PROP_SHUTDOWN_CAR),	 /* 关机时剩余电量(μAh) 	   读写 */GAUGE_SYSFS_INFO_FIELD_RW(car_tune_value, GAUGE_PROP_CAR_TUNE_VALUE),		/* 库仑计数器校准值	       读写 */GAUGE_SYSFS_INFO_FIELD_RW(r_fg_value, GAUGE_PROP_R_FG_VALUE),				/* 电量计内阻值(mΩ)	       读写 */GAUGE_SYSFS_INFO_FIELD_RW(vbat2_detect_time, GAUGE_PROP_VBAT2_DETECT_TIME),GAUGE_SYSFS_INFO_FIELD_RW(vbat2_detect_counter, GAUGE_PROP_VBAT2_DETECT_COUNTER),GAUGE_SYSFS_FIELD_WO(bat_temp_froze_en_set, GAUGE_PROP_BAT_TEMP_FROZE_EN),		/* 温度冻结使能(调试用)    控制 */GAUGE_SYSFS_FIELD_RO(battery_voltage_cali, GAUGE_PROP_BAT_EOC),	/* 充电结束电流(EOC)校准   只读 */GAUGE_SYSFS_FIELD_RO(regmap_type_get, GAUGE_PROP_REGMAP_TYPE),	/* 寄存器映射类型(SPI/I2C) 只读 */GAUGE_SYSFS_FIELD_RO(battery_cic2_get, GAUGE_PROP_CIC2),	    /* CIC2寄存器值(调试)	   只读 */
};static struct attribute *mt6358_sysfs_attrs[GAUGE_PROP_MAX + 1];static const struct attribute_group mt6358_sysfs_attr_group = {.attrs = mt6358_sysfs_attrs,
};static void mt6358_sysfs_init_attrs(void)
{int i, limit = ARRAY_SIZE(mt6358_sysfs_field_tbl);for (i = 0; i < limit; i++)mt6358_sysfs_attrs[i] = &mt6358_sysfs_field_tbl[i].attr.attr;mt6358_sysfs_attrs[limit] = NULL; /* Has additional entry for this */
}static int mt6358_sysfs_create_group(struct mtk_gauge *gauge)
{mt6358_sysfs_init_attrs();return sysfs_create_group(&gauge->psy->dev.kobj,&mt6358_sysfs_attr_group);
}
kernel/kernel_device_modules-6.6/drivers/power/supply/mtk_gauge.h
enum gauge_property {					  /* 功能描述                 类型 */GAUGE_PROP_INITIAL,				 	  /* 电量计初始化标志 		   控制	*/GAUGE_PROP_BATTERY_CURRENT,			  /* 实时电池电流(μA)	       只读	*/GAUGE_PROP_COULOMB,					  /* 累积充放电电量(μAh)	   只读 */GAUGE_PROP_COULOMB_HT_INTERRUPT,	  /* 库仑计数高阈值中断设置	    控制 */GAUGE_PROP_COULOMB_LT_INTERRUPT,	  /* 库仑计数低阈值中断设置	    控制 */GAUGE_PROP_BATTERY_EXIST,			  /* 电池在位检测(0/1)	   只读 */GAUGE_PROP_HW_VERSION,				  /* 硬件版本信息	           只读 */GAUGE_PROP_BATTERY_VOLTAGE,			  /* 实时电池电压(μV)	        只读 */GAUGE_PROP_BATTERY_TEMPERATURE_ADC,	  /* 电池温度(ADC原始值)	    只读 */GAUGE_PROP_BIF_VOLTAGE,				  /* 电池接口电压(BIF)	    只读 */GAUGE_PROP_EN_HIGH_VBAT_INTERRUPT,	  /* 高电压中断使能				控制 */GAUGE_PROP_EN_LOW_VBAT_INTERRUPT,	  /* 低电压中断使能				控制 */GAUGE_PROP_VBAT_HT_INTR_THRESHOLD,	  /* 高电压阈值(μV)			控制 */GAUGE_PROP_VBAT_LT_INTR_THRESHOLD,	  /* 低电压阈值(μV)			控制 */GAUGE_PROP_RTC_UI_SOC,				  /* RTC保存的电池百分比(0~100)读写 */GAUGE_PROP_PTIM_BATTERY_VOLTAGE,	  /* PTIM模式下的电池电压	    只读 */GAUGE_PROP_PTIM_RESIST,				  /* PTIM测量的电池内阻(mΩ)	只读 */GAUGE_PROP_RESET,					  /* 重置电量计                控制 */GAUGE_PROP_BOOT_ZCV,				  /* 启动时的ZCV值(μV)	   只读 */GAUGE_PROP_ZCV,						  /* 零电流电压(μV)	       只读 */GAUGE_PROP_ZCV_CURRENT,				  /* ZCV测量时的电流(μA)      只读 *//* 电池未连接(NAFG)检测 */GAUGE_PROP_NAFG_CNT,				  /* NAFG事件计数	           只读 */GAUGE_PROP_NAFG_DLTV,				  /* NAFG电压下降阈值	       只读 */GAUGE_PROP_NAFG_C_DLTV,				  /* NAFG电流下降阈值	       	读写 */GAUGE_PROP_NAFG_EN,					  /* NAFG检测使能	           控制 */GAUGE_PROP_NAFG_ZCV,				  /* NAFG模式下的ZCV值	       只读 */GAUGE_PROP_NAFG_VBAT,				  /* NAFG模式下的电池电压	    只读 */GAUGE_PROP_RESET_FG_RTC,GAUGE_PROP_GAUGE_INITIALIZED,		  /* 电量计初始化状态	        状态 */GAUGE_PROP_AVERAGE_CURRENT,			  /* 平均电流(μA)	            只读 */GAUGE_PROP_BAT_PLUGOUT_EN,			  /* 电池拔出检测使能	        控制 */GAUGE_PROP_ZCV_INTR_THRESHOLD,		  /* ZCV中断阈值	           控制 */GAUGE_PROP_ZCV_INTR_EN,				  /* ZCV中断使能	           控制 */GAUGE_PROP_SOFF_RESET,				  /* SOFF(关机)状态重置	    控制 */GAUGE_PROP_NCAR_RESET,				  /* NCAR(噪声校准)重置	    控制 */GAUGE_PROP_BAT_CYCLE_INTR_THRESHOLD,GAUGE_PROP_HW_INFO,					  /* 硬件信息	               状态 */GAUGE_PROP_EVENT,					  /* 触发自定义事件(调试)	    控制 */GAUGE_PROP_EN_BAT_TMP_HT,			  /* 高温中断使能	           控制 */GAUGE_PROP_EN_BAT_TMP_LT,			  /* 低温中断使能	           控制 */GAUGE_PROP_BAT_TMP_HT_THRESHOLD,	  /* 高温阈值(m°C)	       控制 */GAUGE_PROP_BAT_TMP_LT_THRESHOLD,	  /* 低温阈值(m°C)	       控制 */GAUGE_PROP_2SEC_REBOOT,//bit info	  /* 2秒强制重启标志	       控制 */GAUGE_PROP_PL_CHARGING_STATUS,		  /* 充电状态标志	           读写 */GAUGE_PROP_MONITER_PLCHG_STATUS,GAUGE_PROP_BAT_PLUG_STATUS,			  /* 电池插入状态	           读写 */GAUGE_PROP_IS_NVRAM_FAIL_MODE,GAUGE_PROP_MONITOR_SOFF_VALIDTIME,GAUGE_PROP_CON0_SOC,				  /* 实时电池百分比(未校准)	读写 */GAUGE_PROP_CON1_UISOC,				  /* 用户界面显示的电池百分比	读写 */GAUGE_PROP_CON1_VAILD,				  /* SOC数据有效性标志	       读写 */GAUGE_PROP_SHUTDOWN_CAR,			  /* 关机时剩余电量(μAh) 	   读写 */GAUGE_PROP_CAR_TUNE_VALUE,			  /* 库仑计数器校准值	       读写 */GAUGE_PROP_R_FG_VALUE,				  /* 电量计内阻值(mΩ)	       读写 */GAUGE_PROP_VBAT2_DETECT_TIME,GAUGE_PROP_VBAT2_DETECT_COUNTER,GAUGE_PROP_BAT_TEMP_FROZE_EN,		  /* 温度冻结使能(调试用)    控制 */GAUGE_PROP_BAT_EOC,					  /* 充电结束电流(EOC)校准   只读 */GAUGE_PROP_REGMAP_TYPE,				  /* 寄存器映射类型(SPI/I2C) 只读 */GAUGE_PROP_CIC2,					  /* CIC2寄存器值(调试)	   只读 */GAUGE_PROP_MAX,
};

4.分析battery_init函数

****检查启动模式,读取lk阶段记录的电池信息,电量计参数初始化,电量计服务初始化,电池信息更新。

int battery_init(struct platform_device *pdev)
{int ret = 0;bool b_recovery_mode = 0;struct mtk_battery *gm;struct mtk_gauge *gauge;gauge = dev_get_drvdata(&pdev->dev);gm = gauge->gm;gm->fixed_bat_tmp = 0xffff;gm->tmp_table = fg_temp_table;gm->log_level = BMLOG_ERROR_LEVEL;gm->sw_iavg_gap = 3000;gm->in_sleep = false;mutex_init(&gm->fg_update_lock);init_waitqueue_head(&gm->wait_que);/*检查启动模式*/fg_check_bootmode(&pdev->dev, gm);/* 在启动时读取 LK(Little Kernel,Bootloader)阶段 记录的电池信息(如电压、电流、关机时间),用于电池校准或初始化。 */fg_check_lk_swocv(&pdev->dev, gm);/* 属性控制参数初始化 */fg_prop_control_init(gm);/* 检测电池类型 */fg_check_bat_type(pdev, gm);/* 电量计参数初始化 */fg_custom_init_from_header(gm);fg_custom_init_from_dts(pdev, gm);mtk_irq_thread_init(gm);/* 电量计服务初始化 */gauge_coulomb_service_init(gm);gm->coulomb_plus.callback = fg_coulomb_int_h_handler;gauge_coulomb_consumer_init(&gm->coulomb_plus, &pdev->dev, "car+1%");gm->coulomb_minus.callback = fg_coulomb_int_l_handler;gauge_coulomb_consumer_init(&gm->coulomb_minus, &pdev->dev, "car-1%");gauge_coulomb_consumer_init(&gm->uisoc_plus, &pdev->dev, "uisoc+1%");gm->uisoc_plus.callback = fg_bat_int2_h_handler;gauge_coulomb_consumer_init(&gm->uisoc_minus, &pdev->dev, "uisoc-1%");gm->uisoc_minus.callback = fg_bat_int2_l_handler;alarm_init(&gm->tracking_timer, ALARM_BOOTTIME,tracking_timer_callback);INIT_WORK(&gm->tracking_timer_work, tracking_timer_work_handler);alarm_init(&gm->one_percent_timer, ALARM_BOOTTIME,one_percent_timer_callback);INIT_WORK(&gm->one_percent_timer_work, one_percent_timer_work_handler);alarm_init(&gm->sw_uisoc_timer, ALARM_BOOTTIME,sw_uisoc_timer_callback);INIT_WORK(&gm->sw_uisoc_timer_work, sw_uisoc_timer_work_handler);/*电池信息更新*/kthread_run(battery_update_routine, gm, "%s", gm->gauge->name);gm->pm_nb.notifier_call = system_pm_notify;ret = register_pm_notifier(&gm->pm_nb);if (ret)bm_err(gm, "%s failed to register system pm notify\n", __func__);fg_drv_thread_hrtimer_init(gm);battery_sysfs_create_group(gm);gm->battery_sysfs = battery_sysfs_field_tbl;/* for gauge hal hw ocv */gm->battery_temp = force_get_tbat(gm, true);//mtk_power_misc_init(gm);ret = mtk_battery_daemon_init(pdev);b_recovery_mode = is_recovery_mode(gm);gm->is_probe_done = true;if (ret == 0 && b_recovery_mode == 0)bm_err(gm, "[%s]: daemon mode DONE\n", __func__);else {gm->algo.active = true;battery_algo_init(gm);bm_err(gm, "[%s]: enable Kernel mode Gauge\n", __func__);}return 0;
}

4.1 电量计库伦服务初始化 - gauge_coulomb_service_init

void gauge_coulomb_service_init(struct mtk_battery *gm)
{int val = 0;struct mtk_coulomb_service *cs;int ret = 0;bm_debug(gm, "[%s] into\n", __func__);cs = &gm->cs;cs->gm = gm;ret = snprintf(cs->name, 20, "%s gct", gm->gauge->name);if (ret < 0)bm_err(gm, "[%s] something wrong\n", __func__);INIT_LIST_HEAD(&cs->coulomb_head_minus);INIT_LIST_HEAD(&cs->coulomb_head_plus);mutex_init(&cs->coulomb_lock);mutex_init(&cs->hw_coulomb_lock);spin_lock_init(&cs->slock);cs->wlock = wakeup_source_register(NULL, "gauge coulomb wakelock");init_waitqueue_head(&cs->wait_que);atomic_set(&cs->in_sleep, 0);kthread_run(gauge_coulomb_thread, cs, "%s", cs->name);	/*函数非常重要*/cs->pm_nb.notifier_call = system_pm_notify;ret = register_pm_notifier(&cs->pm_nb);if (ret)bm_err(gm, "failed to register system pm notify\n");ret = devm_request_threaded_irq(&gm->gauge->pdev->dev,gm->gauge->irq_no[COULOMB_H_IRQ],NULL, coulomb_irq,IRQF_ONESHOT | IRQF_TRIGGER_HIGH,"mtk_gauge_coulomb_high",gm);//disable_irq_nosync(gm->gauge->coulomb_h_irq);if (ret)bm_err(gm, "failed to request coulomb h irq\n");ret = devm_request_threaded_irq(&gm->gauge->pdev->dev,gm->gauge->irq_no[COULOMB_L_IRQ],NULL, coulomb_irq,IRQF_ONESHOT | IRQF_TRIGGER_HIGH,"mtk_gauge_coulomb_low",gm);//disable_irq_nosync(gm->gauge->coulomb_l_irq);if (ret)bm_err(gm, "failed to request coulomb l irq\n");gauge_get_property(gm, GAUGE_PROP_COULOMB, &val);cs->pre_coulomb = val;cs->init = true;
}

分析电量计库伦统计线程 - gauge_coulomb_thread

static int gauge_coulomb_thread(void *arg)
{struct mtk_coulomb_service *cs = (struct mtk_coulomb_service *)arg;unsigned long flags = 0;ktime_t start, end, duraction;int ret = 0;struct mtk_battery *gm =container_of(cs, struct mtk_battery, cs);bm_debug(gm, "[%s]%s:=>\n", cs->name, __func__);while (1) {/*coulomb_thread_timeout为真且不是休眠状态*/ret = wait_event_interruptible(cs->wait_que,cs->coulomb_thread_timeout == true &&!atomic_read(&cs->in_sleep));if (atomic_read(&cs->in_sleep) || ret < 0) {__pm_relax(cs->wlock);continue;}cs->coulomb_thread_timeout = false;start = ktime_get_boottime();mutex_lock(&cs->coulomb_lock);gauge_coulomb_int_handler(cs);	//核心处理函数mutex_unlock(&cs->coulomb_lock);spin_lock_irqsave(&cs->slock, flags);__pm_relax(cs->wlock);spin_unlock_irqrestore(&cs->slock, flags);end = ktime_get_boottime();duraction = end - start;bm_debug(gm, "%s time:%d ms\n", __func__,(int)(div_s64(duraction, 1000000)));}return 0;
}

分析gauge_coulomb_int_handler函数

static void gauge_coulomb_int_handler(struct mtk_coulomb_service *cs)
{int car = 0, hw_car;struct list_head *pos;struct list_head *phead;struct gauge_consumer *ptr = NULL;struct mtk_battery *gm =container_of(cs, struct mtk_battery, cs);/* 获取当前库仑计值打印当前值和上次值 */gauge_get_property(cs->gm, GAUGE_PROP_COULOMB, &car);bm_debug(gm, "[%s]%s car:%d preCar:%d\n",cs->name, __func__,car, cs->pre_coulomb);/* 充电时刻 */if (list_empty(&cs->coulomb_head_plus) != true) {pos = cs->coulomb_head_plus.next;phead = &cs->coulomb_head_plus;for (pos = phead->next; pos != phead;) {struct list_head *ptmp;ptr = container_of(pos, struct gauge_consumer, list);/*充电满*/if (ptr->end <= car) {ptmp = pos;pos = pos->next;list_del_init(ptmp);bm_debug(gm,"[%s %s]+ %s s:%ld e:%ld car:%d %d int:%d timeout\n",cs->name,__func__,ptr->name,ptr->start, ptr->end, car,cs->pre_coulomb, ptr->variable);if (ptr->callback) {mutex_unlock(&cs->coulomb_lock);ptr->callback(cs->gm, ptr);mutex_lock(&cs->coulomb_lock);pos = cs->coulomb_head_plus.next;}} elsebreak;}if (list_empty(&cs->coulomb_head_plus) != true) {pos = cs->coulomb_head_plus.next;ptr = container_of(pos, struct gauge_consumer, list);hw_car = ptr->end - car;	/*下一次库仑计数高阈值中断值*/bm_debug(gm,"[%s %s]+ %s %ld %ld %d now:%d dif:%d\n",cs->name,__func__,ptr->name,ptr->start, ptr->end,ptr->variable, car, hw_car);mutex_lock(&cs->hw_coulomb_lock);gauge_set_property(cs->gm, GAUGE_PROP_COULOMB_HT_INTERRUPT,hw_car);	mutex_unlock(&cs->hw_coulomb_lock);} elsebm_debug(gm, "%s + list is empty\n", cs->name);} elsebm_debug(gm, "%s + list is empty\n", cs->name);/*放电时刻*/if (list_empty(&cs->coulomb_head_minus) != true) {pos = cs->coulomb_head_minus.next;phead = &cs->coulomb_head_minus;for (pos = phead->next; pos != phead;) {struct list_head *ptmp;ptr = container_of(pos, struct gauge_consumer, list);if (ptr->end >= car) {ptmp = pos;pos = pos->next;list_del_init(ptmp);bm_debug(gm,"[%s %s]- %s s:%ld e:%ld car:%d %d int:%d timeout\n",cs->name,__func__,ptr->name,ptr->start, ptr->end,car, cs->pre_coulomb, ptr->variable);if (ptr->callback) {mutex_unlock(&cs->coulomb_lock);ptr->callback(cs->gm, ptr);mutex_lock(&cs->coulomb_lock);pos = cs->coulomb_head_minus.next;}} elsebreak;}if (list_empty(&cs->coulomb_head_minus) != true) {pos = cs->coulomb_head_minus.next;ptr = container_of(pos, struct gauge_consumer, list);hw_car = car - ptr->end;bm_debug(gm,"[%s %s]- %s %ld %ld %d now:%d dif:%d\n",cs->name,__func__,ptr->name,ptr->start, ptr->end,ptr->variable, car, hw_car);mutex_lock(&cs->hw_coulomb_lock);gauge_set_property(cs->gm, GAUGE_PROP_COULOMB_LT_INTERRUPT,hw_car);mutex_unlock(&cs->hw_coulomb_lock);} elsebm_debug(gm, "%s - list is empty\n", cs->name);} elsebm_debug(gm, "%s - list is empty\n", cs->name);cs->pre_coulomb = car;
}

4.2 电池状态信息更新 - battery_update_routine

****电池管理后台线程函数,用于在非睡眠状态下周期性地更新硬件状态(如电压、电流、电量等)

int battery_update_routine(void *arg)
{struct mtk_battery *gm = (struct mtk_battery *)arg;int ret = 0, retry = 0;while (1) {/* 当fg_update_flag > 0 和 非休眠态时触发 */ret = wait_event_interruptible(gm->wait_que,(gm->fg_update_flag > 0) && !gm->in_sleep);if (ret < 0) {retry++;if (retry < 0xFFFFFFFF)continue;else {bm_err(gm, "%s something wrong retry: %d\n", __func__, retry);break;}}retry = 0;mutex_lock(&gm->fg_update_lock);if (gm->in_sleep)goto in_sleep;gm->fg_update_flag = 0;fg_drv_update_hw_status(gm);/* 更新电池硬件状态 */
in_sleep:mutex_unlock(&gm->fg_update_lock);}return 0;
}/* 更新电池硬件状态 */
static void fg_drv_update_hw_status(struct mtk_battery *gm)
{ktime_t ktime;struct property_control *prop_control;char gp_name[MAX_GAUGE_PROP_LEN];char reg_type_name[MAX_REGMAP_TYPE_LEN];int i, regmap_type, is_battery_exist = 0;long car;prop_control = &gm->prop_control;fg_update_porp_control(prop_control);/* 强制读取电池温度、电池电压、电流、电池存在标志 */gm->tbat = force_get_tbat_internal(gm);gm->vbat = gauge_get_int_property(gm,GAUGE_PROP_BATTERY_VOLTAGE);gm->ibat = gauge_get_int_property(gm,GAUGE_PROP_BATTERY_CURRENT);car = gauge_get_int_property(gm, GAUGE_PROP_COULOMB);gauge_get_property_control(gm, GAUGE_PROP_BATTERY_EXIST,&is_battery_exist, 0);bm_err(gm, "[%s] car[%ld,%ld,%ld,%ld,%ld] tmp:%d soc:%d uisoc:%d vbat:%d ibat:%d baton:%d algo:%d gm3:%d %d %d %d %d %d, get_prop:%d %lld %d %d %d %lld %ld %lld, boot:%d rac:%d\n",gm->gauge->name,car,gm->coulomb_plus.end, gm->coulomb_minus.end,gm->uisoc_plus.end, gm->uisoc_minus.end,gm->tbat,gm->soc, gm->ui_soc,gm->vbat,gm->ibat,gm->baton,gm->algo.active,gm->disableGM30, gm->fg_cust_data.disable_nafg,gm->ntc_disable_nafg, gm->cmd_disable_nafg, gm->vbat0_flag, gm->is_evb_board,gm->no_prop_timeout_control, prop_control->last_period.tv_sec,prop_control->last_binder_counter, prop_control->total_fail,prop_control->max_gp, prop_control->max_get_prop_time.tv_sec,prop_control->max_get_prop_time.tv_nsec/1000000,prop_control->last_diff_time.tv_sec, gm->bootmode,gauge_get_int_property(gm, GAUGE_PROP_PTIM_RESIST));fg_drv_update_daemon(gm);/* 硬件访问超时异常处理*/prop_control->max_get_prop_time = ktime_to_timespec64(0);if (prop_control->end_get_prop_time == 0 &&prop_control->last_diff_time.tv_sec > prop_control->i2c_fail_th) {gp_number_to_name(gm, gp_name, prop_control->curr_gp);regmap_type = gauge_get_int_property(gm, GAUGE_PROP_REGMAP_TYPE);reg_type_to_name(gm, reg_type_name, regmap_type);bm_err(gm, "[%s_Error] get %s hang over 3 sec, time:%lld\n",reg_type_name, gp_name, prop_control->last_diff_time.tv_sec);
#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)if (!gm->disableGM30)aee_kernel_warning("BATTERY", "gauge get prop over 3 sec\n");
#endif}if (!gm->disableGM30 && prop_control->total_fail > 20) {regmap_type = gauge_get_int_property(gm,GAUGE_PROP_REGMAP_TYPE);reg_type_to_name(gm, reg_type_name, regmap_type);bm_err(gm, "[%s_Error] Binder last counter: %d, period: %lld", reg_type_name,prop_control->last_binder_counter, prop_control->last_period.tv_sec);for (i = 0; i < GAUGE_PROP_MAX; i++) {gp_number_to_name(gm, gp_name, i);bm_err(gm, "[%s_Error] %s, fail_counter: %d\n",reg_type_name, gp_name, prop_control->i2c_fail_counter[i]);prop_control->i2c_fail_counter[i] = 0;}#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)aee_kernel_warning("BATTERY",  "gauge get prop fail case over 20 times\n");
#endif}gauge_coulomb_dump_list(gm);/*库仑计容错处理*/if ((car < gm->coulomb_minus.end-30 || car > gm->coulomb_plus.end+30) && is_battery_exist) {bm_err(gm, "coulomb service stop %ld %ld %d %d %d",car, gm->coulomb_minus.end, car > gm->coulomb_plus.end,car < gm->coulomb_minus.end, car > gm->coulomb_plus.end);wake_up_gauge_coulomb(gm);}if (gm->algo.active == true)battery_update(gm->bm);	// 触发电量算法更新if (gm->log_level >= BMLOG_DEBUG_LEVEL)ktime = ktime_set(10, 0);elsektime = ktime_set(60, 0);hrtimer_start(&gm->fg_hrtimer, ktime, HRTIMER_MODE_REL);
}

5.日志

	bm_err(gm, "[%s] car[%ld,%ld,%ld,%ld,%ld] tmp:%d soc:%d uisoc:%d vbat:%d ibat:%d baton:%d algo:%d gm3:%d %d %d %d %d %d, get_prop:%d %lld %d %d %d %lld %ld %lld, boot:%d rac:%d\n",gm->gauge->name,	/*电量计名称*/car,				/*当前库仑计累计值*//*充电方向阈值(充满电) 放电方向阈值(低电告警)*/gm->coulomb_plus.end, gm->coulomb_minus.end,	/*UI显示的充电完成SOC阈值(%) UI显示的低电量SOC阈值(%)*/gm->uisoc_plus.end, gm->uisoc_minus.end,/*电池温度*/		gm->tbat,/*系统内部计算的精确电量 显示给用户的电量(平滑处理)*/gm->soc, gm->ui_soc,gm->vbat,	/* 电池电压 */gm->ibat,	/* 电池电流(正:充电,负:放电)*/gm->baton,	/* 电池在位状态(1=存在)*/gm->algo.active, /* 电量算法是否激活 *//* 是否禁用GM3.0算法 禁用NAFG(噪声抑制)功能 */gm->disableGM30, gm->fg_cust_data.disable_nafg,/* NTC温度导致的NAFG禁用 命令强制禁用NAFG  电池电压为0的特殊标志  是否开发板环境*/gm->ntc_disable_nafg, gm->cmd_disable_nafg, gm->vbat0_flag, gm->is_evb_board,/* 是否禁用属性获取超时控制 上次属性获取周期时长 */gm->no_prop_timeout_control, prop_control->last_period.tv_sec,/* 最近一次binder调用计数  总失败次数 */prop_control->last_binder_counter, prop_control->total_fail,/* 耗时最长的属性ID  单次属性获取最大耗时(秒) */prop_control->max_gp, prop_control->max_get_prop_time.tv_sec,/* 最大耗时的毫秒部分 */prop_control->max_get_prop_time.tv_nsec/1000000,/* 最近一次操作耗时 启动模式 */prop_control->last_diff_time.tv_sec, gm->bootmode,gauge_get_int_property(gm, GAUGE_PROP_PTIM_RESIST));

6736: <5>[ 73.044317][ T170] fgauge: fgauge:[fgauge] car[-250,6,-510,-201,-503] tmp:25 soc:34 uisoc:34 vbat:3754 ibat:-4638 baton:806 algo:0 gm3:0 0 0 0 0 0, get_prop:0 60 626 0 9 0 53 0, boot:0 rac:90

http://www.lryc.cn/news/612333.html

相关文章:

  • Linux发行版分类与Centos替代品
  • 媒体资产管理系统和OCR文字识别的结合
  • 笔试——Day30
  • 简单介绍cgroups以及在K8s中的应用
  • 小程序中,给一段富文本字符串文案特殊内容加样式监听点击事件
  • 无人机遥控器舵量技术解析
  • cad c#二次开发 图层封装 获取当前层
  • 无人机遥控器波特率技术解析
  • 基于AI的自动驾驶汽车(AI-AV)网络安全威胁缓解框架
  • 开疆智能ModbusTCP转Profinet网关连接EPSON机器人配置案例
  • Docker国内可用镜像(2025.08.06测试)
  • 深入理解数据库连接池(Connection Pool):原理、优势与常见实现
  • wordpress网站的“管理员邮箱地址”有什么用?
  • Linux86 sheel流程控制前瞻4 判断vsftpd服务启动,如果启动,打印端口号,进程id
  • 系统运维之LiveCD详解
  • 【图像处理基石】浅谈3D城市生成中的数据融合技术
  • 【图像处理基石】什么是数字高程模型?如何使用数字高程模型?
  • dify之推送飞书群消息工作流
  • 飞书对接E签宝完整方案
  • 《动手学深度学习》读书笔记—9.7序列到序列学习
  • CPP网络编程-异步sever
  • 内部类详解:Java中的嵌套艺术
  • MATLAB深度学习之数据集-数据库构建方法详解
  • 202506 电子学会青少年等级考试机器人三级实际操作真题
  • KVazaar:开源H.265/HEVC编码器技术深度解析
  • 三、Istio流量治理(二)
  • 进程管理块(PCB):操作系统进程管理的核心数据结构
  • Linux systemd 服务管理与 Firewall 防火墙配置
  • envFrom 是一个 列表类型字段bug
  • LeetCode:1408.数组中的字符串匹配