Android & linux充电模块分析

24 篇文章 1 订阅
22 篇文章 4 订阅

一、结构分析

核心模块是

drivers/power/supply/power_supply_core.c
drivers/power/supply/power_supply_leds.c
drivers/power/supply/power_supply_fysfs.c

核心数据结构:struct power_supply

// include\linux\power_supply.h

struct power_supply {
	const struct power_supply_desc *desc;

	char **supplied_to;
	size_t num_supplicants;

	char **supplied_from;
	size_t num_supplies;
	struct device_node *of_node;

	/* Driver private data */
	void *drv_data;

	/* private */
	struct device dev;
	struct work_struct changed_work;
	struct delayed_work deferred_register_work;
	spinlock_t changed_lock;
	bool changed;
	bool initialized;
	bool removing;
	atomic_t use_cnt;
#ifdef CONFIG_THERMAL
	struct thermal_zone_device *tzd;
	struct thermal_cooling_device *tcd;
#endif

#ifdef CONFIG_LEDS_TRIGGERS
	struct led_trigger *charging_full_trig;
	char *charging_full_trig_name;
	struct led_trigger *charging_trig;
	char *charging_trig_name;
	struct led_trigger *full_trig;
	char *full_trig_name;
	struct led_trigger *online_trig;
	char *online_trig_name;
	struct led_trigger *charging_blink_full_solid_trig;
	char *charging_blink_full_solid_trig_name;
#endif
};

supplied_to,一个字符串数组,保存了由该PSY供电的PSY列表,以此可将PSY组织成相互级联的PSY链。这些“被供电”的PSY,称作supplicant(客户端、乞求者);
num_supplicants, supplicant的个数;
supplied_from,一个字符串数组,保存了向该PSY供电的PSY列表,也称作supply(提供者)。从另一个方向,组织PSY之间的级联关系;
num_supplies,supply的个数;

二、驱动核心模块分析

1、模块入口函数在power_supply_core.c中

subsys_initcall(power_supply_class_init);

提前于驱动模块的加载。

// drivers/power/supply/power_supply_core.c

static int __init power_supply_class_init(void)
{
	power_supply_class = class_create(THIS_MODULE, "power_supply");

	if (IS_ERR(power_supply_class))
		return PTR_ERR(power_supply_class);

	power_supply_class->dev_uevent = power_supply_uevent;
	power_supply_init_attrs(&power_supply_dev_type);

	return 0;
}

这里面首先是创建了一个电源相关的类,名字叫“power_supply”,这样在手机的sys/class下面就会出现一个power_supply目录。
在这里插入图片描述

然后是设置uevent相关,这里还没搞清楚。
然后是通过power_supply_init_attrs初始化电源相关的属性节点。这里面的power_supply_dev_type为全局变量,这里通过函数power_supply_init_attrs将power_supply_dev_type进行填充。

// drivers/power/supply/power_supply_core.c

static struct device_type power_supply_dev_type;

2、接下来分析一下这个宏POWER_SUPPLY_ATTR

// drivers/power/supply/power_supply_fysfs.c

#define POWER_SUPPLY_ATTR(_name)					\
{									\
	.attr = { .name = #_name },					\
	.show = power_supply_show_property,				\
	.store = power_supply_store_property,				\
}

这里是设置struct device_attribute.

// include/linux/device.h

/* interface for exporting device attributes */
struct device_attribute {
	struct attribute	attr;
	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
			char *buf);
	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count);
};
// include/linux/sysfs.h

struct attribute {
	const char		*name;
	umode_t			mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	bool			ignore_lockdep:1;
	struct lock_class_key	*key;
	struct lock_class_key	skey;
#endif
};

这个宏初始化了device_attribute中的 show 和store和struct attribute中的const char *name。但是没有初始化struct attribute中的mode,这个会在其他地方初始化。
3、然后分析power_supply_init_attrs函数。

// drivers/power/supply/power_supply_core.c

void power_supply_init_attrs(struct device_type *dev_type)
{
	int i;

	dev_type->groups = power_supply_attr_groups;

	for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
		__power_supply_attrs[i] = &power_supply_attrs[i].attr;
}

这里面用到了power_supply_attr_groups。power_supply_attr_groups通过以下函数已经初始化好,但是这里面__power_supply_attrs这个时候还是空的。

// drivers/power/supply/power_supply_core.c

static struct attribute *
__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];

static struct attribute_group power_supply_attr_group = {
	.attrs = __power_supply_attrs,
	.is_visible = power_supply_attr_is_visible,
};

static const struct attribute_group *power_supply_attr_groups[] = {
	&power_supply_attr_group,
	NULL,
};

这里面在static struct attribute_group power_supply_attr_group中还实现is_visible,struct attribute_group中的struct attribute的umode_t mode会被函数is_visible的返回值替换,如果之前实现了umode_t mode,则umode_t mode会被is_visible(umode_t (*is_visible)(struct kobject *, struct attribute *, int);)返回的数据替换。is_visible 会结合attrs 中的每个attribute,依次被调用,所以attrs 中的umode_t mode都会被实现。
__power_supply_attrs内容的实现是通过

	for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
		__power_supply_attrs[i] = &power_supply_attrs[i].attr;

