Commit 157ba1bb authored by Sebastian Reichel's avatar Sebastian Reichel Committed by Sebastian Reichel
Browse files

power: supply: charger-manager: fix race-condition in sysfs registration



This registers custom sysfs properties using the native functionality
of the power-supply framework, which cleans up the code a bit and
fixes a race-condition. Before this patch the sysfs attributes were
not properly registered to udev.

Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parent efcca6bd
Loading
Loading
Loading
Loading
+22 −29
Original line number Diff line number Diff line
@@ -1351,7 +1351,7 @@ static ssize_t charger_externally_control_store(struct device *dev,
}

/**
 * charger_manager_register_sysfs - Register sysfs entry for each charger
 * charger_manager_prepare_sysfs - Prepare sysfs entry for each charger
 * @cm: the Charger Manager representing the battery.
 *
 * This function add sysfs entry for charger(regulator) to control charger from
@@ -1363,13 +1363,12 @@ static ssize_t charger_externally_control_store(struct device *dev,
 * externally_control, this charger isn't controlled from charger-manager and
 * always stay off state of regulator.
 */
static int charger_manager_register_sysfs(struct charger_manager *cm)
static int charger_manager_prepare_sysfs(struct charger_manager *cm)
{
	struct charger_desc *desc = cm->desc;
	struct charger_regulator *charger;
	int chargers_externally_control = 1;
	char *name;
	int ret;
	int i;

	/* Create sysfs entry to control charger(regulator) */
@@ -1384,8 +1383,10 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
		charger->attrs[1] = &charger->attr_state.attr;
		charger->attrs[2] = &charger->attr_externally_control.attr;
		charger->attrs[3] = NULL;
		charger->attr_g.name = name;
		charger->attr_g.attrs = charger->attrs;

		charger->attr_grp.name = name;
		charger->attr_grp.attrs = charger->attrs;
		desc->sysfs_groups[i] = &charger->attr_grp;

		sysfs_attr_init(&charger->attr_name.attr);
		charger->attr_name.attr.name = "name";
@@ -1412,14 +1413,6 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)

		dev_info(cm->dev, "'%s' regulator's externally_control is %d\n",
			 charger->regulator_name, charger->externally_control);

		ret = sysfs_create_group(&cm->charger_psy->dev.kobj,
					&charger->attr_g);
		if (ret < 0) {
			dev_err(cm->dev, "Cannot create sysfs entry of %s regulator\n",
				charger->regulator_name);
			return ret;
		}
	}

	if (chargers_externally_control) {
@@ -1560,6 +1553,13 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)

		desc->charger_regulators = chg_regs;

		desc->sysfs_groups = devm_kcalloc(dev,
					desc->num_charger_regulators + 1,
					sizeof(*desc->sysfs_groups),
					GFP_KERNEL);
		if (!desc->sysfs_groups)
			return ERR_PTR(-ENOMEM);

		for_each_child_of_node(np, child) {
			struct charger_cable *cables;
			struct device_node *_child;
@@ -1762,6 +1762,15 @@ static int charger_manager_probe(struct platform_device *pdev)

	INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk);

	/* Register sysfs entry for charger(regulator) */
	ret = charger_manager_prepare_sysfs(cm);
	if (ret < 0) {
		dev_err(&pdev->dev,
			"Cannot prepare sysfs entry of regulators\n");
		return ret;
	}
	psy_cfg.attr_grp = desc->sysfs_groups;

	cm->charger_psy = power_supply_register(&pdev->dev,
						&cm->charger_psy_desc,
						&psy_cfg);
@@ -1778,14 +1787,6 @@ static int charger_manager_probe(struct platform_device *pdev)
		goto err_reg_extcon;
	}

	/* Register sysfs entry for charger(regulator) */
	ret = charger_manager_register_sysfs(cm);
	if (ret < 0) {
		dev_err(&pdev->dev,
			"Cannot initialize sysfs entry of regulator\n");
		goto err_reg_sysfs;
	}

	/* Add to the list */
	mutex_lock(&cm_list_mtx);
	list_add(&cm->entry, &cm_list);
@@ -1809,14 +1810,6 @@ static int charger_manager_probe(struct platform_device *pdev)

	return 0;

err_reg_sysfs:
	for (i = 0; i < desc->num_charger_regulators; i++) {
		struct charger_regulator *charger;

		charger = &desc->charger_regulators[i];
		sysfs_remove_group(&cm->charger_psy->dev.kobj,
				&charger->attr_g);
	}
err_reg_extcon:
	for (i = 0; i < desc->num_charger_regulators; i++) {
		struct charger_regulator *charger;
+2 −1
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ struct charger_regulator {
	struct charger_cable *cables;
	int num_cables;

	struct attribute_group attr_g;
	struct attribute_group attr_grp;
	struct device_attribute attr_name;
	struct device_attribute attr_state;
	struct device_attribute attr_externally_control;
@@ -186,6 +186,7 @@ struct charger_desc {

	int num_charger_regulators;
	struct charger_regulator *charger_regulators;
	const struct attribute_group **sysfs_groups;

	const char *psy_fuel_gauge;