aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/charger-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/charger-manager.c')
-rw-r--r--drivers/power/charger-manager.c310
1 files changed, 184 insertions, 126 deletions
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 6ba047f5ac2c..8acc3f8d303c 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -669,15 +669,21 @@ static void _setup_polling(struct work_struct *work)
669 WARN(cm_wq == NULL, "charger-manager: workqueue not initialized" 669 WARN(cm_wq == NULL, "charger-manager: workqueue not initialized"
670 ". try it later. %s\n", __func__); 670 ". try it later. %s\n", __func__);
671 671
672 /*
673 * Use mod_delayed_work() iff the next polling interval should
674 * occur before the currently scheduled one. If @cm_monitor_work
675 * isn't active, the end result is the same, so no need to worry
676 * about stale @next_polling.
677 */
672 _next_polling = jiffies + polling_jiffy; 678 _next_polling = jiffies + polling_jiffy;
673 679
674 if (!delayed_work_pending(&cm_monitor_work) || 680 if (time_before(_next_polling, next_polling)) {
675 (delayed_work_pending(&cm_monitor_work) &&
676 time_after(next_polling, _next_polling))) {
677 next_polling = jiffies + polling_jiffy;
678 mod_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy); 681 mod_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy);
682 next_polling = _next_polling;
683 } else {
684 if (queue_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy))
685 next_polling = _next_polling;
679 } 686 }
680
681out: 687out:
682 mutex_unlock(&cm_list_mtx); 688 mutex_unlock(&cm_list_mtx);
683} 689}
@@ -751,8 +757,7 @@ static void misc_event_handler(struct charger_manager *cm,
751 if (cm_suspended) 757 if (cm_suspended)
752 device_set_wakeup_capable(cm->dev, true); 758 device_set_wakeup_capable(cm->dev, true);
753 759
754 if (!delayed_work_pending(&cm_monitor_work) && 760 if (is_polling_required(cm) && cm->desc->polling_interval_ms)
755 is_polling_required(cm) && cm->desc->polling_interval_ms)
756 schedule_work(&setup_polling); 761 schedule_work(&setup_polling);
757 uevent_notify(cm, default_event_names[type]); 762 uevent_notify(cm, default_event_names[type]);
758} 763}
@@ -1170,8 +1175,7 @@ static int charger_extcon_notifier(struct notifier_block *self,
1170 * when charger cable is attached. 1175 * when charger cable is attached.
1171 */ 1176 */
1172 if (cable->attached && is_polling_required(cable->cm)) { 1177 if (cable->attached && is_polling_required(cable->cm)) {
1173 if (work_pending(&setup_polling)) 1178 cancel_work_sync(&setup_polling);
1174 cancel_work_sync(&setup_polling);
1175 schedule_work(&setup_polling); 1179 schedule_work(&setup_polling);
1176 } 1180 }
1177 1181
@@ -1215,6 +1219,55 @@ static int charger_extcon_init(struct charger_manager *cm,
1215 return ret; 1219 return ret;
1216} 1220}
1217 1221
1222/**
1223 * charger_manager_register_extcon - Register extcon device to recevie state
1224 * of charger cable.
1225 * @cm: the Charger Manager representing the battery.
1226 *
1227 * This function support EXTCON(External Connector) subsystem to detect the
1228 * state of charger cables for enabling or disabling charger(regulator) and
1229 * select the charger cable for charging among a number of external cable
1230 * according to policy of H/W board.
1231 */
1232static int charger_manager_register_extcon(struct charger_manager *cm)
1233{
1234 struct charger_desc *desc = cm->desc;
1235 struct charger_regulator *charger;
1236 int ret = 0;
1237 int i;
1238 int j;
1239
1240 for (i = 0; i < desc->num_charger_regulators; i++) {
1241 charger = &desc->charger_regulators[i];
1242
1243 charger->consumer = regulator_get(cm->dev,
1244 charger->regulator_name);
1245 if (charger->consumer == NULL) {
1246 dev_err(cm->dev, "Cannot find charger(%s)n",
1247 charger->regulator_name);
1248 ret = -EINVAL;
1249 goto err;
1250 }
1251 charger->cm = cm;
1252
1253 for (j = 0; j < charger->num_cables; j++) {
1254 struct charger_cable *cable = &charger->cables[j];
1255
1256 ret = charger_extcon_init(cm, cable);
1257 if (ret < 0) {
1258 dev_err(cm->dev, "Cannot initialize charger(%s)n",
1259 charger->regulator_name);
1260 goto err;
1261 }
1262 cable->charger = charger;
1263 cable->cm = cm;
1264 }
1265 }
1266
1267err:
1268 return ret;
1269}
1270
1218/* help function of sysfs node to control charger(regulator) */ 1271/* help function of sysfs node to control charger(regulator) */
1219static ssize_t charger_name_show(struct device *dev, 1272static ssize_t charger_name_show(struct device *dev,
1220 struct device_attribute *attr, char *buf) 1273 struct device_attribute *attr, char *buf)
@@ -1274,7 +1327,7 @@ static ssize_t charger_externally_control_store(struct device *dev,
1274 1327
1275 for (i = 0; i < desc->num_charger_regulators; i++) { 1328 for (i = 0; i < desc->num_charger_regulators; i++) {
1276 if (&desc->charger_regulators[i] != charger && 1329 if (&desc->charger_regulators[i] != charger &&
1277 !desc->charger_regulators[i].externally_control) { 1330 !desc->charger_regulators[i].externally_control) {
1278 /* 1331 /*
1279 * At least, one charger is controlled by 1332 * At least, one charger is controlled by
1280 * charger-manager 1333 * charger-manager
@@ -1303,13 +1356,107 @@ static ssize_t charger_externally_control_store(struct device *dev,
1303 return count; 1356 return count;
1304} 1357}
1305 1358
1359/**
1360 * charger_manager_register_sysfs - Register sysfs entry for each charger
1361 * @cm: the Charger Manager representing the battery.
1362 *
1363 * This function add sysfs entry for charger(regulator) to control charger from
1364 * user-space. If some development board use one more chargers for charging
1365 * but only need one charger on specific case which is dependent on user
1366 * scenario or hardware restrictions, the user enter 1 or 0(zero) to '/sys/
1367 * class/power_supply/battery/charger.[index]/externally_control'. For example,
1368 * if user enter 1 to 'sys/class/power_supply/battery/charger.[index]/
1369 * externally_control, this charger isn't controlled from charger-manager and
1370 * always stay off state of regulator.
1371 */
1372static int charger_manager_register_sysfs(struct charger_manager *cm)
1373{
1374 struct charger_desc *desc = cm->desc;
1375 struct charger_regulator *charger;
1376 int chargers_externally_control = 1;
1377 char buf[11];
1378 char *str;
1379 int ret = 0;
1380 int i;
1381
1382 /* Create sysfs entry to control charger(regulator) */
1383 for (i = 0; i < desc->num_charger_regulators; i++) {
1384 charger = &desc->charger_regulators[i];
1385
1386 snprintf(buf, 10, "charger.%d", i);
1387 str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
1388 if (!str) {
1389 dev_err(cm->dev, "Cannot allocate memory: %s\n",
1390 charger->regulator_name);
1391 ret = -ENOMEM;
1392 goto err;
1393 }
1394 strcpy(str, buf);
1395
1396 charger->attrs[0] = &charger->attr_name.attr;
1397 charger->attrs[1] = &charger->attr_state.attr;
1398 charger->attrs[2] = &charger->attr_externally_control.attr;
1399 charger->attrs[3] = NULL;
1400 charger->attr_g.name = str;
1401 charger->attr_g.attrs = charger->attrs;
1402
1403 sysfs_attr_init(&charger->attr_name.attr);
1404 charger->attr_name.attr.name = "name";
1405 charger->attr_name.attr.mode = 0444;
1406 charger->attr_name.show = charger_name_show;
1407
1408 sysfs_attr_init(&charger->attr_state.attr);
1409 charger->attr_state.attr.name = "state";
1410 charger->attr_state.attr.mode = 0444;
1411 charger->attr_state.show = charger_state_show;
1412
1413 sysfs_attr_init(&charger->attr_externally_control.attr);
1414 charger->attr_externally_control.attr.name
1415 = "externally_control";
1416 charger->attr_externally_control.attr.mode = 0644;
1417 charger->attr_externally_control.show
1418 = charger_externally_control_show;
1419 charger->attr_externally_control.store
1420 = charger_externally_control_store;
1421
1422 if (!desc->charger_regulators[i].externally_control ||
1423 !chargers_externally_control)
1424 chargers_externally_control = 0;
1425
1426 dev_info(cm->dev, "'%s' regulator's externally_control"
1427 "is %d\n", charger->regulator_name,
1428 charger->externally_control);
1429
1430 ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
1431 &charger->attr_g);
1432 if (ret < 0) {
1433 dev_err(cm->dev, "Cannot create sysfs entry"
1434 "of %s regulator\n",
1435 charger->regulator_name);
1436 ret = -EINVAL;
1437 goto err;
1438 }
1439 }
1440
1441 if (chargers_externally_control) {
1442 dev_err(cm->dev, "Cannot register regulator because "
1443 "charger-manager must need at least "
1444 "one charger for charging battery\n");
1445
1446 ret = -EINVAL;
1447 goto err;
1448 }
1449
1450err:
1451 return ret;
1452}
1453
1306static int charger_manager_probe(struct platform_device *pdev) 1454static int charger_manager_probe(struct platform_device *pdev)
1307{ 1455{
1308 struct charger_desc *desc = dev_get_platdata(&pdev->dev); 1456 struct charger_desc *desc = dev_get_platdata(&pdev->dev);
1309 struct charger_manager *cm; 1457 struct charger_manager *cm;
1310 int ret = 0, i = 0; 1458 int ret = 0, i = 0;
1311 int j = 0; 1459 int j = 0;
1312 int chargers_externally_control = 1;
1313 union power_supply_propval val; 1460 union power_supply_propval val;
1314 1461
1315 if (g_desc && !rtc_dev && g_desc->rtc_name) { 1462 if (g_desc && !rtc_dev && g_desc->rtc_name) {
@@ -1440,11 +1587,10 @@ static int charger_manager_probe(struct platform_device *pdev)
1440 1587
1441 memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default)); 1588 memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default));
1442 1589
1443 if (!desc->psy_name) { 1590 if (!desc->psy_name)
1444 strncpy(cm->psy_name_buf, psy_default.name, PSY_NAME_MAX); 1591 strncpy(cm->psy_name_buf, psy_default.name, PSY_NAME_MAX);
1445 } else { 1592 else
1446 strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX); 1593 strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX);
1447 }
1448 cm->charger_psy.name = cm->psy_name_buf; 1594 cm->charger_psy.name = cm->psy_name_buf;
1449 1595
1450 /* Allocate for psy properties because they may vary */ 1596 /* Allocate for psy properties because they may vary */
@@ -1496,105 +1642,19 @@ static int charger_manager_probe(struct platform_device *pdev)
1496 goto err_register; 1642 goto err_register;
1497 } 1643 }
1498 1644
1499 for (i = 0 ; i < desc->num_charger_regulators ; i++) { 1645 /* Register extcon device for charger cable */
1500 struct charger_regulator *charger 1646 ret = charger_manager_register_extcon(cm);
1501 = &desc->charger_regulators[i]; 1647 if (ret < 0) {
1502 char buf[11]; 1648 dev_err(&pdev->dev, "Cannot initialize extcon device\n");
1503 char *str; 1649 goto err_reg_extcon;
1504
1505 charger->consumer = regulator_get(&pdev->dev,
1506 charger->regulator_name);
1507 if (charger->consumer == NULL) {
1508 dev_err(&pdev->dev, "Cannot find charger(%s)n",
1509 charger->regulator_name);
1510 ret = -EINVAL;
1511 goto err_chg_get;
1512 }
1513 charger->cm = cm;
1514
1515 for (j = 0 ; j < charger->num_cables ; j++) {
1516 struct charger_cable *cable = &charger->cables[j];
1517
1518 ret = charger_extcon_init(cm, cable);
1519 if (ret < 0) {
1520 dev_err(&pdev->dev, "Cannot find charger(%s)n",
1521 charger->regulator_name);
1522 goto err_extcon;
1523 }
1524 cable->charger = charger;
1525 cable->cm = cm;
1526 }
1527
1528 /* Create sysfs entry to control charger(regulator) */
1529 snprintf(buf, 10, "charger.%d", i);
1530 str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
1531 if (!str) {
1532 for (i--; i >= 0; i--) {
1533 charger = &desc->charger_regulators[i];
1534 kfree(charger->attr_g.name);
1535 }
1536 ret = -ENOMEM;
1537
1538 goto err_extcon;
1539 }
1540 strcpy(str, buf);
1541
1542 charger->attrs[0] = &charger->attr_name.attr;
1543 charger->attrs[1] = &charger->attr_state.attr;
1544 charger->attrs[2] = &charger->attr_externally_control.attr;
1545 charger->attrs[3] = NULL;
1546 charger->attr_g.name = str;
1547 charger->attr_g.attrs = charger->attrs;
1548
1549 sysfs_attr_init(&charger->attr_name.attr);
1550 charger->attr_name.attr.name = "name";
1551 charger->attr_name.attr.mode = 0444;
1552 charger->attr_name.show = charger_name_show;
1553
1554 sysfs_attr_init(&charger->attr_state.attr);
1555 charger->attr_state.attr.name = "state";
1556 charger->attr_state.attr.mode = 0444;
1557 charger->attr_state.show = charger_state_show;
1558
1559 sysfs_attr_init(&charger->attr_externally_control.attr);
1560 charger->attr_externally_control.attr.name
1561 = "externally_control";
1562 charger->attr_externally_control.attr.mode = 0644;
1563 charger->attr_externally_control.show
1564 = charger_externally_control_show;
1565 charger->attr_externally_control.store
1566 = charger_externally_control_store;
1567
1568 if (!desc->charger_regulators[i].externally_control ||
1569 !chargers_externally_control) {
1570 chargers_externally_control = 0;
1571 }
1572 dev_info(&pdev->dev, "'%s' regulator's externally_control"
1573 "is %d\n", charger->regulator_name,
1574 charger->externally_control);
1575
1576 ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
1577 &charger->attr_g);
1578 if (ret < 0) {
1579 dev_info(&pdev->dev, "Cannot create sysfs entry"
1580 "of %s regulator\n",
1581 charger->regulator_name);
1582 }
1583 }
1584
1585 if (chargers_externally_control) {
1586 dev_err(&pdev->dev, "Cannot register regulator because "
1587 "charger-manager must need at least "
1588 "one charger for charging battery\n");
1589
1590 ret = -EINVAL;
1591 goto err_chg_enable;
1592 } 1650 }
1593 1651
1594 ret = try_charger_enable(cm, true); 1652 /* Register sysfs entry for charger(regulator) */
1595 if (ret) { 1653 ret = charger_manager_register_sysfs(cm);
1596 dev_err(&pdev->dev, "Cannot enable charger regulators\n"); 1654 if (ret < 0) {
1597 goto err_chg_enable; 1655 dev_err(&pdev->dev,
1656 "Cannot initialize sysfs entry of regulator\n");
1657 goto err_reg_sysfs;
1598 } 1658 }
1599 1659
1600 /* Add to the list */ 1660 /* Add to the list */
@@ -1613,27 +1673,28 @@ static int charger_manager_probe(struct platform_device *pdev)
1613 1673
1614 return 0; 1674 return 0;
1615 1675
1616err_chg_enable: 1676err_reg_sysfs:
1617 for (i = 0; i < desc->num_charger_regulators; i++) { 1677 for (i = 0; i < desc->num_charger_regulators; i++) {
1618 struct charger_regulator *charger; 1678 struct charger_regulator *charger;
1619 1679
1620 charger = &desc->charger_regulators[i]; 1680 charger = &desc->charger_regulators[i];
1621 sysfs_remove_group(&cm->charger_psy.dev->kobj, 1681 sysfs_remove_group(&cm->charger_psy.dev->kobj,
1622 &charger->attr_g); 1682 &charger->attr_g);
1683
1623 kfree(charger->attr_g.name); 1684 kfree(charger->attr_g.name);
1624 } 1685 }
1625err_extcon: 1686err_reg_extcon:
1626 for (i = 0 ; i < desc->num_charger_regulators ; i++) { 1687 for (i = 0; i < desc->num_charger_regulators; i++) {
1627 struct charger_regulator *charger 1688 struct charger_regulator *charger;
1628 = &desc->charger_regulators[i]; 1689
1629 for (j = 0 ; j < charger->num_cables ; j++) { 1690 charger = &desc->charger_regulators[i];
1691 for (j = 0; j < charger->num_cables; j++) {
1630 struct charger_cable *cable = &charger->cables[j]; 1692 struct charger_cable *cable = &charger->cables[j];
1631 extcon_unregister_interest(&cable->extcon_dev); 1693 extcon_unregister_interest(&cable->extcon_dev);
1632 } 1694 }
1633 } 1695
1634err_chg_get:
1635 for (i = 0 ; i < desc->num_charger_regulators ; i++)
1636 regulator_put(desc->charger_regulators[i].consumer); 1696 regulator_put(desc->charger_regulators[i].consumer);
1697 }
1637 1698
1638 power_supply_unregister(&cm->charger_psy); 1699 power_supply_unregister(&cm->charger_psy);
1639err_register: 1700err_register:
@@ -1661,10 +1722,8 @@ static int charger_manager_remove(struct platform_device *pdev)
1661 list_del(&cm->entry); 1722 list_del(&cm->entry);
1662 mutex_unlock(&cm_list_mtx); 1723 mutex_unlock(&cm_list_mtx);
1663 1724
1664 if (work_pending(&setup_polling)) 1725 cancel_work_sync(&setup_polling);
1665 cancel_work_sync(&setup_polling); 1726 cancel_delayed_work_sync(&cm_monitor_work);
1666 if (delayed_work_pending(&cm_monitor_work))
1667 cancel_delayed_work_sync(&cm_monitor_work);
1668 1727
1669 for (i = 0 ; i < desc->num_charger_regulators ; i++) { 1728 for (i = 0 ; i < desc->num_charger_regulators ; i++) {
1670 struct charger_regulator *charger 1729 struct charger_regulator *charger
@@ -1733,8 +1792,7 @@ static int cm_suspend_prepare(struct device *dev)
1733 cm_suspended = true; 1792 cm_suspended = true;
1734 } 1793 }
1735 1794
1736 if (delayed_work_pending(&cm->fullbatt_vchk_work)) 1795 cancel_delayed_work(&cm->fullbatt_vchk_work);
1737 cancel_delayed_work(&cm->fullbatt_vchk_work);
1738 cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm); 1796 cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm);
1739 cm->status_save_batt = is_batt_present(cm); 1797 cm->status_save_batt = is_batt_present(cm);
1740 1798