实现的。这里面用到了power_supply_attrs,这是一个定义好的全局变量。由前面我们可知POWER_SUPPLY_ATTR这个宏初始化了device_attribute中的 show 和store和struct attribute中的const char *name。到这里创建节点的所有工作都已经做好。这里把之前的准备工作全部准备好的power_supply_attr_groups赋值给了power_supply_dev_type的groups。

// drivers/power/supply/power_supply_fysfs.c

/* Must be in the same order as POWER_SUPPLY_PROP_* */
static struct device_attribute power_supply_attrs[] = {
	/* Properties of type `int' */
	POWER_SUPPLY_ATTR(status),
	POWER_SUPPLY_ATTR(charge_type),
	POWER_SUPPLY_ATTR(health),
	POWER_SUPPLY_ATTR(present),
	POWER_SUPPLY_ATTR(online),
	POWER_SUPPLY_ATTR(authentic),
	POWER_SUPPLY_ATTR(technology),
	POWER_SUPPLY_ATTR(cycle_count),
	POWER_SUPPLY_ATTR(voltage_max),
	POWER_SUPPLY_ATTR(voltage_min),
	POWER_SUPPLY_ATTR(voltage_max_design),
	POWER_SUPPLY_ATTR(voltage_min_design),
	POWER_SUPPLY_ATTR(voltage_now),
	POWER_SUPPLY_ATTR(voltage_avg),
	POWER_SUPPLY_ATTR(voltage_ocv),
	POWER_SUPPLY_ATTR(voltage_boot),
	POWER_SUPPLY_ATTR(current_max),
	POWER_SUPPLY_ATTR(current_now),
	POWER_SUPPLY_ATTR(current_avg),
	POWER_SUPPLY_ATTR(current_boot),
	POWER_SUPPLY_ATTR(power_now),
	POWER_SUPPLY_ATTR(power_avg),
	POWER_SUPPLY_ATTR(charge_full_design),
	POWER_SUPPLY_ATTR(charge_empty_design),
	POWER_SUPPLY_ATTR(charge_full),
	POWER_SUPPLY_ATTR(charge_empty),
	POWER_SUPPLY_ATTR(charge_now),
	POWER_SUPPLY_ATTR(charge_avg),
	POWER_SUPPLY_ATTR(charge_counter),
	POWER_SUPPLY_ATTR(constant_charge_current),
	POWER_SUPPLY_ATTR(constant_charge_current_max),
	POWER_SUPPLY_ATTR(constant_charge_voltage),
	POWER_SUPPLY_ATTR(constant_charge_voltage_max),
	POWER_SUPPLY_ATTR(charge_control_limit),
	POWER_SUPPLY_ATTR(charge_control_limit_max),
	POWER_SUPPLY_ATTR(input_current_limit),
	POWER_SUPPLY_ATTR(energy_full_design),
	POWER_SUPPLY_ATTR(energy_empty_design),
	POWER_SUPPLY_ATTR(energy_full),
	POWER_SUPPLY_ATTR(energy_empty),
	POWER_SUPPLY_ATTR(energy_now),
	POWER_SUPPLY_ATTR(energy_avg),
	POWER_SUPPLY_ATTR(capacity),
	POWER_SUPPLY_ATTR(capacity_alert_min),
	POWER_SUPPLY_ATTR(capacity_alert_max),
	POWER_SUPPLY_ATTR(capacity_level),
	POWER_SUPPLY_ATTR(shutdown_delay),
	POWER_SUPPLY_ATTR(soc_decimal),
	POWER_SUPPLY_ATTR(soc_decimal_rate),
	POWER_SUPPLY_ATTR(cold_thermal_level),
	POWER_SUPPLY_ATTR(temp),
	POWER_SUPPLY_ATTR(temp_max),
	POWER_SUPPLY_ATTR(temp_min),
	POWER_SUPPLY_ATTR(temp_alert_min),
	POWER_SUPPLY_ATTR(temp_alert_max),
	POWER_SUPPLY_ATTR(temp_ambient),
	POWER_SUPPLY_ATTR(temp_ambient_alert_min),
	POWER_SUPPLY_ATTR(temp_ambient_alert_max),
	POWER_SUPPLY_ATTR(time_to_empty_now),
	POWER_SUPPLY_ATTR(time_to_empty_avg),
	POWER_SUPPLY_ATTR(time_to_full_now),
	POWER_SUPPLY_ATTR(time_to_full_avg),
	POWER_SUPPLY_ATTR(type),
	POWER_SUPPLY_ATTR(usb_type),
	POWER_SUPPLY_ATTR(scope),
	POWER_SUPPLY_ATTR(precharge_current),
	POWER_SUPPLY_ATTR(charge_term_current),
	POWER_SUPPLY_ATTR(calibrate),
	/* Local extensions */
	POWER_SUPPLY_ATTR(usb_hc),
	POWER_SUPPLY_ATTR(usb_otg),
	POWER_SUPPLY_ATTR(charge_enabled),
	POWER_SUPPLY_ATTR(set_ship_mode),
	POWER_SUPPLY_ATTR(real_type),
	POWER_SUPPLY_ATTR(hvdcp3_type),
	POWER_SUPPLY_ATTR(quick_charge_type),
	POWER_SUPPLY_ATTR(charge_now_raw),
	POWER_SUPPLY_ATTR(charge_now_error),
	POWER_SUPPLY_ATTR(capacity_raw),
	POWER_SUPPLY_ATTR(battery_charging_enabled),
	POWER_SUPPLY_ATTR(charging_enabled),
	POWER_SUPPLY_ATTR(step_charging_enabled),
	POWER_SUPPLY_ATTR(step_charging_step),
	POWER_SUPPLY_ATTR(pin_enabled),
	POWER_SUPPLY_ATTR(input_suspend),
	POWER_SUPPLY_ATTR(input_voltage_regulation),
	POWER_SUPPLY_ATTR(input_voltage_vrect),
	POWER_SUPPLY_ATTR(rx_iout),
	POWER_SUPPLY_ATTR(input_current_max),
	POWER_SUPPLY_ATTR(input_current_trim),
	POWER_SUPPLY_ATTR(input_current_settled),
	POWER_SUPPLY_ATTR(input_voltage_settled),
	POWER_SUPPLY_ATTR(bypass_vchg_loop_debouncer),
	POWER_SUPPLY_ATTR(charge_counter_shadow),
	POWER_SUPPLY_ATTR(hi_power),
	POWER_SUPPLY_ATTR(low_power),
	POWER_SUPPLY_ATTR(temp_cool),
	POWER_SUPPLY_ATTR(temp_warm),
	POWER_SUPPLY_ATTR(temp_cold),
	POWER_SUPPLY_ATTR(temp_hot),
	POWER_SUPPLY_ATTR(system_temp_level),
	POWER_SUPPLY_ATTR(resistance),
	POWER_SUPPLY_ATTR(resistance_capacitive),
	POWER_SUPPLY_ATTR(resistance_id),
	POWER_SUPPLY_ATTR(resistance_now),
	POWER_SUPPLY_ATTR(flash_current_max),
	POWER_SUPPLY_ATTR(update_now),
	POWER_SUPPLY_ATTR(esr_count),
	POWER_SUPPLY_ATTR(buck_freq),
	POWER_SUPPLY_ATTR(boost_current),
	POWER_SUPPLY_ATTR(safety_timer_enabled),
	POWER_SUPPLY_ATTR(charge_done),
	POWER_SUPPLY_ATTR(hiz_mode),
	POWER_SUPPLY_ATTR(usb_current_now),
	POWER_SUPPLY_ATTR(usb_voltage_now),
	POWER_SUPPLY_ATTR(flash_active),
	POWER_SUPPLY_ATTR(flash_trigger),
	POWER_SUPPLY_ATTR(force_tlim),
	POWER_SUPPLY_ATTR(dp_dm),
	POWER_SUPPLY_ATTR(input_current_limited),
	POWER_SUPPLY_ATTR(input_current_now),
	POWER_SUPPLY_ATTR(charge_qnovo_enable),
	POWER_SUPPLY_ATTR(current_qnovo),
	POWER_SUPPLY_ATTR(voltage_qnovo),
	POWER_SUPPLY_ATTR(rerun_aicl),
	POWER_SUPPLY_ATTR(cycle_count_id),
	POWER_SUPPLY_ATTR(safety_timer_expired),
	POWER_SUPPLY_ATTR(restricted_charging),
	POWER_SUPPLY_ATTR(current_capability),
	POWER_SUPPLY_ATTR(typec_mode),
	POWER_SUPPLY_ATTR(typec_cc_orientation),
	POWER_SUPPLY_ATTR(typec_power_role),
	POWER_SUPPLY_ATTR(typec_boost_otg_disable),
	POWER_SUPPLY_ATTR(typec_src_rp),
	POWER_SUPPLY_ATTR(pd_allowed),
	POWER_SUPPLY_ATTR(pd_active),
	POWER_SUPPLY_ATTR(pd_in_hard_reset),
	POWER_SUPPLY_ATTR(pd_current_max),
	POWER_SUPPLY_ATTR(apdo_max),
	POWER_SUPPLY_ATTR(pd_usb_suspend_supported),
	POWER_SUPPLY_ATTR(charger_temp),
	POWER_SUPPLY_ATTR(charger_temp_max),
	POWER_SUPPLY_ATTR(parallel_disable),
	POWER_SUPPLY_ATTR(pe_start),
	POWER_SUPPLY_ATTR(soc_reporting_ready),
	POWER_SUPPLY_ATTR(debug_battery),
	POWER_SUPPLY_ATTR(fcc_delta),
	POWER_SUPPLY_ATTR(icl_reduction),
	POWER_SUPPLY_ATTR(parallel_mode),
	POWER_SUPPLY_ATTR(die_health),
	POWER_SUPPLY_ATTR(connector_health),
	POWER_SUPPLY_ATTR(connector_temp),
	POWER_SUPPLY_ATTR(vbus_disable),
	POWER_SUPPLY_ATTR(arti_vbus_enable),
	POWER_SUPPLY_ATTR(ctm_current_max),
	POWER_SUPPLY_ATTR(hw_current_max),
	POWER_SUPPLY_ATTR(pr_swap),
	POWER_SUPPLY_ATTR(cc_step),
	POWER_SUPPLY_ATTR(cc_step_sel),
	POWER_SUPPLY_ATTR(sw_jeita_enabled),
	POWER_SUPPLY_ATTR(pd_voltage_max),
	POWER_SUPPLY_ATTR(pd_voltage_min),
	POWER_SUPPLY_ATTR(sdp_current_max),
	POWER_SUPPLY_ATTR(dc_thermal_levels),
	POWER_SUPPLY_ATTR(connector_type),
	POWER_SUPPLY_ATTR(parallel_batfet_mode),
	POWER_SUPPLY_ATTR(parallel_fcc_max),
	POWER_SUPPLY_ATTR(wireless_version),
	POWER_SUPPLY_ATTR(wireless_fw_version),
	POWER_SUPPLY_ATTR(signal_strength),
	POWER_SUPPLY_ATTR(wireless_cp_en),
	POWER_SUPPLY_ATTR(wireless_power_good_en),
	POWER_SUPPLY_ATTR(sw_disabel_dc_en),
	POWER_SUPPLY_ATTR(wireless_wakelock),
	POWER_SUPPLY_ATTR(tx_adapter),
	POWER_SUPPLY_ATTR(tx_mac),
	POWER_SUPPLY_ATTR(rx_cr),
	POWER_SUPPLY_ATTR(rx_cep),
	POWER_SUPPLY_ATTR(bt_state),
	POWER_SUPPLY_ATTR(min_icl),
	POWER_SUPPLY_ATTR(moisture_detected),
	POWER_SUPPLY_ATTR(batt_profile_version),
	POWER_SUPPLY_ATTR(batt_full_current),
	POWER_SUPPLY_ATTR(warm_fake_charging),
	POWER_SUPPLY_ATTR(recharge_soc),
	POWER_SUPPLY_ATTR(hvdcp_opti_allowed),
	POWER_SUPPLY_ATTR(smb_en_mode),
	POWER_SUPPLY_ATTR(smb_en_reason),
	POWER_SUPPLY_ATTR(esr_actual),
	POWER_SUPPLY_ATTR(esr_nominal),
	POWER_SUPPLY_ATTR(soh),
	POWER_SUPPLY_ATTR(clear_soh),
	POWER_SUPPLY_ATTR(force_recharge),
	POWER_SUPPLY_ATTR(fcc_stepper_enable),
	POWER_SUPPLY_ATTR(smb_en_allowed),
	POWER_SUPPLY_ATTR(batt_2s_mode),
	POWER_SUPPLY_ATTR(toggle_stat),
	POWER_SUPPLY_ATTR(type_recheck),
	POWER_SUPPLY_ATTR(main_fcc_max),
	POWER_SUPPLY_ATTR(fg_reset),
	POWER_SUPPLY_ATTR(qc_opti_disable),
	POWER_SUPPLY_ATTR(cc_soc),
	POWER_SUPPLY_ATTR(batt_age_level),
	POWER_SUPPLY_ATTR(scale_mode_en),
	POWER_SUPPLY_ATTR(voltage_vph),
	POWER_SUPPLY_ATTR(chip_version),
	POWER_SUPPLY_ATTR(therm_icl_limit),
	POWER_SUPPLY_ATTR(dc_reset),
	POWER_SUPPLY_ATTR(voltage_max_limit),
	POWER_SUPPLY_ATTR(real_capacity),
	POWER_SUPPLY_ATTR(force_main_icl),
	POWER_SUPPLY_ATTR(force_main_fcc),
	POWER_SUPPLY_ATTR(comp_clamp_level),
	POWER_SUPPLY_ATTR(adapter_cc_mode),
	POWER_SUPPLY_ATTR(non_compatible),
	POWER_SUPPLY_ATTR(skin_health),
	POWER_SUPPLY_ATTR(aicl_done),
	POWER_SUPPLY_ATTR(voltage_step),
	POWER_SUPPLY_ATTR(apsd_rerun),
	POWER_SUPPLY_ATTR(apsd_timeout),
	/* Charge pump properties */
	POWER_SUPPLY_ATTR(cp_status1),
	POWER_SUPPLY_ATTR(cp_status2),
	POWER_SUPPLY_ATTR(cp_enable),
	POWER_SUPPLY_ATTR(cp_switcher_en),
	POWER_SUPPLY_ATTR(cp_die_temp),
	POWER_SUPPLY_ATTR(cp_isns),
	POWER_SUPPLY_ATTR(cp_isns_slave),
	POWER_SUPPLY_ATTR(cp_toggle_switcher),
	POWER_SUPPLY_ATTR(cp_irq_status),
	POWER_SUPPLY_ATTR(cp_ilim),
	POWER_SUPPLY_ATTR(irq_status),
	POWER_SUPPLY_ATTR(parallel_output_mode),
	POWER_SUPPLY_ATTR(cp_win_ov),
	POWER_SUPPLY_ATTR(cp_passthrough_mode),
	POWER_SUPPLY_ATTR(cp_passthrough_config),
	POWER_SUPPLY_ATTR(cp_ovp_config),
	POWER_SUPPLY_ATTR(cp_cfly_ss_status),
	/* Bq charge pump properties */
	POWER_SUPPLY_ATTR(ti_battery_present),
	POWER_SUPPLY_ATTR(ti_vbus_present),
	POWER_SUPPLY_ATTR(ti_battery_voltage),
	POWER_SUPPLY_ATTR(ti_battery_current),
	POWER_SUPPLY_ATTR(ti_battery_temperature),
	POWER_SUPPLY_ATTR(ti_bus_voltage),
	POWER_SUPPLY_ATTR(ti_bus_current),
	POWER_SUPPLY_ATTR(ti_bus_temperature),
	POWER_SUPPLY_ATTR(ti_die_temperature),
	POWER_SUPPLY_ATTR(ti_alarm_status),
	POWER_SUPPLY_ATTR(ti_fault_status),
	POWER_SUPPLY_ATTR(ti_reg_status),
	POWER_SUPPLY_ATTR(ti_set_bus_protection_for_qc3),
	POWER_SUPPLY_ATTR(fastcharge_mode),
	POWER_SUPPLY_ATTR(dp_dm_bq),
	POWER_SUPPLY_ATTR(pd_authentication),
	POWER_SUPPLY_ATTR(passthrough_curr_max),
	POWER_SUPPLY_ATTR(termination_current),
	POWER_SUPPLY_ATTR(ffc_termination_current),
	POWER_SUPPLY_ATTR(sys_termination_current),
	POWER_SUPPLY_ATTR(ffc_sys_termination_current),
	POWER_SUPPLY_ATTR(vbatt_full_vol),
	POWER_SUPPLY_ATTR(fcc_vbatt_full_vol),
	POWER_SUPPLY_ATTR(ki_coeff_current),
	POWER_SUPPLY_ATTR(recharge_vbat),
	POWER_SUPPLY_ATTR(step_vfloat_index),
#ifdef CONFIG_BATT_VERIFY_BY_DS28E16
	/* battery verify properties */
	POWER_SUPPLY_ATTR(romid),
	POWER_SUPPLY_ATTR(ds_status),
	POWER_SUPPLY_ATTR(pagenumber),
	POWER_SUPPLY_ATTR(pagedata),
	POWER_SUPPLY_ATTR(authen_result),
	POWER_SUPPLY_ATTR(session_seed),
	POWER_SUPPLY_ATTR(s_secret),
	POWER_SUPPLY_ATTR(challenge),
	POWER_SUPPLY_ATTR(auth_anon),
	POWER_SUPPLY_ATTR(auth_bdconst),
	POWER_SUPPLY_ATTR(page0_data),
	POWER_SUPPLY_ATTR(page1_data),
	POWER_SUPPLY_ATTR(verify_model_name),
	POWER_SUPPLY_ATTR(maxim_batt_cycle_count),
#endif
	POWER_SUPPLY_ATTR(chip_ok),
	/* DIV 2 properties */
	POWER_SUPPLY_ATTR(div_2_mode),
	POWER_SUPPLY_ATTR(reverse_chg_mode),
	POWER_SUPPLY_ATTR(reverse_chg_state),
	POWER_SUPPLY_ATTR(reverse_gpio_state),
	POWER_SUPPLY_ATTR(reset_div_2_mode),
	POWER_SUPPLY_ATTR(aicl_enable),
	POWER_SUPPLY_ATTR(otg_state),
	/* Local extensions of type int64_t */
	POWER_SUPPLY_ATTR(charge_counter_ext),
	/* Properties of type `const char *' */
	POWER_SUPPLY_ATTR(model_name),
	POWER_SUPPLY_ATTR(manufacturer),
	POWER_SUPPLY_ATTR(battery_type),
	POWER_SUPPLY_ATTR(cycle_counts),
	POWER_SUPPLY_ATTR(serial_number),
};

4、通过

// drivers/power/supply/power_supply_sysfs.c

static umode_t power_supply_attr_is_visible(struct kobject *kobj,
					   struct attribute *attr,
					   int attrno)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct power_supply *psy = dev_get_drvdata(dev);
	umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
	int i;

	if (attrno == POWER_SUPPLY_PROP_TYPE)
		return mode;

	for (i = 0; i < psy->desc->num_properties; i++) {
		int property = psy->desc->properties[i];

		if (property == attrno) {
			if (psy->desc->property_is_writeable &&
			    psy->desc->property_is_writeable(psy, property) > 0)
				mode |= S_IWUSR;

			return mode;
		}
	}

	return 0;
}

可知,power_supply_attrs中的属性有很多,但是并不是所有的属性都会被创建,只有符合条件的属性才会被创建,只有当属性的属性号和充电ic驱动实现的属性相同时,才会被正常返回umode_t mode,其中属性号为POWER_SUPPLY_PROP_TYPE时也会被创建。其他的都是返回0,返回0的属性都不会被创建。这里以高通的一款手机为例,举例说明。

static enum power_supply_property smb1351_parallel_properties[] = {
	POWER_SUPPLY_PROP_CHARGING_ENABLED,
	POWER_SUPPLY_PROP_STATUS,
	POWER_SUPPLY_PROP_CURRENT_MAX,
	POWER_SUPPLY_PROP_VOLTAGE_MAX,
	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
	POWER_SUPPLY_PROP_CHARGE_TYPE,
	POWER_SUPPLY_PROP_PARALLEL_MODE,
	POWER_SUPPLY_PROP_INPUT_SUSPEND,
	POWER_SUPPLY_PROP_MODEL_NAME,
};

这里面充电ic的驱动实现了这么多的属性号,通过查static struct device_attribute power_supply_attrs[] 可以查到对应的属性名。进入到手机里面可以看到对应的属性节点。
在这里插入图片描述

三、应用分析

1、
这里以 bq2597x为例进行分析

static int bq2597x_psy_register(struct bq2597x *bq)
{
	int ret;

	bq->psy_cfg.drv_data = bq;
	bq->psy_cfg.of_node = bq->dev->of_node;

	if (bq->mode == BQ25970_ROLE_MASTER)
		bq->psy_desc.name = "bq2597x-master";
	else if (bq->mode == BQ25970_ROLE_SLAVE)
		bq->psy_desc.name = "bq2597x-slave";
	else
		bq->psy_desc.name = "bq2597x-standalone";

	bq->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
	bq->psy_desc.properties = bq2597x_charger_props;
	bq->psy_desc.num_properties = ARRAY_SIZE(bq2597x_charger_props);
	bq->psy_desc.get_property = bq2597x_charger_get_property;
	bq->psy_desc.set_property = bq2597x_charger_set_property;
	bq->psy_desc.property_is_writeable = bq2597x_charger_is_writeable;


	bq->fc2_psy = devm_power_supply_register(bq->dev,
			&bq->psy_desc, &bq->psy_cfg);
	if (IS_ERR(bq->fc2_psy)) {
		bq_err("failed to register fc2_psy:%d\n", ret);
		return PTR_ERR(bq->fc2_psy);
	}

	bq_info("%s power supply register successfully\n", bq->psy_desc.name);

	return 0;
}

