All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework
@ 2013-09-23 18:03 Jenny TC
  2013-09-23 18:03 ` [PATCH 1/7] power_supply: Add charger control properties Jenny TC
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:03 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC

The Power Supply charging framework connects multiple subsystems to
do charging in a generic way. The framework makes use of different
new features - Battery Identification framework, pluggable charging
algorithms, charger cable arbitrations. PSE compliant charging
algorithm also enabled as part of this patch set.

With this framework the charging logic can be kept outside the charger
driver.The charger driver just need to expose th get_property and
set_property functions to get and set a specific set of power supply
properties. The driver can convert these values to the hardware
configurations to setup charging.


Jenny TC (7):
  power_supply: Add charger control properties
  power_supply : add charger cable properties
  power_supply: add throttle state
  power_supply: Add power_supply notifier
  power_supply : Introduce battery identification framework
  power_supply: Introduce Power Supply charging framework
  power_supply: Introduce PSE compliant algorithm

 Documentation/power/power_supply_class.txt |  202 ++++++
 drivers/power/Kconfig                      |   30 +
 drivers/power/Makefile                     |    3 +
 drivers/power/battery_id.c                 |   87 +++
 drivers/power/charging_algo_pse.c          |  202 ++++++
 drivers/power/power_supply.h               |   21 +
 drivers/power/power_supply_charger.c       | 1011 ++++++++++++++++++++++++++++
 drivers/power/power_supply_charger.h       |  130 ++++
 drivers/power/power_supply_core.c          |   38 ++
 drivers/power/power_supply_sysfs.c         |    8 +
 include/linux/power/battery_id.h           |  100 +++
 include/linux/power_supply.h               |  335 +++++++++
 12 files changed, 2167 insertions(+)
 create mode 100644 drivers/power/battery_id.c
 create mode 100644 drivers/power/charging_algo_pse.c
 create mode 100644 drivers/power/power_supply_charger.c
 create mode 100644 drivers/power/power_supply_charger.h
 create mode 100644 include/linux/power/battery_id.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/7] power_supply: Add charger control properties
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
@ 2013-09-23 18:03 ` Jenny TC
  2013-10-27 23:46   ` Anton Vorontsov
  2013-09-23 18:04 ` [PATCH 2/7] power_supply : add charger cable properties Jenny TC
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:03 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC

The battery charger needs to have control path along
with the reporting charger properties. In existing solutions
this is implemented using regulator framework. A regulator
framework doesn't fit a charger driver requirement because of the
following reason
Charger needs support two paths - charger path (charger to platform)
and charging (charger to battery).Disabling the charging path alone
(eg over battery temperature) will allow the platform to work with
power from charger without discharging the battery. And the charger
may need to be disabled completely based on the charger temperature
or the platform temperature.
Charger has more than one pair of voltage/current to control (CC,CV,INLMT)
These features will not directly fit in the regulator framework

Since the charger driver sits in the power supply subsystem it make sense
to add the properties to control the charger.
Signed-off-by: Jenny TC <jenny.tc@intel.com>

Change-Id: Id91dbbd8f34499afa97b7d8f11ecf5467847f6a8
---
 Documentation/power/power_supply_class.txt |   16 ++++++++++++++++
 drivers/power/power_supply_sysfs.c         |    8 ++++++++
 include/linux/power_supply.h               |    8 ++++++++
 3 files changed, 32 insertions(+)

diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index 3f10b39..5a5e7fa 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -118,6 +118,10 @@ relative, time-based measurements.
 CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger.
 CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by the
 power supply object.
+INPUT_CURRENT_LIMIT - input current limit programmed by charger. Indicates
+the current drawn from a charging source.
+CHARGE_TERM_CUR - Charge termination current used to detect the end of charge
+condition
 
 CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
 CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the
@@ -140,12 +144,24 @@ TEMP_ALERT_MAX - maximum battery temperature alert value in milli centigrade.
 TEMP_AMBIENT - ambient temperature.
 TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert value in milli centigrade.
 TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert value in milli centigrade.
+MIN_TEMP - minimum operatable temperature
+MAX_TEMP - maximum operatable temperature
 
 TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e.
 while battery powers a load)
 TIME_TO_FULL - seconds left for battery to be considered full (i.e.
 while battery is charging)
 
+ENABLE_CHARGING - Enable/disable charging. Write is used to enable/disable charging.
+Reading the interface indicates whether the charging is enabled/disabled by the charger h/w.
+ENABLE_CHARGER - Enable/disable charger. Write is used to enable/disable charger.
+Reading the interface indicates whether the charger is enabled/disabled. When charger
+is disabled platform is not expected to draw current from charging source.
+
+CABLE_TYPE - Used to indicate the type of cable used for charging.
+PRIORITY - Indicates the priority of a power supply charger object. Useful
+to setup charging on platforms with multiple charger chips.(Wireless/USB/AC etc.)
+
 
 Battery <-> external power supply interaction
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 44420d1..d45c813 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -167,6 +167,7 @@ static struct device_attribute power_supply_attrs[] = {
 	POWER_SUPPLY_ATTR(constant_charge_voltage_max),
 	POWER_SUPPLY_ATTR(charge_control_limit),
 	POWER_SUPPLY_ATTR(charge_control_limit_max),
+	POWER_SUPPLY_ATTR(input_cur_limit),
 	POWER_SUPPLY_ATTR(energy_full_design),
 	POWER_SUPPLY_ATTR(energy_empty_design),
 	POWER_SUPPLY_ATTR(energy_full),
@@ -178,6 +179,8 @@ static struct device_attribute power_supply_attrs[] = {
 	POWER_SUPPLY_ATTR(capacity_alert_max),
 	POWER_SUPPLY_ATTR(capacity_level),
 	POWER_SUPPLY_ATTR(temp),
+	POWER_SUPPLY_ATTR(max_temp),
+	POWER_SUPPLY_ATTR(min_temp),
 	POWER_SUPPLY_ATTR(temp_alert_min),
 	POWER_SUPPLY_ATTR(temp_alert_max),
 	POWER_SUPPLY_ATTR(temp_ambient),
@@ -189,6 +192,11 @@ static struct device_attribute power_supply_attrs[] = {
 	POWER_SUPPLY_ATTR(time_to_full_avg),
 	POWER_SUPPLY_ATTR(type),
 	POWER_SUPPLY_ATTR(scope),
+	POWER_SUPPLY_ATTR(charge_term_cur),
+	POWER_SUPPLY_ATTR(enable_charging),
+	POWER_SUPPLY_ATTR(enable_charger),
+	POWER_SUPPLY_ATTR(cable_type),
+	POWER_SUPPLY_ATTR(priority),
 	/* Properties of type `const char *' */
 	POWER_SUPPLY_ATTR(model_name),
 	POWER_SUPPLY_ATTR(manufacturer),
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 5c26006..ddeab05 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -119,6 +119,7 @@ enum power_supply_property {
 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
+	POWER_SUPPLY_PROP_INLMT,
 	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
 	POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
 	POWER_SUPPLY_PROP_ENERGY_FULL,
@@ -130,6 +131,8 @@ enum power_supply_property {
 	POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX, /* in percents! */
 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
 	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_MAX_TEMP,
+	POWER_SUPPLY_PROP_MIN_TEMP,
 	POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
 	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
 	POWER_SUPPLY_PROP_TEMP_AMBIENT,
@@ -141,6 +144,11 @@ enum power_supply_property {
 	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
 	POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
 	POWER_SUPPLY_PROP_SCOPE,
+	POWER_SUPPLY_PROP_CHARGE_TERM_CUR,
+	POWER_SUPPLY_PROP_ENABLE_CHARGING,
+	POWER_SUPPLY_PROP_ENABLE_CHARGER,
+	POWER_SUPPLY_PROP_CABLE_TYPE,
+	POWER_SUPPLY_PROP_PRIORITY,
 	/* Properties of type `const char *' */
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_MANUFACTURER,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/7] power_supply : add charger cable properties
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
  2013-09-23 18:03 ` [PATCH 1/7] power_supply: Add charger control properties Jenny TC
@ 2013-09-23 18:04 ` Jenny TC
  2013-09-23 18:04 ` [PATCH 3/7] power_supply: add throttle state Jenny TC
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:04 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC

Since the charger cables are related to power supply subsystem it
makes sense to define the properties associate with charger cables.
The properties include cable events and the input current. The cable
properties may come from different sources. Since they are associated
with power_supply subsystem, it make sense to unify the properties
in the power supply susbsyem layer.

Also a charger can support different types of charger sources (cables).
It make sense to define a field to inform the power supply subsystem
what kind of cable  a charger driver supports. Since a bitmask would
be the easy way to do define, it's good to have a enum which has
the bitmask definition for each cable types

Change-Id: Ia655c0924b7a5a845121342aa8f5d3840cccfbc4
Signed-off-by: Jenny TC <jenny.tc@intel.com>
---
 include/linux/power_supply.h |   38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index ddeab05..c3ce514a 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -166,6 +166,43 @@ enum power_supply_type {
 	POWER_SUPPLY_TYPE_USB_ACA,	/* Accessory Charger Adapters */
 };
 
+enum psy_charger_cable_event {
+	PSY_CHARGER_CABLE_EVENT_CONNECT = 0,
+	PSY_CHARGER_CABLE_EVENT_UPDATE,
+	PSY_CHARGER_CABLE_EVENT_RESUME,
+	PSY_CHARGER_CABLE_EVENT_SUSPEND,
+	PSY_CHARGER_CABLE_EVENT_DISCONNECT,
+};
+
+enum psy_charger_cable_type {
+	PSY_CHARGER_CABLE_TYPE_NONE = 0,
+	PSY_CHARGER_CABLE_TYPE_USB_SDP = 1 << 0,
+	PSY_CHARGER_CABLE_TYPE_USB_DCP = 1 << 1,
+	PSY_CHARGER_CABLE_TYPE_USB_CDP = 1 << 2,
+	PSY_CHARGER_CABLE_TYPE_USB_ACA = 1 << 3,
+	PSY_CHARGER_CABLE_TYPE_AC = 1 << 4,
+	PSY_CHARGER_CABLE_TYPE_ACA_DOCK = 1 << 5,
+	PSY_CHARGER_CABLE_TYPE_ACA_A = 1 << 6,
+	PSY_CHARGER_CABLE_TYPE_ACA_B = 1 << 7,
+	PSY_CHARGER_CABLE_TYPE_ACA_C = 1 << 8,
+	PSY_CHARGER_CABLE_TYPE_SE1 = 1 << 9,
+	PSY_CHARGER_CABLE_TYPE_MHL = 1 << 10,
+	PSY_CHARGER_CABLE_TYPE_B_DEVICE = 1 << 11,
+};
+
+struct psy_cable_props {
+	enum psy_charger_cable_event	chrg_evt;
+	enum psy_charger_cable_type	chrg_type;
+	unsigned int			mA;	/* input current limit */
+};
+
+#define PSY_CHARGER_CABLE_TYPE_USB \
+	(PSY_CHARGER_CABLE_TYPE_USB_SDP | \
+	PSY_CHARGER_CABLE_TYPE_USB_DCP | \
+	PSY_CHARGER_CABLE_TYPE_USB_CDP | \
+	PSY_CHARGER_CABLE_TYPE_USB_ACA | \
+	PSY_CHARGER_CABLE_TYPE_ACA_DOCK)
+
 union power_supply_propval {
 	int intval;
 	const char *strval;
@@ -181,6 +218,7 @@ struct power_supply {
 
 	char **supplied_to;
 	size_t num_supplicants;
+	unsigned long supported_cables;
 
 	char **supplied_from;
 	size_t num_supplies;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/7] power_supply: add throttle state
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
  2013-09-23 18:03 ` [PATCH 1/7] power_supply: Add charger control properties Jenny TC
  2013-09-23 18:04 ` [PATCH 2/7] power_supply : add charger cable properties Jenny TC
@ 2013-09-23 18:04 ` Jenny TC
  2013-09-23 18:04 ` [PATCH 4/7] power_supply: Add power_supply notifier Jenny TC
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:04 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC

The charger and battery temperature contribute to the
platform thermal. The only way to control the temperature
is to control the charging. The charging can be controlled in different
way. This could be disabling charger, disabling charging, adjusting CC,
or by adjusting the INLMT. This patch adds a structure to define the
charger throttle actions. Also this patch adds a throttle_states
field to the struct power_supply which can be used by the charger
driver to define it's throttle actions for different states

Change-Id: I390a4c7479df4a7e17f73682802e4be05ea58541
Signed-off-by: Jenny TC <jenny.tc@intel.com>
---
 include/linux/power_supply.h |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index c3ce514a..e99c78d 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -210,6 +210,18 @@ union power_supply_propval {
 
 struct device_node;
 
+enum psy_throttle_action {
+
+	PSY_THROTTLE_DISABLE_CHARGER = 0,
+	PSY_THROTTLE_DISABLE_CHARGING,
+	PSY_THROTTLE_CC_LIMIT,
+	PSY_THROTTLE_INPUT_LIMIT,
+};
+
+struct psy_throttle_state {
+	enum psy_throttle_action throttle_action;
+	unsigned throttle_val;
+};
 struct power_supply {
 	const char *name;
 	enum power_supply_type type;
@@ -224,6 +236,9 @@ struct power_supply {
 	size_t num_supplies;
 	struct device_node *of_node;
 
+	struct psy_throttle_state *throttle_states;
+	size_t num_throttle_states;
+
 	int (*get_property)(struct power_supply *psy,
 			    enum power_supply_property psp,
 			    union power_supply_propval *val);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/7] power_supply: Add power_supply notifier
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
                   ` (2 preceding siblings ...)
  2013-09-23 18:04 ` [PATCH 3/7] power_supply: add throttle state Jenny TC
@ 2013-09-23 18:04 ` Jenny TC
  2013-09-23 18:04 ` [PATCH 5/7] power_supply : Introduce battery identification framework Jenny TC
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:04 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC

This patch adds a notifier chain to the power_supply.
This notifier helps drivers in other subsystem to listen to
changes in power supply subsystem. This would help to take some
actions in those drivers on changing the power supply properties.
One such scenario is to increase/decrease system performance based
on the battery capacity/voltage. Another scenario is to adjust the
h/w peak current detection voltage/current thresholds based on battery
voltage/capacity. The notifier helps drivers to listen to changes
in power_suppy susbystem without polling the power_supply properties

Change-Id: Ic05aa85491e73c60dbb80a479974c8a128bc3aa5
Signed-off-by: Jenny TC <jenny.tc@intel.com>
---
 drivers/power/power_supply_core.c |   17 +++++++++++++++++
 include/linux/power_supply.h      |   10 ++++++++++
 2 files changed, 27 insertions(+)

diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 00e6672..08bce22 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -24,6 +24,9 @@
 struct class *power_supply_class;
 EXPORT_SYMBOL_GPL(power_supply_class);
 
+ATOMIC_NOTIFIER_HEAD(power_supply_notifier);
+EXPORT_SYMBOL_GPL(power_supply_notifier);
+
 static struct device_type power_supply_dev_type;
 
 static bool __power_supply_is_supplied_by(struct power_supply *supplier,
@@ -80,6 +83,8 @@ static void power_supply_changed_work(struct work_struct *work)
 		class_for_each_device(power_supply_class, NULL, psy,
 				      __power_supply_changed_work);
 		power_supply_update_leds(psy);
+		atomic_notifier_call_chain(&power_supply_notifier,
+				PSY_EVENT_PROP_CHANGED, psy);
 		kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
 		spin_lock_irqsave(&psy->changed_lock, flags);
 	}
@@ -347,6 +352,18 @@ static void power_supply_dev_release(struct device *dev)
 	kfree(dev);
 }
 
+int power_supply_reg_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&power_supply_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(power_supply_reg_notifier);
+
+void power_supply_unreg_notifier(struct notifier_block *nb)
+{
+	atomic_notifier_chain_unregister(&power_supply_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(power_supply_unreg_notifier);
+
 #ifdef CONFIG_THERMAL
 static int power_supply_read_temp(struct thermal_zone_device *tzd,
 		unsigned long *temp)
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index e99c78d..95a3dd7 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -218,6 +218,13 @@ enum psy_throttle_action {
 	PSY_THROTTLE_INPUT_LIMIT,
 };
 
+enum power_supply_notifier_events {
+	PSY_EVENT_NONE,
+	PSY_EVENT_PROP_CHANGED,
+	PSY_EVENT_BATTERY,
+	PSY_EVENT_CABLE,
+};
+
 struct psy_throttle_state {
 	enum psy_throttle_action throttle_action;
 	unsigned throttle_val;
@@ -296,6 +303,9 @@ struct power_supply_info {
 	int use_for_apm;
 };
 
+extern struct atomic_notifier_head    power_supply_notifier;
+extern int power_supply_reg_notifier(struct notifier_block *nb);
+extern void power_supply_unreg_notifier(struct notifier_block *nb);
 extern struct power_supply *power_supply_get_by_name(const char *name);
 extern void power_supply_changed(struct power_supply *psy);
 extern int power_supply_am_i_supplied(struct power_supply *psy);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/7] power_supply : Introduce battery identification framework
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
                   ` (3 preceding siblings ...)
  2013-09-23 18:04 ` [PATCH 4/7] power_supply: Add power_supply notifier Jenny TC
@ 2013-09-23 18:04 ` Jenny TC
  2013-09-23 18:04 ` [PATCH 6/7] power_supply: Introduce Power Supply charging framework Jenny TC
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:04 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC, adavidra

This patch introduces generic battid framework. Different battid
drivers sitting on different linux kernel subsystem (1wire,
I2C, SFI etc) can interface with the power supply susbsytem using
the APIs exposed in the power supply usbsystem. The consumers (charger
driver/battery driver/power management drivers) can register
for notification from the battery id drivers using the APIs from this
framework

Change-Id: I3f77f5fd63e050eba13d7e98fcb6bfbbe817621f
Signed-off-by: Jenny TC <jenny.tc@intel.com>
Signed-off-by: adavidra <ajay.thomas.david.rajamanickam@intel.com>
---
 Documentation/power/power_supply_class.txt |   12 ++++
 drivers/power/Kconfig                      |    8 +++
 drivers/power/Makefile                     |    1 +
 drivers/power/battery_id.c                 |   87 ++++++++++++++++++++++++++++
 include/linux/power/battery_id.h           |   55 ++++++++++++++++++
 5 files changed, 163 insertions(+)
 create mode 100644 drivers/power/battery_id.c
 create mode 100644 include/linux/power/battery_id.h

diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index 5a5e7fa..fc2ff29d 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -177,6 +177,18 @@ External power supply (AC) lists supplicants (batteries) names in
 issued by external power supply will notify supplicants via
 external_power_changed callback.
 
+Reading Battery charging profile
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Power Supply class battery identification framework (battery_id.c)
+exposes APIs to retrieve battery profile of a battery. The battery
+profile can be read by battery identification driver which may be
+1wire/I2C/SFI driver. Battery identification driver can register
+the battery profile with the power supply class using the API
+psy_battery_prop_changed(). The framework also exposes API
+psy_get_batt_prop() to retrieve the battery profile which can be
+used by power supply drivers to setup the charging. Also drivers
+can register for battery removal/insertion notifications using
+power_supply_reg_notifier()
 
 QA
 ~~
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index e6f92b4..c95bc55 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -8,6 +8,14 @@ menuconfig POWER_SUPPLY
 
 if POWER_SUPPLY
 
+config POWER_SUPPLY_BATTID
+	bool "Power Supply Battery Identification Framework"
+	help
+	 Say Y here to enable the power supply battery idnetification
+	 framework. The framework would allow different battery identification
+	 drivers to interface with power supply subsystem. Also it allows consumer
+	 drivers to register for notification from the power_supply subsystem.
+
 config POWER_SUPPLY_DEBUG
 	bool "Power supply debug"
 	help
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index a4b7417..a8d71db 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -3,6 +3,7 @@ ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG
 power_supply-y				:= power_supply_core.o
 power_supply-$(CONFIG_SYSFS)		+= power_supply_sysfs.o
 power_supply-$(CONFIG_LEDS_TRIGGERS)	+= power_supply_leds.o
+power_supply-$(CONFIG_POWER_SUPPLY_BATTID) += battery_id.o
 
 obj-$(CONFIG_POWER_SUPPLY)	+= power_supply.o
 obj-$(CONFIG_GENERIC_ADC_BATTERY)	+= generic-adc-battery.o
diff --git a/drivers/power/battery_id.c b/drivers/power/battery_id.c
new file mode 100644
index 0000000..c5a5d02
--- /dev/null
+++ b/drivers/power/battery_id.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Jenny TC <jenny.tc@intel.com>
+ * Author: Ajay Thomas David Rajamanickam <ajay.thomas.david.rajamanickam@intel.com>
+ */
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/notifier.h>
+#include <linux/power_supply.h>
+#include <linux/power/battery_id.h>
+
+static struct psy_ps_batt_chg_prof batt_property;
+static int batt_status;
+
+DEFINE_SPINLOCK(battid_spinlock);
+
+/**
+ * psy_battery_prop_changed - Update properties when  battery connection status
+ *                        changes
+ * @battery_conn_stat : The current connection status of battery
+ * @batt_prop : Address of the psy_ps_batt_chg_prof structure with the updated
+ *              values passed from the calling function
+ *
+ * Whenever the battery connection status changes this function will be called
+ * to indicate a change in the status and to update the status and value of
+ * properties
+ */
+void psy_battery_prop_changed(int battery_conn_stat,
+			struct psy_ps_batt_chg_prof *batt_prop)
+{
+
+	spin_lock(&battid_spinlock);
+	if (batt_status != battery_conn_stat) {
+		if (battery_conn_stat == POWER_SUPPLY_BATTERY_INSERTED)
+			memcpy(&batt_property, batt_prop,
+				sizeof(batt_property));
+		batt_status = battery_conn_stat;
+	}
+	spin_unlock(&battid_spinlock);
+
+	atomic_notifier_call_chain(&power_supply_notifier,
+			PSY_EVENT_BATTERY, &(batt_property));
+}
+EXPORT_SYMBOL_GPL(psy_battery_prop_changed);
+
+/**
+ * psy_get_batt_prop - Get the battery connection status and updated properties
+ * @batt_prop : battery properties structure copied to this address
+ */
+int psy_get_batt_prop(struct psy_ps_batt_chg_prof *batt_prop)
+{
+	int ret = 0;
+
+	spin_lock(&battid_spinlock);
+
+	if (batt_status != POWER_SUPPLY_BATTERY_INSERTED)
+		ret = -ENODATA;
+	else
+		memcpy(batt_prop, &batt_property,
+			sizeof(batt_property));
+
+	spin_unlock(&battid_spinlock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(psy_get_batt_prop);
diff --git a/include/linux/power/battery_id.h b/include/linux/power/battery_id.h
new file mode 100644
index 0000000..ef4d0f9
--- /dev/null
+++ b/include/linux/power/battery_id.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Jenny TC <jenny.tc@intel.com>
+ * Author: Ajay Thomas David Rajamanickam <ajay.thomas.david.rajamanickam@intel.com>
+ */
+#ifndef __BATTERY_ID_H__
+
+#define __BATTERY_ID_H__
+
+enum {
+	POWER_SUPPLY_BATTERY_REMOVED = 0,
+	POWER_SUPPLY_BATTERY_INSERTED,
+};
+
+enum psy_batt_chrg_prof_type {
+	PSY_CHRG_PROF_NONE = 0,
+};
+
+/* charging profile structure definition */
+struct psy_ps_batt_chg_prof {
+	enum psy_batt_chrg_prof_type chrg_prof_type;
+	void *batt_prof;
+};
+
+#ifdef CONFIG_POWER_SUPPLY_BATTID
+extern int psy_get_batt_prop(struct psy_ps_batt_chg_prof *batt_prop);
+extern void psy_battery_prop_changed(int battery_conn_stat,
+				struct psy_ps_batt_chg_prof *batt_prop);
+#else
+static inline int psy_get_batt_prop(struct psy_ps_batt_chg_prof *batt_prop)
+{
+	return -ENOMEM;
+}
+static void psy_battery_prop_changed(int battery_conn_stat,
+				struct psy_ps_batt_chg_prof *batt_prop) { }
+#endif
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/7] power_supply: Introduce Power Supply charging framework
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
                   ` (4 preceding siblings ...)
  2013-09-23 18:04 ` [PATCH 5/7] power_supply : Introduce battery identification framework Jenny TC
@ 2013-09-23 18:04 ` Jenny TC
  2013-09-23 18:04 ` [PATCH 7/7] power_supply: Introduce PSE compliant algorithm Jenny TC
  2013-10-25 16:49 ` [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Tc, Jenny
  7 siblings, 0 replies; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:04 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC

The Power Supply charging framework connects multiple subsystems
to do charging in a generic way. The subsystems involves power_supply,
extcon, and thermal. With this the charging is handled in a generic way.

The framework makes use of different new features - Battery Identification
framework, pluggable charging algorithms, charger cable arbitrations etc.

At present the charging is done based on the static battery characteristics.
This is done at the boot time by passing the battery properties (max_voltage,
capacity) etc. as platform data to the charger/battery driver.
But new generation high volt batteries needs to be identified dynamically
to do charging in a safe manner. The batteries are coming with different
communication protocols. It become necessary to communicate with battery and
identify it's charging profiles before setup charging

Also the charging algorithms can vary based on the battery characteristics
and the platform characteristics. To handle charging in a generic way it's
necessary to support pluggable charging algorithms. Charging framework uses
selected algorithms based on the type of battery charging profile.
This is a simple binding and can be improved later. This may be improved to
select the algorithms based on the platform requirements. Also we can extend
this framework to plug algorithms from the user space.

The framework also introduces the charger cable arbitration. A charger may
supports multiple cables, but it may not be able to charge with multiple
cables at a time. The arbitration logic inside the framework selects the cable
based on it's capabilities and the maximum charge current the platform can
support

Also this framework exposes features to control charging on different platform
states. One such feature is thermal. The framework register with the thermal
subsystem and control charging based on the thermal subsystem requirements.

Overall this framework removes the charging logic out of the charger driver and
the charger driver can just listen to the request from the framework to set
the charger properties. This can be implemented by exposing get_property and set
property callbacks.

Change-Id: I800770a11bb3a9f7a0a7d8d743604fc0daf0a5a8
Signed-off-by: Jenny TC <jenny.tc@intel.com>
---
 Documentation/power/power_supply_class.txt |  174 +++++
 drivers/power/Kconfig                      |   10 +
 drivers/power/Makefile                     |    1 +
 drivers/power/power_supply.h               |   21 +
 drivers/power/power_supply_charger.c       | 1023 ++++++++++++++++++++++++++++
 drivers/power/power_supply_charger.h       |  130 ++++
 drivers/power/power_supply_core.c          |   21 +
 include/linux/power_supply.h               |  264 +++++++
 8 files changed, 1644 insertions(+)
 create mode 100644 drivers/power/power_supply_charger.c
 create mode 100644 drivers/power/power_supply_charger.h

diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
index fc2ff29d..a2be269 100644
--- a/Documentation/power/power_supply_class.txt
+++ b/Documentation/power/power_supply_class.txt
@@ -190,6 +190,180 @@ used by power supply drivers to setup the charging. Also drivers
 can register for battery removal/insertion notifications using
 power_supply_reg_notifier()
 
+Use Charging Framework to setup charging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Register the driver with the power_supply class and pass the
+  charging framework related parameters
+* Expose set_property and get_property functions so that charging
+  framework can control the charging
+
+Registering charger driver with power supply class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+struct power_supply_class psy_usb;
+psy_usb.name = DEV_NAME;
+psy_usb.type = POWER_SUPPLY_TYPE_USB;
+
+/* pointer to power supply property structure */
+psy_usb.properties =  &psy_usb_props;
+psy_usb.num_properties = ARRAY_SIZE(psy_usb_props);
+
+/* pointer to power supply get property function */
+psy_usb.get_property = psy_usb_get_property;
+
+/* pointer to power supply set property function */
+psy_usb.set_property = psy_usb_set_property;
+
+/* pointer to the supplied_to argument to indicate the batteries
+   to which this charger is supplying power  */
+psy_usb.supplied_to = supplied_to;
+psy_usb.num_supplicants = num_supplicants;
+
+/* Additional Interfaces to support charging framework */
+
+/* pointer to throttle states */
+psy_usb.throttle_states = throttle_states;
+
+/* Number of throttle states */
+psy_usb.num_throttle_states = num_throttle_states;
+
+/* define supported cable types for this driver */
+psy_usb.supported_cables = POWER_SUPPLY_CHARGER_TYPE_USB;
+
+/* register with power_supply subsystem */
+power_supply_registe(device, &psy_usb);
+
+Properties exposed by charger driver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* POWER_SUPPLY_PROP_ONLINE
+	* Read access using get_property_function
+		* Returns the online property set using the set_property function
+	* Write access using set_property function
+		* Expose the value through get_property_fucntion.
+* POWER_SUPPLY_PROP_PRESENT
+	* Read access using get_property_function
+		* Returns the present property set using the set_property function
+	* Write access using set_property function
+		* Expose the value through get_property_fucntion.
+* POWER_SUPPLY_PROP_HEALTH
+	* Read access using get_property_function
+		* Returns charger health
+* POWER_SUPPLY_PROP_TYPE
+	* Read access using power_supply structure
+		* Returns charger type
+* POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT
+	* Read access using get property
+		* Returns the present charge control limit
+	* Write access using set property
+		* Set charge control limit.
+		* Action: Driver is not expected to take any actions on this.
+			  Instead need to expose this on the read interface.
+			  Charging framework process this and notifies the
+		  	  charging parameters accordingly.
+* POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX
+	* Read access using get property
+		* Returns the maximum charge control limit
+* POWER_SUPPLY_PROP_ENABLE_CHARGING
+	* Read access using get property
+		* Return 1 if charging is enabled  else return 0
+	* Write access using set property
+		* Enable/disable charging
+		* Action : Write h/w register to enable/disable charging
+* POWER_SUPPLY_PROP_ENABLE_CHARGER
+	* Read access using get property
+		* Return 1 if charger is enabled  else return 0
+	* Write access using set property
+		* Enable/disable charger
+		* Action : Write h/w register to enable/disable charger
+* POWER_SUPPLY_PROP_INLMT
+	* Read access using get property
+		* Returns the input current limit passed by set_property function
+		* Default value : 0
+	* Write access using set property
+		* Set input current limit
+		* Action : Write h/w register to set the input current limit
+			   based on the value
+* POWER_SUPPLY_PROP_CHARGE_CURRENT
+	* Read access using get property
+		* Returns charge current passed by set_property function
+		* Default value : 0
+	* Write access using set property
+		* Set charge current
+		* Action : Write h/w register to set the charge current based
+			   on the value
+* POWER_SUPPLY_PROP_CHARGE_VOLTAGE
+	* Read access using get property
+		* Returns charge voltage passed by set_property function
+		* Default value: 0
+	* Write access using set property
+		* Set charge voltage
+		* Action : Write h/w register to set the charge voltage based
+			   on the value
+* POWER_SUPPLY_PROP_CHARGE_TERM_CUR
+	* Read access using get property
+		* Returns charge termination current passed by set_property function
+		* Default value : 0
+	* Write access using set property
+		* Set charge termination current
+		* Action : Write h/w register to set the charge termination current
+			   based on the value
+* POWER_SUPPLY_PROP_CABLE_TYPE
+	* Read access using get property
+		* Returns cable type passed by set_property function
+		* Default value : POWER_SUPPLY_CABLE_TYPE_UNKNOWN
+	* Write access using set property
+		* Set cable type
+		* Action : Used by the driver to report POWER_SUPPLY_PROP_TYPE.
+		* Report POWER_SUPPLY_PROP_TYPE
+			* Set type field of struct power_supply based on the cable type
+* POWER_SUPPLY_PROP_MIN_TEMP
+	* Read access using get property
+		* Returns minimum charging  temperature passed by set_property
+		* Default value : Platform dependant
+	* Write access using set_property
+		* Set Minimum charging temperature
+		* Action : Write h/w register to set the minimum charging temperature
+			   based on the value
+* POWER_SUPPLY_PROP_MAX_TEMP
+	* Write access using set_property
+		* Set Maximum charging temperature
+		* Action : Write h/w register to set the maximum charging temperature
+			   based on the value
+	* Read access using get property
+		* Returns maximum charging  temperature passed by set_property
+		* Default value : Platform dependent
+* POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT
+	* Read access using get property
+		* Returns maximum charging  current passed by set_property
+		* Default value : Platform dependent
+	* Write access using set_property
+		* Set Maximum charging current
+		* Action: Configure safety charging registers if any. If not no actions
+		  	  expected for this.
+* POWER_SUPPLY_PROP_MAX_CHARGE_VOLTAGE
+	* Read access using get property
+		* Returns maximum charging  current passed by set_property
+		* Default value : Platform dependent
+	* Write access using set_property
+		* Set Maximum charging voltage
+		* Action: Configure safety charging registers if any. If not,
+			  no actions expected for this.
+Registering new charging alogorithm
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Populate algorithm structure
+	struct psy_charging_algo new_algo;
+	/* populate the type charging profile the algorithm handles */
+	pse_algo.chrg_prof_type = PSY_CHRG_PROF_PSE;
+	pse_algo.name = "my_algo";
+	/* callback function to retrieve CC and CV */
+	pse_algo.get_next_cc_cv = my_algo_get_next_cc_cv;
+	/* callback function to retreive battery thresholds */
+	pse_algo.get_batt_thresholds = my_algo__get_bat_thresholds;
+	/* register charging algorithm */
+	power_supply_register_charging_algo(&pse_algo);
+
+When the type of charging profile reported by battery and algorithm matches,
+the algorithm will be invoked to get the charging parameters.
+
 QA
 ~~
 Q: Where is POWER_SUPPLY_PROP_XYZ attribute?
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index c95bc55..ff361ee 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -8,6 +8,16 @@ menuconfig POWER_SUPPLY
 
 if POWER_SUPPLY
 
+config POWER_SUPPLY_CHARGER
+	bool "Power Supply Charger"
+	select EXTCON
+	select POWER_SUPPLY_BATTID
+	help
+	  Say Y here to enable the power supply charger framework. Charger
+	  framework supports charging in a generic way. This allows the charger
+	  drivers to keep the charging logic outside and the charger driver
+	  just need to abstract the charger hardware
+
 config POWER_SUPPLY_BATTID
 	bool "Power Supply Battery Identification Framework"
 	help
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index a8d71db..021b97a 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -3,6 +3,7 @@ ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG
 power_supply-y				:= power_supply_core.o
 power_supply-$(CONFIG_SYSFS)		+= power_supply_sysfs.o
 power_supply-$(CONFIG_LEDS_TRIGGERS)	+= power_supply_leds.o
+power_supply-$(CONFIG_POWER_SUPPLY_CHARGER) += power_supply_charger.o
 power_supply-$(CONFIG_POWER_SUPPLY_BATTID) += battery_id.o
 
 obj-$(CONFIG_POWER_SUPPLY)	+= power_supply.o
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index cc439fd..d2b3a53 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -40,3 +40,24 @@ static inline int power_supply_create_triggers(struct power_supply *psy)
 static inline void power_supply_remove_triggers(struct power_supply *psy) {}
 
 #endif /* CONFIG_LEDS_TRIGGERS */
+#ifdef CONFIG_POWER_SUPPLY_CHARGER
+
+extern void power_supply_trigger_charging_handler(struct power_supply *psy);
+extern int power_supply_register_charger(struct power_supply *psy);
+extern int power_supply_unregister_charger(struct power_supply *psy);
+extern int psy_charger_throttle_charger(struct power_supply *psy,
+					unsigned long state);
+
+#else
+
+static inline void
+	power_supply_trigger_charging_handler(struct power_supply *psy) { }
+static inline int power_supply_register_charger(struct power_supply *psy)
+{ return 0; }
+static inline int power_supply_unregister_charger(struct power_supply *psy)
+{ return 0; }
+static inline int psy_charger_throttle_charger(struct power_supply *psy,
+					unsigned long state)
+{ return 0; }
+
+#endif
diff --git a/drivers/power/power_supply_charger.c b/drivers/power/power_supply_charger.c
new file mode 100644
index 0000000..8e6630f
--- /dev/null
+++ b/drivers/power/power_supply_charger.c
@@ -0,0 +1,1023 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Jenny TC <jenny.tc@intel.com>
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/thermal.h>
+#include <linux/extcon.h>
+#include <linux/power/battery_id.h>
+#include <linux/notifier.h>
+#include <linux/usb/otg.h>
+#include "power_supply.h"
+#include "power_supply_charger.h"
+
+struct work_struct notifier_work;
+#define MAX_CHARGER_COUNT 5
+
+static LIST_HEAD(algo_list);
+
+struct power_supply_charger {
+	bool is_cable_evt_reg;
+	/*cache battery and charger properties */
+	struct list_head chrgr_cache_lst;
+	struct list_head batt_cache_lst;
+	struct list_head evt_queue;
+	struct work_struct algo_trigger_work;
+	struct mutex evt_lock;
+	wait_queue_head_t wait_chrg_enable;
+};
+
+struct charger_cable {
+	struct work_struct work;
+	struct notifier_block nb;
+	struct psy_cable_props cable_props;
+	enum psy_charger_cable_type psy_cable_type;
+};
+
+static struct power_supply_charger psy_chrgr;
+
+static struct charger_cable cable_list[] = {
+	{
+	 .psy_cable_type = PSY_CHARGER_CABLE_TYPE_USB_SDP,
+	 },
+	{
+	 .psy_cable_type = PSY_CHARGER_CABLE_TYPE_USB_CDP,
+	 },
+	{
+	 .psy_cable_type = PSY_CHARGER_CABLE_TYPE_USB_DCP,
+	 },
+	{
+	 .psy_cable_type = PSY_CHARGER_CABLE_TYPE_USB_ACA,
+	 },
+	{
+	 .psy_cable_type = PSY_CHARGER_CABLE_TYPE_ACA_DOCK,
+	 },
+	{
+	 .psy_cable_type = PSY_CHARGER_CABLE_TYPE_SE1,
+	 },
+	{
+	 .psy_cable_type = PSY_CHARGER_CABLE_TYPE_AC,
+	 },
+};
+
+static int get_supplied_by_list(struct power_supply *psy,
+				struct power_supply *psy_lst[]);
+
+static int handle_cable_notification(struct notifier_block *nb,
+				   unsigned long event, void *data);
+struct usb_phy *otg_xceiver;
+struct notifier_block nb = {
+		   .notifier_call = handle_cable_notification,
+		};
+static void configure_chrgr_source(struct charger_cable *cable_lst);
+
+struct charger_cable *get_cable(unsigned long chrgr_type)
+{
+	switch (chrgr_type) {
+	case PSY_CHARGER_CABLE_TYPE_USB_SDP:
+		return &cable_list[0];
+	case PSY_CHARGER_CABLE_TYPE_USB_CDP:
+		return &cable_list[1];
+	case PSY_CHARGER_CABLE_TYPE_USB_DCP:
+		return &cable_list[2];
+	case PSY_CHARGER_CABLE_TYPE_USB_ACA:
+		return &cable_list[3];
+	case PSY_CHARGER_CABLE_TYPE_ACA_DOCK:
+		return &cable_list[4];
+	case PSY_CHARGER_CABLE_TYPE_AC:
+		return &cable_list[6];
+	case PSY_CHARGER_CABLE_TYPE_SE1:
+		return &cable_list[5];
+	}
+
+	return NULL;
+}
+
+static void notifier_event_worker(struct work_struct *work)
+{
+	configure_chrgr_source(cable_list);
+}
+
+static int process_cable_props(struct psy_cable_props *cap)
+{
+	struct charger_cable *cable = NULL;
+
+	pr_info("%s: event:%d, type:%d, mA:%d\n",
+		__func__, cap->chrg_evt, cap->chrg_type, cap->mA);
+
+	cable = get_cable(cap->chrg_type);
+	if (!cable) {
+
+		pr_err("%s:%d Error in getting charger cable from get_cable\n",
+				__FILE__, __LINE__);
+		return -EINVAL;
+	}
+	memcpy((void *)&cable->cable_props, (void *)cap,
+			sizeof(cable->cable_props));
+
+	schedule_work(&notifier_work);
+
+
+	return 0;
+}
+
+static int handle_cable_notification(struct notifier_block *nb,
+				   unsigned long event, void *data)
+{
+	struct psy_cable_props cap;
+
+	memcpy(&cap, data, sizeof(struct psy_cable_props));
+
+	if (event != USB_EVENT_CHARGER && event != PSY_EVENT_CABLE)
+		return NOTIFY_DONE;
+
+	process_cable_props(&cap);
+
+	return NOTIFY_OK;
+}
+
+static int register_notifier(void)
+{
+	int retval = 0;
+
+	otg_xceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+
+	if (IS_ERR(otg_xceiver)) {
+		pr_err("failure to get otg transceiver\n");
+		retval = -EIO;
+		goto notifier_reg_failed;
+	}
+
+	retval = usb_register_notifier(otg_xceiver, &nb);
+	if (retval) {
+		pr_err("failure to register otg notifier\n");
+		goto notifier_reg_failed;
+	}
+
+	retval = power_supply_reg_notifier(&nb);
+	if (retval) {
+		pr_err("failure to register power_supply notifier\n");
+		goto notifier_reg_failed;
+
+	}
+
+	INIT_WORK(&notifier_work, notifier_event_worker);
+
+notifier_reg_failed:
+	return retval;
+}
+
+struct psy_charging_algo *power_supply_get_charging_algo
+		(struct power_supply *, struct psy_ps_batt_chg_prof *);
+
+static void init_charger_cables(struct charger_cable *cable_lst, int count)
+{
+	struct charger_cable *cable;
+
+	register_notifier();
+
+	while (--count) {
+		cable = cable_lst++;
+		/* initialize cable instance */
+		cable->cable_props.chrg_evt =
+			PSY_CHARGER_CABLE_EVENT_DISCONNECT;
+		cable->cable_props.mA = 0;
+	}
+}
+
+static inline void get_cur_chrgr_prop(struct power_supply *psy,
+				      struct psy_charger_props *chrgr_prop)
+{
+	chrgr_prop->is_charging = psy_is_charging_enabled(psy);
+	chrgr_prop->name = psy->name;
+	chrgr_prop->online = psy_is_online(psy);
+	chrgr_prop->present = psy_is_present(psy);
+	chrgr_prop->cable = PSY_CABLE_TYPE(psy);
+	chrgr_prop->health = PSY_HEALTH(psy);
+	chrgr_prop->tstamp = get_jiffies_64();
+
+}
+
+static inline int get_chrgr_prop_cache(struct power_supply *psy,
+				       struct psy_charger_props *chrgr_cache)
+{
+	struct psy_charger_props *chrgr_prop;
+	int ret = -ENODEV;
+
+	list_for_each_entry(chrgr_prop, &psy_chrgr.chrgr_cache_lst, node) {
+		if (!strcmp(chrgr_prop->name, psy->name)) {
+			memcpy(chrgr_cache, chrgr_prop, sizeof(*chrgr_cache));
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void dump_charger_props(struct psy_charger_props *props)
+{
+	pr_devel("%s:name=%s present=%d is_charging=%d health=%d online=%d cable=%ld tstamp=%ld\n",
+		__func__, props->name, props->present, props->is_charging,
+		props->health, props->online, props->cable, props->tstamp);
+}
+
+static void dump_battery_props(struct psy_batt_props *props)
+{
+	pr_devel("%s:name=%s voltage_now=%ld current_now=%ld temperature=%d status=%ld health=%d tstamp=%lld algo_stat=%d ",
+		__func__, props->name, props->voltage_now, props->current_now,
+		props->temperature, props->status, props->health,
+		props->tstamp, props->algo_stat);
+}
+
+static inline void cache_chrgr_prop(struct psy_charger_props *chrgr_prop_new)
+{
+	struct psy_charger_props *chrgr_cache;
+
+	list_for_each_entry(chrgr_cache, &psy_chrgr.chrgr_cache_lst, node) {
+		if (!strcmp(chrgr_cache->name, chrgr_prop_new->name))
+			goto update_props;
+	}
+
+	chrgr_cache = kzalloc(sizeof(*chrgr_cache), GFP_KERNEL);
+	if (chrgr_cache == NULL) {
+		pr_err("%s:%dError in allocating memory\n", __FILE__, __LINE__);
+		return;
+	}
+
+	INIT_LIST_HEAD(&chrgr_cache->node);
+	list_add_tail(&chrgr_cache->node, &psy_chrgr.chrgr_cache_lst);
+
+	chrgr_cache->name = chrgr_prop_new->name;
+
+update_props:
+	chrgr_cache->is_charging = chrgr_prop_new->is_charging;
+	chrgr_cache->online = chrgr_prop_new->online;
+	chrgr_cache->health = chrgr_prop_new->health;
+	chrgr_cache->present = chrgr_prop_new->present;
+	chrgr_cache->cable = chrgr_prop_new->cable;
+	chrgr_cache->tstamp = chrgr_prop_new->tstamp;
+}
+
+
+static inline bool is_chrgr_prop_changed(struct power_supply *psy)
+{
+	struct psy_charger_props chrgr_prop_cache, chrgr_prop;
+
+	get_cur_chrgr_prop(psy, &chrgr_prop);
+	/* Get cached battery property. If no cached property available
+	 *  then cache the new property and return true
+	 */
+	if (get_chrgr_prop_cache(psy, &chrgr_prop_cache)) {
+		cache_chrgr_prop(&chrgr_prop);
+		return true;
+	}
+
+	pr_devel("%s\n", __func__);
+	dump_charger_props(&chrgr_prop);
+	dump_charger_props(&chrgr_prop_cache);
+
+	if (!psy_is_charger_prop_changed(chrgr_prop, chrgr_prop_cache))
+		return false;
+
+	cache_chrgr_prop(&chrgr_prop);
+	return true;
+}
+static void cache_successive_samples(long *sample_array, long new_sample)
+{
+	int i;
+
+	for (i = 0; i < MAX_CUR_VOLT_SAMPLES - 1; ++i)
+		*(sample_array + i) = *(sample_array + i + 1);
+
+	*(sample_array + i) = new_sample;
+}
+
+static inline void cache_bat_prop(struct psy_batt_props *bat_prop_new)
+{
+	struct psy_batt_props *bat_cache;
+
+	/* Find entry in cache list. If an entry is located update
+	 * the existing entry else create new entry in the list */
+	list_for_each_entry(bat_cache, &psy_chrgr.batt_cache_lst, node) {
+		if (!strcmp(bat_cache->name, bat_prop_new->name))
+			goto update_props;
+	}
+
+	bat_cache = kzalloc(sizeof(*bat_cache), GFP_KERNEL);
+	if (bat_cache == NULL) {
+		pr_err("%s:%dError in allocating memory\n", __FILE__, __LINE__);
+		return;
+	}
+	INIT_LIST_HEAD(&bat_cache->node);
+	list_add_tail(&bat_cache->node, &psy_chrgr.batt_cache_lst);
+
+	bat_cache->name = bat_prop_new->name;
+
+update_props:
+	if (time_after64(bat_prop_new->tstamp,
+		(bat_cache->tstamp + DEF_CUR_VOLT_SAMPLE_JIFF)) ||
+						bat_cache->tstamp == 0) {
+		cache_successive_samples(bat_cache->voltage_now_cache,
+						bat_prop_new->voltage_now);
+		cache_successive_samples(bat_cache->current_now_cache,
+						bat_prop_new->current_now);
+		bat_cache->tstamp = bat_prop_new->tstamp;
+	}
+
+	bat_cache->voltage_now = bat_prop_new->voltage_now;
+	bat_cache->current_now = bat_prop_new->current_now;
+	bat_cache->health = bat_prop_new->health;
+
+	bat_cache->temperature = bat_prop_new->temperature;
+	bat_cache->status = bat_prop_new->status;
+	bat_cache->algo_stat = bat_prop_new->algo_stat;
+	bat_cache->throttle_state = bat_prop_new->throttle_state;
+}
+
+static inline int get_bat_prop_cache(struct power_supply *psy,
+				     struct psy_batt_props *bat_cache)
+{
+	struct psy_batt_props *bat_prop;
+	int ret = -ENODEV;
+
+	list_for_each_entry(bat_prop, &psy_chrgr.batt_cache_lst, node) {
+		if (!strcmp(bat_prop->name, psy->name)) {
+			memcpy(bat_cache, bat_prop, sizeof(*bat_cache));
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static inline void get_cur_bat_prop(struct power_supply *psy,
+				    struct psy_batt_props *bat_prop)
+{
+	struct psy_batt_props bat_prop_cache;
+	int ret;
+
+	bat_prop->name = psy->name;
+	bat_prop->voltage_now = PSY_VOLTAGE_OCV(psy) / 1000;
+	bat_prop->current_now = PSY_CURRENT_NOW(psy) / 1000;
+	bat_prop->temperature = PSY_TEMPERATURE(psy) / 10;
+	bat_prop->status = PSY_STATUS(psy);
+	bat_prop->health = PSY_HEALTH(psy);
+	bat_prop->tstamp = get_jiffies_64();
+	bat_prop->throttle_state = PSY_CURRENT_THROTTLE_STATE(psy);
+
+	/* Populate cached algo data to new profile */
+	ret = get_bat_prop_cache(psy, &bat_prop_cache);
+	if (!ret)
+		bat_prop->algo_stat = bat_prop_cache.algo_stat;
+}
+
+static inline bool is_batt_prop_changed(struct power_supply *psy)
+{
+	struct psy_batt_props bat_prop_cache, bat_prop;
+
+	/* Get cached battery property. If no cached property available
+	 *  then cache the new property and return true
+	 */
+	get_cur_bat_prop(psy, &bat_prop);
+	if (get_bat_prop_cache(psy, &bat_prop_cache)) {
+		cache_bat_prop(&bat_prop);
+		return true;
+	}
+
+	pr_devel("%s\n", __func__);
+	dump_battery_props(&bat_prop);
+	dump_battery_props(&bat_prop_cache);
+
+	if (!psy_is_battery_prop_changed(bat_prop, bat_prop_cache))
+		return false;
+
+	cache_bat_prop(&bat_prop);
+	return true;
+}
+
+static inline bool is_supplied_to_has_ext_pwr_changed(struct power_supply *psy)
+{
+	int i;
+	struct power_supply *psb;
+	bool is_pwr_changed_defined = true;
+
+	for (i = 0; i < psy->num_supplicants; i++) {
+		psb =
+		    power_supply_get_by_name(psy->
+					     supplied_to[i]);
+		if (psb && !psb->external_power_changed)
+			is_pwr_changed_defined &= false;
+	}
+
+	return is_pwr_changed_defined;
+}
+
+static inline bool is_supplied_by_changed(struct power_supply *psy)
+{
+	int cnt;
+	struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
+
+	cnt = get_supplied_by_list(psy, chrgr_lst);
+	while (cnt--) {
+		if ((psy_is_charger(chrgr_lst[cnt])) &&
+			is_chrgr_prop_changed(chrgr_lst[cnt]))
+			return true;
+	}
+
+	return false;
+}
+
+static inline bool is_trigger_charging_algo(struct power_supply *psy)
+{
+	/* trigger charging alorithm if battery or
+	 * charger properties are changed. Also no need to
+	 * invoke algorithm for power_supply_changed from
+	 * charger, if all supplied_to has the ext_port_changed defined.
+	 * On invoking the ext_port_changed the supplied to can send
+	 * power_supplied_changed event.
+	 */
+
+	if ((psy_is_charger(psy) && !is_supplied_to_has_ext_pwr_changed(psy)) &&
+			is_chrgr_prop_changed(psy))
+		return true;
+
+	if ((psy_is_battery(psy)) && (is_batt_prop_changed(psy) ||
+				is_supplied_by_changed(psy)))
+		return true;
+
+	return false;
+}
+
+static int get_supplied_by_list(struct power_supply *psy,
+				struct power_supply *psy_lst[])
+{
+	struct class_dev_iter iter;
+	struct device *dev;
+	struct power_supply *pst;
+	int cnt = 0, i, j;
+
+	if (!psy_is_battery(psy))
+		return 0;
+
+	/* Identify chargers which are supplying power to the battery */
+	class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
+		pst = (struct power_supply *)dev_get_drvdata(dev);
+		if (!psy_is_charger(pst))
+			continue;
+		for (i = 0; i < pst->num_supplicants; i++) {
+			if (!strcmp(pst->supplied_to[i], psy->name))
+				psy_lst[cnt++] = pst;
+		}
+	}
+	class_dev_iter_exit(&iter);
+
+	if (cnt <= 1)
+		return cnt;
+
+	/*sort based on priority. 0 has the highest priority  */
+	for (i = 0; i < cnt; ++i)
+		for (j = 0; j < cnt; ++j)
+			if (PSY_PRIORITY(psy_lst[j]) > PSY_PRIORITY(psy_lst[i]))
+				swap(psy_lst[j], psy_lst[i]);
+
+	return cnt;
+}
+
+static int get_battery_status(struct power_supply *psy)
+{
+	int cnt, status, ret;
+	struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
+	struct psy_batt_props bat_prop;
+
+	if (!psy_is_battery(psy))
+		return -EINVAL;
+
+	ret = get_bat_prop_cache(psy, &bat_prop);
+	if (ret)
+		return ret;
+
+	status = POWER_SUPPLY_STATUS_DISCHARGING;
+	cnt = get_supplied_by_list(psy, chrgr_lst);
+
+	while (cnt--) {
+
+
+		if (psy_is_present(chrgr_lst[cnt]))
+			status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+		if (is_charging_can_be_enabled(chrgr_lst[cnt]) &&
+			(psy_is_health_good(psy)) &&
+				(psy_is_health_good(chrgr_lst[cnt]))) {
+
+			if ((bat_prop.algo_stat == PSY_ALGO_STAT_FULL) ||
+				(bat_prop.algo_stat == PSY_ALGO_STAT_MAINT))
+				status = POWER_SUPPLY_STATUS_FULL;
+			else if (psy_is_charging_enabled(chrgr_lst[cnt]))
+				status = POWER_SUPPLY_STATUS_CHARGING;
+		}
+	}
+
+	pr_devel("%s: Set status=%d for %s\n", __func__, status, psy->name);
+
+	return status;
+}
+
+static void update_charger_online(struct power_supply *psy)
+{
+	if (psy_is_charger_enabled(psy))
+		psy_set_charger_online(psy, 1);
+	else
+		psy_set_charger_online(psy, 0);
+}
+
+static void update_sysfs(struct power_supply *psy)
+{
+	int i, cnt;
+	struct power_supply *psb;
+	struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
+
+	if (psy_is_battery(psy)) {
+		/* set battery status */
+		psy_set_battery_status(psy, get_battery_status(psy));
+
+		/* set charger online */
+		cnt = get_supplied_by_list(psy, chrgr_lst);
+		while (cnt--) {
+			if (!psy_is_present(chrgr_lst[cnt]))
+				continue;
+
+			update_charger_online(psy);
+		}
+	} else {
+		/*set battery status */
+		for (i = 0; i < psy->num_supplicants; i++) {
+			psb =
+			    power_supply_get_by_name(psy->
+						     supplied_to[i]);
+			if (psb && psy_is_battery(psb) && psy_is_present(psb))
+				psy_set_battery_status(psb,
+					get_battery_status(psb));
+		}
+
+		/*set charger online */
+		update_charger_online(psy);
+	}
+}
+
+static int trigger_algo(struct power_supply *psy)
+{
+	unsigned long cc = 0, cv = 0, cc_min;
+	struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
+	struct psy_batt_props bat_prop;
+	struct psy_charging_algo *algo;
+	struct psy_ps_batt_chg_prof chrg_profile;
+	int cnt;
+
+	if (psy->type != POWER_SUPPLY_TYPE_BATTERY)
+		return 0;
+
+	if (psy_get_batt_prop(&chrg_profile)) {
+		pr_err("Error in getting charge profile:%s:%d\n", __FILE__,
+		       __LINE__);
+		return -EINVAL;
+	}
+
+	get_bat_prop_cache(psy, &bat_prop);
+
+	algo = power_supply_get_charging_algo(psy, &chrg_profile);
+	if (!algo) {
+		pr_err("%s:Error in getting charging algo!!\n", __func__);
+		return -EINVAL;
+	}
+
+	bat_prop.algo_stat = algo->get_next_cc_cv(bat_prop,
+						chrg_profile, &cc, &cv);
+
+	pr_info("%s:Algo_status:%d\n", __func__, bat_prop.algo_stat);
+
+	cache_bat_prop(&bat_prop);
+
+	if (!cc || !cv)
+		return -ENODATA;
+
+	/* CC needs to be updated for all chargers which are supplying
+	 *  power to this battery to ensure that the sum of CCs of all
+	 * chargers are never more than the CC selected by the algo.
+	 * The CC is set based on the charger priority.
+	 */
+	cnt = get_supplied_by_list(psy, chrgr_lst);
+
+	while (cnt--) {
+		if (!psy_is_present(chrgr_lst[cnt]))
+			continue;
+
+		cc_min = min_t(unsigned long, PSY_MAX_CC(chrgr_lst[cnt]), cc);
+		if (cc_min < 0)
+			cc_min = 0;
+		cc -= cc_min;
+		psy_set_cc(chrgr_lst[cnt], cc_min);
+		psy_set_cv(chrgr_lst[cnt], cv);
+	}
+
+	return 0;
+}
+
+static inline void wait_for_charging_enabled(struct power_supply *psy)
+{
+	wait_event_timeout(psy_chrgr.wait_chrg_enable,
+			(psy_is_charging_enabled(psy)), HZ);
+}
+
+static inline void enable_supplied_by_charging
+		(struct power_supply *psy, bool is_enable)
+{
+	struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
+	int cnt;
+
+	if (psy->type != POWER_SUPPLY_TYPE_BATTERY)
+		return;
+	/* Get list of chargers supplying power to this battery and
+	 * disable charging for all chargers
+	 */
+	cnt = get_supplied_by_list(psy, chrgr_lst);
+	if (cnt == 0)
+		return;
+
+	while (cnt--) {
+		if (!psy_is_present(chrgr_lst[cnt]))
+			continue;
+		if (is_enable && is_charging_can_be_enabled(chrgr_lst[cnt])) {
+			psy_enable_charging(chrgr_lst[cnt]);
+			wait_for_charging_enabled(chrgr_lst[cnt]);
+		} else
+			psy_disable_charging(chrgr_lst[cnt]);
+	}
+}
+
+static void __power_supply_trigger_charging_handler(struct power_supply *psy)
+{
+	int i;
+	struct power_supply *psb = NULL;
+
+	mutex_lock(&psy_chrgr.evt_lock);
+
+	if (is_trigger_charging_algo(psy)) {
+		if (psy_is_battery(psy)) {
+			if (trigger_algo(psy))
+				enable_supplied_by_charging(psy, false);
+			else
+				enable_supplied_by_charging(psy, true);
+		} else if (psy_is_charger(psy)) {
+			for (i = 0; i < psy->num_supplicants; i++) {
+				psb =
+				    power_supply_get_by_name(psy->
+							     supplied_to[i]);
+
+				if (psb && psy_is_battery(psb) &&
+							psy_is_present(psb)) {
+					if (trigger_algo(psb)) {
+						psy_disable_charging(psy);
+						break;
+					} else if (is_charging_can_be_enabled
+								(psy)) {
+						psy_enable_charging(psy);
+						wait_for_charging_enabled(psy);
+					}
+				}
+			}
+		}
+		update_sysfs(psy);
+		power_supply_changed(psy);
+	}
+	mutex_unlock(&psy_chrgr.evt_lock);
+}
+
+static int __trigger_charging_handler(struct device *dev, void *data)
+{
+	struct power_supply *psy = dev_get_drvdata(dev);
+
+	__power_supply_trigger_charging_handler(psy);
+
+	return 0;
+}
+
+static void trigger_algo_psy_class(struct work_struct *work)
+{
+	class_for_each_device(power_supply_class, NULL, NULL,
+			__trigger_charging_handler);
+}
+
+static bool is_cable_connected(void)
+{
+	int i;
+	struct charger_cable *cable;
+
+	for (i = 0; i < ARRAY_SIZE(cable_list); ++i) {
+		cable = cable_list + i;
+		if (psy_is_cable_active(cable->cable_props.chrg_evt))
+			return true;
+	}
+	return false;
+}
+
+void power_supply_trigger_charging_handler(struct power_supply *psy)
+{
+	if (!psy_chrgr.is_cable_evt_reg || !is_cable_connected())
+		return;
+
+	wake_up(&psy_chrgr.wait_chrg_enable);
+
+	if (psy)
+		__power_supply_trigger_charging_handler(psy);
+	else
+		schedule_work(&psy_chrgr.algo_trigger_work);
+
+}
+EXPORT_SYMBOL(power_supply_trigger_charging_handler);
+
+static inline int get_battery_thresholds(struct power_supply *psy,
+	struct psy_batt_thresholds *bat_thresh)
+{
+	struct psy_charging_algo *algo;
+	struct psy_ps_batt_chg_prof chrg_profile;
+
+	/* FIXME: Get iterm only for supplied_to arguments*/
+	if (psy_get_batt_prop(&chrg_profile)) {
+		pr_err("%s:Error in getting charge profile\n", __func__);
+		return -EINVAL;
+	}
+
+	algo = power_supply_get_charging_algo(psy, &chrg_profile);
+	if (!algo) {
+		pr_err("%s:Error in getting charging algo!!\n", __func__);
+		return -EINVAL;
+	}
+
+	if (algo->get_batt_thresholds) {
+		algo->get_batt_thresholds(chrg_profile, bat_thresh);
+	} else {
+		pr_err("%s:Error in getting battery thresholds from: %s\n",
+			__func__, algo->name);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int select_chrgr_cable(struct device *dev, void *data)
+{
+	struct power_supply *psy = dev_get_drvdata(dev);
+	struct charger_cable *cable, *max_mA_cable = NULL;
+	struct charger_cable *cable_lst = (struct charger_cable *)data;
+	unsigned int max_mA = 0;
+	int i;
+
+	if (!psy_is_charger(psy))
+		return 0;
+
+	mutex_lock(&psy_chrgr.evt_lock);
+
+	/* get cable with maximum capability */
+	for (i = 0; i < ARRAY_SIZE(cable_list); ++i) {
+		cable = cable_lst + i;
+		if ((!psy_is_cable_active(cable->cable_props.chrg_evt)) ||
+		    (!is_supported_cable(psy, cable->psy_cable_type)))
+			continue;
+
+		if (cable->cable_props.mA > max_mA) {
+			max_mA_cable = cable;
+			max_mA = cable->cable_props.mA;
+		}
+	}
+
+	/* no cable connected. disable charging */
+	if (!max_mA_cable) {
+
+		if ((psy_is_charger_enabled(psy) ||
+				psy_is_charging_enabled(psy))) {
+			psy_disable_charging(psy);
+			psy_disable_charger(psy);
+		}
+		psy_set_cc(psy, 0);
+		psy_set_cv(psy, 0);
+		psy_set_inlmt(psy, 0);
+
+		/* set present and online as 0 */
+		psy_set_present(psy, 0);
+		update_charger_online(psy);
+
+		psy_switch_cable(psy, PSY_CHARGER_CABLE_TYPE_NONE);
+
+		mutex_unlock(&psy_chrgr.evt_lock);
+		power_supply_changed(psy);
+		return 0;
+	}
+
+	/* cable type changed.New cable connected or existing cable
+	 * capabilities changed.switch cable and enable charger and charging
+	 */
+	psy_set_present(psy, 1);
+
+	if (PSY_CABLE_TYPE(psy) != max_mA_cable->psy_cable_type)
+		psy_switch_cable(psy, max_mA_cable->psy_cable_type);
+
+	if (psy_is_charger_can_be_enabled(psy)) {
+		struct psy_batt_thresholds bat_thresh;
+		memset(&bat_thresh, 0, sizeof(bat_thresh));
+		psy_enable_charger(psy);
+
+		update_charger_online(psy);
+
+		psy_set_inlmt(psy, max_mA_cable->cable_props.mA);
+		if (!get_battery_thresholds(psy, &bat_thresh)) {
+			psy_set_iterm(psy, bat_thresh.iterm);
+			psy_set_min_temp(psy, bat_thresh.temp_min);
+			psy_set_max_temp(psy, bat_thresh.temp_max);
+		}
+
+	} else {
+
+		psy_disable_charger(psy);
+		update_charger_online(psy);
+	}
+
+	mutex_unlock(&psy_chrgr.evt_lock);
+	power_supply_trigger_charging_handler(NULL);
+	/* Cable status is same as previous. No action to be taken */
+	return 0;
+}
+
+static void configure_chrgr_source(struct charger_cable *cable_lst)
+{
+	class_for_each_device(power_supply_class, NULL,
+			      cable_lst, select_chrgr_cable);
+}
+
+int psy_charger_throttle_charger(struct power_supply *psy,
+					unsigned long state)
+{
+	int ret = 0;
+
+	if (state < 0 || state > PSY_MAX_THROTTLE_STATE(psy))
+		return -EINVAL;
+
+	mutex_lock(&psy_chrgr.evt_lock);
+
+	switch PSY_THROTTLE_ACTION(psy, state)
+	{
+		case PSY_THROTTLE_DISABLE_CHARGER:
+			psy_set_max_cc(psy, 0);
+			psy_disable_charger(psy);
+			break;
+		case PSY_THROTTLE_DISABLE_CHARGING:
+			psy_set_max_cc(psy, 0);
+			psy_disable_charging(psy);
+			break;
+		case PSY_THROTTLE_CC_LIMIT:
+			psy_set_max_cc(psy, PSY_THROTTLE_CC_VALUE(psy, state));
+			break;
+		case PSY_THROTTLE_INPUT_LIMIT:
+			psy_set_inlmt(psy, PSY_THROTTLE_CC_VALUE(psy, state));
+			break;
+		default:
+			pr_err("Invalid throttle action for %s\n", psy->name);
+			ret = -EINVAL;
+			break;
+	}
+	mutex_unlock(&psy_chrgr.evt_lock);
+
+	/* Configure the driver based on new state */
+	if (!ret)
+		configure_chrgr_source(cable_list);
+	return ret;
+}
+EXPORT_SYMBOL(psy_charger_throttle_charger);
+
+int power_supply_register_charger(struct power_supply *psy)
+{
+	int ret = 0;
+
+	if (!psy_chrgr.is_cable_evt_reg) {
+		mutex_init(&psy_chrgr.evt_lock);
+		init_waitqueue_head(&psy_chrgr.wait_chrg_enable);
+		init_charger_cables(cable_list, ARRAY_SIZE(cable_list));
+		INIT_LIST_HEAD(&psy_chrgr.chrgr_cache_lst);
+		INIT_LIST_HEAD(&psy_chrgr.batt_cache_lst);
+		INIT_WORK(&psy_chrgr.algo_trigger_work, trigger_algo_psy_class);
+		psy_chrgr.is_cable_evt_reg = true;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(power_supply_register_charger);
+
+static inline void flush_charger_context(struct power_supply *psy)
+{
+	struct psy_charger_props *chrgr_prop, *tmp;
+
+
+	list_for_each_entry_safe(chrgr_prop, tmp,
+				&psy_chrgr.chrgr_cache_lst, node) {
+		if (!strcmp(chrgr_prop->name, psy->name)) {
+			list_del(&chrgr_prop->node);
+			kfree(chrgr_prop);
+		}
+	}
+}
+
+int power_supply_unregister_charger(struct power_supply *psy)
+{
+	flush_charger_context(psy);
+	return 0;
+}
+EXPORT_SYMBOL(power_supply_unregister_charger);
+
+int power_supply_register_charging_algo(struct psy_charging_algo *algo)
+{
+
+	struct psy_charging_algo *algo_new;
+
+	algo_new = kzalloc(sizeof(*algo_new), GFP_KERNEL);
+	if (algo_new == NULL) {
+		pr_err("%s: Error allocating memory for algo!!", __func__);
+		return -ENOMEM;
+	}
+	memcpy(algo_new, algo, sizeof(*algo_new));
+
+	list_add_tail(&algo_new->node, &algo_list);
+	return 0;
+}
+EXPORT_SYMBOL(power_supply_register_charging_algo);
+
+int power_supply_unregister_charging_algo(struct psy_charging_algo *algo)
+{
+	struct psy_charging_algo *algo_l, *tmp;
+
+	list_for_each_entry_safe(algo_l, tmp, &algo_list, node) {
+		if (!strcmp(algo_l->name, algo->name)) {
+			list_del(&algo_l->node);
+			kfree(algo_l);
+		}
+	}
+	return 0;
+
+}
+EXPORT_SYMBOL(power_supply_unregister_charging_algo);
+
+static struct psy_charging_algo *get_charging_algo_byname(char *algo_name)
+{
+	struct psy_charging_algo *algo;
+
+	list_for_each_entry(algo, &algo_list, node) {
+		if (!strcmp(algo->name, algo_name))
+			return algo;
+	}
+
+	return NULL;
+}
+
+static struct psy_charging_algo *get_charging_algo_by_type
+		(enum psy_batt_chrg_prof_type chrg_prof_type)
+{
+	struct psy_charging_algo *algo;
+
+	list_for_each_entry(algo, &algo_list, node) {
+		if (algo->chrg_prof_type == chrg_prof_type)
+			return algo;
+	}
+
+	return NULL;
+}
+
+struct psy_charging_algo *power_supply_get_charging_algo
+	(struct power_supply *psy, struct psy_ps_batt_chg_prof *batt_prof)
+{
+
+	return get_charging_algo_by_type(batt_prof->chrg_prof_type);
+
+}
+EXPORT_SYMBOL_GPL(power_supply_get_charging_algo);
diff --git a/drivers/power/power_supply_charger.h b/drivers/power/power_supply_charger.h
new file mode 100644
index 0000000..7ca0455
--- /dev/null
+++ b/drivers/power/power_supply_charger.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Jenny TC <jenny.tc@intel.com>
+ */
+#ifndef __POWER_SUPPLY_CHARGER_H__
+
+#define __POWER_SUPPLY_CHARGER_H__
+#include <linux/power/battery_id.h>
+#include <linux/power_supply.h>
+
+#define MAX_CUR_VOLT_SAMPLES 3
+#define DEF_CUR_VOLT_SAMPLE_JIFF (30*HZ)
+
+enum psy_algo_stat {
+	PSY_ALGO_STAT_UNKNOWN,
+	PSY_ALGO_STAT_NOT_CHARGE,
+	PSY_ALGO_STAT_CHARGE,
+	PSY_ALGO_STAT_FULL,
+	PSY_ALGO_STAT_MAINT,
+};
+
+struct psy_batt_props {
+	struct list_head node;
+	const char *name;
+	long voltage_now;
+	long voltage_now_cache[MAX_CUR_VOLT_SAMPLES];
+	long current_now;
+	long current_now_cache[MAX_CUR_VOLT_SAMPLES];
+	int temperature;
+	long status;
+	unsigned long long tstamp;
+	enum psy_algo_stat algo_stat;
+	int health;
+	int throttle_state;
+};
+
+struct psy_charger_props {
+	struct list_head node;
+	const char *name;
+	bool present;
+	bool is_charging;
+	int health;
+	bool online;
+	unsigned long cable;
+	unsigned long tstamp;
+};
+
+struct psy_batt_thresholds {
+	int temp_min;
+	int temp_max;
+	unsigned int iterm;
+};
+
+struct psy_charging_algo {
+	struct list_head node;
+	unsigned int chrg_prof_type;
+	char *name;
+	enum psy_algo_stat (*get_next_cc_cv)(struct psy_batt_props,
+			struct psy_ps_batt_chg_prof, unsigned long *cc,
+			unsigned long *cv);
+	int (*get_batt_thresholds)(struct psy_ps_batt_chg_prof,
+			struct psy_batt_thresholds *bat_thr);
+};
+
+
+extern int power_supply_register_charging_algo(struct psy_charging_algo *);
+extern int power_supply_unregister_charging_algo(struct psy_charging_algo *);
+
+/* Define a TTL for some properies to optimize the frequency of
+* algorithm calls. This can be used by properties which will be changed
+* very frequently (eg. current, volatge..)
+*/
+#define PROP_TTL (HZ*10)
+
+static inline bool psy_is_battery_prop_changed(struct psy_batt_props bat_prop,
+		struct psy_batt_props bat_cache)
+{
+	/* return true if temperature, health or throttling state changed
+	*/
+	if ((bat_cache.temperature != bat_prop.temperature) ||
+		(bat_cache.health != bat_prop.health) ||
+		(bat_cache.throttle_state != bat_prop.throttle_state))
+		return true;
+
+	/* return true if voltage or current changed not within TTL limit
+	*/
+	if (time_after64(bat_prop.tstamp, bat_cache.tstamp + PROP_TTL) &&
+		(bat_cache.current_now != bat_prop.current_now ||
+		bat_cache.voltage_now != bat_prop.voltage_now))
+		return true;
+
+	return false;
+}
+
+static inline bool psy_is_charger_prop_changed(struct psy_charger_props prop,
+		struct psy_charger_props cache_prop)
+{
+	/* if online/prsent/health/is_charging is changed, then return true
+	*/
+
+	if (cache_prop.online != prop.online ||
+		cache_prop.present != prop.present ||
+		cache_prop.is_charging != prop.is_charging ||
+		cache_prop.health != prop.health)
+		return true;
+	else
+		return false;
+
+}
+
+
+
+#endif
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 08bce22..47e73eb 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -19,6 +19,7 @@
 #include <linux/power_supply.h>
 #include <linux/thermal.h>
 #include "power_supply.h"
+#include "power_supply_charger.h"
 
 /* exported for the APM Power driver, APM emulation */
 struct class *power_supply_class;
@@ -83,6 +84,7 @@ static void power_supply_changed_work(struct work_struct *work)
 		class_for_each_device(power_supply_class, NULL, psy,
 				      __power_supply_changed_work);
 		power_supply_update_leds(psy);
+		power_supply_trigger_charging_handler(psy);
 		atomic_notifier_call_chain(&power_supply_notifier,
 				PSY_EVENT_PROP_CHANGED, psy);
 		kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
@@ -102,6 +104,18 @@ void power_supply_changed(struct power_supply *psy)
 {
 	unsigned long flags;
 
+	/* If psy == NULL, invoke charging handler. This can be
+	*  used by drivers to notify charging framework without
+	*  notifying the user space. This would avoid frequent
+	*  wakeup of the user space stack when charger/battery
+	*  driver notifies the framework.
+	*/
+
+	if (psy == NULL) {
+		power_supply_trigger_charging_handler(psy);
+		return;
+	}
+
 	dev_dbg(psy->dev, "%s\n", __func__);
 
 	spin_lock_irqsave(&psy->changed_lock, flags);
@@ -561,6 +575,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
 	if (rc)
 		goto create_triggers_failed;
 
+	if (psy_is_charger(psy))
+		rc = power_supply_register_charger(psy);
+	if (rc)
+		pr_debug("device: '%s': power_supply_register_charger failed\n",
+				dev_name(dev));
 	power_supply_changed(psy);
 
 	goto success;
@@ -586,6 +605,8 @@ void power_supply_unregister(struct power_supply *psy)
 	cancel_work_sync(&psy->changed_work);
 	sysfs_remove_link(&psy->dev->kobj, "powers");
 	power_supply_remove_triggers(psy);
+	if (psy_is_charger(psy))
+		power_supply_unregister_charger(psy);
 	psy_unregister_cooler(psy);
 	psy_unregister_thermal(psy);
 	device_init_wakeup(psy->dev, false);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 95a3dd7..d19b179 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -375,4 +375,268 @@ static inline bool power_supply_is_watt_property(enum power_supply_property psp)
 	return 0;
 }
 
+static inline int psy_set_ps_int_property(struct power_supply *psy,
+				      enum power_supply_property psp,
+				      int prop_val)
+{
+	union power_supply_propval val;
+
+	val.intval = prop_val;
+	return psy->set_property(psy, psp, &val);
+}
+
+static inline int psy_get_ps_int_property(struct power_supply *psy,
+				      enum power_supply_property psp)
+{
+	union power_supply_propval val;
+
+	val.intval = 0;
+	psy->get_property(psy, psp, &val);
+	return val.intval;
+}
+
+#define PSY_HEALTH(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_HEALTH)
+#define PSY_CV(psy) \
+		psy_get_ps_int_property(psy,\
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE)
+#define PSY_CC(psy) \
+		psy_get_ps_int_property(psy,\
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT)
+#define PSY_INLMT(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_INLMT)
+#define PSY_MAX_CC(psy) \
+		psy_get_ps_int_property(psy,\
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX)
+#define PSY_MAX_CV(psy) \
+		psy_get_ps_int_property(psy,\
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX)
+#define PSY_VOLTAGE_NOW(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW)
+#define PSY_VOLTAGE_OCV(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_VOLTAGE_OCV)
+#define PSY_CURRENT_NOW(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW)
+#define PSY_STATUS(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_STATUS)
+#define PSY_TEMPERATURE(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_TEMP)
+#define PSY_BATTERY_TYPE(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_TECHNOLOGY)
+#define PSY_PRIORITY(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_PRIORITY)
+#define PSY_CABLE_TYPE(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_CABLE_TYPE)
+#define PSY_ONLINE(psy) \
+		psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_ONLINE)
+#define PSY_THROTTLE_ACTION(psy, state)\
+		(((psy->throttle_states)+state)->throttle_action)
+#define PSY_MAX_THROTTLE_STATE(psy)\
+		((psy->num_throttle_states))
+#define PSY_CURRENT_THROTTLE_STATE(psy)\
+		(psy_get_ps_int_property(psy,\
+			POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT))
+#define PSY_CURRENT_THROTTLE_ACTION(psy)\
+		PSY_THROTTLE_ACTION(psy, PSY_CURRENT_THROTTLE_STATE(psy))
+#define PSY_THROTTLE_CC_VALUE(psy, state)\
+		(((psy->throttle_states)+state)->throttle_val)
+
+
+static inline int psy_set_present(struct power_supply *psy, int present)
+{
+	return	psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_PRESENT, present);
+}
+
+static inline int psy_set_iterm(struct power_supply *psy, int iterm)
+{
+	return	psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_CHARGE_TERM_CUR, iterm);
+}
+
+static inline int psy_set_max_temp(struct power_supply *psy, int temp)
+{
+	return	psy_set_ps_int_property(psy, POWER_SUPPLY_PROP_MAX_TEMP, temp);
+}
+
+static inline int psy_set_min_temp(struct power_supply *psy, int temp)
+{
+	return	psy_set_ps_int_property(psy, POWER_SUPPLY_PROP_MIN_TEMP, temp);
+}
+
+static inline int psy_is_charging_enabled(struct power_supply *psy)
+{
+	return	psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_ENABLE_CHARGING);
+}
+
+static inline int psy_is_charger_enabled(struct power_supply *psy)
+{
+	return	psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_ENABLE_CHARGER);
+}
+
+static inline int psy_is_online(struct power_supply *psy)
+{
+	return	psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_ONLINE);
+}
+
+static inline int psy_is_present(struct power_supply *psy)
+{
+	return	psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_PRESENT);
+}
+
+static inline int psy_is_supported_cable(struct power_supply *psy,
+		enum psy_charger_cable_type cable_type)
+{
+	return psy->supported_cables && (psy->supported_cables & cable_type);
+}
+static inline bool psy_is_health_good(struct power_supply *psy)
+{
+	return PSY_HEALTH(psy) == POWER_SUPPLY_HEALTH_GOOD;
+}
+static inline int psy_enable_charger(struct power_supply *psy)
+{
+	return psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_ENABLE_CHARGER, true);
+}
+static inline int psy_enable_charging(struct power_supply *psy)
+{
+	int ret;
+
+	if ((PSY_CABLE_TYPE(psy) != PSY_CHARGER_CABLE_TYPE_NONE) &&
+			!psy_is_charging_enabled(psy)) {
+
+		ret = psy_enable_charger(psy);
+		if (ret)
+			return ret;
+		ret = psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_ENABLE_CHARGING, true);
+		if (ret)
+			return ret;
+
+	}
+
+	/* Charging is already disabled or disabling is success.
+	*  So return 0.
+	*/
+	return 0;
+}
+
+static inline int psy_disable_charging(struct power_supply *psy)
+{
+	return psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_ENABLE_CHARGING, false);
+}
+
+static inline int psy_disable_charger(struct power_supply *psy)
+{
+	psy_disable_charging(psy);
+	return psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_ENABLE_CHARGER, false);
+}
+
+static inline int psy_set_cc(struct power_supply *psy, int cc)
+{
+	return	psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, cc);
+}
+
+static inline int psy_set_cv(struct power_supply *psy, int cc)
+{
+	return	psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, cc);
+}
+
+static inline int psy_set_inlmt(struct power_supply *psy, int inlmt)
+{
+	return	psy_set_ps_int_property(psy, POWER_SUPPLY_PROP_INLMT, inlmt);
+}
+
+static inline int psy_set_max_cc(struct power_supply *psy, int max_cc)
+{
+	return psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, max_cc);
+}
+
+static inline int psy_set_max_cv(struct power_supply *psy, int max_cv)
+{
+	return psy_set_ps_int_property(psy,
+			POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, max_cv);
+}
+
+static inline int psy_switch_cable(struct power_supply *psy,
+		enum psy_charger_cable_type cable)
+{
+	return	psy_set_ps_int_property(psy,
+		POWER_SUPPLY_PROP_CABLE_TYPE, cable);
+}
+
+static inline bool psy_is_battery(struct power_supply *psy)
+{
+	return (psy->type == POWER_SUPPLY_TYPE_BATTERY);
+}
+
+static inline bool psy_is_charger(struct power_supply *psy)
+{
+	return (psy->type == POWER_SUPPLY_TYPE_USB ||
+			psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
+			psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
+			psy->type == POWER_SUPPLY_TYPE_USB_ACA);
+}
+
+static inline bool is_online(struct power_supply *psy)
+{
+	return (psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_ONLINE) == 1);
+}
+
+static inline bool is_present(struct power_supply *psy)
+{
+	return (psy_get_ps_int_property(psy, POWER_SUPPLY_PROP_PRESENT) == 1);
+}
+
+static inline bool is_supported_cable(struct power_supply *psy,
+		enum psy_charger_cable_type cable_type)
+{
+	return	psy->supported_cables & cable_type;
+}
+
+static inline bool is_charging_can_be_enabled(struct power_supply *psy)
+{
+	return ((PSY_CURRENT_THROTTLE_ACTION(psy) !=
+					PSY_THROTTLE_DISABLE_CHARGER) &&
+		(PSY_CURRENT_THROTTLE_ACTION(psy) !=
+				PSY_THROTTLE_DISABLE_CHARGING));
+}
+
+static inline bool psy_is_charger_can_be_enabled(struct power_supply *psy)
+{
+	return (PSY_CURRENT_THROTTLE_ACTION(psy) !=
+			PSY_THROTTLE_DISABLE_CHARGER);
+}
+
+static inline void psy_set_battery_status(struct power_supply *psy, int status)
+{
+
+	if (PSY_STATUS(psy) != status)
+		psy_set_ps_int_property(psy, POWER_SUPPLY_PROP_STATUS, status);
+
+}
+
+static inline void psy_set_charger_online(struct power_supply *psy, int online)
+{
+
+	if (PSY_ONLINE(psy) != online)
+		psy_set_ps_int_property(psy, POWER_SUPPLY_PROP_ONLINE, online);
+
+}
+
+static inline bool psy_is_cable_active(unsigned long status)
+{
+	if (status == PSY_CHARGER_CABLE_EVENT_DISCONNECT ||
+			status == PSY_CHARGER_CABLE_EVENT_SUSPEND)
+		return false;
+	else
+		return true;
+}
+
+
 #endif /* __LINUX_POWER_SUPPLY_H__ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 7/7] power_supply: Introduce PSE compliant algorithm
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
                   ` (5 preceding siblings ...)
  2013-09-23 18:04 ` [PATCH 6/7] power_supply: Introduce Power Supply charging framework Jenny TC
@ 2013-09-23 18:04 ` Jenny TC
  2013-10-28  6:17   ` Anton Vorontsov
  2013-10-25 16:49 ` [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Tc, Jenny
  7 siblings, 1 reply; 16+ messages in thread
From: Jenny TC @ 2013-09-23 18:04 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov; +Cc: Jenny TC

As per PSE standard the battery characteristics and thereby the
charging rates can vary on different temperature zones. This
patch introduces a PSE compliant charging algorithm with
maintenance charging support. The algorithm can be selected by the
charging framework based on the type of the battery charging profile.

Change-Id: I85149c49b3eb3e259fba72f1d066ba2b020717cd
Signed-off-by: Jenny TC <jenny.tc@intel.com>
---
 drivers/power/Kconfig                |   12 ++
 drivers/power/Makefile               |    1 +
 drivers/power/charging_algo_pse.c    |  202 ++++++++++++++++++++++++++++++++++
 drivers/power/power_supply_charger.c |   12 --
 include/linux/power/battery_id.h     |   45 ++++++++
 5 files changed, 260 insertions(+), 12 deletions(-)
 create mode 100644 drivers/power/charging_algo_pse.c

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index ff361ee..ec3cf4f 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -18,6 +18,18 @@ config POWER_SUPPLY_CHARGER
 	  drivers to keep the charging logic outside and the charger driver
 	  just need to abstract the charger hardware
 
+config POWER_SUPPLY_CHARGING_ALGO_PSE
+	bool "PSE compliant charging algorithm"
+	help
+	  Say Y here to select PSE compliant charging algorithm. As per PSE
+	  standard the battery characteristics and thereby the charging rates
+	  can vary on different temperature zones. This config will enable PSE
+	  compliant charging algorithm with maintenance charging support. The
+	  algorithm can be selected by the charging framework based on the type
+	  of the battery charging profile.
+
+	depends on POWER_SUPPLY_CHARGER
+
 config POWER_SUPPLY_BATTID
 	bool "Power Supply Battery Identification Framework"
 	help
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 021b97a..1909ac2 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -9,6 +9,7 @@ power_supply-$(CONFIG_POWER_SUPPLY_BATTID) += battery_id.o
 obj-$(CONFIG_POWER_SUPPLY)	+= power_supply.o
 obj-$(CONFIG_GENERIC_ADC_BATTERY)	+= generic-adc-battery.o
 
+obj-$(CONFIG_POWER_SUPPLY_CHARGING_ALGO_PSE) += charging_algo_pse.o
 obj-$(CONFIG_PDA_POWER)		+= pda_power.o
 obj-$(CONFIG_APM_POWER)		+= apm_power.o
 obj-$(CONFIG_MAX8925_POWER)	+= max8925_power.o
diff --git a/drivers/power/charging_algo_pse.c b/drivers/power/charging_algo_pse.c
new file mode 100644
index 0000000..217799c
--- /dev/null
+++ b/drivers/power/charging_algo_pse.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Jenny TC <jenny.tc@intel.com>
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/thermal.h>
+#include <linux/power/battery_id.h>
+#include "power_supply.h"
+#include "power_supply_charger.h"
+
+/* 98% of CV is considered as voltage to detect Full */
+#define FULL_CV_MIN 98
+
+/* Offset to exit from maintenance charging. In maintenance charging
+*  if the volatge is less than the (maintenance_lower_threshold -
+*  MAINT_EXIT_OFFSET) then system can switch to normal charging
+*/
+#define MAINT_EXIT_OFFSET 50  /* mV */
+
+static int get_tempzone(struct psy_ps_pse_mod_prof *pse_mod_bprof,
+		int temp)
+{
+
+	int i = 0;
+	int temp_range_cnt = min_t(u16, pse_mod_bprof->temp_mon_ranges,
+					BATT_TEMP_NR_RNG);
+
+	if ((temp < pse_mod_bprof->temp_low_lim) ||
+		(temp > pse_mod_bprof->temp_mon_range[0].temp_up_lim))
+		return -EINVAL;
+
+	for (i = 0; i < temp_range_cnt; ++i)
+		if (temp > pse_mod_bprof->temp_mon_range[i].temp_up_lim)
+			break;
+	return i-1;
+}
+
+static inline bool __is_battery_full
+	(long volt, long cur, long iterm, unsigned long cv)
+{
+	pr_devel("%s:current=%ld pse_mod_bprof->chrg_term_mA =%ld voltage_now=%ld full_cond=%ld",
+			__func__, cur, iterm, volt * 100, (FULL_CV_MIN * cv));
+
+	return ((cur > 0) && (cur <= iterm) &&
+	((volt * 100)  >= (FULL_CV_MIN * cv)));
+
+}
+
+static inline bool is_battery_full(struct psy_batt_props bat_prop,
+		struct psy_ps_pse_mod_prof *pse_mod_bprof, unsigned long cv)
+{
+
+	int i;
+	/* Software full detection. Check the battery charge current to detect
+	*  battery Full. The voltage also verified to avoid false charge
+	*  full detection.
+	*/
+	pr_devel("%s:current=%ld pse_mod_bprof->chrg_term_mA =%d bat_prop.voltage_now=%ld full_cond=%ld",
+		__func__, bat_prop.current_now, (pse_mod_bprof->chrg_term_mA),
+		bat_prop.voltage_now * 100, (FULL_CV_MIN * cv));
+
+	for (i = (MAX_CUR_VOLT_SAMPLES - 1); i >= 0; --i) {
+
+		if (!(__is_battery_full(bat_prop.voltage_now_cache[i],
+				bat_prop.current_now_cache[i],
+				pse_mod_bprof->chrg_term_mA, cv)))
+			return false;
+	}
+
+	return true;
+}
+
+static int  pse_get_bat_thresholds(struct psy_ps_batt_chg_prof  bprof,
+			struct psy_batt_thresholds *bat_thresh)
+{
+	struct psy_ps_pse_mod_prof *pse_mod_bprof =
+			(struct psy_ps_pse_mod_prof *) bprof.batt_prof;
+
+	if ((bprof.chrg_prof_type != PSY_CHRG_PROF_PSE) || (!pse_mod_bprof))
+		return -EINVAL;
+
+	bat_thresh->iterm = pse_mod_bprof->chrg_term_mA;
+	bat_thresh->temp_min = pse_mod_bprof->temp_low_lim;
+	bat_thresh->temp_max = pse_mod_bprof->temp_mon_range[0].temp_up_lim;
+
+	return 0;
+}
+
+static enum psy_algo_stat pse_get_next_cc_cv(struct psy_batt_props bat_prop,
+	struct psy_ps_batt_chg_prof  bprof,
+			unsigned long *cc, unsigned long *cv)
+{
+	int tzone;
+	struct psy_ps_pse_mod_prof *pse_mod_bprof =
+			(struct psy_ps_pse_mod_prof *) bprof.batt_prof;
+	enum psy_algo_stat algo_stat = bat_prop.algo_stat;
+	int maint_exit_volt;
+
+	*cc = *cv = 0;
+
+	/* If STATUS is discharging, assume that charger is not connected.
+	*  If charger is not connected, no need to take any action.
+	*  If charge profile type is not PSY_CHRG_PROF_PSE or the charge profile
+	*  is not present, no need to take any action.
+	*/
+
+	pr_devel("%s:battery status = %ld algo_status=%d\n",
+			__func__, bat_prop.status, algo_stat);
+
+	if ((bprof.chrg_prof_type != PSY_CHRG_PROF_PSE) || (!pse_mod_bprof))
+		return PSY_ALGO_STAT_NOT_CHARGE;
+
+	tzone = get_tempzone(pse_mod_bprof, bat_prop.temperature);
+
+	if (tzone < 0)
+		return PSY_ALGO_STAT_NOT_CHARGE;
+
+	/* Change the algo status to not charging, if battery is
+	*  not really charging or less than maintenance exit threshold.
+	*  This way algorithm can switch to normal
+	*  charging if current status is full/maintenace
+	*/
+	maint_exit_volt = pse_mod_bprof->
+			temp_mon_range[tzone].maint_chrg_vol_ll -
+				MAINT_EXIT_OFFSET;
+
+	if ((bat_prop.status == POWER_SUPPLY_STATUS_DISCHARGING) ||
+		(bat_prop.status == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
+			bat_prop.voltage_now < maint_exit_volt) {
+
+		algo_stat = PSY_ALGO_STAT_NOT_CHARGE;
+
+	}
+
+	/* read cc and cv based on temperature and algorithm status*/
+	if (algo_stat == PSY_ALGO_STAT_FULL ||
+			algo_stat == PSY_ALGO_STAT_MAINT) {
+
+		/* if status is full and voltage is lower than maintenance lower
+		*  threshold change status to maintenenance
+		*/
+
+		if (algo_stat == PSY_ALGO_STAT_FULL && (bat_prop.voltage_now <=
+			pse_mod_bprof->temp_mon_range[tzone].maint_chrg_vol_ll))
+				algo_stat = PSY_ALGO_STAT_MAINT;
+
+		/* Read maintenance CC and CV */
+		if (algo_stat == PSY_ALGO_STAT_MAINT) {
+			*cv = pse_mod_bprof->temp_mon_range
+					[tzone].maint_chrg_vol_ul;
+			*cc = pse_mod_bprof->temp_mon_range
+					[tzone].maint_chrg_cur;
+		}
+	} else {
+		*cv = pse_mod_bprof->temp_mon_range[tzone].full_chrg_vol;
+		*cc = pse_mod_bprof->temp_mon_range[tzone].full_chrg_cur;
+		algo_stat = PSY_ALGO_STAT_CHARGE;
+	}
+
+	if (is_battery_full(bat_prop, pse_mod_bprof, *cv)) {
+		*cc = *cv = 0;
+		algo_stat = PSY_ALGO_STAT_FULL;
+	}
+
+	return algo_stat;
+}
+
+static int __init pse_algo_init(void)
+{
+	struct psy_charging_algo pse_algo;
+	pse_algo.chrg_prof_type = PSY_CHRG_PROF_PSE;
+	pse_algo.name = "pse_algo";
+	pse_algo.get_next_cc_cv = pse_get_next_cc_cv;
+	pse_algo.get_batt_thresholds = pse_get_bat_thresholds;
+	power_supply_register_charging_algo(&pse_algo);
+	return 0;
+}
+
+module_init(pse_algo_init);
diff --git a/drivers/power/power_supply_charger.c b/drivers/power/power_supply_charger.c
index 8e6630f..97c1c31 100644
--- a/drivers/power/power_supply_charger.c
+++ b/drivers/power/power_supply_charger.c
@@ -988,18 +988,6 @@ int power_supply_unregister_charging_algo(struct psy_charging_algo *algo)
 }
 EXPORT_SYMBOL(power_supply_unregister_charging_algo);
 
-static struct psy_charging_algo *get_charging_algo_byname(char *algo_name)
-{
-	struct psy_charging_algo *algo;
-
-	list_for_each_entry(algo, &algo_list, node) {
-		if (!strcmp(algo->name, algo_name))
-			return algo;
-	}
-
-	return NULL;
-}
-
 static struct psy_charging_algo *get_charging_algo_by_type
 		(enum psy_batt_chrg_prof_type chrg_prof_type)
 {
diff --git a/include/linux/power/battery_id.h b/include/linux/power/battery_id.h
index ef4d0f9..2d35f58 100644
--- a/include/linux/power/battery_id.h
+++ b/include/linux/power/battery_id.h
@@ -31,6 +31,7 @@ enum {
 
 enum psy_batt_chrg_prof_type {
 	PSY_CHRG_PROF_NONE = 0,
+	PSY_CHRG_PROF_PSE,
 };
 
 /* charging profile structure definition */
@@ -39,6 +40,50 @@ struct psy_ps_batt_chg_prof {
 	void *batt_prof;
 };
 
+/* PSE Modified Algo Structure */
+/* Parameters defining the charging range */
+struct psy_ps_temp_chg_table {
+	/* upper temperature limit for each zone */
+	short int temp_up_lim;
+	/* charge current and voltage */
+	short int full_chrg_vol;
+	short int full_chrg_cur;
+	/* maintenance thresholds */
+	/* maintenance lower threshold. Once battery hits full, charging
+	*  charging will be resumed when battery voltage <= this voltage
+	*/
+	short int maint_chrg_vol_ll;
+	/* Charge current and voltage in maintenance mode */
+	short int maint_chrg_vol_ul;
+	short int maint_chrg_cur;
+} __packed;
+
+
+#define BATTID_STR_LEN		8
+#define BATT_TEMP_NR_RNG	6
+/* Charging Profile */
+struct psy_ps_pse_mod_prof {
+	/* battery id */
+	char batt_id[BATTID_STR_LEN];
+	/* type of battery */
+	u16 battery_type;
+	u16 capacity;
+	u16 voltage_max;
+	/* charge termination current */
+	u16 chrg_term_mA;
+	/* Low battery level voltage */
+	u16 low_batt_mV;
+	/* upper and lower temperature limits on discharging */
+	u8 disch_tmp_ul;
+	u8 disch_tmp_ll;
+	/* number of temperature monitoring ranges */
+	u16 temp_mon_ranges;
+	struct psy_ps_temp_chg_table temp_mon_range[BATT_TEMP_NR_RNG];
+	/* Lowest temperature supported */
+	short int temp_low_lim;
+} __packed;
+
+
 #ifdef CONFIG_POWER_SUPPLY_BATTID
 extern int psy_get_batt_prop(struct psy_ps_batt_chg_prof *batt_prop);
 extern void psy_battery_prop_changed(int battery_conn_stat,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* RE: [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework
  2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
                   ` (6 preceding siblings ...)
  2013-09-23 18:04 ` [PATCH 7/7] power_supply: Introduce PSE compliant algorithm Jenny TC
@ 2013-10-25 16:49 ` Tc, Jenny
  7 siblings, 0 replies; 16+ messages in thread
