一、结构分析
核心模块是
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,通知用户空间。