在bq2597x驱动中,在porbe函数中注册psy,内容如上所示,这里面初始化了

	struct power_supply_desc psy_desc;
	struct power_supply_config psy_cfg;

这两个机构体,然后通过devm_power_supply_register注册power_supply。
2、

// drivers/power/supply/power_supply_core.c

/**
 * devm_power_supply_register() - Register managed power supply
 * @parent:	Device to be a parent of power supply's device, usually
 *		the device which probe function calls this
 * @desc:	Description of power supply, must be valid through whole
 *		lifetime of this power supply
 * @cfg:	Run-time specific configuration accessed during registering,
 *		may be NULL
 *
 * Return: A pointer to newly allocated power_supply on success
 * or ERR_PTR otherwise.
 * The returned power_supply pointer will be automatically unregistered
 * on driver detach.
 */
struct power_supply *__must_check
devm_power_supply_register(struct device *parent,
		const struct power_supply_desc *desc,
		const struct power_supply_config *cfg)
{
	struct power_supply **ptr, *psy;

	ptr = devres_alloc(devm_power_supply_release, sizeof(*ptr), GFP_KERNEL);

	if (!ptr)
		return ERR_PTR(-ENOMEM);
	psy = __power_supply_register(parent, desc, cfg, true);
	if (IS_ERR(psy)) {
		devres_free(ptr);
	} else {
		*ptr = psy;
		devres_add(parent, ptr);
	}
	return psy;
}
EXPORT_SYMBOL_GPL(devm_power_supply_register);

这里面主要功能是由__power_supply_register实现。

// drivers/power/supply/power_supply_core.c

static struct power_supply *__must_check
__power_supply_register(struct device *parent,
				   const struct power_supply_desc *desc,
				   const struct power_supply_config *cfg,
				   bool ws)
{
	struct device *dev;
	struct power_supply *psy;
	int i, rc;

	if (!parent)
		pr_warn("%s: Expected proper parent device for '%s'\n",
			__func__, desc->name);

	if (!desc || !desc->name || !desc->properties || !desc->num_properties)
		return ERR_PTR(-EINVAL);

	for (i = 0; i < desc->num_properties; ++i) {
		if ((desc->properties[i] == POWER_SUPPLY_PROP_USB_TYPE) &&
		    (!desc->usb_types || !desc->num_usb_types))
			return ERR_PTR(-EINVAL);
	}

	psy = kzalloc(sizeof(*psy), GFP_KERNEL);
	if (!psy)
		return ERR_PTR(-ENOMEM);

	dev = &psy->dev;

	device_initialize(dev);

	dev->class = power_supply_class;
	dev->type = &power_supply_dev_type;
	dev->parent = parent;
	dev->release = power_supply_dev_release;
	dev_set_drvdata(dev, psy);
	psy->desc = desc;
	if (cfg) {
		psy->drv_data = cfg->drv_data;
		psy->of_node =
			cfg->fwnode ? to_of_node(cfg->fwnode) : cfg->of_node;
		psy->supplied_to = cfg->supplied_to;
		psy->num_supplicants = cfg->num_supplicants;
	}

	rc = dev_set_name(dev, "%s", desc->name);
	if (rc)
		goto dev_set_name_failed;

	INIT_WORK(&psy->changed_work, power_supply_changed_work);
	INIT_DELAYED_WORK(&psy->deferred_register_work,
			  power_supply_deferred_register_work);

	rc = power_supply_check_supplies(psy);
	if (rc) {
		dev_info(dev, "Not all required supplies found, defer probe\n");
		goto check_supplies_failed;
	}

	spin_lock_init(&psy->changed_lock);
	rc = device_init_wakeup(dev, ws);
	if (rc)
		goto wakeup_init_failed;

	rc = device_add(dev);
	if (rc)
		goto device_add_failed;

	rc = psy_register_thermal(psy);
	if (rc)
		goto register_thermal_failed;

	rc = power_supply_create_triggers(psy);
	if (rc)
		goto create_triggers_failed;

	/*
	 * Update use_cnt after any uevents (most notably from device_add()).
	 * We are here still during driver's probe but
	 * the power_supply_uevent() calls back driver's get_property
	 * method so:
	 * 1. Driver did not assigned the returned struct power_supply,
	 * 2. Driver could not finish initialization (anything in its probe
	 *    after calling power_supply_register()).
	 */
	atomic_inc(&psy->use_cnt);
	psy->initialized = true;

	queue_delayed_work(system_power_efficient_wq,
			   &psy->deferred_register_work,
			   POWER_SUPPLY_DEFERRED_REGISTER_TIME);

	return psy;

create_triggers_failed:
	psy_unregister_thermal(psy);
register_thermal_failed:
	device_del(dev);
device_add_failed:
wakeup_init_failed:
check_supplies_failed:
dev_set_name_failed:
	put_device(dev);
	return ERR_PTR(rc);
}

这里面主要是创建了struct power_supply,并填充相关的内容。
首先是初始化了一个struct device, 并填充一些成员。
然后依据struct power_supply_config里面的成员对struct power_supply的一些成员进行填充。
然后是设置设备名字,这里是依据struct power_supply_desc里面的成员进行设置,其在其他提供struct power_supply_desc的驱动中已经设置好。
然后就是最重要的两个初始化了两个工作,power_supply_changed_work是当power_supply_changed被调用的时候开始工作。我们在后边分析这两个函数。

// drivers/power/supply/power_supply_core.c

/*
 * Notify that power supply was registered after parent finished the probing.
 *
 * Often power supply is registered from driver's probe function. However
 * calling power_supply_changed() directly from power_supply_register()
 * would lead to execution of get_property() function provided by the driver
 * too early - before the probe ends.
 * Also, registering cooling device from the probe will execute the
 * get_property() function. So register the cooling device after the probe.
 *
 * Avoid that by waiting on parent's mutex.
 */
static void power_supply_deferred_register_work(struct work_struct *work)
{
	struct power_supply *psy = container_of(work, struct power_supply,
						deferred_register_work.work);

	if (psy->dev.parent) {
		while (!mutex_trylock(&psy->dev.parent->mutex)) {
			if (psy->removing)
				return;
			msleep(10);
		}
	}

	psy_register_cooler(psy->dev.parent, psy);
	power_supply_changed(psy);

	if (psy->dev.parent)
		mutex_unlock(&psy->dev.parent->mutex);
}

power_supply_deferred_register_work是在__power_supply_register注册结束时调用,其延时调用power_supply_changed。其中psy_register_cooler还没有进行分析
psy_register_thermal 和 power_supply_create_triggers也还没有具体分析
3、
注册完成power_supply之后,当注册的驱动模块中的psy状态发生变化时就可以调用power_supply_changed告诉power supply core发出相应的通知。
例如在

static irqreturn_t bq2597x_charger_interrupt(int irq, void *dev_id)
{
	struct bq2597x *bq = dev_id;

	bq_info("INT OCCURED\n");

	mutex_lock(&bq->irq_complete);
	bq->irq_waiting = true;
	if (!bq->resume_completed) {
		dev_dbg(bq->dev, "IRQ triggered before device-resume\n");
		if (!bq->irq_disabled) {
			disable_irq_nosync(irq);
			bq->irq_disabled = true;
		}
		bq->irq_waiting = false;
		mutex_unlock(&bq->irq_complete);
		return IRQ_HANDLED;
	}
	bq->irq_waiting = false;
	/* dump some impoartant registers and alarm fault status for debug */
	bq2597x_dump_important_regs(bq);
	bq2597x_check_alarm_status(bq);
	bq2597x_check_fault_status(bq);
	mutex_unlock(&bq->irq_complete);

	/* power_supply_changed(bq->fc2_psy); */

	return IRQ_HANDLED;
}

中,当发生中断时,会更新psy的相关的成员变量,然后调用power_supply_changed告诉power supply core,psy已经发生变化。

// drivers/power/supply/power_supply_core.c

void power_supply_changed(struct power_supply *psy)
{
	unsigned long flags;

	dev_dbg(&psy->dev, "%s\n", __func__);

	spin_lock_irqsave(&psy->changed_lock, flags);
	psy->changed = true;
	pm_stay_awake(&psy->dev);
	spin_unlock_irqrestore(&psy->changed_lock, flags);
	schedule_work(&psy->changed_work);
}
EXPORT_SYMBOL_GPL(power_supply_changed);

由power_supply_changed可知这里面首先是设置是psy->changed = true,这个变量在接下来的工作中会进行判断。然后是调用了schedule_work(&psy->changed_work)即之前注册power_supply时设置的工作power_supply_changed_work。

// drivers/power/supply/power_supply_core.c

static void power_supply_changed_work(struct work_struct *work)
{
	unsigned long flags;
	struct power_supply *psy = container_of(work, struct power_supply,
						changed_work);

	dev_dbg(&psy->dev, "%s\n", __func__);

	spin_lock_irqsave(&psy->changed_lock, flags);
	/*
	 * Check 'changed' here to avoid issues due to race between
	 * power_supply_changed() and this routine. In worst case
	 * power_supply_changed() can be called again just before we take above
	 * lock. During the first call of this routine we will mark 'changed' as
	 * false and it will stay false for the next call as well.
	 */
	if (likely(psy->changed)) {
		psy->changed = false;
		spin_unlock_irqrestore(&psy->changed_lock, flags);
		class_for_each_device(power_supply_class, NULL, psy,
				      __power_supply_changed_work);
		power_supply_update_leds(psy);
		atomic_notifier_call_chain(&power_supply_notifier,
				PSY_EVENT_PROP_CHANGED, psy);
		kobject_uevent(&psy->dev.kobj, KOBJ_CHANGE);
		spin_lock_irqsave(&psy->changed_lock, flags);
	}

	/*
	 * Hold the wakeup_source until all events are processed.
	 * power_supply_changed() might have called again and have set 'changed'
	 * to true.
	 */
	if (likely(!psy->changed))
		pm_relax(&psy->dev);
	spin_unlock_irqrestore(&psy->changed_lock, flags);
}

这里面改主要做了4件事。
1)、__power_supply_changed_work:如果该PSY是其他PSY的供电源,调用这些PSY的external_power_changed回调函数,通知他们。

// drivers/power/supply/power_supply_core.c

static int __power_supply_changed_work(struct device *dev, void *data)
{
	struct power_supply *psy = data;
	struct power_supply *pst = dev_get_drvdata(dev);

	if (__power_supply_is_supplied_by(psy, pst)) {
		if (pst->desc->external_power_changed)
			pst->desc->external_power_changed(pst);
	}

	return 0;
}

2)、power_supply_update_leds:如果配置了CONFIG_LEDS_TRIGGERS,调用power_supply_update_leds更新该PSY有关的LED状态。这里还没有具体研究
3)、atomic_notifier_call_chain通知所有关心psy的模块,该psy已经发生变化。关系该psy的模块只需要通过如下函数进行注册,同时实现notifier_block 中的回调函数即可,这样回调函数就可以接受到该通知。该函数可以在不同模块中进行多次调用,其notifier_block 都会被添加到power_supply_notifier的相关链表中。

int power_supply_reg_notifier(struct notifier_block *nb)
{
	return atomic_notifier_chain_register(&power_supply_notifier, nb);
}
EXPORT_SYMBOL_GPL(power_supply_reg_notifier);

4、 kobject_uevent:以统一的格式向用户空间发送uevent,通知用户空间。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值