charger-manager: Use EXTCON Subsystem to detect charger cables for charging
This patch support that charger-manager use EXTCON(External Connector) Subsystem to detect the state of charger cables for enabling or disabling charger(regulator) and select the charger cable for charging among a number of external cable according to policy of H/W board. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
This commit is contained in:
Родитель
85a392d47c
Коммит
bee737bccb
|
@ -271,16 +271,13 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
|
|||
if (enable) {
|
||||
if (cm->emergency_stop)
|
||||
return -EAGAIN;
|
||||
err = regulator_bulk_enable(desc->num_charger_regulators,
|
||||
desc->charger_regulators);
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++)
|
||||
regulator_enable(desc->charger_regulators[i].consumer);
|
||||
} else {
|
||||
/*
|
||||
* Abnormal battery state - Stop charging forcibly,
|
||||
* even if charger was enabled at the other places
|
||||
*/
|
||||
err = regulator_bulk_disable(desc->num_charger_regulators,
|
||||
desc->charger_regulators);
|
||||
|
||||
for (i = 0; i < desc->num_charger_regulators; i++) {
|
||||
if (regulator_is_enabled(
|
||||
desc->charger_regulators[i].consumer)) {
|
||||
|
@ -288,7 +285,7 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
|
|||
desc->charger_regulators[i].consumer);
|
||||
dev_warn(cm->dev,
|
||||
"Disable regulator(%s) forcibly.\n",
|
||||
desc->charger_regulators[i].supply);
|
||||
desc->charger_regulators[i].regulator_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -994,11 +991,77 @@ int setup_charger_manager(struct charger_global_desc *gd)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(setup_charger_manager);
|
||||
|
||||
/**
|
||||
* charger_extcon_work - enable/diable charger according to the state
|
||||
* of charger cable
|
||||
*
|
||||
* @work: work_struct of the function charger_extcon_work.
|
||||
*/
|
||||
static void charger_extcon_work(struct work_struct *work)
|
||||
{
|
||||
struct charger_cable *cable =
|
||||
container_of(work, struct charger_cable, wq);
|
||||
|
||||
try_charger_enable(cable->cm, cable->attached);
|
||||
}
|
||||
|
||||
/**
|
||||
* charger_extcon_notifier - receive the state of charger cable
|
||||
* when registered cable is attached or detached.
|
||||
*
|
||||
* @self: the notifier block of the charger_extcon_notifier.
|
||||
* @event: the cable state.
|
||||
* @ptr: the data pointer of notifier block.
|
||||
*/
|
||||
static int charger_extcon_notifier(struct notifier_block *self,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct charger_cable *cable =
|
||||
container_of(self, struct charger_cable, nb);
|
||||
|
||||
cable->attached = event;
|
||||
schedule_work(&cable->wq);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* charger_extcon_init - register external connector to use it
|
||||
* as the charger cable
|
||||
*
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
* @cable: the Charger cable representing the external connector.
|
||||
*/
|
||||
static int charger_extcon_init(struct charger_manager *cm,
|
||||
struct charger_cable *cable)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Charger manager use Extcon framework to identify
|
||||
* the charger cable among various external connector
|
||||
* cable (e.g., TA, USB, MHL, Dock).
|
||||
*/
|
||||
INIT_WORK(&cable->wq, charger_extcon_work);
|
||||
cable->nb.notifier_call = charger_extcon_notifier;
|
||||
ret = extcon_register_interest(&cable->extcon_dev,
|
||||
cable->extcon_name, cable->name, &cable->nb);
|
||||
if (ret < 0) {
|
||||
pr_info("Cannot register extcon_dev for %s(cable: %s).\n",
|
||||
cable->extcon_name,
|
||||
cable->name);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int charger_manager_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct charger_desc *desc = dev_get_platdata(&pdev->dev);
|
||||
struct charger_manager *cm;
|
||||
int ret = 0, i = 0;
|
||||
int j = 0;
|
||||
union power_supply_propval val;
|
||||
|
||||
if (g_desc && !rtc_dev && g_desc->rtc_name) {
|
||||
|
@ -1167,11 +1230,31 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
goto err_register;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators,
|
||||
desc->charger_regulators);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot get charger regulators.\n");
|
||||
goto err_bulk_get;
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
|
||||
struct charger_regulator *charger
|
||||
= &desc->charger_regulators[i];
|
||||
|
||||
charger->consumer = regulator_get(&pdev->dev,
|
||||
charger->regulator_name);
|
||||
if (charger->consumer == NULL) {
|
||||
dev_err(&pdev->dev, "Cannot find charger(%s)n",
|
||||
charger->regulator_name);
|
||||
ret = -EINVAL;
|
||||
goto err_chg_get;
|
||||
}
|
||||
|
||||
for (j = 0 ; j < charger->num_cables ; j++) {
|
||||
struct charger_cable *cable = &charger->cables[j];
|
||||
|
||||
ret = charger_extcon_init(cm, cable);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot find charger(%s)n",
|
||||
charger->regulator_name);
|
||||
goto err_extcon;
|
||||
}
|
||||
cable->charger = charger;
|
||||
cable->cm = cm;
|
||||
}
|
||||
}
|
||||
|
||||
ret = try_charger_enable(cm, true);
|
||||
|
@ -1197,9 +1280,19 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_chg_enable:
|
||||
regulator_bulk_free(desc->num_charger_regulators,
|
||||
desc->charger_regulators);
|
||||
err_bulk_get:
|
||||
err_extcon:
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
|
||||
struct charger_regulator *charger
|
||||
= &desc->charger_regulators[i];
|
||||
for (j = 0 ; j < charger->num_cables ; j++) {
|
||||
struct charger_cable *cable = &charger->cables[j];
|
||||
extcon_unregister_interest(&cable->extcon_dev);
|
||||
}
|
||||
}
|
||||
err_chg_get:
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++)
|
||||
regulator_put(desc->charger_regulators[i].consumer);
|
||||
|
||||
power_supply_unregister(&cm->charger_psy);
|
||||
err_register:
|
||||
kfree(cm->charger_psy.properties);
|
||||
|
@ -1218,6 +1311,8 @@ static int __devexit charger_manager_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct charger_manager *cm = platform_get_drvdata(pdev);
|
||||
struct charger_desc *desc = cm->desc;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
/* Remove from the list */
|
||||
mutex_lock(&cm_list_mtx);
|
||||
|
@ -1229,8 +1324,18 @@ static int __devexit charger_manager_remove(struct platform_device *pdev)
|
|||
if (delayed_work_pending(&cm_monitor_work))
|
||||
cancel_delayed_work_sync(&cm_monitor_work);
|
||||
|
||||
regulator_bulk_free(desc->num_charger_regulators,
|
||||
desc->charger_regulators);
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
|
||||
struct charger_regulator *charger
|
||||
= &desc->charger_regulators[i];
|
||||
for (j = 0 ; j < charger->num_cables ; j++) {
|
||||
struct charger_cable *cable = &charger->cables[j];
|
||||
extcon_unregister_interest(&cable->extcon_dev);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0 ; i < desc->num_charger_regulators ; i++)
|
||||
regulator_put(desc->charger_regulators[i].consumer);
|
||||
|
||||
power_supply_unregister(&cm->charger_psy);
|
||||
|
||||
try_charger_enable(cm, false);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define _CHARGER_MANAGER_H
|
||||
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/extcon.h>
|
||||
|
||||
enum data_source {
|
||||
CM_BATTERY_PRESENT,
|
||||
|
@ -64,6 +65,62 @@ struct charger_global_desc {
|
|||
bool assume_timer_stops_in_suspend;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct charger_cable
|
||||
* @extcon_name: the name of extcon device.
|
||||
* @name: the name of charger cable(external connector).
|
||||
* @extcon_dev: the extcon device.
|
||||
* @wq: the workqueue to control charger according to the state of
|
||||
* charger cable. If charger cable is attached, enable charger.
|
||||
* But if charger cable is detached, disable charger.
|
||||
* @nb: the notifier block to receive changed state from EXTCON
|
||||
* (External Connector) when charger cable is attached/detached.
|
||||
* @attached: the state of charger cable.
|
||||
* true: the charger cable is attached
|
||||
* false: the charger cable is detached
|
||||
* @charger: the instance of struct charger_regulator.
|
||||
* @cm: the Charger Manager representing the battery.
|
||||
*/
|
||||
struct charger_cable {
|
||||
const char *extcon_name;
|
||||
const char *name;
|
||||
|
||||
/* The charger-manager use Exton framework*/
|
||||
struct extcon_specific_cable_nb extcon_dev;
|
||||
struct work_struct wq;
|
||||
struct notifier_block nb;
|
||||
|
||||
/* The state of charger cable */
|
||||
bool attached;
|
||||
|
||||
struct charger_regulator *charger;
|
||||
struct charger_manager *cm;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct charger_regulator
|
||||
* @regulator_name: the name of regulator for using charger.
|
||||
* @consumer: the regulator consumer for the charger.
|
||||
* @cables:
|
||||
* the array of charger cables to enable/disable charger
|
||||
* and set current limit according to constratint data of
|
||||
* struct charger_cable if only charger cable included
|
||||
* in the array of charger cables is attached/detached.
|
||||
* @num_cables: the number of charger cables.
|
||||
*/
|
||||
struct charger_regulator {
|
||||
/* The name of regulator for charging */
|
||||
const char *regulator_name;
|
||||
struct regulator *consumer;
|
||||
|
||||
/*
|
||||
* Store constraint information related to current limit,
|
||||
* each cable have different condition for charging.
|
||||
*/
|
||||
struct charger_cable *cables;
|
||||
int num_cables;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct charger_desc
|
||||
* @psy_name: the name of power-supply-class for charger manager
|
||||
|
@ -109,7 +166,7 @@ struct charger_desc {
|
|||
char **psy_charger_stat;
|
||||
|
||||
int num_charger_regulators;
|
||||
struct regulator_bulk_data *charger_regulators;
|
||||
struct charger_regulator *charger_regulators;
|
||||
|
||||
char *psy_fuel_gauge;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче