charger-manager.c revision 1bbe24d465db626fed050e0128a7244b9cb407f4
13bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* 23bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Copyright (C) 2011 Samsung Electronics Co., Ltd. 33bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * MyungJoo Ham <myungjoo.ham@samsung.com> 43bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 53bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * This driver enables to monitor battery health and control charger 63bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * during suspend-to-mem. 73bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Charger manager depends on other devices. register this later than 83bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * the depending devices. 93bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * This program is free software; you can redistribute it and/or modify 113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * it under the terms of the GNU General Public License version 2 as 123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * published by the Free Software Foundation. 133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim**/ 143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/io.h> 163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/module.h> 173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/irq.h> 183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/interrupt.h> 193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/rtc.h> 203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/slab.h> 213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/workqueue.h> 223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/platform_device.h> 233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/power/charger-manager.h> 243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#include <linux/regulator/consumer.h> 253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* 273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for 283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * delayed works so that we can run delayed works with CM_JIFFIES_SMALL 293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * without any delays. 303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#define CM_JIFFIES_SMALL (2) 323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* If y is valid (> 0) and smaller than x, do x = y */ 343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#define CM_MIN_VALID(x, y) x = (((y > 0) && ((x) > (y))) ? (y) : (x)) 353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* 373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Regard CM_RTC_SMALL (sec) is small enough to ignore error in invoking 383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * rtc alarm. It should be 2 or larger 393bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 403bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#define CM_RTC_SMALL (2) 413bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 423bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim#define UEVENT_BUF_SIZE 32 433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic LIST_HEAD(cm_list); 453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic DEFINE_MUTEX(cm_list_mtx); 463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* About in-suspend (suspend-again) monitoring */ 483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic struct rtc_device *rtc_dev; 493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* 503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Backup RTC alarm 513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Save the wakeup alarm before entering suspend-to-RAM 523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic struct rtc_wkalrm rtc_wkalarm_save; 543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* Backup RTC alarm time in terms of seconds since 01-01-1970 00:00:00 */ 553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic unsigned long rtc_wkalarm_save_time; 563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool cm_suspended; 573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool cm_rtc_set; 583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic unsigned long cm_suspend_duration_ms; 593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/* Global charger-manager description */ 613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic struct charger_global_desc *g_desc; /* init with setup_charger_manager */ 623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 633bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * is_batt_present - See if the battery presents in place. 653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @cm: the Charger Manager representing the battery. 663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 673bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool is_batt_present(struct charger_manager *cm) 683bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 693bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim union power_supply_propval val; 703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim bool present = false; 713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim int i, ret; 723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 733bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim switch (cm->desc->battery_present) { 743bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim case CM_FUEL_GAUGE: 753bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 763bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim POWER_SUPPLY_PROP_PRESENT, &val); 773bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (ret == 0 && val.intval) 783bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim present = true; 793bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim break; 803bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim case CM_CHARGER_STAT: 813bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim for (i = 0; cm->charger_stat[i]; i++) { 823bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = cm->charger_stat[i]->get_property( 833bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->charger_stat[i], 843bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim POWER_SUPPLY_PROP_PRESENT, &val); 853bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (ret == 0 && val.intval) { 863bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim present = true; 873bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim break; 883bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 893bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 903bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim break; 913bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 923bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 933bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return present; 943bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 953bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 963bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 973bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * is_ext_pwr_online - See if an external power source is attached to charge 983bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @cm: the Charger Manager representing the battery. 993bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 1003bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Returns true if at least one of the chargers of the battery has an external 1013bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * power source attached to charge the battery regardless of whether it is 1023bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * actually charging or not. 1033bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 1043bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool is_ext_pwr_online(struct charger_manager *cm) 1053bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 1063bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim union power_supply_propval val; 1073bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim bool online = false; 1083bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim int i, ret; 1093bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 1103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* If at least one of them has one, it's yes. */ 1113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim for (i = 0; cm->charger_stat[i]; i++) { 1123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = cm->charger_stat[i]->get_property( 1133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->charger_stat[i], 1143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim POWER_SUPPLY_PROP_ONLINE, &val); 1153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (ret == 0 && val.intval) { 1163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim online = true; 1173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim break; 1183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 1193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 1203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 1213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return online; 1223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 1233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 1243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 125ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * get_batt_uV - Get the voltage level of the battery 126ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * @cm: the Charger Manager representing the battery. 127ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * @uV: the voltage level returned. 128ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * 129ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * Returns 0 if there is no error. 130ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * Returns a negative value on error. 131ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim */ 132ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kimstatic int get_batt_uV(struct charger_manager *cm, int *uV) 133ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim{ 134ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim union power_supply_propval val; 135ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim int ret; 136ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 137ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (cm->fuel_gauge) 138ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 139ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); 140ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim else 141ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim return -ENODEV; 142ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 143ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (ret) 144ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim return ret; 145ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 146ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim *uV = val.intval; 147ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim return 0; 148ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim} 149ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 150ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim/** 1513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * is_charging - Returns true if the battery is being charged. 1523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @cm: the Charger Manager representing the battery. 1533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 1543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool is_charging(struct charger_manager *cm) 1553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 1563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim int i, ret; 1573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim bool charging = false; 1583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim union power_supply_propval val; 1593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 1603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* If there is no battery, it cannot be charged */ 1613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!is_batt_present(cm)) 1623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return false; 1633bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 1643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* If at least one of the charger is charging, return yes */ 1653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim for (i = 0; cm->charger_stat[i]; i++) { 1663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* 1. The charger sholuld not be DISABLED */ 1673bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (cm->emergency_stop) 1683bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 1693bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm->charger_enabled) 1703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 1713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 1723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* 2. The charger should be online (ext-power) */ 1733bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = cm->charger_stat[i]->get_property( 1743bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->charger_stat[i], 1753bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim POWER_SUPPLY_PROP_ONLINE, &val); 1763bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (ret) { 1773bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_warn(cm->dev, "Cannot read ONLINE value from %s.\n", 1783bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->desc->psy_charger_stat[i]); 1793bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 1803bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 1813bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (val.intval == 0) 1823bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 1833bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 1843bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* 1853bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 3. The charger should not be FULL, DISCHARGING, 1863bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * or NOT_CHARGING. 1873bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 1883bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = cm->charger_stat[i]->get_property( 1893bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->charger_stat[i], 1903bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim POWER_SUPPLY_PROP_STATUS, &val); 1913bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (ret) { 1923bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_warn(cm->dev, "Cannot read STATUS value from %s.\n", 1933bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->desc->psy_charger_stat[i]); 1943bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 1953bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 1963bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (val.intval == POWER_SUPPLY_STATUS_FULL || 1973bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim val.intval == POWER_SUPPLY_STATUS_DISCHARGING || 1983bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim val.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) 1993bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 2003bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2013bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Then, this is charging. */ 2023bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim charging = true; 2033bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim break; 2043bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 2053bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2063bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return charging; 2073bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 2083bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2093bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 2103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * is_polling_required - Return true if need to continue polling for this CM. 2113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @cm: the Charger Manager representing the battery. 2123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 2133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool is_polling_required(struct charger_manager *cm) 2143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 2153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim switch (cm->desc->polling_mode) { 2163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim case CM_POLL_DISABLE: 2173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return false; 2183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim case CM_POLL_ALWAYS: 2193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return true; 2203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim case CM_POLL_EXTERNAL_POWER_ONLY: 2213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return is_ext_pwr_online(cm); 2223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim case CM_POLL_CHARGING_ONLY: 2233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return is_charging(cm); 2243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim default: 2253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_warn(cm->dev, "Incorrect polling_mode (%d)\n", 2263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->desc->polling_mode); 2273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 2283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return false; 2303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 2313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 2333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * try_charger_enable - Enable/Disable chargers altogether 2343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @cm: the Charger Manager representing the battery. 2353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @enable: true: enable / false: disable 2363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 2373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Note that Charger Manager keeps the charger enabled regardless whether 2383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * the charger is charging or not (because battery is full or no external 2393bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * power source exists) except when CM needs to disable chargers forcibly 2403bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * bacause of emergency causes; when the battery is overheated or too cold. 2413bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 2423bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic int try_charger_enable(struct charger_manager *cm, bool enable) 2433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 2443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim int err = 0, i; 2453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_desc *desc = cm->desc; 2463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Ignore if it's redundent command */ 2483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (enable && cm->charger_enabled) 2493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return 0; 2503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!enable && !cm->charger_enabled) 2513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return 0; 2523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (enable) { 2543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (cm->emergency_stop) 2553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return -EAGAIN; 2563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim err = regulator_bulk_enable(desc->num_charger_regulators, 2573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators); 2583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } else { 2593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* 2603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Abnormal battery state - Stop charging forcibly, 2613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * even if charger was enabled at the other places 2623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 2633bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim err = regulator_bulk_disable(desc->num_charger_regulators, 2643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators); 2653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim for (i = 0; i < desc->num_charger_regulators; i++) { 2673bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (regulator_is_enabled( 2683bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators[i].consumer)) { 2693bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim regulator_force_disable( 2703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators[i].consumer); 2713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_warn(cm->dev, 2723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim "Disable regulator(%s) forcibly.\n", 2733bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators[i].supply); 2743bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 2753bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 2763bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 2773bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2783bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!err) 2793bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->charger_enabled = enable; 2803bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2813bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return err; 2823bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 2833bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 2843bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 2853bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * uevent_notify - Let users know something has changed. 2863bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @cm: the Charger Manager representing the battery. 2873bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @event: the event string. 2883bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 2893bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * If @event is null, it implies that uevent_notify is called 2903bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * by resume function. When called in the resume function, cm_suspended 2913bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * should be already reset to false in order to let uevent_notify 2923bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * notify the recent event during the suspend to users. While 2933bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * suspended, uevent_notify does not notify users, but tracks 2943bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * events so that uevent_notify can notify users later after resumed. 2953bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 2963bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic void uevent_notify(struct charger_manager *cm, const char *event) 2973bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 2983bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim static char env_str[UEVENT_BUF_SIZE + 1] = ""; 2993bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim static char env_str_save[UEVENT_BUF_SIZE + 1] = ""; 3003bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3013bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (cm_suspended) { 3023bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Nothing in suspended-event buffer */ 3033bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (env_str_save[0] == 0) { 3043bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!strncmp(env_str, event, UEVENT_BUF_SIZE)) 3053bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return; /* status not changed */ 3063bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim strncpy(env_str_save, event, UEVENT_BUF_SIZE); 3073bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return; 3083bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 3093bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!strncmp(env_str_save, event, UEVENT_BUF_SIZE)) 3113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return; /* Duplicated. */ 3123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim else 3133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim strncpy(env_str_save, event, UEVENT_BUF_SIZE); 3143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return; 3163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 3173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (event == NULL) { 3193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* No messages pending */ 3203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!env_str_save[0]) 3213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return; 3223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim strncpy(env_str, env_str_save, UEVENT_BUF_SIZE); 3243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE); 3253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim env_str_save[0] = 0; 3263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return; 3283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 3293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* status not changed */ 3313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!strncmp(env_str, event, UEVENT_BUF_SIZE)) 3323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return; 3333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* save the status and notify the update */ 3353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim strncpy(env_str, event, UEVENT_BUF_SIZE); 3363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE); 3373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_info(cm->dev, event); 3393bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 3403bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3413bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 3423bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * _cm_monitor - Monitor the temperature and return true for exceptions. 3433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @cm: the Charger Manager representing the battery. 3443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 3453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Returns true if there is an event to notify for the battery. 3463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * (True if the status of "emergency_stop" changes) 3473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 3483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool _cm_monitor(struct charger_manager *cm) 3493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 3503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_desc *desc = cm->desc; 3513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim int temp = desc->temperature_out_of_range(&cm->last_temp_mC); 3523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n", 3543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->last_temp_mC / 1000, cm->last_temp_mC % 1000); 3553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* It has been stopped or charging already */ 3573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!!temp == !!cm->emergency_stop) 3583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return false; 3593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (temp) { 3613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->emergency_stop = temp; 3623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!try_charger_enable(cm, false)) { 3633bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (temp > 0) 3643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim uevent_notify(cm, "OVERHEAT"); 3653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim else 3663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim uevent_notify(cm, "COLD"); 3673bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 3683bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } else { 3693bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->emergency_stop = 0; 3703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!try_charger_enable(cm, true)) 3713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim uevent_notify(cm, "CHARGING"); 3723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 3733bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3743bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return true; 3753bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 3763bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3773bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 3783bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * cm_monitor - Monitor every battery. 3793bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 3803bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Returns true if there is an event to notify from any of the batteries. 3813bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * (True if the status of "emergency_stop" changes) 3823bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 3833bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool cm_monitor(void) 3843bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 3853bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim bool stop = false; 3863bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_manager *cm; 3873bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3883bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_lock(&cm_list_mtx); 3893bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3903bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim list_for_each_entry(cm, &cm_list, entry) 3913bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim stop = stop || _cm_monitor(cm); 3923bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3933bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_unlock(&cm_list_mtx); 3943bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 3953bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return stop; 3963bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 3973bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 398ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kimstatic int charger_get_property(struct power_supply *psy, 399ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim enum power_supply_property psp, 400ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim union power_supply_propval *val) 401ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim{ 402ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim struct charger_manager *cm = container_of(psy, 403ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim struct charger_manager, charger_psy); 404ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim struct charger_desc *desc = cm->desc; 405ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim int i, ret = 0, uV; 406ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 407ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim switch (psp) { 408ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_STATUS: 409ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (is_charging(cm)) 410ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = POWER_SUPPLY_STATUS_CHARGING; 411ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim else if (is_ext_pwr_online(cm)) 412ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 413ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim else 414ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 415ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 416ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_HEALTH: 417ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (cm->emergency_stop > 0) 418ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 419ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim else if (cm->emergency_stop < 0) 420ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = POWER_SUPPLY_HEALTH_COLD; 421ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim else 422ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = POWER_SUPPLY_HEALTH_GOOD; 423ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 424ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_PRESENT: 425ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (is_batt_present(cm)) 426ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 1; 427ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim else 428ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 0; 429ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 430ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_VOLTAGE_NOW: 431ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = get_batt_uV(cm, &i); 432ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = i; 433ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 434ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_CURRENT_NOW: 435ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 436ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CURRENT_NOW, val); 437ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 438ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_TEMP: 439ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* in thenth of centigrade */ 440ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (cm->last_temp_mC == INT_MIN) 441ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim desc->temperature_out_of_range(&cm->last_temp_mC); 442ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = cm->last_temp_mC / 100; 443ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!desc->measure_battery_temp) 444ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = -ENODEV; 445ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 446ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_TEMP_AMBIENT: 447ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* in thenth of centigrade */ 448ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (cm->last_temp_mC == INT_MIN) 449ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim desc->temperature_out_of_range(&cm->last_temp_mC); 450ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = cm->last_temp_mC / 100; 451ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (desc->measure_battery_temp) 452ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = -ENODEV; 453ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 454ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_CAPACITY: 455ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!cm->fuel_gauge) { 456ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = -ENODEV; 457ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 458ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 459ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 460ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!is_batt_present(cm)) { 461ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* There is no battery. Assume 100% */ 462ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 100; 463ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 464ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 465ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 466ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 467ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CAPACITY, val); 468ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (ret) 469ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 470ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 471ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (val->intval > 100) { 472ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 100; 473ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 474ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 475ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (val->intval < 0) 476ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 0; 477ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 478ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Do not adjust SOC when charging: voltage is overrated */ 479ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (is_charging(cm)) 480ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 481ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 482ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* 483ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * If the capacity value is inconsistent, calibrate it base on 484ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * the battery voltage values and the thresholds given as desc 485ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim */ 486ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = get_batt_uV(cm, &uV); 487ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (ret) { 488ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Voltage information not available. No calibration */ 489ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = 0; 490ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 491ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 492ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 493ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV && 494ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim !is_charging(cm)) { 495ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 100; 496ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 497ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 498ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 499ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 500ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_ONLINE: 501ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (is_ext_pwr_online(cm)) 502ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 1; 503ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim else 504ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 0; 505ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 506ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_CHARGE_FULL: 507ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (cm->fuel_gauge) { 508ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (cm->fuel_gauge->get_property(cm->fuel_gauge, 509ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CHARGE_FULL, val) == 0) 510ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 511ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 512ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 513ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (is_ext_pwr_online(cm)) { 514ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Not full if it's charging. */ 515ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (is_charging(cm)) { 516ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 0; 517ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 518ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 519ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* 520ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * Full if it's powered but not charging andi 521ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * not forced stop by emergency 522ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim */ 523ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!cm->emergency_stop) { 524ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 1; 525ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 526ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 527ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 528ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 529ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Full if it's over the fullbatt voltage */ 530ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = get_batt_uV(cm, &uV); 531ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!ret && desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV && 532ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim !is_charging(cm)) { 533ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 1; 534ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 535ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 536ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 537ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Full if the cap is 100 */ 538ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (cm->fuel_gauge) { 539ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 540ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CAPACITY, val); 541ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!ret && val->intval >= 100 && !is_charging(cm)) { 542ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 1; 543ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 544ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 545ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 546ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 547ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 0; 548ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = 0; 549ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 550ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim case POWER_SUPPLY_PROP_CHARGE_NOW: 551ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (is_charging(cm)) { 552ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = cm->fuel_gauge->get_property(cm->fuel_gauge, 553ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CHARGE_NOW, 554ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val); 555ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (ret) { 556ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 1; 557ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = 0; 558ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } else { 559ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* If CHARGE_NOW is supplied, use it */ 560ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = (val->intval > 0) ? 561ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval : 1; 562ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 563ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } else { 564ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim val->intval = 0; 565ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 566ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim break; 567ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim default: 568ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim return -EINVAL; 569ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 570ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim return ret; 571ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim} 572ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 573ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim#define NUM_CHARGER_PSY_OPTIONAL (4) 574ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kimstatic enum power_supply_property default_charger_props[] = { 575ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Guaranteed to provide */ 576ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_STATUS, 577ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_HEALTH, 578ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_PRESENT, 579ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_VOLTAGE_NOW, 580ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CAPACITY, 581ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_ONLINE, 582ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CHARGE_FULL, 583ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* 584ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * Optional properties are: 585ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * POWER_SUPPLY_PROP_CHARGE_NOW, 586ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * POWER_SUPPLY_PROP_CURRENT_NOW, 587ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * POWER_SUPPLY_PROP_TEMP, and 588ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * POWER_SUPPLY_PROP_TEMP_AMBIENT, 589ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim */ 590ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim}; 591ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 592ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kimstatic struct power_supply psy_default = { 593ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim .name = "battery", 594ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim .type = POWER_SUPPLY_TYPE_BATTERY, 595ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim .properties = default_charger_props, 596ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim .num_properties = ARRAY_SIZE(default_charger_props), 597ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim .get_property = charger_get_property, 598ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim}; 599ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 6003bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 6013bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * cm_setup_timer - For in-suspend monitoring setup wakeup alarm 6023bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * for suspend_again. 6033bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 6043bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Returns true if the alarm is set for Charger Manager to use. 6053bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Returns false if 6063bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * cm_setup_timer fails to set an alarm, 6073bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * cm_setup_timer does not need to set an alarm for Charger Manager, 6083bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * or an alarm previously configured is to be used. 6093bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 6103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic bool cm_setup_timer(void) 6113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 6123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_manager *cm; 6133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim unsigned int wakeup_ms = UINT_MAX; 6143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim bool ret = false; 6153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_lock(&cm_list_mtx); 6173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim list_for_each_entry(cm, &cm_list, entry) { 6193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Skip if polling is not required for this CM */ 6203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!is_polling_required(cm) && !cm->emergency_stop) 6213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 6223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (cm->desc->polling_interval_ms == 0) 6233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim continue; 6243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim CM_MIN_VALID(wakeup_ms, cm->desc->polling_interval_ms); 6253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 6263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_unlock(&cm_list_mtx); 6283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (wakeup_ms < UINT_MAX && wakeup_ms > 0) { 6303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim pr_info("Charger Manager wakeup timer: %u ms.\n", wakeup_ms); 6313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_dev) { 6323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct rtc_wkalrm tmp; 6333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim unsigned long time, now; 6343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim unsigned long add = DIV_ROUND_UP(wakeup_ms, 1000); 6353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* 6373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Set alarm with the polling interval (wakeup_ms) 6383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * except when rtc_wkalarm_save comes first. 6393bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * However, the alarm time should be NOW + 6403bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * CM_RTC_SMALL or later. 6413bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 6423bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim tmp.enabled = 1; 6433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_read_time(rtc_dev, &tmp.time); 6443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_tm_to_time(&tmp.time, &now); 6453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (add < CM_RTC_SMALL) 6463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim add = CM_RTC_SMALL; 6473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim time = now + add; 6483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = true; 6503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_wkalarm_save.enabled && 6523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_wkalarm_save_time && 6533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_wkalarm_save_time < time) { 6543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_wkalarm_save_time < now + CM_RTC_SMALL) 6553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim time = now + CM_RTC_SMALL; 6563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim else 6573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim time = rtc_wkalarm_save_time; 6583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* The timer is not appointed by CM */ 6603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = false; 6613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 6623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6633bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim pr_info("Waking up after %lu secs.\n", 6643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim time - now); 6653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_time_to_tm(time, &tmp.time); 6673bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_set_alarm(rtc_dev, &tmp); 6683bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm_suspend_duration_ms += wakeup_ms; 6693bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return ret; 6703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 6713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 6723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6733bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_dev) 6743bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_set_alarm(rtc_dev, &rtc_wkalarm_save); 6753bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return false; 6763bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 6773bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6783bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 6793bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * cm_suspend_again - Determine whether suspend again or not 6803bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * 6813bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Returns true if the system should be suspended again 6823bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * Returns false if the system should be woken up 6833bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 6843bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimbool cm_suspend_again(void) 6853bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 6863bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_manager *cm; 6873bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim bool ret = false; 6883bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6893bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!g_desc || !g_desc->rtc_only_wakeup || !g_desc->rtc_only_wakeup() || 6903bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim !cm_rtc_set) 6913bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return false; 6923bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6933bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (cm_monitor()) 6943bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto out; 6953bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 6963bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = true; 6973bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_lock(&cm_list_mtx); 6983bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim list_for_each_entry(cm, &cm_list, entry) { 6993bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (cm->status_save_ext_pwr_inserted != is_ext_pwr_online(cm) || 7003bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->status_save_batt != is_batt_present(cm)) 7013bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = false; 7023bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7033bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_unlock(&cm_list_mtx); 7043bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7053bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm_rtc_set = cm_setup_timer(); 7063bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimout: 7073bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* It's about the time when the non-CM appointed timer goes off */ 7083bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_wkalarm_save.enabled) { 7093bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim unsigned long now; 7103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct rtc_time tmp; 7113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_read_time(rtc_dev, &tmp); 7133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_tm_to_time(&tmp, &now); 7143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_wkalarm_save_time && 7163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim now + CM_RTC_SMALL >= rtc_wkalarm_save_time) 7173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return false; 7183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return ret; 7203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 7213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun KimEXPORT_SYMBOL_GPL(cm_suspend_again); 7223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim/** 7243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * setup_charger_manager - initialize charger_global_desc data 7253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim * @gd: pointer to instance of charger_global_desc 7263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim */ 7273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimint setup_charger_manager(struct charger_global_desc *gd) 7283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 7293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!gd) 7303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return -EINVAL; 7313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_dev) 7333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_class_close(rtc_dev); 7343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_dev = NULL; 7353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim g_desc = NULL; 7363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!gd->rtc_only_wakeup) { 7383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim pr_err("The callback rtc_only_wakeup is not given.\n"); 7393bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return -EINVAL; 7403bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7413bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7423bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (gd->rtc_name) { 7433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_dev = rtc_class_open(gd->rtc_name); 7443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (IS_ERR_OR_NULL(rtc_dev)) { 7453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_dev = NULL; 7463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Retry at probe. RTC may be not registered yet */ 7473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } else { 7493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim pr_warn("No wakeup timer is given for charger manager." 7503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim "In-suspend monitoring won't work.\n"); 7513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim g_desc = gd; 7543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return 0; 7553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 7563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun KimEXPORT_SYMBOL_GPL(setup_charger_manager); 7573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic int charger_manager_probe(struct platform_device *pdev) 7593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 7603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_desc *desc = dev_get_platdata(&pdev->dev); 7613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_manager *cm; 7623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim int ret = 0, i = 0; 763ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim union power_supply_propval val; 7643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (g_desc && !rtc_dev && g_desc->rtc_name) { 7663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_dev = rtc_class_open(g_desc->rtc_name); 7673bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (IS_ERR_OR_NULL(rtc_dev)) { 7683bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_dev = NULL; 7693bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "Cannot get RTC %s.\n", 7703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim g_desc->rtc_name); 7713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -ENODEV; 7723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_alloc; 7733bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7743bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7753bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7763bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!desc) { 7773bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "No platform data (desc) found.\n"); 7783bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -ENODEV; 7793bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_alloc; 7803bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7813bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7823bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm = kzalloc(sizeof(struct charger_manager), GFP_KERNEL); 7833bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm) { 7843bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "Cannot allocate memory.\n"); 7853bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -ENOMEM; 7863bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_alloc; 7873bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7883bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 7893bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Basic Values. Unspecified are Null or 0 */ 7903bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->dev = &pdev->dev; 7913bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->desc = kzalloc(sizeof(struct charger_desc), GFP_KERNEL); 7923bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm->desc) { 7933bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "Cannot allocate memory.\n"); 7943bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -ENOMEM; 7953bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_alloc_desc; 7963bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 7973bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim memcpy(cm->desc, desc, sizeof(struct charger_desc)); 7983bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ 7993bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8003bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!desc->charger_regulators || desc->num_charger_regulators < 1) { 8013bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -EINVAL; 8023bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "charger_regulators undefined.\n"); 8033bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_no_charger; 8043bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8053bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8063bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) { 8073bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "No power supply defined.\n"); 8083bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -EINVAL; 8093bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_no_charger_stat; 8103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Counting index only */ 8133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim while (desc->psy_charger_stat[i]) 8143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim i++; 8153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->charger_stat = kzalloc(sizeof(struct power_supply *) * (i + 1), 8173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim GFP_KERNEL); 8183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm->charger_stat) { 8193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -ENOMEM; 8203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_no_charger_stat; 8213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim for (i = 0; desc->psy_charger_stat[i]; i++) { 8243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->charger_stat[i] = power_supply_get_by_name( 8253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->psy_charger_stat[i]); 8263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm->charger_stat[i]) { 8273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "Cannot find power supply " 8283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim "\"%s\"\n", 8293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->psy_charger_stat[i]); 8303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -ENODEV; 8313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_chg_stat; 8323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge); 8363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm->fuel_gauge) { 8373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", 8383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->psy_fuel_gauge); 8393bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -ENODEV; 8403bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_chg_stat; 8413bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8423bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (desc->polling_interval_ms == 0 || 8443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim msecs_to_jiffies(desc->polling_interval_ms) <= CM_JIFFIES_SMALL) { 8453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "polling_interval_ms is too small\n"); 8463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -EINVAL; 8473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_chg_stat; 8483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!desc->temperature_out_of_range) { 8513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "there is no temperature_out_of_range\n"); 8523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = -EINVAL; 8533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_chg_stat; 8543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 8553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 8563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim platform_set_drvdata(pdev, cm); 8573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 858ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim memcpy(&cm->charger_psy, &psy_default, 859ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim sizeof(psy_default)); 860ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!desc->psy_name) { 861ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim strncpy(cm->psy_name_buf, psy_default.name, 862ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim PSY_NAME_MAX); 863ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } else { 864ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX); 865ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 866ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.name = cm->psy_name_buf; 867ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 868ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Allocate for psy properties because they may vary */ 869ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.properties = kzalloc(sizeof(enum power_supply_property) 870ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim * (ARRAY_SIZE(default_charger_props) + 871ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim NUM_CHARGER_PSY_OPTIONAL), 872ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim GFP_KERNEL); 873ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!cm->charger_psy.properties) { 874ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim dev_err(&pdev->dev, "Cannot allocate for psy properties.\n"); 875ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = -ENOMEM; 876ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim goto err_chg_stat; 877ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 878ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim memcpy(cm->charger_psy.properties, default_charger_props, 879ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim sizeof(enum power_supply_property) * 880ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ARRAY_SIZE(default_charger_props)); 881ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.num_properties = psy_default.num_properties; 882ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 883ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim /* Find which optional psy-properties are available */ 884ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!cm->fuel_gauge->get_property(cm->fuel_gauge, 885ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CHARGE_NOW, &val)) { 886ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.properties[cm->charger_psy.num_properties] = 887ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CHARGE_NOW; 888ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.num_properties++; 889ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 890ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!cm->fuel_gauge->get_property(cm->fuel_gauge, 891ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CURRENT_NOW, 892ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim &val)) { 893ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.properties[cm->charger_psy.num_properties] = 894ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_CURRENT_NOW; 895ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.num_properties++; 896ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 897ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (!desc->measure_battery_temp) { 898ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.properties[cm->charger_psy.num_properties] = 899ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_TEMP_AMBIENT; 900ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.num_properties++; 901ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 902ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (desc->measure_battery_temp) { 903ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.properties[cm->charger_psy.num_properties] = 904ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim POWER_SUPPLY_PROP_TEMP; 905ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim cm->charger_psy.num_properties++; 906ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 907ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 908ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim ret = power_supply_register(NULL, &cm->charger_psy); 909ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim if (ret) { 910ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim dev_err(&pdev->dev, "Cannot register charger-manager with" 911ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim " name \"%s\".\n", cm->charger_psy.name); 912ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim goto err_register; 913ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim } 914ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 9153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators, 9163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators); 9173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (ret) { 9183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "Cannot get charger regulators.\n"); 919ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim goto err_bulk_get; 9203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 9213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim ret = try_charger_enable(cm, true); 9233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (ret) { 9243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev_err(&pdev->dev, "Cannot enable charger regulators\n"); 9253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim goto err_chg_enable; 9263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 9273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Add to the list */ 9293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_lock(&cm_list_mtx); 9303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim list_add(&cm->entry, &cm_list); 9313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_unlock(&cm_list_mtx); 9323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return 0; 9343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimerr_chg_enable: 9363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (desc->charger_regulators) 9373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim regulator_bulk_free(desc->num_charger_regulators, 9383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators); 939ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kimerr_bulk_get: 940ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim power_supply_unregister(&cm->charger_psy); 941ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kimerr_register: 942ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim kfree(cm->charger_psy.properties); 9433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimerr_chg_stat: 9443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kfree(cm->charger_stat); 9453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimerr_no_charger_stat: 9463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimerr_no_charger: 9473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kfree(cm->desc); 9483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimerr_alloc_desc: 9493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kfree(cm); 9503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimerr_alloc: 9513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return ret; 9523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 9533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic int __devexit charger_manager_remove(struct platform_device *pdev) 9553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 9563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_manager *cm = platform_get_drvdata(pdev); 9573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_desc *desc = cm->desc; 9583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim /* Remove from the list */ 9603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_lock(&cm_list_mtx); 9613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim list_del(&cm->entry); 9623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim mutex_unlock(&cm_list_mtx); 9633bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (desc->charger_regulators) 9653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim regulator_bulk_free(desc->num_charger_regulators, 9663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim desc->charger_regulators); 967ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim 968ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim power_supply_unregister(&cm->charger_psy); 969ad3d13eee78ec44194bf919a37e2f711e53cbdf0Donggeun Kim kfree(cm->charger_psy.properties); 9703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kfree(cm->charger_stat); 9713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kfree(cm->desc); 9723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim kfree(cm); 9733bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9743bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return 0; 9753bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 9763bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9771bbe24d465db626fed050e0128a7244b9cb407f4Axel Linstatic const struct platform_device_id charger_manager_id[] = { 9783bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim { "charger-manager", 0 }, 9793bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim { }, 9803bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim}; 9811bbe24d465db626fed050e0128a7244b9cb407f4Axel LinMODULE_DEVICE_TABLE(platform, charger_manager_id); 9823bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9833bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic int cm_suspend_prepare(struct device *dev) 9843bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 9853bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct platform_device *pdev = container_of(dev, struct platform_device, 9863bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev); 9873bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_manager *cm = platform_get_drvdata(pdev); 9883bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9893bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm_suspended) { 9903bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_dev) { 9913bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct rtc_time tmp; 9923bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim unsigned long now; 9933bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9943bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_read_alarm(rtc_dev, &rtc_wkalarm_save); 9953bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_read_time(rtc_dev, &tmp); 9963bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 9973bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_wkalarm_save.enabled) { 9983bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_tm_to_time(&rtc_wkalarm_save.time, 9993bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim &rtc_wkalarm_save_time); 10003bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_tm_to_time(&tmp, &now); 10013bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (now > rtc_wkalarm_save_time) 10023bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_wkalarm_save_time = 0; 10033bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } else { 10043bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_wkalarm_save_time = 0; 10053bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 10063bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 10073bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm_suspended = true; 10083bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 10093bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10103bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm); 10113bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm->status_save_batt = is_batt_present(cm); 10123bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10133bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (!cm_rtc_set) { 10143bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm_suspend_duration_ms = 0; 10153bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm_rtc_set = cm_setup_timer(); 10163bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 10173bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10183bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return 0; 10193bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 10203bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10213bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic void cm_suspend_complete(struct device *dev) 10223bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 10233bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct platform_device *pdev = container_of(dev, struct platform_device, 10243bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim dev); 10253bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct charger_manager *cm = platform_get_drvdata(pdev); 10263bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10273bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (cm_suspended) { 10283bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim if (rtc_dev) { 10293bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim struct rtc_wkalrm tmp; 10303bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10313bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_read_alarm(rtc_dev, &tmp); 10323bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_wkalarm_save.pending = tmp.pending; 10333bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim rtc_set_alarm(rtc_dev, &rtc_wkalarm_save); 10343bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 10353bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm_suspended = false; 10363bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim cm_rtc_set = false; 10373bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim } 10383bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10393bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim uevent_notify(cm, NULL); 10403bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 10413bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10423bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic const struct dev_pm_ops charger_manager_pm = { 10433bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .prepare = cm_suspend_prepare, 10443bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .complete = cm_suspend_complete, 10453bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim}; 10463bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10473bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic struct platform_driver charger_manager_driver = { 10483bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .driver = { 10493bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .name = "charger-manager", 10503bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .owner = THIS_MODULE, 10513bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .pm = &charger_manager_pm, 10523bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim }, 10533bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .probe = charger_manager_probe, 10543bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .remove = __devexit_p(charger_manager_remove), 10553bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim .id_table = charger_manager_id, 10563bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim}; 10573bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10583bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic int __init charger_manager_init(void) 10593bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 10603bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim return platform_driver_register(&charger_manager_driver); 10613bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 10623bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimlate_initcall(charger_manager_init); 10633bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10643bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimstatic void __exit charger_manager_cleanup(void) 10653bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim{ 10663bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim platform_driver_unregister(&charger_manager_driver); 10673bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim} 10683bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kimmodule_exit(charger_manager_cleanup); 10693bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun Kim 10703bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun KimMODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 10713bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun KimMODULE_DESCRIPTION("Charger Manager"); 10723bb3dbbd56ea39e5537db8f8041ea95d28f16a7fDonggeun KimMODULE_LICENSE("GPL"); 1073