diff options
author | Chanwoo Choi <cw00.choi@samsung.com> | 2012-09-21 05:49:37 -0400 |
---|---|---|
committer | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-09-21 19:32:40 -0400 |
commit | 3950c7865cd7c963982a2c94457182b96732f4c9 (patch) | |
tree | e5fdab9c3c128362f3ac423d8275dc7b12e7439b /drivers/power/charger-manager.c | |
parent | 8fcfe088e21aa0db9d62eaf565757def673efba6 (diff) |
charger-manager: Add support sysfs entry for charger
This patch add support sysfs entry for each charger(regulator).
Charger-manager use one or more chargers for charging battery but some
charger isn't necessary on specific scenario. So, if some charger isn't
needed, can disable specific charger through 'externally_control' entry
while system is on state and confirm the information(name, state) of
charger.
The list of added sysfs entry
- /sys/class/power_supply/battery/chargers/charger.[index]/name
show name of charger(regulator)
- /sys/class/power_supply/battery/chargers/charger.[index]/state
show either enabled or disabled state of charger
- /sys/class/power_supply/battery/chargers/charger.[index]/externally_control
If 'externally_control' of specific charger is 1, Charger-manager cannot
enable regulator for charging when charger cable is attached and charger
must be maintained with disabled state. If 'externally_control' is zero,
Charger-manager usually can control to enable/disable regulator.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Diffstat (limited to 'drivers/power/charger-manager.c')
-rw-r--r-- | drivers/power/charger-manager.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index e92ec55ced91..92dfa5c64876 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/power/charger-manager.h> | 23 | #include <linux/power/charger-manager.h> |
24 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
25 | #include <linux/sysfs.h> | ||
25 | 26 | ||
26 | static const char * const default_event_names[] = { | 27 | static const char * const default_event_names[] = { |
27 | [CM_EVENT_UNKNOWN] = "Unknown", | 28 | [CM_EVENT_UNKNOWN] = "Unknown", |
@@ -332,6 +333,9 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
332 | cm->charging_end_time = 0; | 333 | cm->charging_end_time = 0; |
333 | 334 | ||
334 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 335 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
336 | if (desc->charger_regulators[i].externally_control) | ||
337 | continue; | ||
338 | |||
335 | err = regulator_enable(desc->charger_regulators[i].consumer); | 339 | err = regulator_enable(desc->charger_regulators[i].consumer); |
336 | if (err < 0) { | 340 | if (err < 0) { |
337 | dev_warn(cm->dev, | 341 | dev_warn(cm->dev, |
@@ -348,6 +352,9 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) | |||
348 | cm->charging_end_time = ktime_to_ms(ktime_get()); | 352 | cm->charging_end_time = ktime_to_ms(ktime_get()); |
349 | 353 | ||
350 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 354 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
355 | if (desc->charger_regulators[i].externally_control) | ||
356 | continue; | ||
357 | |||
351 | err = regulator_disable(desc->charger_regulators[i].consumer); | 358 | err = regulator_disable(desc->charger_regulators[i].consumer); |
352 | if (err < 0) { | 359 | if (err < 0) { |
353 | dev_warn(cm->dev, | 360 | dev_warn(cm->dev, |
@@ -1217,12 +1224,101 @@ static int charger_extcon_init(struct charger_manager *cm, | |||
1217 | return ret; | 1224 | return ret; |
1218 | } | 1225 | } |
1219 | 1226 | ||
1227 | /* help function of sysfs node to control charger(regulator) */ | ||
1228 | static ssize_t charger_name_show(struct device *dev, | ||
1229 | struct device_attribute *attr, char *buf) | ||
1230 | { | ||
1231 | struct charger_regulator *charger | ||
1232 | = container_of(attr, struct charger_regulator, attr_name); | ||
1233 | |||
1234 | return sprintf(buf, "%s\n", charger->regulator_name); | ||
1235 | } | ||
1236 | |||
1237 | static ssize_t charger_state_show(struct device *dev, | ||
1238 | struct device_attribute *attr, char *buf) | ||
1239 | { | ||
1240 | struct charger_regulator *charger | ||
1241 | = container_of(attr, struct charger_regulator, attr_state); | ||
1242 | int state = 0; | ||
1243 | |||
1244 | if (!charger->externally_control) | ||
1245 | state = regulator_is_enabled(charger->consumer); | ||
1246 | |||
1247 | return sprintf(buf, "%s\n", state ? "enabled" : "disabled"); | ||
1248 | } | ||
1249 | |||
1250 | static ssize_t charger_externally_control_show(struct device *dev, | ||
1251 | struct device_attribute *attr, char *buf) | ||
1252 | { | ||
1253 | struct charger_regulator *charger = container_of(attr, | ||
1254 | struct charger_regulator, attr_externally_control); | ||
1255 | |||
1256 | return sprintf(buf, "%d\n", charger->externally_control); | ||
1257 | } | ||
1258 | |||
1259 | static ssize_t charger_externally_control_store(struct device *dev, | ||
1260 | struct device_attribute *attr, const char *buf, | ||
1261 | size_t count) | ||
1262 | { | ||
1263 | struct charger_regulator *charger | ||
1264 | = container_of(attr, struct charger_regulator, | ||
1265 | attr_externally_control); | ||
1266 | struct charger_manager *cm = charger->cm; | ||
1267 | struct charger_desc *desc = cm->desc; | ||
1268 | int i; | ||
1269 | int ret; | ||
1270 | int externally_control; | ||
1271 | int chargers_externally_control = 1; | ||
1272 | |||
1273 | ret = sscanf(buf, "%d", &externally_control); | ||
1274 | if (ret == 0) { | ||
1275 | ret = -EINVAL; | ||
1276 | return ret; | ||
1277 | } | ||
1278 | |||
1279 | if (!externally_control) { | ||
1280 | charger->externally_control = 0; | ||
1281 | return count; | ||
1282 | } | ||
1283 | |||
1284 | for (i = 0; i < desc->num_charger_regulators; i++) { | ||
1285 | if (&desc->charger_regulators[i] != charger && | ||
1286 | !desc->charger_regulators[i].externally_control) { | ||
1287 | /* | ||
1288 | * At least, one charger is controlled by | ||
1289 | * charger-manager | ||
1290 | */ | ||
1291 | chargers_externally_control = 0; | ||
1292 | break; | ||
1293 | } | ||
1294 | } | ||
1295 | |||
1296 | if (!chargers_externally_control) { | ||
1297 | if (cm->charger_enabled) { | ||
1298 | try_charger_enable(charger->cm, false); | ||
1299 | charger->externally_control = externally_control; | ||
1300 | try_charger_enable(charger->cm, true); | ||
1301 | } else { | ||
1302 | charger->externally_control = externally_control; | ||
1303 | } | ||
1304 | } else { | ||
1305 | dev_warn(cm->dev, | ||
1306 | "'%s' regulator should be controlled " | ||
1307 | "in charger-manager because charger-manager " | ||
1308 | "must need at least one charger for charging\n", | ||
1309 | charger->regulator_name); | ||
1310 | } | ||
1311 | |||
1312 | return count; | ||
1313 | } | ||
1314 | |||
1220 | static int charger_manager_probe(struct platform_device *pdev) | 1315 | static int charger_manager_probe(struct platform_device *pdev) |
1221 | { | 1316 | { |
1222 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); | 1317 | struct charger_desc *desc = dev_get_platdata(&pdev->dev); |
1223 | struct charger_manager *cm; | 1318 | struct charger_manager *cm; |
1224 | int ret = 0, i = 0; | 1319 | int ret = 0, i = 0; |
1225 | int j = 0; | 1320 | int j = 0; |
1321 | int chargers_externally_control = 1; | ||
1226 | union power_supply_propval val; | 1322 | union power_supply_propval val; |
1227 | 1323 | ||
1228 | if (g_desc && !rtc_dev && g_desc->rtc_name) { | 1324 | if (g_desc && !rtc_dev && g_desc->rtc_name) { |
@@ -1412,6 +1508,8 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1412 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 1508 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1413 | struct charger_regulator *charger | 1509 | struct charger_regulator *charger |
1414 | = &desc->charger_regulators[i]; | 1510 | = &desc->charger_regulators[i]; |
1511 | char buf[11]; | ||
1512 | char *str; | ||
1415 | 1513 | ||
1416 | charger->consumer = regulator_get(&pdev->dev, | 1514 | charger->consumer = regulator_get(&pdev->dev, |
1417 | charger->regulator_name); | 1515 | charger->regulator_name); |
@@ -1421,6 +1519,7 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1421 | ret = -EINVAL; | 1519 | ret = -EINVAL; |
1422 | goto err_chg_get; | 1520 | goto err_chg_get; |
1423 | } | 1521 | } |
1522 | charger->cm = cm; | ||
1424 | 1523 | ||
1425 | for (j = 0 ; j < charger->num_cables ; j++) { | 1524 | for (j = 0 ; j < charger->num_cables ; j++) { |
1426 | struct charger_cable *cable = &charger->cables[j]; | 1525 | struct charger_cable *cable = &charger->cables[j]; |
@@ -1434,6 +1533,71 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1434 | cable->charger = charger; | 1533 | cable->charger = charger; |
1435 | cable->cm = cm; | 1534 | cable->cm = cm; |
1436 | } | 1535 | } |
1536 | |||
1537 | /* Create sysfs entry to control charger(regulator) */ | ||
1538 | snprintf(buf, 10, "charger.%d", i); | ||
1539 | str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL); | ||
1540 | if (!str) { | ||
1541 | for (i--; i >= 0; i--) { | ||
1542 | charger = &desc->charger_regulators[i]; | ||
1543 | kfree(charger->attr_g.name); | ||
1544 | } | ||
1545 | ret = -ENOMEM; | ||
1546 | |||
1547 | goto err_extcon; | ||
1548 | } | ||
1549 | strcpy(str, buf); | ||
1550 | |||
1551 | charger->attrs[0] = &charger->attr_name.attr; | ||
1552 | charger->attrs[1] = &charger->attr_state.attr; | ||
1553 | charger->attrs[2] = &charger->attr_externally_control.attr; | ||
1554 | charger->attrs[3] = NULL; | ||
1555 | charger->attr_g.name = str; | ||
1556 | charger->attr_g.attrs = charger->attrs; | ||
1557 | |||
1558 | sysfs_attr_init(&charger->attr_name.attr); | ||
1559 | charger->attr_name.attr.name = "name"; | ||
1560 | charger->attr_name.attr.mode = 0444; | ||
1561 | charger->attr_name.show = charger_name_show; | ||
1562 | |||
1563 | sysfs_attr_init(&charger->attr_state.attr); | ||
1564 | charger->attr_state.attr.name = "state"; | ||
1565 | charger->attr_state.attr.mode = 0444; | ||
1566 | charger->attr_state.show = charger_state_show; | ||
1567 | |||
1568 | sysfs_attr_init(&charger->attr_externally_control.attr); | ||
1569 | charger->attr_externally_control.attr.name | ||
1570 | = "externally_control"; | ||
1571 | charger->attr_externally_control.attr.mode = 0644; | ||
1572 | charger->attr_externally_control.show | ||
1573 | = charger_externally_control_show; | ||
1574 | charger->attr_externally_control.store | ||
1575 | = charger_externally_control_store; | ||
1576 | |||
1577 | if (!desc->charger_regulators[i].externally_control || | ||
1578 | !chargers_externally_control) { | ||
1579 | chargers_externally_control = 0; | ||
1580 | } | ||
1581 | dev_info(&pdev->dev, "'%s' regulator's externally_control" | ||
1582 | "is %d\n", charger->regulator_name, | ||
1583 | charger->externally_control); | ||
1584 | |||
1585 | ret = sysfs_create_group(&cm->charger_psy.dev->kobj, | ||
1586 | &charger->attr_g); | ||
1587 | if (ret < 0) { | ||
1588 | dev_info(&pdev->dev, "Cannot create sysfs entry" | ||
1589 | "of %s regulator\n", | ||
1590 | charger->regulator_name); | ||
1591 | } | ||
1592 | } | ||
1593 | |||
1594 | if (chargers_externally_control) { | ||
1595 | dev_err(&pdev->dev, "Cannot register regulator because " | ||
1596 | "charger-manager must need at least " | ||
1597 | "one charger for charging battery\n"); | ||
1598 | |||
1599 | ret = -EINVAL; | ||
1600 | goto err_chg_enable; | ||
1437 | } | 1601 | } |
1438 | 1602 | ||
1439 | ret = try_charger_enable(cm, true); | 1603 | ret = try_charger_enable(cm, true); |
@@ -1459,6 +1623,14 @@ static int charger_manager_probe(struct platform_device *pdev) | |||
1459 | return 0; | 1623 | return 0; |
1460 | 1624 | ||
1461 | err_chg_enable: | 1625 | err_chg_enable: |
1626 | for (i = 0; i < desc->num_charger_regulators; i++) { | ||
1627 | struct charger_regulator *charger; | ||
1628 | |||
1629 | charger = &desc->charger_regulators[i]; | ||
1630 | sysfs_remove_group(&cm->charger_psy.dev->kobj, | ||
1631 | &charger->attr_g); | ||
1632 | kfree(charger->attr_g.name); | ||
1633 | } | ||
1462 | err_extcon: | 1634 | err_extcon: |
1463 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { | 1635 | for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
1464 | struct charger_regulator *charger | 1636 | struct charger_regulator *charger |