From: Tc, Jenny @ 2013-10-25 16:49 UTC (permalink / raw)
  To: linux-kernel, Anton Vorontsov, Anton Vorontsov

Anton,

Could you please review these patches?

-Jenny

> -----Original Message-----
> From: Tc, Jenny
> Sent: Monday, September 23, 2013 11:34 PM
> To: linux-kernel@vger.kernel.org; Anton Vorontsov; Anton Vorontsov
> Cc: Tc, Jenny
> Subject: [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework
> 
> The Power Supply charging framework connects multiple subsystems to do charging in a
> generic way. The framework makes use of different new features - Battery Identification
> framework, pluggable charging algorithms, charger cable arbitrations. PSE compliant
> charging algorithm also enabled as part of this patch set.
> 
> With this framework the charging logic can be kept outside the charger driver.The charger
> driver just need to expose th get_property and set_property functions to get and set a
> specific set of power supply properties. The driver can convert these values to the
> hardware configurations to setup charging.
> 
> 
> Jenny TC (7):
>   power_supply: Add charger control properties
>   power_supply : add charger cable properties
>   power_supply: add throttle state
>   power_supply: Add power_supply notifier
>   power_supply : Introduce battery identification framework
>   power_supply: Introduce Power Supply charging framework
>   power_supply: Introduce PSE compliant algorithm
> 
>  Documentation/power/power_supply_class.txt |  202 ++++++
>  drivers/power/Kconfig                      |   30 +
>  drivers/power/Makefile                     |    3 +
>  drivers/power/battery_id.c                 |   87 +++
>  drivers/power/charging_algo_pse.c          |  202 ++++++
>  drivers/power/power_supply.h               |   21 +
>  drivers/power/power_supply_charger.c       | 1011 ++++++++++++++++++++++++++++
>  drivers/power/power_supply_charger.h       |  130 ++++
>  drivers/power/power_supply_core.c          |   38 ++
>  drivers/power/power_supply_sysfs.c         |    8 +
>  include/linux/power/battery_id.h           |  100 +++
>  include/linux/power_supply.h               |  335 +++++++++
>  12 files changed, 2167 insertions(+)
>  create mode 100644 drivers/power/battery_id.c  create mode 100644
> drivers/power/charging_algo_pse.c  create mode 100644
> drivers/power/power_supply_charger.c
>  create mode 100644 drivers/power/power_supply_charger.h
>  create mode 100644 include/linux/power/battery_id.h
> 
> --
> 1.7.9.5


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/7] power_supply: Add charger control properties
  2013-09-23 18:03 ` [PATCH 1/7] power_supply: Add charger control properties Jenny TC
@ 2013-10-27 23:46   ` Anton Vorontsov
  2013-10-28  3:36     ` Tc, Jenny
  0 siblings, 1 reply; 16+ messages in thread
From: Anton Vorontsov @ 2013-10-27 23:46 UTC (permalink / raw)
  To: Jenny TC
  Cc: linux-kernel, Kim, Milo, Lee Jones, Jingoo Han, Chanwoo Choi,
	Sachin Kamat, Rupesh Kumar, Lars-Peter Clausen, Pali Rohár,
	Mark Brown, Rhyland Klein

Hello Jenny,

Thanks a lot for your work on this!

On Mon, Sep 23, 2013 at 11:33:59PM +0530, Jenny TC wrote:
> The battery charger needs to have control path along
> with the reporting charger properties. In existing solutions
> this is implemented using regulator framework. A regulator
> framework doesn't fit a charger driver requirement because of the
> following reason
>

General note:

Please always Cc as many relevant developers as possible, not just me. For
me it takes months to review patches, and you surely want to get at least
a preliminary review from other power supply folks. By Cc'ing just me you
are slowing yourself down.

If you get some Acks/Reviews from other developers on your patches that
shows that the feature is surely in demand and makes sense in general.

"git shortlog -s -n -e drivers/power/*charg*" is a good start to see whom
you'd better Cc in this case.

(Unrelated to these patches, but just FYI, having a chain of

Reviewed-by: Somebody1 <...@same_company.foo>
Reviewed-by: Somebody2 <...@same_company.foo>
...
Reviewed-by: SomebodyN <...@same_company.foo>

Works in opposite direction, it makes me suspicious. :)

> and charging (charger to battery).Disabling the charging path alone
> (eg over battery temperature) will allow the platform to work with
> power from charger without discharging the battery. And the charger
> may need to be disabled completely based on the charger temperature
> or the platform temperature.
> Charger has more than one pair of voltage/current to control (CC,CV,INLMT)
> These features will not directly fit in the regulator framework
> 
> Since the charger driver sits in the power supply subsystem it make sense
> to add the properties to control the charger.

Looking into the patches, it seems that we are putting a lot of
charger-specific knobs into the power supply class, but the primary idea
of power supply subsystem is to monitor the power supplies of the system
itself and system's devices like mouse/keyboard's batteries.

The border of what we define as power supply class object is blurry, so
there is a lot of confusion indeed. For example, some chargers register
TYPE_MAINS or TYPE_USB power_supply objects, but they do it since the
charger chip itself is responsible for monitoring these supplies, so it is
fine, and it does not affect the power supply class itself.

But do we really want to control the chargers through the power_supply's
user-visible interface? It makes the whole power supply thing so
complicated that I'm already losing track of it. Right now I think I would
prefer to move all the charger logic out of the psy class.

More specifically, this code:

> @@ -561,6 +575,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
>       if (rc)
>               goto create_triggers_failed;
>
> +     if (psy_is_charger(psy))
> +             rc = power_supply_register_charger(psy);
> +     if (rc)
> +             pr_debug("device: '%s': power_supply_register_charger failed\n",
> +                             dev_name(dev));

I have a weird feeling about the fact that the power_supply_register()
registers a charger. OK, we have thermal stuff registration there, but it
is completely different. We have the cooling device registration there as
well, and this stuff would be really nice to move out to some "chargers
subsystem".

So, Jenny, the question is: can we separate chargers logic from the power
supply? So that we don't have "charger enable"/"charger disable" knobs in
the psy class itself. It is still fine if you need to have some interface
to the psy class so that the chargers subsystem would interface with it,
though. But I think that charger drivers have to register itself with two
subsystems: chargers and power_supply (optionally).

Thanks,

Anton

> Signed-off-by: Jenny TC <jenny.tc@intel.com>
> 
> Change-Id: Id91dbbd8f34499afa97b7d8f11ecf5467847f6a8
> ---
>  Documentation/power/power_supply_class.txt |   16 ++++++++++++++++
>  drivers/power/power_supply_sysfs.c         |    8 ++++++++
>  include/linux/power_supply.h               |    8 ++++++++
>  3 files changed, 32 insertions(+)
> 
> diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt
> index 3f10b39..5a5e7fa 100644
> --- a/Documentation/power/power_supply_class.txt
> +++ b/Documentation/power/power_supply_class.txt
> @@ -118,6 +118,10 @@ relative, time-based measurements.
>  CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger.
>  CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by the
>  power supply object.
> +INPUT_CURRENT_LIMIT - input current limit programmed by charger. Indicates
> +the current drawn from a charging source.
> +CHARGE_TERM_CUR - Charge termination current used to detect the end of charge
> +condition
>  
>  CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
>  CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the
> @@ -140,12 +144,24 @@ TEMP_ALERT_MAX - maximum battery temperature alert value in milli centigrade.
>  TEMP_AMBIENT - ambient temperature.
>  TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert value in milli centigrade.
>  TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert value in milli centigrade.
> +MIN_TEMP - minimum operatable temperature
> +MAX_TEMP - maximum operatable temperature

TEMP_MAX, TEMP_MIN. Be consistent with the rest of the properties...

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [PATCH 1/7] power_supply: Add charger control properties
  2013-10-27 23:46   ` Anton Vorontsov
