aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/charger-manager.c
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2012-09-21 05:49:37 -0400
committerAnton Vorontsov <anton.vorontsov@linaro.org>2012-09-21 19:32:40 -0400
commit3950c7865cd7c963982a2c94457182b96732f4c9 (patch)
treee5fdab9c3c128362f3ac423d8275dc7b12e7439b /drivers/power/charger-manager.c
parent8fcfe088e21aa0db9d62eaf565757def673efba6 (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.c172
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
26static const char * const default_event_names[] = { 27static 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) */
1228static 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
1237static 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
1250static 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
1259static 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
1220static int charger_manager_probe(struct platform_device *pdev) 1315static 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
1461err_chg_enable: 1625err_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 }
1462err_extcon: 1634err_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