diff options
Diffstat (limited to 'drivers/staging/greybus/power_supply.c')
-rw-r--r-- | drivers/staging/greybus/power_supply.c | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/staging/greybus/power_supply.c b/drivers/staging/greybus/power_supply.c index 578d38b25d71..68dd3d2f7585 100644 --- a/drivers/staging/greybus/power_supply.c +++ b/drivers/staging/greybus/power_supply.c @@ -50,6 +50,8 @@ struct gb_power_supply { bool changed; struct gb_power_supply_prop *props; enum power_supply_property *props_raw; + bool pm_acquired; + struct mutex supply_lock; }; struct gb_power_supplies { @@ -75,10 +77,13 @@ struct gb_power_supply_changes { struct gb_power_supply_prop *prop); }; +static void gb_power_supply_state_change(struct gb_power_supply *gbpsy, + struct gb_power_supply_prop *prop); + static const struct gb_power_supply_changes psy_props_changes[] = { { .prop = GB_POWER_SUPPLY_PROP_STATUS, .tolerance_change = 0, - .prop_changed = NULL, + .prop_changed = gb_power_supply_state_change, }, { .prop = GB_POWER_SUPPLY_PROP_TEMP, .tolerance_change = 500, @@ -349,6 +354,40 @@ static void __gb_power_supply_changed(struct gb_power_supply *gbpsy) } #endif +static void gb_power_supply_state_change(struct gb_power_supply *gbpsy, + struct gb_power_supply_prop *prop) +{ + struct gb_connection *connection = get_conn_from_psy(gbpsy); + int ret; + + /* + * Check gbpsy->pm_acquired to make sure only one pair of 'get_sync' + * and 'put_autosuspend' runtime pm call for state property change. + */ + mutex_lock(&gbpsy->supply_lock); + + if ((prop->val == GB_POWER_SUPPLY_STATUS_CHARGING) && + !gbpsy->pm_acquired) { + ret = gb_pm_runtime_get_sync(connection->bundle); + if (ret) + dev_err(&connection->bundle->dev, + "Fail to set wake lock for charging state\n"); + else + gbpsy->pm_acquired = true; + } else { + if (gbpsy->pm_acquired) { + ret = gb_pm_runtime_put_autosuspend(connection->bundle); + if (ret) + dev_err(&connection->bundle->dev, + "Fail to set wake unlock for none charging\n"); + else + gbpsy->pm_acquired = false; + } + } + + mutex_unlock(&gbpsy->supply_lock); +} + static void check_changed(struct gb_power_supply *gbpsy, struct gb_power_supply_prop *prop) { @@ -655,12 +694,17 @@ static int is_cache_valid(struct gb_power_supply *gbpsy) static int gb_power_supply_status_get(struct gb_power_supply *gbpsy) { + struct gb_connection *connection = get_conn_from_psy(gbpsy); int ret = 0; int i; if (is_cache_valid(gbpsy)) return 0; + ret = gb_pm_runtime_get_sync(connection->bundle); + if (ret) + return ret; + for (i = 0; i < gbpsy->properties_count; i++) { ret = __gb_power_supply_property_update(gbpsy, gbpsy->props[i].prop); @@ -671,6 +715,7 @@ static int gb_power_supply_status_get(struct gb_power_supply *gbpsy) if (ret == 0) gbpsy->last_update = jiffies; + gb_pm_runtime_put_autosuspend(connection->bundle); return ret; } @@ -725,9 +770,16 @@ static int gb_power_supply_property_set(struct gb_power_supply *gbpsy, struct gb_power_supply_set_property_request req; int ret; + ret = gb_pm_runtime_get_sync(connection->bundle); + if (ret) + return ret; + prop = get_psy_prop(gbpsy, psp); - if (!prop) - return -EINVAL; + if (!prop) { + ret = -EINVAL; + goto out; + } + req.psy_id = gbpsy->id; req.property = prop->gb_prop; req.prop_val = cpu_to_le32((s32)val); @@ -741,6 +793,7 @@ static int gb_power_supply_property_set(struct gb_power_supply *gbpsy, prop->val = val; out: + gb_pm_runtime_put_autosuspend(connection->bundle); return ret; } @@ -883,6 +936,8 @@ static int gb_power_supply_enable(struct gb_power_supply *gbpsy) if (ret < 0) return ret; + mutex_init(&gbpsy->supply_lock); + ret = gb_power_supply_register(gbpsy); if (ret < 0) return ret; @@ -1067,6 +1122,7 @@ static int gb_power_supply_probe(struct gb_bundle *bundle, if (ret < 0) goto error_connection_disable; + gb_pm_runtime_put_autosuspend(bundle); return 0; error_connection_disable: |