@ 2013-10-28  3:36     ` Tc, Jenny
  2013-10-28  6:18       ` Anton Vorontsov
  0 siblings, 1 reply; 16+ messages in thread
From: Tc, Jenny @ 2013-10-28  3:36 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: linux-kernel, Kim, Milo, Lee Jones, Jingoo Han, Chanwoo Choi,
	Sachin Kamat, Rupesh Kumar, Lars-Peter Clausen, Pali Rohár,
	Mark Brown, Rhyland Klein

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4443 bytes --]

Anton,


 
> But do we really want to control the chargers through the power_supply's user-visible
> interface? It makes the whole power supply thing so complicated that I'm already losing
> track of it. Right now I think I would prefer to move all the charger logic out of the psy
> class.
>

I think exposing properties make the logic generic, otherwise it may end up in having callback
functions. Also there are some scenarios where the charging algorithm has to be in the
user space. If the driver need to remove the control interface from the user space, it can use
property_is_writeable callback. Using standard power supply properties, provide the
flexibility to interface the charging algorithms from the user space or the kernel space. 
This makes the charger driver implementation simple - it just need to register with psy class,
no extra API or callback required. 

> More specifically, this code:
> 
> > @@ -561,6 +575,11 @@ int power_supply_register(struct device *parent, struct
> power_supply *psy)
> >       if (rc)
> >               goto create_triggers_failed;
> >
> > +     if (psy_is_charger(psy))
> > +             rc = power_supply_register_charger(psy);
> > +     if (rc)
> > +             pr_debug("device: '%s': power_supply_register_charger failed\n",
> > +                             dev_name(dev));
> 
> I have a weird feeling about the fact that the power_supply_register() registers a charger.
> OK, we have thermal stuff registration there, but it is completely different. We have the
> cooling device registration there as well, and this stuff would be really nice to move out to
> some "chargers subsystem".
> 
> So, Jenny, the question is: can we separate chargers logic from the power supply? So that
> we don't have "charger enable"/"charger disable" knobs in the psy class itself. It is still fine
> if you need to have some interface to the psy class so that the chargers subsystem would
> interface with it, though. But I think that charger drivers have to register itself with two
> subsystems: chargers and power_supply (optionally).
> 

