Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'for-v3.14' of git://git.infradead.org/battery-2.6

Pull battery updates from Dmitry Eremin-Solenikov:
"I'm picking up power supply maintainership from Anton Vorontov. Could
you please pull battery-2.6 git tree changes prepared for the v3.14
release.

Highlights:

- Power supply notifier

- Several drivers gained DT support

- Added Maxim 14577 driver

- Change of maintainer"

* tag 'for-v3.14' of git://git.infradead.org/battery-2.6:
MAINTAINERS: Pick up power supply maintainership
max17042_battery: Add IRQF_ONESHOT flag to use default irq handler
gpio-charger: Support wakeup events
power_supply: Add charger support for Maxim 14577
dt: Binding documentation for isp1704 charger
isp1704_charger: Add DT support
charger-manager: of_cm_parse_desc() should be static
bq2415x_charger: Add DT support
power_supply: Add power_supply_get_by_phandle
bq2415x_charger: Use power_supply notifier for automode
power: reset: Add as3722 power-off driver
mfd: AS3722: Add dt node properties for system power controller
charger-manager: Support deivce tree in charger manager driver
charger-manager: Modify the way of checking battery's temperature
power_supply: Add power_supply notifier

+1043 -132
+11
Documentation/devicetree/bindings/mfd/as3722.txt
··· 112 112 ams,enable-tracking: Enable tracking with SD1, only supported 113 113 by LDO3. 114 114 115 + Power-off: 116 + ========= 117 + AS3722 supports the system power off by turning off all its rail. This 118 + is provided through pm_power_off. 119 + The device node should have the following properties to enable this 120 + functionality 121 + ams,system-power-controller: Boolean, to enable the power off functionality 122 + through this device. 123 + 115 124 Example: 116 125 -------- 117 126 #include <dt-bindings/mfd/as3722.h> ··· 128 119 ams3722 { 129 120 compatible = "ams,as3722"; 130 121 reg = <0x48>; 122 + 123 + ams,system-power-controller; 131 124 132 125 interrupt-parent = <&intc>; 133 126 interrupt-controller;
+17
Documentation/devicetree/bindings/power/isp1704.txt
··· 1 + Binding for NXP ISP1704 USB Charger Detection 2 + 3 + Required properties: 4 + - compatible: Should contain one of the following: 5 + * "nxp,isp1704" 6 + - nxp,enable-gpio: Should contain a phandle + gpio-specifier 7 + to the GPIO pin connected to the chip's enable pin. 8 + - usb-phy: Should contain a phandle to the USB PHY 9 + the ISP1704 is connected to. 10 + 11 + Example: 12 + 13 + isp1704 { 14 + compatible = "nxp,isp1704"; 15 + nxp,enable-gpio = <&gpio3 3 GPIO_ACTIVE_LOW>; 16 + usb-phy = <&usb2_phy>; 17 + };
+81
Documentation/devicetree/bindings/power_supply/charger-manager.txt
··· 1 + charger-manager bindings 2 + ~~~~~~~~~~~~~~~~~~~~~~~~ 3 + 4 + Required properties : 5 + - compatible : "charger-manager" 6 + - <>-supply : for regulator consumer 7 + - cm-num-chargers : number of chargers 8 + - cm-chargers : name of chargers 9 + - cm-fuel-gauge : name of battery fuel gauge 10 + - subnode <regulator> : 11 + - cm-regulator-name : name of charger regulator 12 + - subnode <cable> : 13 + - cm-cable-name : name of charger cable 14 + - cm-cable-extcon : name of extcon dev 15 + (optional) - cm-cable-min : minimum current of cable 16 + (optional) - cm-cable-max : maximum current of cable 17 + 18 + Optional properties : 19 + - cm-name : charger manager's name (default : "battery") 20 + - cm-poll-mode : polling mode (enum polling_modes) 21 + - cm-poll-interval : polling interval 22 + - cm-battery-stat : battery status (enum data_source) 23 + - cm-fullbatt-* : data for full battery checking 24 + - cm-thermal-zone : name of external thermometer's thermal zone 25 + - cm-battery-* : threshold battery temperature for charging 26 + -cold : critical cold temperature of battery for charging 27 + -cold-in-minus : flag that cold temerature is in minus degree 28 + -hot : critical hot temperature of battery for charging 29 + -temp-diff : temperature difference to allow recharging 30 + - cm-dis/charging-max = limits of charging duration 31 + 32 + Example : 33 + charger-manager@0 { 34 + compatible = "charger-manager"; 35 + chg-reg-supply = <&charger_regulator>; 36 + 37 + cm-name = "battery"; 38 + /* Always polling ON : 30s */ 39 + cm-poll-mode = <1>; 40 + cm-poll-interval = <30000>; 41 + 42 + cm-fullbatt-vchkdrop-ms = <30000>; 43 + cm-fullbatt-vchkdrop-volt = <150000>; 44 + cm-fullbatt-soc = <100>; 45 + 46 + cm-battery-stat = <3>; 47 + 48 + cm-num-chargers = <3>; 49 + cm-chargers = "charger0", "charger1", "charger2"; 50 + 51 + cm-fuel-gauge = "fuelgauge0"; 52 + 53 + cm-thermal-zone = "thermal_zone.1" 54 + /* in deci centigrade */ 55 + cm-battery-cold = <50>; 56 + cm-battery-cold-in-minus; 57 + cm-battery-hot = <800>; 58 + cm-battery-temp-diff = <100>; 59 + 60 + /* Allow charging for 5hr */ 61 + cm-charging-max = <18000000>; 62 + /* Allow discharging for 2hr */ 63 + cm-discharging-max = <7200000>; 64 + 65 + regulator@0 { 66 + cm-regulator-name = "chg-reg"; 67 + cable@0 { 68 + cm-cable-name = "USB"; 69 + cm-cable-extcon = "extcon-dev.0"; 70 + cm-cable-min = <475000>; 71 + cm-cable-max = <500000>; 72 + }; 73 + cable@1 { 74 + cm-cable-name = "TA"; 75 + cm-cable-extcon = "extcon-dev.0"; 76 + cm-cable-min = <650000>; 77 + cm-cable-max = <675000>; 78 + }; 79 + }; 80 + 81 + };
+1 -1
MAINTAINERS
··· 6712 6712 F: kernel/*timer* 6713 6713 6714 6714 POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS 6715 - M: Anton Vorontsov <anton@enomsg.org> 6715 + M: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 6716 6716 M: David Woodhouse <dwmw2@infradead.org> 6717 6717 T: git git://git.infradead.org/battery-2.6.git 6718 6718 S: Maintained
+7
drivers/power/Kconfig
··· 317 317 runtime and in suspend-to-RAM by waking up the system periodically 318 318 with help of suspend_again support. 319 319 320 + config CHARGER_MAX14577 321 + tristate "Maxim MAX14577 MUIC battery charger driver" 322 + depends on MFD_MAX14577 323 + help 324 + Say Y to enable support for the battery charger control sysfs and 325 + platform data of MAX14577 MUICs. 326 + 320 327 config CHARGER_MAX8997 321 328 tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" 322 329 depends on MFD_MAX8997 && REGULATOR_MAX8997
+1
drivers/power/Makefile
··· 48 48 obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o 49 49 obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o 50 50 obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o 51 + obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o 51 52 obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o 52 53 obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o 53 54 obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
+98 -23
drivers/power/bq2415x_charger.c
··· 1 1 /* 2 2 * bq2415x charger driver 3 3 * 4 - * Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com> 4 + * Copyright (C) 2011-2013 Pali Rohár <pali.rohar@gmail.com> 5 5 * 6 6 * This program is free software; you can redistribute it and/or modify 7 7 * it under the terms of the GNU General Public License as published by ··· 170 170 struct bq2415x_platform_data init_data; 171 171 struct power_supply charger; 172 172 struct delayed_work work; 173 + struct power_supply *notify_psy; 174 + struct notifier_block nb; 173 175 enum bq2415x_mode reported_mode;/* mode reported by hook function */ 174 176 enum bq2415x_mode mode; /* current configured mode */ 175 177 enum bq2415x_chip chip; ··· 797 795 798 796 } 799 797 800 - /* hook function called by other driver which set reported mode */ 801 - static void bq2415x_hook_function(enum bq2415x_mode mode, void *data) 798 + static int bq2415x_notifier_call(struct notifier_block *nb, 799 + unsigned long val, void *v) 802 800 { 803 - struct bq2415x_device *bq = data; 801 + struct bq2415x_device *bq = 802 + container_of(nb, struct bq2415x_device, nb); 803 + struct power_supply *psy = v; 804 + enum bq2415x_mode mode; 805 + union power_supply_propval prop; 806 + int ret; 807 + int mA; 804 808 805 - if (!bq) 806 - return; 809 + if (val != PSY_EVENT_PROP_CHANGED) 810 + return NOTIFY_OK; 807 811 808 - dev_dbg(bq->dev, "hook function was called\n"); 812 + if (psy != bq->notify_psy) 813 + return NOTIFY_OK; 814 + 815 + dev_dbg(bq->dev, "notifier call was called\n"); 816 + 817 + ret = psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &prop); 818 + if (ret != 0) 819 + return NOTIFY_OK; 820 + 821 + mA = prop.intval; 822 + 823 + if (mA == 0) 824 + mode = BQ2415X_MODE_OFF; 825 + else if (mA < 500) 826 + mode = BQ2415X_MODE_NONE; 827 + else if (mA < 1800) 828 + mode = BQ2415X_MODE_HOST_CHARGER; 829 + else 830 + mode = BQ2415X_MODE_DEDICATED_CHARGER; 831 + 832 + if (bq->reported_mode == mode) 833 + return NOTIFY_OK; 834 + 809 835 bq->reported_mode = mode; 810 836 811 837 /* if automode is not enabled do not tell about reported_mode */ 812 838 if (bq->automode < 1) 813 - return; 839 + return NOTIFY_OK; 814 840 815 841 sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode"); 816 842 bq2415x_set_mode(bq, bq->reported_mode); 817 843 844 + return NOTIFY_OK; 818 845 } 819 846 820 847 /**** timer functions ****/ ··· 1543 1512 int num; 1544 1513 char *name; 1545 1514 struct bq2415x_device *bq; 1515 + struct device_node *np = client->dev.of_node; 1516 + struct bq2415x_platform_data *pdata = client->dev.platform_data; 1546 1517 1547 - if (!client->dev.platform_data) { 1548 - dev_err(&client->dev, "platform data not set\n"); 1518 + if (!np && !pdata) { 1519 + dev_err(&client->dev, "platform data missing\n"); 1549 1520 return -ENODEV; 1550 1521 } 1551 1522 ··· 1572 1539 goto error_2; 1573 1540 } 1574 1541 1542 + if (np) { 1543 + bq->notify_psy = power_supply_get_by_phandle(np, "ti,usb-charger-detection"); 1544 + 1545 + if (!bq->notify_psy) 1546 + return -EPROBE_DEFER; 1547 + } 1548 + else if (pdata->notify_device) 1549 + bq->notify_psy = power_supply_get_by_name(pdata->notify_device); 1550 + else 1551 + bq->notify_psy = NULL; 1552 + 1575 1553 i2c_set_clientdata(client, bq); 1576 1554 1577 1555 bq->id = num; ··· 1594 1550 bq->autotimer = 0; 1595 1551 bq->automode = 0; 1596 1552 1597 - memcpy(&bq->init_data, client->dev.platform_data, 1598 - sizeof(bq->init_data)); 1553 + if (np) { 1554 + ret = of_property_read_u32(np, "ti,current-limit", 1555 + &bq->init_data.current_limit); 1556 + if (ret) 1557 + return ret; 1558 + ret = of_property_read_u32(np, "ti,weak-battery-voltage", 1559 + &bq->init_data.weak_battery_voltage); 1560 + if (ret) 1561 + return ret; 1562 + ret = of_property_read_u32(np, "ti,battery-regulation-voltage", 1563 + &bq->init_data.battery_regulation_voltage); 1564 + if (ret) 1565 + return ret; 1566 + ret = of_property_read_u32(np, "ti,charge-current", 1567 + &bq->init_data.charge_current); 1568 + if (ret) 1569 + return ret; 1570 + ret = of_property_read_u32(np, "ti,termination-current", 1571 + &bq->init_data.termination_current); 1572 + if (ret) 1573 + return ret; 1574 + ret = of_property_read_u32(np, "ti,resistor-sense", 1575 + &bq->init_data.resistor_sense); 1576 + if (ret) 1577 + return ret; 1578 + } else { 1579 + memcpy(&bq->init_data, pdata, sizeof(bq->init_data)); 1580 + } 1599 1581 1600 1582 bq2415x_reset_chip(bq); 1601 1583 ··· 1643 1573 goto error_4; 1644 1574 } 1645 1575 1646 - if (bq->init_data.set_mode_hook) { 1647 - if (bq->init_data.set_mode_hook( 1648 - bq2415x_hook_function, bq)) { 1649 - bq->automode = 1; 1650 - bq2415x_set_mode(bq, bq->reported_mode); 1651 - dev_info(bq->dev, "automode enabled\n"); 1652 - } else { 1653 - bq->automode = -1; 1654 - dev_info(bq->dev, "automode failed\n"); 1576 + if (bq->notify_psy) { 1577 + bq->nb.notifier_call = bq2415x_notifier_call; 1578 + ret = power_supply_reg_notifier(&bq->nb); 1579 + if (ret) { 1580 + dev_err(bq->dev, "failed to reg notifier: %d\n", ret); 1581 + goto error_5; 1655 1582 } 1583 + 1584 + /* Query for initial reported_mode and set it */ 1585 + bq2415x_notifier_call(&bq->nb, PSY_EVENT_PROP_CHANGED, bq->notify_psy); 1586 + bq2415x_set_mode(bq, bq->reported_mode); 1587 + 1588 + bq->automode = 1; 1589 + dev_info(bq->dev, "automode enabled\n"); 1656 1590 } else { 1657 1591 bq->automode = -1; 1658 1592 dev_info(bq->dev, "automode not supported\n"); ··· 1668 1594 dev_info(bq->dev, "driver registered\n"); 1669 1595 return 0; 1670 1596 1597 + error_5: 1671 1598 error_4: 1672 1599 bq2415x_sysfs_exit(bq); 1673 1600 error_3: ··· 1689 1614 { 1690 1615 struct bq2415x_device *bq = i2c_get_clientdata(client); 1691 1616 1692 - if (bq->init_data.set_mode_hook) 1693 - bq->init_data.set_mode_hook(NULL, NULL); 1617 + if (bq->notify_psy) 1618 + power_supply_unreg_notifier(&bq->nb); 1694 1619 1695 1620 bq2415x_sysfs_exit(bq); 1696 1621 bq2415x_power_supply_exit(bq);
+255 -44
drivers/power/charger-manager.c
··· 25 25 #include <linux/power/charger-manager.h> 26 26 #include <linux/regulator/consumer.h> 27 27 #include <linux/sysfs.h> 28 + #include <linux/of.h> 29 + #include <linux/thermal.h> 30 + 31 + /* 32 + * Default termperature threshold for charging. 33 + * Every temperature units are in tenth of centigrade. 34 + */ 35 + #define CM_DEFAULT_RECHARGE_TEMP_DIFF 50 36 + #define CM_DEFAULT_CHARGE_TEMP_MAX 500 28 37 29 38 static const char * const default_event_names[] = { 30 39 [CM_EVENT_UNKNOWN] = "Unknown", 31 40 [CM_EVENT_BATT_FULL] = "Battery Full", 32 41 [CM_EVENT_BATT_IN] = "Battery Inserted", 33 42 [CM_EVENT_BATT_OUT] = "Battery Pulled Out", 43 + [CM_EVENT_BATT_OVERHEAT] = "Battery Overheat", 44 + [CM_EVENT_BATT_COLD] = "Battery Cold", 34 45 [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", 35 46 [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", 36 47 [CM_EVENT_OTHERS] = "Other battery events" ··· 529 518 duration = curr - cm->charging_start_time; 530 519 531 520 if (duration > desc->charging_max_duration_ms) { 532 - dev_info(cm->dev, "Charging duration exceed %lldms\n", 521 + dev_info(cm->dev, "Charging duration exceed %ums\n", 533 522 desc->charging_max_duration_ms); 534 523 uevent_notify(cm, "Discharging"); 535 524 try_charger_enable(cm, false); ··· 540 529 541 530 if (duration > desc->charging_max_duration_ms && 542 531 is_ext_pwr_online(cm)) { 543 - dev_info(cm->dev, "Discharging duration exceed %lldms\n", 532 + dev_info(cm->dev, "Discharging duration exceed %ums\n", 544 533 desc->discharging_max_duration_ms); 545 534 uevent_notify(cm, "Recharging"); 546 535 try_charger_enable(cm, true); 547 536 ret = true; 548 537 } 549 538 } 539 + 540 + return ret; 541 + } 542 + 543 + static int cm_get_battery_temperature(struct charger_manager *cm, 544 + int *temp) 545 + { 546 + int ret; 547 + 548 + if (!cm->desc->measure_battery_temp) 549 + return -ENODEV; 550 + 551 + #ifdef CONFIG_THERMAL 552 + ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); 553 + if (!ret) 554 + /* Calibrate temperature unit */ 555 + *temp /= 100; 556 + #else 557 + ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 558 + POWER_SUPPLY_PROP_TEMP, 559 + (union power_supply_propval *)temp); 560 + #endif 561 + return ret; 562 + } 563 + 564 + static int cm_check_thermal_status(struct charger_manager *cm) 565 + { 566 + struct charger_desc *desc = cm->desc; 567 + int temp, upper_limit, lower_limit; 568 + int ret = 0; 569 + 570 + ret = cm_get_battery_temperature(cm, &temp); 571 + if (ret) { 572 + /* FIXME: 573 + * No information of battery temperature might 574 + * occur hazadous result. We have to handle it 575 + * depending on battery type. 576 + */ 577 + dev_err(cm->dev, "Failed to get battery temperature\n"); 578 + return 0; 579 + } 580 + 581 + upper_limit = desc->temp_max; 582 + lower_limit = desc->temp_min; 583 + 584 + if (cm->emergency_stop) { 585 + upper_limit -= desc->temp_diff; 586 + lower_limit += desc->temp_diff; 587 + } 588 + 589 + if (temp > upper_limit) 590 + ret = CM_EVENT_BATT_OVERHEAT; 591 + else if (temp < lower_limit) 592 + ret = CM_EVENT_BATT_COLD; 550 593 551 594 return ret; 552 595 } ··· 614 549 */ 615 550 static bool _cm_monitor(struct charger_manager *cm) 616 551 { 617 - struct charger_desc *desc = cm->desc; 618 - int temp = desc->temperature_out_of_range(&cm->last_temp_mC); 552 + int temp_alrt; 619 553 620 - dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", 621 - cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); 554 + temp_alrt = cm_check_thermal_status(cm); 622 555 623 556 /* It has been stopped already */ 624 - if (temp && cm->emergency_stop) 557 + if (temp_alrt && cm->emergency_stop) 625 558 return false; 626 559 627 560 /* 628 561 * Check temperature whether overheat or cold. 629 562 * If temperature is out of range normal state, stop charging. 630 563 */ 631 - if (temp) { 632 - cm->emergency_stop = temp; 633 - if (!try_charger_enable(cm, false)) { 634 - if (temp > 0) 635 - uevent_notify(cm, "OVERHEAT"); 636 - else 637 - uevent_notify(cm, "COLD"); 638 - } 564 + if (temp_alrt) { 565 + cm->emergency_stop = temp_alrt; 566 + if (!try_charger_enable(cm, false)) 567 + uevent_notify(cm, default_event_names[temp_alrt]); 639 568 640 569 /* 641 570 * Check whole charging duration and discharing duration ··· 861 802 POWER_SUPPLY_PROP_CURRENT_NOW, val); 862 803 break; 863 804 case POWER_SUPPLY_PROP_TEMP: 864 - /* in thenth of centigrade */ 865 - if (cm->last_temp_mC == INT_MIN) 866 - desc->temperature_out_of_range(&cm->last_temp_mC); 867 - val->intval = cm->last_temp_mC / 100; 868 - if (!desc->measure_battery_temp) 869 - ret = -ENODEV; 870 - break; 871 805 case POWER_SUPPLY_PROP_TEMP_AMBIENT: 872 - /* in thenth of centigrade */ 873 - if (cm->last_temp_mC == INT_MIN) 874 - desc->temperature_out_of_range(&cm->last_temp_mC); 875 - val->intval = cm->last_temp_mC / 100; 876 - if (desc->measure_battery_temp) 877 - ret = -ENODEV; 878 - break; 806 + return cm_get_battery_temperature(cm, &val->intval); 879 807 case POWER_SUPPLY_PROP_CAPACITY: 880 808 if (!cm->fuel_gauge) { 881 809 ret = -ENODEV; ··· 1485 1439 return ret; 1486 1440 } 1487 1441 1442 + static int cm_init_thermal_data(struct charger_manager *cm) 1443 + { 1444 + struct charger_desc *desc = cm->desc; 1445 + union power_supply_propval val; 1446 + int ret; 1447 + 1448 + /* Verify whether fuel gauge provides battery temperature */ 1449 + ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 1450 + POWER_SUPPLY_PROP_TEMP, &val); 1451 + 1452 + if (!ret) { 1453 + cm->charger_psy.properties[cm->charger_psy.num_properties] = 1454 + POWER_SUPPLY_PROP_TEMP; 1455 + cm->charger_psy.num_properties++; 1456 + cm->desc->measure_battery_temp = true; 1457 + } 1458 + #ifdef CONFIG_THERMAL 1459 + cm->tzd_batt = cm->fuel_gauge->tzd; 1460 + 1461 + if (ret && desc->thermal_zone) { 1462 + cm->tzd_batt = 1463 + thermal_zone_get_zone_by_name(desc->thermal_zone); 1464 + if (IS_ERR(cm->tzd_batt)) 1465 + return PTR_ERR(cm->tzd_batt); 1466 + 1467 + /* Use external thermometer */ 1468 + cm->charger_psy.properties[cm->charger_psy.num_properties] = 1469 + POWER_SUPPLY_PROP_TEMP_AMBIENT; 1470 + cm->charger_psy.num_properties++; 1471 + cm->desc->measure_battery_temp = true; 1472 + ret = 0; 1473 + } 1474 + #endif 1475 + if (cm->desc->measure_battery_temp) { 1476 + /* NOTICE : Default allowable minimum charge temperature is 0 */ 1477 + if (!desc->temp_max) 1478 + desc->temp_max = CM_DEFAULT_CHARGE_TEMP_MAX; 1479 + if (!desc->temp_diff) 1480 + desc->temp_diff = CM_DEFAULT_RECHARGE_TEMP_DIFF; 1481 + } 1482 + 1483 + return ret; 1484 + } 1485 + 1486 + static struct of_device_id charger_manager_match[] = { 1487 + { 1488 + .compatible = "charger-manager", 1489 + }, 1490 + {}, 1491 + }; 1492 + 1493 + static struct charger_desc *of_cm_parse_desc(struct device *dev) 1494 + { 1495 + struct charger_desc *desc; 1496 + struct device_node *np = dev->of_node; 1497 + u32 poll_mode = CM_POLL_DISABLE; 1498 + u32 battery_stat = CM_NO_BATTERY; 1499 + int num_chgs = 0; 1500 + 1501 + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); 1502 + if (!desc) 1503 + return ERR_PTR(-ENOMEM); 1504 + 1505 + of_property_read_string(np, "cm-name", &desc->psy_name); 1506 + 1507 + of_property_read_u32(np, "cm-poll-mode", &poll_mode); 1508 + desc->polling_mode = poll_mode; 1509 + 1510 + of_property_read_u32(np, "cm-poll-interval", 1511 + &desc->polling_interval_ms); 1512 + 1513 + of_property_read_u32(np, "cm-fullbatt-vchkdrop-ms", 1514 + &desc->fullbatt_vchkdrop_ms); 1515 + of_property_read_u32(np, "cm-fullbatt-vchkdrop-volt", 1516 + &desc->fullbatt_vchkdrop_uV); 1517 + of_property_read_u32(np, "cm-fullbatt-voltage", &desc->fullbatt_uV); 1518 + of_property_read_u32(np, "cm-fullbatt-soc", &desc->fullbatt_soc); 1519 + of_property_read_u32(np, "cm-fullbatt-capacity", 1520 + &desc->fullbatt_full_capacity); 1521 + 1522 + of_property_read_u32(np, "cm-battery-stat", &battery_stat); 1523 + desc->battery_present = battery_stat; 1524 + 1525 + /* chargers */ 1526 + of_property_read_u32(np, "cm-num-chargers", &num_chgs); 1527 + if (num_chgs) { 1528 + /* Allocate empty bin at the tail of array */ 1529 + desc->psy_charger_stat = devm_kzalloc(dev, sizeof(char *) 1530 + * (num_chgs + 1), GFP_KERNEL); 1531 + if (desc->psy_charger_stat) { 1532 + int i; 1533 + for (i = 0; i < num_chgs; i++) 1534 + of_property_read_string_index(np, "cm-chargers", 1535 + i, &desc->psy_charger_stat[i]); 1536 + } else { 1537 + return ERR_PTR(-ENOMEM); 1538 + } 1539 + } 1540 + 1541 + of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge); 1542 + 1543 + of_property_read_string(np, "cm-thermal-zone", &desc->thermal_zone); 1544 + 1545 + of_property_read_u32(np, "cm-battery-cold", &desc->temp_min); 1546 + if (of_get_property(np, "cm-battery-cold-in-minus", NULL)) 1547 + desc->temp_min *= -1; 1548 + of_property_read_u32(np, "cm-battery-hot", &desc->temp_max); 1549 + of_property_read_u32(np, "cm-battery-temp-diff", &desc->temp_diff); 1550 + 1551 + of_property_read_u32(np, "cm-charging-max", 1552 + &desc->charging_max_duration_ms); 1553 + of_property_read_u32(np, "cm-discharging-max", 1554 + &desc->discharging_max_duration_ms); 1555 + 1556 + /* battery charger regualtors */ 1557 + desc->num_charger_regulators = of_get_child_count(np); 1558 + if (desc->num_charger_regulators) { 1559 + struct charger_regulator *chg_regs; 1560 + struct device_node *child; 1561 + 1562 + chg_regs = devm_kzalloc(dev, sizeof(*chg_regs) 1563 + * desc->num_charger_regulators, 1564 + GFP_KERNEL); 1565 + if (!chg_regs) 1566 + return ERR_PTR(-ENOMEM); 1567 + 1568 + desc->charger_regulators = chg_regs; 1569 + 1570 + for_each_child_of_node(np, child) { 1571 + struct charger_cable *cables; 1572 + struct device_node *_child; 1573 + 1574 + of_property_read_string(child, "cm-regulator-name", 1575 + &chg_regs->regulator_name); 1576 + 1577 + /* charger cables */ 1578 + chg_regs->num_cables = of_get_child_count(child); 1579 + if (chg_regs->num_cables) { 1580 + cables = devm_kzalloc(dev, sizeof(*cables) 1581 + * chg_regs->num_cables, 1582 + GFP_KERNEL); 1583 + if (!cables) 1584 + return ERR_PTR(-ENOMEM); 1585 + 1586 + chg_regs->cables = cables; 1587 + 1588 + for_each_child_of_node(child, _child) { 1589 + of_property_read_string(_child, 1590 + "cm-cable-name", &cables->name); 1591 + of_property_read_string(_child, 1592 + "cm-cable-extcon", 1593 + &cables->extcon_name); 1594 + of_property_read_u32(_child, 1595 + "cm-cable-min", 1596 + &cables->min_uA); 1597 + of_property_read_u32(_child, 1598 + "cm-cable-max", 1599 + &cables->max_uA); 1600 + cables++; 1601 + } 1602 + } 1603 + chg_regs++; 1604 + } 1605 + } 1606 + return desc; 1607 + } 1608 + 1609 + static inline struct charger_desc *cm_get_drv_data(struct platform_device *pdev) 1610 + { 1611 + if (pdev->dev.of_node) 1612 + return of_cm_parse_desc(&pdev->dev); 1613 + return (struct charger_desc *)dev_get_platdata(&pdev->dev); 1614 + } 1615 + 1488 1616 static int charger_manager_probe(struct platform_device *pdev) 1489 1617 { 1490 - struct charger_desc *desc = dev_get_platdata(&pdev->dev); 1618 + struct charger_desc *desc = cm_get_drv_data(pdev); 1491 1619 struct charger_manager *cm; 1492 1620 int ret = 0, i = 0; 1493 1621 int j = 0; ··· 1690 1470 /* Basic Values. Unspecified are Null or 0 */ 1691 1471 cm->dev = &pdev->dev; 1692 1472 cm->desc = desc; 1693 - cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ 1694 1473 1695 1474 /* 1696 1475 * The following two do not need to be errors. ··· 1752 1533 return -EINVAL; 1753 1534 } 1754 1535 1755 - if (!desc->temperature_out_of_range) { 1756 - dev_err(&pdev->dev, "there is no temperature_out_of_range\n"); 1757 - return -EINVAL; 1758 - } 1759 - 1760 1536 if (!desc->charging_max_duration_ms || 1761 1537 !desc->discharging_max_duration_ms) { 1762 1538 dev_info(&pdev->dev, "Cannot limit charging duration checking mechanism to prevent overcharge/overheat and control discharging duration\n"); ··· 1797 1583 cm->charger_psy.num_properties++; 1798 1584 } 1799 1585 1800 - if (desc->measure_battery_temp) { 1801 - cm->charger_psy.properties[cm->charger_psy.num_properties] = 1802 - POWER_SUPPLY_PROP_TEMP; 1803 - cm->charger_psy.num_properties++; 1804 - } else { 1805 - cm->charger_psy.properties[cm->charger_psy.num_properties] = 1806 - POWER_SUPPLY_PROP_TEMP_AMBIENT; 1807 - cm->charger_psy.num_properties++; 1586 + ret = cm_init_thermal_data(cm); 1587 + if (ret) { 1588 + dev_err(&pdev->dev, "Failed to initialize thermal data\n"); 1589 + cm->desc->measure_battery_temp = false; 1808 1590 } 1809 1591 1810 1592 INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); ··· 2018 1808 .name = "charger-manager", 2019 1809 .owner = THIS_MODULE, 2020 1810 .pm = &charger_manager_pm, 1811 + .of_match_table = charger_manager_match, 2021 1812 }, 2022 1813 .probe = charger_manager_probe, 2023 1814 .remove = charger_manager_remove,
+18 -1
drivers/power/gpio-charger.c
··· 28 28 struct gpio_charger { 29 29 const struct gpio_charger_platform_data *pdata; 30 30 unsigned int irq; 31 + bool wakeup_enabled; 31 32 32 33 struct power_supply charger; 33 34 }; ··· 137 136 138 137 platform_set_drvdata(pdev, gpio_charger); 139 138 139 + device_init_wakeup(&pdev->dev, 1); 140 + 140 141 return 0; 141 142 142 143 err_gpio_free: ··· 162 159 } 163 160 164 161 #ifdef CONFIG_PM_SLEEP 162 + static int gpio_charger_suspend(struct device *dev) 163 + { 164 + struct gpio_charger *gpio_charger = dev_get_drvdata(dev); 165 + 166 + if (device_may_wakeup(dev)) 167 + gpio_charger->wakeup_enabled = 168 + enable_irq_wake(gpio_charger->irq); 169 + 170 + return 0; 171 + } 172 + 165 173 static int gpio_charger_resume(struct device *dev) 166 174 { 167 175 struct platform_device *pdev = to_platform_device(dev); 168 176 struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); 169 177 178 + if (gpio_charger->wakeup_enabled) 179 + disable_irq_wake(gpio_charger->irq); 170 180 power_supply_changed(&gpio_charger->charger); 171 181 172 182 return 0; 173 183 } 174 184 #endif 175 185 176 - static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume); 186 + static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, 187 + gpio_charger_suspend, gpio_charger_resume); 177 188 178 189 static struct platform_driver gpio_charger_driver = { 179 190 .probe = gpio_charger_probe,
+50 -4
drivers/power/isp1704_charger.c
··· 29 29 #include <linux/platform_device.h> 30 30 #include <linux/power_supply.h> 31 31 #include <linux/delay.h> 32 + #include <linux/of.h> 33 + #include <linux/of_gpio.h> 32 34 33 35 #include <linux/usb/otg.h> 34 36 #include <linux/usb/ulpi.h> ··· 90 88 91 89 if (board && board->set_power) 92 90 board->set_power(on); 91 + else if (board) 92 + gpio_set_value(board->enable_gpio, on); 93 93 } 94 94 95 95 /* ··· 404 400 struct isp1704_charger *isp; 405 401 int ret = -ENODEV; 406 402 403 + struct isp1704_charger_data *pdata = dev_get_platdata(&pdev->dev); 404 + struct device_node *np = pdev->dev.of_node; 405 + 406 + if (np) { 407 + int gpio = of_get_named_gpio(np, "nxp,enable-gpio", 0); 408 + 409 + if (gpio < 0) 410 + return gpio; 411 + 412 + pdata = devm_kzalloc(&pdev->dev, 413 + sizeof(struct isp1704_charger_data), GFP_KERNEL); 414 + pdata->enable_gpio = gpio; 415 + 416 + dev_info(&pdev->dev, "init gpio %d\n", pdata->enable_gpio); 417 + 418 + ret = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio, 419 + GPIOF_OUT_INIT_HIGH, "isp1704_reset"); 420 + if (ret) 421 + goto fail0; 422 + } 423 + 424 + if (!pdata) { 425 + dev_err(&pdev->dev, "missing platform data!\n"); 426 + return -ENODEV; 427 + } 428 + 429 + 407 430 isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); 408 431 if (!isp) 409 432 return -ENOMEM; 410 433 411 - isp->phy = usb_get_phy(USB_PHY_TYPE_USB2); 412 - if (IS_ERR_OR_NULL(isp->phy)) 434 + if (np) 435 + isp->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); 436 + else 437 + isp->phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 438 + 439 + if (IS_ERR(isp->phy)) { 440 + ret = PTR_ERR(isp->phy); 441 + goto fail0; 442 + } 443 + if (!isp->phy) 413 444 goto fail0; 414 445 415 446 isp->dev = &pdev->dev; ··· 503 464 power_supply_unregister(&isp->psy); 504 465 fail1: 505 466 isp1704_charger_set_power(isp, 0); 506 - usb_put_phy(isp->phy); 507 467 fail0: 508 468 dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret); 509 469 ··· 515 477 516 478 usb_unregister_notifier(isp->phy, &isp->nb); 517 479 power_supply_unregister(&isp->psy); 518 - usb_put_phy(isp->phy); 519 480 isp1704_charger_set_power(isp, 0); 520 481 521 482 return 0; 522 483 } 523 484 485 + #ifdef CONFIG_OF 486 + static const struct of_device_id omap_isp1704_of_match[] = { 487 + { .compatible = "nxp,isp1704", }, 488 + {}, 489 + }; 490 + MODULE_DEVICE_TABLE(of, omap_isp1704_of_match); 491 + #endif 492 + 524 493 static struct platform_driver isp1704_charger_driver = { 525 494 .driver = { 526 495 .name = "isp1704_charger", 496 + .of_match_table = of_match_ptr(omap_isp1704_of_match), 527 497 }, 528 498 .probe = isp1704_charger_probe, 529 499 .remove = isp1704_charger_remove,
+311
drivers/power/max14577_charger.c
··· 1 + /* 2 + * Battery charger driver for the Maxim 14577 3 + * 4 + * Copyright (C) 2013 Samsung Electronics 5 + * Krzysztof Kozlowski <k.kozlowski@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/power_supply.h> 21 + #include <linux/mfd/max14577-private.h> 22 + 23 + struct max14577_charger { 24 + struct device *dev; 25 + struct max14577 *max14577; 26 + struct power_supply charger; 27 + 28 + unsigned int charging_state; 29 + unsigned int battery_state; 30 + }; 31 + 32 + static int max14577_get_charger_state(struct max14577_charger *chg) 33 + { 34 + struct regmap *rmap = chg->max14577->regmap; 35 + int state = POWER_SUPPLY_STATUS_DISCHARGING; 36 + u8 reg_data; 37 + 38 + /* 39 + * Charging occurs only if: 40 + * - CHGCTRL2/MBCHOSTEN == 1 41 + * - STATUS2/CGMBC == 1 42 + * 43 + * TODO: 44 + * - handle FULL after Top-off timer (EOC register may be off 45 + * and the charger won't be charging although MBCHOSTEN is on) 46 + * - handle properly dead-battery charging (respect timer) 47 + * - handle timers (fast-charge and prequal) /MBCCHGERR/ 48 + */ 49 + max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL2, &reg_data); 50 + if ((reg_data & CHGCTRL2_MBCHOSTEN_MASK) == 0) 51 + goto state_set; 52 + 53 + max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, &reg_data); 54 + if (reg_data & STATUS3_CGMBC_MASK) { 55 + /* Charger or USB-cable is connected */ 56 + if (reg_data & STATUS3_EOC_MASK) 57 + state = POWER_SUPPLY_STATUS_FULL; 58 + else 59 + state = POWER_SUPPLY_STATUS_CHARGING; 60 + goto state_set; 61 + } 62 + 63 + state_set: 64 + chg->charging_state = state; 65 + return state; 66 + } 67 + 68 + /* 69 + * Supported charge types: 70 + * - POWER_SUPPLY_CHARGE_TYPE_NONE 71 + * - POWER_SUPPLY_CHARGE_TYPE_FAST 72 + */ 73 + static int max14577_get_charge_type(struct max14577_charger *chg) 74 + { 75 + /* 76 + * TODO: CHARGE_TYPE_TRICKLE (VCHGR_RC or EOC)? 77 + * As spec says: 78 + * [after reaching EOC interrupt] 79 + * "When the battery is fully charged, the 30-minute (typ) 80 + * top-off timer starts. The device continues to trickle 81 + * charge the battery until the top-off timer runs out." 82 + */ 83 + if (max14577_get_charger_state(chg) == POWER_SUPPLY_STATUS_CHARGING) 84 + return POWER_SUPPLY_CHARGE_TYPE_FAST; 85 + return POWER_SUPPLY_CHARGE_TYPE_NONE; 86 + } 87 + 88 + static int max14577_get_online(struct max14577_charger *chg) 89 + { 90 + struct regmap *rmap = chg->max14577->regmap; 91 + u8 reg_data; 92 + 93 + max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, &reg_data); 94 + reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT); 95 + switch (reg_data) { 96 + case MAX14577_CHARGER_TYPE_USB: 97 + case MAX14577_CHARGER_TYPE_DEDICATED_CHG: 98 + case MAX14577_CHARGER_TYPE_SPECIAL_500MA: 99 + case MAX14577_CHARGER_TYPE_SPECIAL_1A: 100 + case MAX14577_CHARGER_TYPE_DEAD_BATTERY: 101 + return 1; 102 + case MAX14577_CHARGER_TYPE_NONE: 103 + case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT: 104 + case MAX14577_CHARGER_TYPE_RESERVED: 105 + default: 106 + return 0; 107 + } 108 + } 109 + 110 + /* 111 + * Supported health statuses: 112 + * - POWER_SUPPLY_HEALTH_DEAD 113 + * - POWER_SUPPLY_HEALTH_OVERVOLTAGE 114 + * - POWER_SUPPLY_HEALTH_GOOD 115 + */ 116 + static int max14577_get_battery_health(struct max14577_charger *chg) 117 + { 118 + struct regmap *rmap = chg->max14577->regmap; 119 + int state = POWER_SUPPLY_HEALTH_GOOD; 120 + u8 reg_data; 121 + 122 + max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, &reg_data); 123 + reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT); 124 + if (reg_data == MAX14577_CHARGER_TYPE_DEAD_BATTERY) { 125 + state = POWER_SUPPLY_HEALTH_DEAD; 126 + goto state_set; 127 + } 128 + 129 + max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, &reg_data); 130 + if (reg_data & STATUS3_OVP_MASK) { 131 + state = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 132 + goto state_set; 133 + } 134 + 135 + state_set: 136 + chg->battery_state = state; 137 + return state; 138 + } 139 + 140 + /* 141 + * Always returns 1. 142 + * The max14577 chip doesn't report any status of battery presence. 143 + * Lets assume that it will always be used with some battery. 144 + */ 145 + static int max14577_get_present(struct max14577_charger *chg) 146 + { 147 + return 1; 148 + } 149 + 150 + /* 151 + * Sets charger registers to proper and safe default values. 152 + * Some of these values are equal to defaults in MAX14577E 153 + * data sheet but there are minor differences. 154 + */ 155 + static void max14577_charger_reg_init(struct max14577_charger *chg) 156 + { 157 + struct regmap *rmap = chg->max14577->regmap; 158 + u8 reg_data; 159 + 160 + /* 161 + * Charger-Type Manual Detection, default off (set CHGTYPMAN to 0) 162 + * Charger-Detection Enable, default on (set CHGDETEN to 1) 163 + * Combined mask of CHGDETEN and CHGTYPMAN will zero the CHGTYPMAN bit 164 + */ 165 + reg_data = 0x1 << CDETCTRL1_CHGDETEN_SHIFT; 166 + max14577_update_reg(rmap, MAX14577_REG_CDETCTRL1, 167 + CDETCTRL1_CHGDETEN_MASK | CDETCTRL1_CHGTYPMAN_MASK, 168 + reg_data); 169 + 170 + /* Battery Fast-Charge Timer, from SM-V700: 6hrs */ 171 + reg_data = 0x3 << CHGCTRL1_TCHW_SHIFT; 172 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL1, reg_data); 173 + 174 + /* 175 + * Wall-Adapter Rapid Charge, default on 176 + * Battery-Charger, default on 177 + */ 178 + reg_data = 0x1 << CHGCTRL2_VCHGR_RC_SHIFT; 179 + reg_data |= 0x1 << CHGCTRL2_MBCHOSTEN_SHIFT; 180 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL2, reg_data); 181 + 182 + /* Battery-Charger Constant Voltage (CV) Mode, from SM-V700: 4.35V */ 183 + reg_data = 0xf << CHGCTRL3_MBCCVWRC_SHIFT; 184 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL3, reg_data); 185 + 186 + /* 187 + * Fast Battery-Charge Current Low, default 200-950mA 188 + * Fast Battery-Charge Current High, from SM-V700: 450mA 189 + */ 190 + reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT; 191 + reg_data |= 0x5 << CHGCTRL4_MBCICHWRCH_SHIFT; 192 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL4, reg_data); 193 + 194 + /* End-of-Charge Current, from SM-V700: 50mA */ 195 + reg_data = 0x0 << CHGCTRL5_EOCS_SHIFT; 196 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL5, reg_data); 197 + 198 + /* Auto Charging Stop, default off */ 199 + reg_data = 0x0 << CHGCTRL6_AUTOSTOP_SHIFT; 200 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL6, reg_data); 201 + 202 + /* Overvoltage-Protection Threshold, from SM-V700: 6.5V */ 203 + reg_data = 0x2 << CHGCTRL7_OTPCGHCVS_SHIFT; 204 + max14577_write_reg(rmap, MAX14577_REG_CHGCTRL7, reg_data); 205 + } 206 + 207 + /* Support property from charger */ 208 + static enum power_supply_property max14577_charger_props[] = { 209 + POWER_SUPPLY_PROP_STATUS, 210 + POWER_SUPPLY_PROP_CHARGE_TYPE, 211 + POWER_SUPPLY_PROP_HEALTH, 212 + POWER_SUPPLY_PROP_PRESENT, 213 + POWER_SUPPLY_PROP_ONLINE, 214 + POWER_SUPPLY_PROP_MODEL_NAME, 215 + POWER_SUPPLY_PROP_MANUFACTURER, 216 + }; 217 + 218 + static const char *model_name = "MAX14577"; 219 + static const char *manufacturer = "Maxim Integrated"; 220 + 221 + static int max14577_charger_get_property(struct power_supply *psy, 222 + enum power_supply_property psp, 223 + union power_supply_propval *val) 224 + { 225 + struct max14577_charger *chg = container_of(psy, 226 + struct max14577_charger, 227 + charger); 228 + int ret = 0; 229 + 230 + switch (psp) { 231 + case POWER_SUPPLY_PROP_STATUS: 232 + val->intval = max14577_get_charger_state(chg); 233 + break; 234 + case POWER_SUPPLY_PROP_CHARGE_TYPE: 235 + val->intval = max14577_get_charge_type(chg); 236 + break; 237 + case POWER_SUPPLY_PROP_HEALTH: 238 + val->intval = max14577_get_battery_health(chg); 239 + break; 240 + case POWER_SUPPLY_PROP_PRESENT: 241 + val->intval = max14577_get_present(chg); 242 + break; 243 + case POWER_SUPPLY_PROP_ONLINE: 244 + val->intval = max14577_get_online(chg); 245 + break; 246 + case POWER_SUPPLY_PROP_MODEL_NAME: 247 + val->strval = model_name; 248 + break; 249 + case POWER_SUPPLY_PROP_MANUFACTURER: 250 + val->strval = manufacturer; 251 + break; 252 + default: 253 + return -EINVAL; 254 + } 255 + 256 + return ret; 257 + } 258 + 259 + static int max14577_charger_probe(struct platform_device *pdev) 260 + { 261 + struct max14577_charger *chg; 262 + struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); 263 + int ret; 264 + 265 + chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); 266 + if (!chg) 267 + return -ENOMEM; 268 + 269 + platform_set_drvdata(pdev, chg); 270 + chg->dev = &pdev->dev; 271 + chg->max14577 = max14577; 272 + 273 + max14577_charger_reg_init(chg); 274 + 275 + chg->charger.name = "max14577-charger", 276 + chg->charger.type = POWER_SUPPLY_TYPE_BATTERY, 277 + chg->charger.properties = max14577_charger_props, 278 + chg->charger.num_properties = ARRAY_SIZE(max14577_charger_props), 279 + chg->charger.get_property = max14577_charger_get_property, 280 + 281 + ret = power_supply_register(&pdev->dev, &chg->charger); 282 + if (ret) { 283 + dev_err(&pdev->dev, "failed: power supply register\n"); 284 + return ret; 285 + } 286 + 287 + return 0; 288 + } 289 + 290 + static int max14577_charger_remove(struct platform_device *pdev) 291 + { 292 + struct max14577_charger *chg = platform_get_drvdata(pdev); 293 + 294 + power_supply_unregister(&chg->charger); 295 + 296 + return 0; 297 + } 298 + 299 + static struct platform_driver max14577_charger_driver = { 300 + .driver = { 301 + .owner = THIS_MODULE, 302 + .name = "max14577-charger", 303 + }, 304 + .probe = max14577_charger_probe, 305 + .remove = max14577_charger_remove, 306 + }; 307 + module_platform_driver(max14577_charger_driver); 308 + 309 + MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>"); 310 + MODULE_DESCRIPTION("MAXIM 14577 charger driver"); 311 + MODULE_LICENSE("GPL");
+3 -3
drivers/power/max17042_battery.c
··· 741 741 742 742 if (client->irq) { 743 743 ret = request_threaded_irq(client->irq, NULL, 744 - max17042_thread_handler, 745 - IRQF_TRIGGER_FALLING, 746 - chip->battery.name, chip); 744 + max17042_thread_handler, 745 + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 746 + chip->battery.name, chip); 747 747 if (!ret) { 748 748 regmap_read(chip->regmap, MAX17042_CONFIG, &val); 749 749 val |= CONFIG_ALRT_BIT_ENBL;
+44
drivers/power/power_supply_core.c
··· 15 15 #include <linux/init.h> 16 16 #include <linux/slab.h> 17 17 #include <linux/device.h> 18 + #include <linux/notifier.h> 18 19 #include <linux/err.h> 19 20 #include <linux/power_supply.h> 20 21 #include <linux/thermal.h> ··· 24 23 /* exported for the APM Power driver, APM emulation */ 25 24 struct class *power_supply_class; 26 25 EXPORT_SYMBOL_GPL(power_supply_class); 26 + 27 + ATOMIC_NOTIFIER_HEAD(power_supply_notifier); 28 + EXPORT_SYMBOL_GPL(power_supply_notifier); 27 29 28 30 static struct device_type power_supply_dev_type; 29 31 ··· 84 80 class_for_each_device(power_supply_class, NULL, psy, 85 81 __power_supply_changed_work); 86 82 power_supply_update_leds(psy); 83 + atomic_notifier_call_chain(&power_supply_notifier, 84 + PSY_EVENT_PROP_CHANGED, psy); 87 85 kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); 88 86 spin_lock_irqsave(&psy->changed_lock, flags); 89 87 } ··· 341 335 } 342 336 EXPORT_SYMBOL_GPL(power_supply_get_by_name); 343 337 338 + #ifdef CONFIG_OF 339 + static int power_supply_match_device_node(struct device *dev, const void *data) 340 + { 341 + return dev->parent && dev->parent->of_node == data; 342 + } 343 + 344 + struct power_supply *power_supply_get_by_phandle(struct device_node *np, 345 + const char *property) 346 + { 347 + struct device_node *power_supply_np; 348 + struct device *dev; 349 + 350 + power_supply_np = of_parse_phandle(np, property, 0); 351 + if (!power_supply_np) 352 + return ERR_PTR(-ENODEV); 353 + 354 + dev = class_find_device(power_supply_class, NULL, power_supply_np, 355 + power_supply_match_device_node); 356 + 357 + of_node_put(power_supply_np); 358 + 359 + return dev ? dev_get_drvdata(dev) : NULL; 360 + } 361 + EXPORT_SYMBOL_GPL(power_supply_get_by_phandle); 362 + #endif /* CONFIG_OF */ 363 + 344 364 int power_supply_powers(struct power_supply *psy, struct device *dev) 345 365 { 346 366 return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers"); ··· 378 346 pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 379 347 kfree(dev); 380 348 } 349 + 350 + int power_supply_reg_notifier(struct notifier_block *nb) 351 + { 352 + return atomic_notifier_chain_register(&power_supply_notifier, nb); 353 + } 354 + EXPORT_SYMBOL_GPL(power_supply_reg_notifier); 355 + 356 + void power_supply_unreg_notifier(struct notifier_block *nb) 357 + { 358 + atomic_notifier_chain_unregister(&power_supply_notifier, nb); 359 + } 360 + EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); 381 361 382 362 #ifdef CONFIG_THERMAL 383 363 static int power_supply_read_temp(struct thermal_zone_device *tzd,
+6
drivers/power/reset/Kconfig
··· 6 6 7 7 Say Y here to enable board reset and power off 8 8 9 + config POWER_RESET_AS3722 10 + bool "ams AS3722 power-off driver" 11 + depends on MFD_AS3722 && POWER_RESET 12 + help 13 + This driver supports turning off board via a ams AS3722 power-off. 14 + 9 15 config POWER_RESET_GPIO 10 16 bool "GPIO power-off driver" 11 17 depends on OF_GPIO && POWER_RESET
+1
drivers/power/reset/Makefile
··· 1 + obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o 1 2 obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o 2 3 obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o 3 4 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
+96
drivers/power/reset/as3722-poweroff.c
··· 1 + /* 2 + * Power off driver for ams AS3722 device. 3 + * 4 + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. 5 + * 6 + * Author: Laxman Dewangan <ldewangan@nvidia.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms and conditions of the GNU General Public License, 10 + * version 2, as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope it will be useful, but WITHOUT 13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 + * more details. 16 + */ 17 + 18 + #include <linux/mfd/as3722.h> 19 + #include <linux/module.h> 20 + #include <linux/of.h> 21 + #include <linux/of_device.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/slab.h> 24 + 25 + struct as3722_poweroff { 26 + struct device *dev; 27 + struct as3722 *as3722; 28 + }; 29 + 30 + static struct as3722_poweroff *as3722_pm_poweroff; 31 + 32 + static void as3722_pm_power_off(void) 33 + { 34 + int ret; 35 + 36 + if (!as3722_pm_poweroff) { 37 + pr_err("AS3722 poweroff is not initialised\n"); 38 + return; 39 + } 40 + 41 + ret = as3722_update_bits(as3722_pm_poweroff->as3722, 42 + AS3722_RESET_CONTROL_REG, AS3722_POWER_OFF, AS3722_POWER_OFF); 43 + if (ret < 0) 44 + dev_err(as3722_pm_poweroff->dev, 45 + "RESET_CONTROL_REG update failed, %d\n", ret); 46 + } 47 + 48 + static int as3722_poweroff_probe(struct platform_device *pdev) 49 + { 50 + struct as3722_poweroff *as3722_poweroff; 51 + struct device_node *np = pdev->dev.parent->of_node; 52 + 53 + if (!np) 54 + return -EINVAL; 55 + 56 + if (!of_property_read_bool(np, "ams,system-power-controller")) 57 + return 0; 58 + 59 + as3722_poweroff = devm_kzalloc(&pdev->dev, sizeof(*as3722_poweroff), 60 + GFP_KERNEL); 61 + if (!as3722_poweroff) 62 + return -ENOMEM; 63 + 64 + as3722_poweroff->as3722 = dev_get_drvdata(pdev->dev.parent); 65 + as3722_poweroff->dev = &pdev->dev; 66 + as3722_pm_poweroff = as3722_poweroff; 67 + if (!pm_power_off) 68 + pm_power_off = as3722_pm_power_off; 69 + 70 + return 0; 71 + } 72 + 73 + static int as3722_poweroff_remove(struct platform_device *pdev) 74 + { 75 + if (pm_power_off == as3722_pm_power_off) 76 + pm_power_off = NULL; 77 + as3722_pm_poweroff = NULL; 78 + 79 + return 0; 80 + } 81 + 82 + static struct platform_driver as3722_poweroff_driver = { 83 + .driver = { 84 + .name = "as3722-power-off", 85 + .owner = THIS_MODULE, 86 + }, 87 + .probe = as3722_poweroff_probe, 88 + .remove = as3722_poweroff_remove, 89 + }; 90 + 91 + module_platform_driver(as3722_poweroff_driver); 92 + 93 + MODULE_DESCRIPTION("Power off driver for ams AS3722 PMIC Device"); 94 + MODULE_ALIAS("platform:as3722-power-off"); 95 + MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 96 + MODULE_LICENSE("GPL v2");
+5 -43
include/linux/power/bq2415x_charger.h
··· 1 1 /* 2 2 * bq2415x charger driver 3 3 * 4 - * Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com> 4 + * Copyright (C) 2011-2013 Pali Rohár <pali.rohar@gmail.com> 5 5 * 6 6 * This program is free software; you can redistribute it and/or modify 7 7 * it under the terms of the GNU General Public License as published by ··· 31 31 * termination current. It it is less or equal to zero, configuring charge 32 32 * and termination current will not be possible. 33 33 * 34 - * Function set_mode_hook is needed for automode (setting correct current 35 - * limit when charger is connected/disconnected or setting boost mode). 36 - * When is NULL, automode function is disabled. When is not NULL, it must 37 - * have this prototype: 38 - * 39 - * int (*set_mode_hook)( 40 - * void (*hook)(enum bq2415x_mode mode, void *data), 41 - * void *data) 42 - * 43 - * hook is hook function (see below) and data is pointer to driver private 44 - * data 45 - * 46 - * bq2415x driver will call it as: 47 - * 48 - * platform_data->set_mode_hook(bq2415x_hook_function, bq2415x_device); 49 - * 50 - * Board/platform function set_mode_hook return non zero value when hook 51 - * function was successful registered. Platform code should call that hook 52 - * function (which get from pointer, with data) every time when charger 53 - * was connected/disconnected or require to enable boost mode. bq2415x 54 - * driver then will set correct current limit, enable/disable charger or 55 - * boost mode. 56 - * 57 - * Hook function has this prototype: 58 - * 59 - * void hook(enum bq2415x_mode mode, void *data); 60 - * 61 - * mode is bq2415x mode (charger or boost) 62 - * data is pointer to driver private data (which get from 63 - * set_charger_type_hook) 64 - * 65 - * When bq driver is being unloaded, it call function: 66 - * 67 - * platform_data->set_mode_hook(NULL, NULL); 68 - * 69 - * (hook function and driver private data are NULL) 70 - * 71 - * After that board/platform code must not call driver hook function! It 72 - * is possible that pointer to hook function will not be valid and calling 73 - * will cause undefined result. 34 + * For automode support is needed to provide name of power supply device 35 + * in value notify_device. Device driver must immediately report property 36 + * POWER_SUPPLY_PROP_CURRENT_MAX when current changed. 74 37 */ 75 38 76 39 /* Supported modes with maximal current limit */ ··· 52 89 int charge_current; /* mA */ 53 90 int termination_current; /* mA */ 54 91 int resistor_sense; /* m ohm */ 55 - int (*set_mode_hook)(void (*hook)(enum bq2415x_mode mode, void *data), 56 - void *data); 92 + const char *notify_device; /* name */ 57 93 }; 58 94 59 95 #endif
+21 -13
include/linux/power/charger-manager.h
··· 37 37 CM_EVENT_BATT_FULL, 38 38 CM_EVENT_BATT_IN, 39 39 CM_EVENT_BATT_OUT, 40 + CM_EVENT_BATT_OVERHEAT, 41 + CM_EVENT_BATT_COLD, 40 42 CM_EVENT_EXT_PWR_IN_OUT, 41 43 CM_EVENT_CHG_START_STOP, 42 44 CM_EVENT_OTHERS, ··· 175 173 * @num_charger_regulator: the number of entries in charger_regulators 176 174 * @charger_regulators: array of charger regulators 177 175 * @psy_fuel_gauge: the name of power-supply for fuel gauge 178 - * @temperature_out_of_range: 179 - * Determine whether the status is overheat or cold or normal. 180 - * return_value > 0: overheat 181 - * return_value == 0: normal 182 - * return_value < 0: cold 176 + * @thermal_zone : the name of thermal zone for battery 177 + * @temp_min : Minimum battery temperature for charging. 178 + * @temp_max : Maximum battery temperature for charging. 179 + * @temp_diff : Temperature diffential to restart charging. 183 180 * @measure_battery_temp: 184 181 * true: measure battery temperature 185 182 * false: measure ambient temperature ··· 191 190 * max_duration_ms', cm start charging. 192 191 */ 193 192 struct charger_desc { 194 - char *psy_name; 193 + const char *psy_name; 195 194 196 195 enum polling_modes polling_mode; 197 196 unsigned int polling_interval_ms; ··· 204 203 205 204 enum data_source battery_present; 206 205 207 - char **psy_charger_stat; 206 + const char **psy_charger_stat; 208 207 209 208 int num_charger_regulators; 210 209 struct charger_regulator *charger_regulators; 211 210 212 - char *psy_fuel_gauge; 211 + const char *psy_fuel_gauge; 213 212 214 - int (*temperature_out_of_range)(int *mC); 213 + const char *thermal_zone; 214 + 215 + int temp_min; 216 + int temp_max; 217 + int temp_diff; 218 + 215 219 bool measure_battery_temp; 216 220 217 - u64 charging_max_duration_ms; 218 - u64 discharging_max_duration_ms; 221 + u32 charging_max_duration_ms; 222 + u32 discharging_max_duration_ms; 219 223 }; 220 224 221 225 #define PSY_NAME_MAX 30 ··· 232 226 * @desc: instance of charger_desc 233 227 * @fuel_gauge: power_supply for fuel gauge 234 228 * @charger_stat: array of power_supply for chargers 229 + * @tzd_batt : thermal zone device for battery 235 230 * @charger_enabled: the state of charger 236 231 * @fullbatt_vchk_jiffies_at: 237 232 * jiffies at the time full battery check will occur. 238 233 * @fullbatt_vchk_work: work queue for full battery check 239 234 * @emergency_stop: 240 235 * When setting true, stop charging 241 - * @last_temp_mC: the measured temperature in milli-Celsius 242 236 * @psy_name_buf: the name of power-supply-class for charger manager 243 237 * @charger_psy: power_supply for charger manager 244 238 * @status_save_ext_pwr_inserted: ··· 256 250 struct power_supply *fuel_gauge; 257 251 struct power_supply **charger_stat; 258 252 253 + #ifdef CONFIG_THERMAL 254 + struct thermal_zone_device *tzd_batt; 255 + #endif 259 256 bool charger_enabled; 260 257 261 258 unsigned long fullbatt_vchk_jiffies_at; 262 259 struct delayed_work fullbatt_vchk_work; 263 260 264 261 int emergency_stop; 265 - int last_temp_mC; 266 262 267 263 char psy_name_buf[PSY_NAME_MAX + 1]; 268 264 struct power_supply charger_psy;
+1
include/linux/power/isp1704_charger.h
··· 24 24 25 25 struct isp1704_charger_data { 26 26 void (*set_power)(bool on); 27 + int enable_gpio; 27 28 }; 28 29 29 30 #endif
+16
include/linux/power_supply.h
··· 16 16 #include <linux/workqueue.h> 17 17 #include <linux/leds.h> 18 18 #include <linux/spinlock.h> 19 + #include <linux/notifier.h> 19 20 20 21 struct device; 21 22 ··· 159 158 POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */ 160 159 }; 161 160 161 + enum power_supply_notifier_events { 162 + PSY_EVENT_PROP_CHANGED, 163 + }; 164 + 162 165 union power_supply_propval { 163 166 int intval; 164 167 const char *strval; ··· 240 235 int use_for_apm; 241 236 }; 242 237 238 + extern struct atomic_notifier_head power_supply_notifier; 239 + extern int power_supply_reg_notifier(struct notifier_block *nb); 240 + extern void power_supply_unreg_notifier(struct notifier_block *nb); 243 241 extern struct power_supply *power_supply_get_by_name(const char *name); 242 + #ifdef CONFIG_OF 243 + extern struct power_supply *power_supply_get_by_phandle(struct device_node *np, 244 + const char *property); 245 + #else /* !CONFIG_OF */ 246 + static inline struct power_supply * 247 + power_supply_get_by_phandle(struct device_node *np, const char *property) 248 + { return NULL; } 249 + #endif /* CONFIG_OF */ 244 250 extern void power_supply_changed(struct power_supply *psy); 245 251 extern int power_supply_am_i_supplied(struct power_supply *psy); 246 252 extern int power_supply_set_battery_charged(struct power_supply *psy);