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