If your concern is in clubbing the charger framework related changes with psy class, 
then I have an alternate proposal. Using the patch https://lkml.org/lkml/2013/7/25/204,
the power supply change notification can be broadcasted. We can add notifier events
for power_supply_register and thermal throttling. This way power_supply_charger.c can
be a separate driver and it can listen to psy notifications to take actions.

> Thanks,
> 
> Anton
> 
> > Signed-off-by: Jenny TC <jenny.tc@intel.com>
> >
> > Change-Id: Id91dbbd8f34499afa97b7d8f11ecf5467847f6a8
> > ---
> >  Documentation/power/power_supply_class.txt |   16 ++++++++++++++++
> >  drivers/power/power_supply_sysfs.c         |    8 ++++++++
> >  include/linux/power_supply.h               |    8 ++++++++
> >  3 files changed, 32 insertions(+)
> >
> > diff --git a/Documentation/power/power_supply_class.txt
> > b/Documentation/power/power_supply_class.txt
> > index 3f10b39..5a5e7fa 100644
> > --- a/Documentation/power/power_supply_class.txt
> > +++ b/Documentation/power/power_supply_class.txt
> > @@ -118,6 +118,10 @@ relative, time-based measurements.
> >  CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger.
> >  CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by
> the
> > power supply object.
> > +INPUT_CURRENT_LIMIT - input current limit programmed by charger.
> > +Indicates the current drawn from a charging source.
> > +CHARGE_TERM_CUR - Charge termination current used to detect the end
> > +of charge condition
> >
> >  CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
> >  CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by
> the
> > @@ -140,12 +144,24 @@ TEMP_ALERT_MAX - maximum battery temperature alert
> value in milli centigrade.
> >  TEMP_AMBIENT - ambient temperature.
> >  TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert value in milli
> centigrade.
> >  TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert value in milli
> centigrade.
> > +MIN_TEMP - minimum operatable temperature MAX_TEMP - maximum
> > +operatable temperature
> 
> TEMP_MAX, TEMP_MIN. Be consistent with the rest of the properties...

