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