power: supply: bq2415x: 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: Sebastian Reichel <sebastian.reichel@collabora.com>
This commit is contained in:
Sebastian Reichel 2018-09-28 10:38:09 +02:00 committed by Sebastian Reichel
parent cef8fe6a38
commit 06215ce999
1 changed files with 49 additions and 70 deletions

View File

@ -1032,54 +1032,6 @@ static int bq2415x_power_supply_get_property(struct power_supply *psy,
return 0; return 0;
} }
static int bq2415x_power_supply_init(struct bq2415x_device *bq)
{
int ret;
int chip;
char revstr[8];
struct power_supply_config psy_cfg = {
.drv_data = bq,
.of_node = bq->dev->of_node,
};
bq->charger_desc.name = bq->name;
bq->charger_desc.type = POWER_SUPPLY_TYPE_USB;
bq->charger_desc.properties = bq2415x_power_supply_props;
bq->charger_desc.num_properties =
ARRAY_SIZE(bq2415x_power_supply_props);
bq->charger_desc.get_property = bq2415x_power_supply_get_property;
ret = bq2415x_detect_chip(bq);
if (ret < 0)
chip = BQUNKNOWN;
else
chip = ret;
ret = bq2415x_detect_revision(bq);
if (ret < 0)
strcpy(revstr, "unknown");
else
sprintf(revstr, "1.%d", ret);
bq->model = kasprintf(GFP_KERNEL,
"chip %s, revision %s, vender code %.3d",
bq2415x_chip_name[chip], revstr,
bq2415x_get_vender_code(bq));
if (!bq->model) {
dev_err(bq->dev, "failed to allocate model name\n");
return -ENOMEM;
}
bq->charger = power_supply_register(bq->dev, &bq->charger_desc,
&psy_cfg);
if (IS_ERR(bq->charger)) {
kfree(bq->model);
return PTR_ERR(bq->charger);
}
return 0;
}
static void bq2415x_power_supply_exit(struct bq2415x_device *bq) static void bq2415x_power_supply_exit(struct bq2415x_device *bq)
{ {
bq->autotimer = 0; bq->autotimer = 0;
@ -1496,7 +1448,7 @@ static DEVICE_ATTR(charge_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
static DEVICE_ATTR(boost_status, S_IRUGO, bq2415x_sysfs_show_status, NULL); static DEVICE_ATTR(boost_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
static DEVICE_ATTR(fault_status, S_IRUGO, bq2415x_sysfs_show_status, NULL); static DEVICE_ATTR(fault_status, S_IRUGO, bq2415x_sysfs_show_status, NULL);
static struct attribute *bq2415x_sysfs_attributes[] = { static struct attribute *bq2415x_sysfs_attrs[] = {
/* /*
* TODO: some (appropriate) of these attrs should be switched to * TODO: some (appropriate) of these attrs should be switched to
* use power supply class props. * use power supply class props.
@ -1525,19 +1477,55 @@ static struct attribute *bq2415x_sysfs_attributes[] = {
NULL, NULL,
}; };
static const struct attribute_group bq2415x_sysfs_attr_group = { ATTRIBUTE_GROUPS(bq2415x_sysfs);
.attrs = bq2415x_sysfs_attributes,
static int bq2415x_power_supply_init(struct bq2415x_device *bq)
{
int ret;
int chip;
char revstr[8];
struct power_supply_config psy_cfg = {
.drv_data = bq,
.of_node = bq->dev->of_node,
.attr_grp = bq2415x_sysfs_groups,
}; };
static int bq2415x_sysfs_init(struct bq2415x_device *bq) bq->charger_desc.name = bq->name;
{ bq->charger_desc.type = POWER_SUPPLY_TYPE_USB;
return sysfs_create_group(&bq->charger->dev.kobj, bq->charger_desc.properties = bq2415x_power_supply_props;
&bq2415x_sysfs_attr_group); bq->charger_desc.num_properties =
ARRAY_SIZE(bq2415x_power_supply_props);
bq->charger_desc.get_property = bq2415x_power_supply_get_property;
ret = bq2415x_detect_chip(bq);
if (ret < 0)
chip = BQUNKNOWN;
else
chip = ret;
ret = bq2415x_detect_revision(bq);
if (ret < 0)
strcpy(revstr, "unknown");
else
sprintf(revstr, "1.%d", ret);
bq->model = kasprintf(GFP_KERNEL,
"chip %s, revision %s, vender code %.3d",
bq2415x_chip_name[chip], revstr,
bq2415x_get_vender_code(bq));
if (!bq->model) {
dev_err(bq->dev, "failed to allocate model name\n");
return -ENOMEM;
} }
static void bq2415x_sysfs_exit(struct bq2415x_device *bq) bq->charger = power_supply_register(bq->dev, &bq->charger_desc,
{ &psy_cfg);
sysfs_remove_group(&bq->charger->dev.kobj, &bq2415x_sysfs_attr_group); if (IS_ERR(bq->charger)) {
kfree(bq->model);
return PTR_ERR(bq->charger);
}
return 0;
} }
/* main bq2415x probe function */ /* main bq2415x probe function */
@ -1651,16 +1639,10 @@ static int bq2415x_probe(struct i2c_client *client,
goto error_2; goto error_2;
} }
ret = bq2415x_sysfs_init(bq);
if (ret) {
dev_err(bq->dev, "failed to create sysfs entries: %d\n", ret);
goto error_3;
}
ret = bq2415x_set_defaults(bq); ret = bq2415x_set_defaults(bq);
if (ret) { if (ret) {
dev_err(bq->dev, "failed to set default values: %d\n", ret); dev_err(bq->dev, "failed to set default values: %d\n", ret);
goto error_4; goto error_3;
} }
if (bq->notify_node || bq->init_data.notify_device) { if (bq->notify_node || bq->init_data.notify_device) {
@ -1668,7 +1650,7 @@ static int bq2415x_probe(struct i2c_client *client,
ret = power_supply_reg_notifier(&bq->nb); ret = power_supply_reg_notifier(&bq->nb);
if (ret) { if (ret) {
dev_err(bq->dev, "failed to reg notifier: %d\n", ret); dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
goto error_4; goto error_3;
} }
bq->automode = 1; bq->automode = 1;
@ -1707,8 +1689,6 @@ static int bq2415x_probe(struct i2c_client *client,
dev_info(bq->dev, "driver registered\n"); dev_info(bq->dev, "driver registered\n");
return 0; return 0;
error_4:
bq2415x_sysfs_exit(bq);
error_3: error_3:
bq2415x_power_supply_exit(bq); bq2415x_power_supply_exit(bq);
error_2: error_2:
@ -1733,7 +1713,6 @@ static int bq2415x_remove(struct i2c_client *client)
power_supply_unreg_notifier(&bq->nb); power_supply_unreg_notifier(&bq->nb);
of_node_put(bq->notify_node); of_node_put(bq->notify_node);
bq2415x_sysfs_exit(bq);
bq2415x_power_supply_exit(bq); bq2415x_power_supply_exit(bq);
bq2415x_reset_chip(bq); bq2415x_reset_chip(bq);