Agreed. Will fix it
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 7/7] power_supply: Introduce PSE compliant algorithm
  2013-09-23 18:04 ` [PATCH 7/7] power_supply: Introduce PSE compliant algorithm Jenny TC
@ 2013-10-28  6:17   ` Anton Vorontsov
  0 siblings, 0 replies; 16+ messages in thread
From: Anton Vorontsov @ 2013-10-28  6:17 UTC (permalink / raw)
  To: Jenny TC; +Cc: linux-kernel

On Mon, Sep 23, 2013 at 11:34:05PM +0530, Jenny TC wrote:
[...]
> +#define BATTID_STR_LEN		8
> +#define BATT_TEMP_NR_RNG	6
> +/* Charging Profile */
> +struct psy_ps_pse_mod_prof {
> +	/* battery id */
> +	char batt_id[BATTID_STR_LEN];
> +	/* type of battery */
> +	u16 battery_type;
> +	u16 capacity;
> +	u16 voltage_max;
> +	/* charge termination current */
> +	u16 chrg_term_mA;
> +	/* Low battery level voltage */
> +	u16 low_batt_mV;
> +	/* upper and lower temperature limits on discharging */
> +	u8 disch_tmp_ul;
> +	u8 disch_tmp_ll;
> +	/* number of temperature monitoring ranges */
> +	u16 temp_mon_ranges;
> +	struct psy_ps_temp_chg_table temp_mon_range[BATT_TEMP_NR_RNG];
> +	/* Lowest temperature supported */
> +	short int temp_low_lim;
> +} __packed;

These all seem like properties of a battery. Why the battery is not
registered with the power_supply framework?

What is PSE, by the way?

Anton

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/7] power_supply: Add charger control properties
  2013-10-28  3:36     ` Tc, Jenny
@ 2013-10-28  6:18       ` Anton Vorontsov
  2013-10-29  4:57         ` NeilBrown
  0 siblings, 1 reply; 16+ messages in thread
From: Anton Vorontsov @ 2013-10-28  6:18 UTC (permalink / raw)
  To: Tc, Jenny
  Cc: linux-kernel, Kim, Milo, Lee Jones, Jingoo Han, Chanwoo Choi,
	Sachin Kamat, Rupesh Kumar, Lars-Peter Clausen, Pali Rohár,
	Mark Brown, Rhyland Klein

On Mon, Oct 28, 2013 at 03:36:36AM +0000, Tc, Jenny wrote:
> > But do we really want to control the chargers through the power_supply's user-visible
> > interface? It makes the whole power supply thing so complicated that I'm already losing
> > track of it. Right now I think I would prefer to move all the charger logic out of the psy
> > class.
> >
> 
> I think exposing properties make the logic generic, otherwise it may end up in having callback
> functions.
>
> Also there are some scenarios where the charging algorithm has to be in the
> user space.

Which scenarios?

Plus, I am more questioning if the power supply framework is the right
thing to control the *chargers*. Chargers are not the power supply to the
system or any device (well, except for the batteries themselves).

> Using the patch https://lkml.org/lkml/2013/7/25/204,
> the power supply change notification can be broadcasted. We can add notifier events
> for power_supply_register and thermal throttling. This way power_supply_charger.c can
> be a separate driver and it can listen to psy notifications to take actions.

If you ever need this particular notifier, I am OK with it (but I'll
consider applying it only together with some its users).

Basically, I am more against these three patches:

[PATCH 3/7] power_supply: add throttle state
[PATCH 2/7] power_supply: add charger cable properties
[PATCH 1/7] power_supply: Add charger control properties (enable_charger part)

These three add too much "charger" specifics to the power_supply stuff. I
think they deserve their own subsystem/class/whatever.

Also, the battid framework is written without any notion of device/driver
separation, uses global variables, and I suspect it should not exist at
all (psy_get_batt_prop function makes me think that you should just
register the i2c/spi/w1 battery with the power_supply and not use the
ad-hoc stuff).

Anton

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/7] power_supply: Add charger control properties
  2013-10-28  6:18       ` Anton Vorontsov
@ 2013-10-29  4:57         ` NeilBrown
  0 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2013-10-29  4:57 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: Tc, Jenny, linux-kernel, Kim, Milo, Lee Jones, Jingoo Han,
	Chanwoo Choi, Sachin Kamat, Rupesh Kumar, Lars-Peter Clausen,
	Pali Rohár, Mark Brown, Rhyland Klein

[-- Attachment #1: Type: text/plain, Size: 4762 bytes --]

On Sun, 27 Oct 2013 23:18:08 -0700 Anton Vorontsov <anton@enomsg.org> wrote:

> On Mon, Oct 28, 2013 at 03:36:36AM +0000, Tc, Jenny wrote:
> > > But do we really want to control the chargers through the power_supply's user-visible
> > > interface? It makes the whole power supply thing so complicated that I'm already losing
> > > track of it. Right now I think I would prefer to move all the charger logic out of the psy
> > > class.
> > >
> > 
> > I think exposing properties make the logic generic, otherwise it may end up in having callback
> > functions.
> >
> > Also there are some scenarios where the charging algorithm has to be in the
> > user space.
> 
> Which scenarios?
> 
> Plus, I am more questioning if the power supply framework is the right
> thing to control the *chargers*. Chargers are not the power supply to the
> system or any device (well, except for the batteries themselves).

I'm not sure this is (always) true.
On my device (gta04.org) the battery, the USB OTG port, and a separate 5VDC
input can each be the power source of the whole device.
The USB and 5VDC cannot both be active concurrently, but either can be active
together with the battery.

The device can function without the battery, so the charger plugged into the
USB-OTG must be supplying power to the system (not just the battery).

The "charger" functionality sits between the battery and the external power
supply monitoring the voltage on the battery and the current from the
external supply.  Based on these values (and some timers and a state machine)
it enabled or disables the external supply and possibly imposes a
current-limit on it.

The three power sources all have "power_supply" devices registered (though
the battery only does because it contains a bq27000 charger counter).
I've been wondering where to put sysfs attributes to control the charging.
I currently place them in the power_supply device for each external power
source.
That makes some sense for the 'current limit' value, but not for the
'battery volts at which to re-start charging' value.
There is also a setting which affects  whether the external source is
switched off if the voltage drops below 4.4V.  In some circumstances I want
to leave the charger enabled then, as it could just mean the cyclist is
taking a break and there should be current again soon.

I think the sensible place for these tune-ables is with the battery.  i.e. the
power_supply that corresponds to the battery could register "min voltage" and
"min current".
The charger driver needs to know about this battery and about any power
sources that can charge it, and uses the state of the battery to decide how
to tune the state of the charger.

I note that there is already something a lot like this between 
   88pm860x_battery.c
and
   88pm860x_charger.c

They manage to locate each other and the charger call get_property and
set_property on the battery.

Maybe formalising this might be a useful way forward.

I'm not sure that we really need a new driver-class for chargers.  Maybe just
a way to link external power supplies to battery power supplies, and maybe
some agreement on what they are allowed to say to each other.

Jenny: would something like that work for you??

Thanks,
NeilBrown



> 
> > Using the patch https://lkml.org/lkml/2013/7/25/204,
> > the power supply change notification can be broadcasted. We can add notifier events
> > for power_supply_register and thermal throttling. This way power_supply_charger.c can
> > be a separate driver and it can listen to psy notifications to take actions.
> 
> If you ever need this particular notifier, I am OK with it (but I'll
> consider applying it only together with some its users).
> 
> Basically, I am more against these three patches:
> 
> [PATCH 3/7] power_supply: add throttle state
> [PATCH 2/7] power_supply: add charger cable properties
> [PATCH 1/7] power_supply: Add charger control properties (enable_charger part)
> 
> These three add too much "charger" specifics to the power_supply stuff. I
> think they deserve their own subsystem/class/whatever.
> 
> Also, the battid framework is written without any notion of device/driver
> separation, uses global variables, and I suspect it should not exist at
> all (psy_get_batt_prop function makes me think that you should just
> register the i2c/spi/w1 battery with the power_supply and not use the
> ad-hoc stuff).
> 
> Anton
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [PATCH 1/7] power_supply: Add charger control properties
  2013-11-01  5:18 [PATCH 1/7] power_supply: Add charger control properties Tc, Jenny
@ 2013-11-27 17:52 ` Tc, Jenny
  0 siblings, 0 replies; 16+ messages in thread
From: Tc, Jenny @ 2013-11-27 17:52 UTC (permalink / raw)
  To: 'NeilBrown', 'Anton Vorontsov'
  Cc: 'linux-kernel@vger.kernel.org', 'Kim, Milo',
	'Lee Jones', 'Jingoo Han', 'Chanwoo Choi',
	'Sachin Kamat', 'Rupesh Kumar',
	'Lars-Peter Clausen', 'Pali Rohár',
	'Mark Brown', 'Rhyland Klein'

Anton,

Does this address your concerns? 

-Jenny



> Subject: RE: [PATCH 1/7] power_supply: Add charger control properties
> 
> > Subject: Re: [PATCH 1/7] power_supply: Add charger control properties
> >
> > On Sun, 27 Oct 2013 23:18:08 -0700 Anton Vorontsov <anton@enomsg.org> wrote:
> >
> > > On Mon, Oct 28, 2013 at 03:36:36AM +0000, Tc, Jenny wrote:
> > > > > But do we really want to control the chargers through the
> > > > > power_supply's user-visible interface? It makes the whole power
> > > > > supply thing so complicated that I'm already losing track of it.
> > > > > Right now I think I would prefer to move all the charger logic out of the psy class.
> > > > >
> > > >
> > > > I think exposing properties make the logic generic, otherwise it
> > > > may end up in having callback functions.
> > > >
> > > > Also there are some scenarios where the charging algorithm has to
> > > > be in the user space.
> > >
> > > Which scenarios?
> 
> Charger may be of two different path. 1) Single path 2) Dual path
> 
> With a single path charger, the charger will be having only one output path. This path
> supplies power to battery(IBAT) and to system (ISYS). With dual path chargers, charger
> will be having two separate output paths -to battery and to system .
> 
> With single path chargers, consider the scenario when system is idle and the maximum
> Allowed charge current is 1A. So the charger output can be set to 1A so that battery can
> charge with 1A. But with a varying load, this may not be good. If the platform consumes
> 500mA, then the charging current would be reduced to 500mA. But increasing the output
> to 1.5A may result in high charge current if the load is reduced.
> 
> Identifying different use case and their power profile helps to handle this scenario.
> This can be better handled by some algorithm in user space which can monitor the running
> applications and derive average platform load. The algorithm can proactively decide the
> charge current based on the power and thermal characteristics of different use case.
> 
> So in this scenario, there is a need to modify the charging parameters from the user space.
> 
> 
> > >
> > > Plus, I am more questioning if the power supply framework is the
> > > right thing to control the *chargers*. Chargers are not the power
> > > supply to the system or any device (well, except for the batteries themselves).
> >
> > I'm not sure this is (always) true.
> > On my device (gta04.org) the battery, the USB OTG port, and a separate
> > 5VDC input can each be the power source of the whole device.
> > The USB and 5VDC cannot both be active concurrently, but either can be
> > active together with the battery.
> >
> > The device can function without the battery, so the charger plugged
> > into the USB-OTG must be supplying power to the system (not just the battery).
> >
> > The "charger" functionality sits between the battery and the external
> > power supply monitoring the voltage on the battery and the current
> > from the external supply.  Based on these values (and some timers and
> > a state machine) it enabled or disables the external supply and possibly imposes a
> current-limit on it.
> >
> > The three power sources all have "power_supply" devices registered
> > (though the battery only does because it contains a bq27000 charger counter).
> > I've been wondering where to put sysfs attributes to control the charging.
> > I currently place them in the power_supply device for each external power source.
> > That makes some sense for the 'current limit' value, but not for the
> > 'battery volts at which to re-start charging' value.
> > There is also a setting which affects  whether the external source is
> > switched off if the voltage drops below 4.4V.  In some circumstances I
> > want to leave the charger enabled then, as it could just mean the cyclist is taking a break
> and there should be current again soon.
> >
> > I think the sensible place for these tune-ables is with the battery.
> > i.e. the power_supply that corresponds to the battery could register "min voltage" and
> "min current".
> > The charger driver needs to know about this battery and about any
> > power sources that can charge it, and uses the state of the battery to decide how to tune
> the state of the charger.
> >
> > I note that there is already something a lot like this between
> >    88pm860x_battery.c
> > and
> >    88pm860x_charger.c
> >
> > They manage to locate each other and the charger call get_property and
> > set_property on the battery.
> >
> > Maybe formalising this might be a useful way forward.
> >
> > I'm not sure that we really need a new driver-class for chargers.
> > Maybe just a way to link external power supplies to battery power
> > supplies, and maybe some agreement on what they are allowed to say to each other.
> >
> > Jenny: would something like that work for you??
> 
> The idea of charging framework is to connect different components to setup and monitor
> charging. This includes battery identification protocols, battery driver, charger driver,
> platform thermal profile for charging, different cables (USB/AC/Wireless/MHL etc),
> different charging algorithms (PSE compliant/ruler based/pulse charging etc).
> This makes the charger driver simple. It can just act as a h/w abstraction layer and doesn't
> need to be aware of the cable types/properties/thermal/battery characteristics. All logic
> resides in the framework layer.
> 
> The proposal separates the battery characteristics (different from runtime battery
> properties) from the charger/battery driver. The battery characteristics can be read based on
> the type of battery identification interface - Analog (BSI) or digital. In case of Analog
> interface, a BSI resistance is used to identify the battery. Based on the BSI resistance
> battery charging profile and characteristics can be loaded.
> 
> In case of digital battery profile, a one wire protocol is used to read the battery properties
> from an EEPROM inside the Battery pack. In some  platforms to reduce the battery pack
> cost, the EEPROM may be on the board and may be connected using I2C lines.
> 
> Separating out this logic from battery driver makes it more modular.  So the proposal uses
> a battery identification layer to read the battery profile. So the charger and battery drivers
> (fuel gauge drivers) can read the profile from the battery identification layer and configure
> the h/w register settings appropriately.
> 
> So the tunable attributes resides in the battery identification layer and the drivers reads
> them from this layer.
> 
> I uploaded a modified version of the Charging Framework ELCE presentation at
> https://drive.google.com/file/d/0B3urTgiXiZF6eGt4MkVZaXNlNlE/edit?usp=sharing
> Hope this would give more idea about the proposal.
> 
> >
> >
> >
> > >
> > > > Using the patch https://lkml.org/lkml/2013/7/25/204,
> > > > the power supply change notification can be broadcasted. We can
> > > > add notifier events for power_supply_register and thermal throttling.
> > > > This way power_supply_charger.c can be a separate driver and it
> > > > can listen to psy
> > notifications to take actions.
> > >
> > > If you ever need this particular notifier, I am OK with it (but I'll
> > > consider applying it only together with some its users).
> > >
> > > Basically, I am more against these three patches:
> > >
> > > [PATCH 3/7] power_supply: add throttle state [PATCH 2/7] power_supply:
> > > add charger cable properties [PATCH 1/7] power_supply: Add charger
> > > control properties (enable_charger part)
> 
> [PATCH 3/7] power_supply: add throttle state and [PATCH 2/7] power_supply: add
> charger cable properties can be reworked I can move them out of power_supply.h to a new
> file include/linux/power/power_supply_charger.h
> 
> But I think the control properties exposed in patch " [PATCH 1/7] power_supply: Add
> charger control properties" qualifies to be part of power_supply.h
> 
> INPUT_CURRENT_LIMIT - Controls the output from external supply.
> CHARGE_TERM_CUR - Decides when to stop supply to battery. When supply to battery
> is stopped, battery starts supplying power to platform.
> 
> MIN_TEMP - minimum temperature for a power supply MAX_TEMP - maximum
> temperature for a power supply ENABLE_CHARGING - enable/disable charging.
> Enable/disable supply to battery.
> ENABLE_CHARGER - enable/disable charger. Enable/disable supply to system and
> battery.
> CABLE_TYPE - type of a cable, helps to identify the cable type PRIORITY - priority for
> charging if multiple charger drivers are present.
> 
> All attributes control the external power supply or the battery. The term charger may get
> confused as "charger IC". Do you have better suggestions?
> 
> > >
> > > These three add too much "charger" specifics to the power_supply
> > > stuff. I think they deserve their own subsystem/class/whatever.
> > >
> > > Also, the battid framework is written without any notion of
> > > device/driver separation, uses global variables, and I suspect it
> > > should not exist at all (psy_get_batt_prop function makes me think
> > > that you should just register the i2c/spi/w1 battery with the
> > > power_supply and not use the ad-hoc stuff).
> 
> These drivers are not power supply. They just reads the static battery profile and exposes
> to the consumers. Hope previous explanation on this would be helpful
> 
> > >
> > > Anton
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe
> > > linux-kernel" in the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > Please read the FAQ at  http://www.tux.org/lkml/


^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [PATCH 1/7] power_supply: Add charger control properties
@ 2013-11-01  5:18 Tc, Jenny
  2013-11-27 17:52 ` Tc, Jenny
  0 siblings, 1 reply; 16+ messages in thread
From: Tc, Jenny @ 2013-11-01  5:18 UTC (permalink / raw)
  To: NeilBrown, Anton Vorontsov
  Cc: linux-kernel, Kim, Milo, Lee Jones, Jingoo Han, Chanwoo Choi,
	Sachin Kamat, Rupesh Kumar, Lars-Peter Clausen, Pali Rohár,
	Mark Brown, Rhyland Klein

> Subject: Re: [PATCH 1/7] power_supply: Add charger control properties
> 
> On Sun, 27 Oct 2013 23:18:08 -0700 Anton Vorontsov <anton@enomsg.org> wrote:
> 
> > On Mon, Oct 28, 2013 at 03:36:36AM +0000, Tc, Jenny wrote:
> > > > But do we really want to control the chargers through the
> > > > power_supply's user-visible interface? It makes the whole power
> > > > supply thing so complicated that I'm already losing track of it.
> > > > Right now I think I would prefer to move all the charger logic out of the psy class.
> > > >
> > >
> > > I think exposing properties make the logic generic, otherwise it may
> > > end up in having callback functions.
> > >
> > > Also there are some scenarios where the charging algorithm has to be
> > > in the user space.
> >
> > Which scenarios?

Charger may be of two different path. 1) Single path 2) Dual path

With a single path charger, the charger will be having only one output
path. This path supplies power to battery(IBAT) and to system (ISYS). With dual path
chargers, charger will be having two separate output paths -to battery and to system .

With single path chargers, consider the scenario when system is idle and the maximum
Allowed charge current is 1A. So the charger output can be set to 1A so that battery can
charge with 1A. But with a varying load, this may not be good. If the platform consumes
500mA, then the charging current would be reduced to 500mA. But increasing the output
to 1.5A may result in high charge current if the load is reduced. 

Identifying different use case and their power profile helps to handle this scenario.
This can be better handled by some algorithm in user space which can monitor the
running applications and derive average platform load. The algorithm can proactively
decide the charge current based on the power and thermal characteristics of different
use case. 

So in this scenario, there is a need to modify the charging parameters from the user space.


> >
> > Plus, I am more questioning if the power supply framework is the right
> > thing to control the *chargers*. Chargers are not the power supply to
> > the system or any device (well, except for the batteries themselves).
> 
> I'm not sure this is (always) true.
> On my device (gta04.org) the battery, the USB OTG port, and a separate 5VDC input can
> each be the power source of the whole device.
> The USB and 5VDC cannot both be active concurrently, but either can be active together
> with the battery.
> 
> The device can function without the battery, so the charger plugged into the USB-OTG
> must be supplying power to the system (not just the battery).
> 
> The "charger" functionality sits between the battery and the external power supply
> monitoring the voltage on the battery and the current from the external supply.  Based on
> these values (and some timers and a state machine) it enabled or disables the external
> supply and possibly imposes a current-limit on it.
> 
> The three power sources all have "power_supply" devices registered (though the battery
> only does because it contains a bq27000 charger counter).
> I've been wondering where to put sysfs attributes to control the charging.
> I currently place them in the power_supply device for each external power source.
> That makes some sense for the 'current limit' value, but not for the 'battery volts at which
> to re-start charging' value.
> There is also a setting which affects  whether the external source is switched off if the
> voltage drops below 4.4V.  In some circumstances I want to leave the charger enabled then,
> as it could just mean the cyclist is taking a break and there should be current again soon.
> 
> I think the sensible place for these tune-ables is with the battery.  i.e. the power_supply
> that corresponds to the battery could register "min voltage" and "min current".
> The charger driver needs to know about this battery and about any power sources that can
> charge it, and uses the state of the battery to decide how to tune the state of the charger.
> 
> I note that there is already something a lot like this between
>    88pm860x_battery.c
> and
>    88pm860x_charger.c
> 
> They manage to locate each other and the charger call get_property and set_property on the
> battery.
> 
> Maybe formalising this might be a useful way forward.
> 
> I'm not sure that we really need a new driver-class for chargers.  Maybe just a way to link
> external power supplies to battery power supplies, and maybe some agreement on what
> they are allowed to say to each other.
> 
> Jenny: would something like that work for you??

The idea of charging framework is to connect different components to setup and monitor
charging. This includes battery identification protocols, battery driver, charger driver,
platform thermal profile for charging, different cables (USB/AC/Wireless/MHL etc),
different charging algorithms (PSE compliant/ruler based/pulse charging etc).
This makes the charger driver simple. It can just act as a h/w abstraction layer
and doesn't need to be aware of the cable types/properties/thermal/battery
characteristics. All logic resides in the framework layer. 

The proposal separates the battery characteristics (different from runtime battery
properties) from the charger/battery driver. The battery characteristics can be
read based on the type of battery identification interface - Analog (BSI)
or digital. In case of Analog interface, a BSI resistance is used to identify the
battery. Based on the BSI resistance battery charging profile and characteristics
can be loaded. 

In case of digital battery profile, a one wire protocol is used to read the battery
properties from an EEPROM inside the Battery pack. In some  platforms to
reduce the battery pack cost, the EEPROM may be on the board and may be
connected using I2C lines.

Separating out this logic from battery driver makes it more modular.  So the
proposal uses a battery identification layer to read the battery profile. So the
charger and battery drivers (fuel gauge drivers) can read the profile from
the battery identification layer and configure the h/w register settings
appropriately. 

So the tunable attributes resides in the battery identification layer and the
drivers reads them from this layer. 

I uploaded a modified version of the Charging Framework ELCE presentation at
https://drive.google.com/file/d/0B3urTgiXiZF6eGt4MkVZaXNlNlE/edit?usp=sharing
Hope this would give more idea about the proposal.

> 
> 
> 
> >
> > > Using the patch https://lkml.org/lkml/2013/7/25/204,
> > > the power supply change notification can be broadcasted. We can add
> > > notifier events for power_supply_register and thermal throttling.
> > > This way power_supply_charger.c can be a separate driver and it can listen to psy
> notifications to take actions.
> >
> > If you ever need this particular notifier, I am OK with it (but I'll
> > consider applying it only together with some its users).
> >
> > Basically, I am more against these three patches:
> >
> > [PATCH 3/7] power_supply: add throttle state [PATCH 2/7] power_supply:
> > add charger cable properties [PATCH 1/7] power_supply: Add charger
> > control properties (enable_charger part)

[PATCH 3/7] power_supply: add throttle state and 
[PATCH 2/7] power_supply: add charger cable properties can be reworked
I can move them out of power_supply.h to a new file
include/linux/power/power_supply_charger.h

But I think the control properties exposed in patch 
" [PATCH 1/7] power_supply: Add charger control properties" qualifies
to be part of power_supply.h

INPUT_CURRENT_LIMIT - Controls the output from external supply.
CHARGE_TERM_CUR - Decides when to stop supply to battery. When supply
to battery is stopped, battery starts supplying power to platform. 

MIN_TEMP - minimum temperature for a power supply
MAX_TEMP - maximum temperature for a power supply
ENABLE_CHARGING - enable/disable charging. Enable/disable supply to battery.
ENABLE_CHARGER - enable/disable charger. Enable/disable supply to system and battery.
CABLE_TYPE - type of a cable, helps to identify the cable type
PRIORITY - priority for charging if multiple charger drivers are present.

All attributes control the external power supply or the battery. The term charger may get
confused as "charger IC". Do you have better suggestions?

> >
> > These three add too much "charger" specifics to the power_supply
> > stuff. I think they deserve their own subsystem/class/whatever.
> >
> > Also, the battid framework is written without any notion of
> > device/driver separation, uses global variables, and I suspect it
> > should not exist at all (psy_get_batt_prop function makes me think
> > that you should just register the i2c/spi/w1 battery with the
> > power_supply and not use the ad-hoc stuff).

These drivers are not power supply. They just reads the static battery profile and
exposes to the consumers. Hope previous explanation on this would be helpful

> >
> > Anton
> > --
> > To unsubscribe from this list: send the line "unsubscribe
> > linux-kernel" in the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-11-27 17:53 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-23 18:03 [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Jenny TC
2013-09-23 18:03 ` [PATCH 1/7] power_supply: Add charger control properties Jenny TC
2013-10-27 23:46   ` Anton Vorontsov
2013-10-28  3:36     ` Tc, Jenny
2013-10-28  6:18       ` Anton Vorontsov
2013-10-29  4:57         ` NeilBrown
2013-09-23 18:04 ` [PATCH 2/7] power_supply : add charger cable properties Jenny TC
2013-09-23 18:04 ` [PATCH 3/7] power_supply: add throttle state Jenny TC
2013-09-23 18:04 ` [PATCH 4/7] power_supply: Add power_supply notifier Jenny TC
2013-09-23 18:04 ` [PATCH 5/7] power_supply : Introduce battery identification framework Jenny TC
2013-09-23 18:04 ` [PATCH 6/7] power_supply: Introduce Power Supply charging framework Jenny TC
2013-09-23 18:04 ` [PATCH 7/7] power_supply: Introduce PSE compliant algorithm Jenny TC
2013-10-28  6:17   ` Anton Vorontsov
2013-10-25 16:49 ` [PATCH 0/7] power_supply: Introduce Power Supply Charging Framework Tc, Jenny
2013-11-01  5:18 [PATCH 1/7] power_supply: Add charger control properties Tc, Jenny
2013-11-27 17:52 ` Tc, Jenny

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.