Commit 32260308 authored by Pali Rohár's avatar Pali Rohár Committed by Anton Vorontsov

bq2415x_charger: Use power_supply notifier for automode

This patch removing set_mode_hook function from board data and replacing
it with new string variable of notifier power supply device. After this
change it is possible to add DT support because driver does not need
specific board function anymore. Only static data and name of power supply
device is required.
Signed-off-by: default avatarPali Rohár <pali.rohar@gmail.com>
Reviewed-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAnton Vorontsov <anton@enomsg.org>
parent 56fb8de5
/* /*
* bq2415x charger driver * bq2415x charger driver
* *
* Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com> * Copyright (C) 2011-2013 Pali Rohár <pali.rohar@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -170,6 +170,7 @@ struct bq2415x_device { ...@@ -170,6 +170,7 @@ struct bq2415x_device {
struct bq2415x_platform_data init_data; struct bq2415x_platform_data init_data;
struct power_supply charger; struct power_supply charger;
struct delayed_work work; struct delayed_work work;
struct notifier_block nb;
enum bq2415x_mode reported_mode;/* mode reported by hook function */ enum bq2415x_mode reported_mode;/* mode reported by hook function */
enum bq2415x_mode mode; /* current configured mode */ enum bq2415x_mode mode; /* current configured mode */
enum bq2415x_chip chip; enum bq2415x_chip chip;
...@@ -795,24 +796,53 @@ static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode) ...@@ -795,24 +796,53 @@ static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode)
} }
/* hook function called by other driver which set reported mode */ static int bq2415x_notifier_call(struct notifier_block *nb,
static void bq2415x_hook_function(enum bq2415x_mode mode, void *data) unsigned long val, void *v)
{ {
struct bq2415x_device *bq = data; struct bq2415x_device *bq =
container_of(nb, struct bq2415x_device, nb);
struct power_supply *psy = v;
enum bq2415x_mode mode;
union power_supply_propval prop;
int ret;
int mA;
if (!bq) if (val != PSY_EVENT_PROP_CHANGED)
return; return NOTIFY_OK;
if (strcmp(psy->name, bq->init_data.notify_device) != 0)
return NOTIFY_OK;
dev_dbg(bq->dev, "notifier call was called\n");
ret = psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
if (ret != 0)
return NOTIFY_OK;
mA = prop.intval;
if (mA == 0)
mode = BQ2415X_MODE_OFF;
else if (mA < 500)
mode = BQ2415X_MODE_NONE;
else if (mA < 1800)
mode = BQ2415X_MODE_HOST_CHARGER;
else
mode = BQ2415X_MODE_DEDICATED_CHARGER;
if (bq->reported_mode == mode)
return NOTIFY_OK;
dev_dbg(bq->dev, "hook function was called\n");
bq->reported_mode = mode; bq->reported_mode = mode;
/* if automode is not enabled do not tell about reported_mode */ /* if automode is not enabled do not tell about reported_mode */
if (bq->automode < 1) if (bq->automode < 1)
return; return NOTIFY_OK;
sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode"); sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode");
bq2415x_set_mode(bq, bq->reported_mode); bq2415x_set_mode(bq, bq->reported_mode);
return NOTIFY_OK;
} }
/**** timer functions ****/ /**** timer functions ****/
...@@ -1512,6 +1542,7 @@ static int bq2415x_probe(struct i2c_client *client, ...@@ -1512,6 +1542,7 @@ static int bq2415x_probe(struct i2c_client *client,
int num; int num;
char *name; char *name;
struct bq2415x_device *bq; struct bq2415x_device *bq;
struct power_supply *psy;
if (!client->dev.platform_data) { if (!client->dev.platform_data) {
dev_err(&client->dev, "platform data not set\n"); dev_err(&client->dev, "platform data not set\n");
...@@ -1573,16 +1604,27 @@ static int bq2415x_probe(struct i2c_client *client, ...@@ -1573,16 +1604,27 @@ static int bq2415x_probe(struct i2c_client *client,
goto error_4; goto error_4;
} }
if (bq->init_data.set_mode_hook) { if (bq->init_data.notify_device) {
if (bq->init_data.set_mode_hook( bq->nb.notifier_call = bq2415x_notifier_call;
bq2415x_hook_function, bq)) { ret = power_supply_reg_notifier(&bq->nb);
bq->automode = 1; if (ret) {
dev_err(bq->dev, "failed to reg notifier: %d\n", ret);
goto error_5;
}
psy = power_supply_get_by_name(bq->init_data.notify_device);
if (psy) {
/* Query for initial reported_mode and set it */
bq2415x_notifier_call(&bq->nb,
PSY_EVENT_PROP_CHANGED, psy);
bq2415x_set_mode(bq, bq->reported_mode); bq2415x_set_mode(bq, bq->reported_mode);
dev_info(bq->dev, "automode enabled\n");
} else { } else {
bq->automode = -1; dev_info(bq->dev, "notifier power supply device (%s) "
dev_info(bq->dev, "automode failed\n"); "for automode is not registred yet... "
"automode will not work without that device\n",
bq->init_data.notify_device);
} }
bq->automode = 1;
dev_info(bq->dev, "automode enabled\n");
} else { } else {
bq->automode = -1; bq->automode = -1;
dev_info(bq->dev, "automode not supported\n"); dev_info(bq->dev, "automode not supported\n");
...@@ -1594,6 +1636,7 @@ static int bq2415x_probe(struct i2c_client *client, ...@@ -1594,6 +1636,7 @@ static int bq2415x_probe(struct i2c_client *client,
dev_info(bq->dev, "driver registered\n"); dev_info(bq->dev, "driver registered\n");
return 0; return 0;
error_5:
error_4: error_4:
bq2415x_sysfs_exit(bq); bq2415x_sysfs_exit(bq);
error_3: error_3:
...@@ -1614,8 +1657,8 @@ static int bq2415x_remove(struct i2c_client *client) ...@@ -1614,8 +1657,8 @@ static int bq2415x_remove(struct i2c_client *client)
{ {
struct bq2415x_device *bq = i2c_get_clientdata(client); struct bq2415x_device *bq = i2c_get_clientdata(client);
if (bq->init_data.set_mode_hook) if (bq->init_data.notify_device)
bq->init_data.set_mode_hook(NULL, NULL); power_supply_unreg_notifier(&bq->nb);
bq2415x_sysfs_exit(bq); bq2415x_sysfs_exit(bq);
bq2415x_power_supply_exit(bq); bq2415x_power_supply_exit(bq);
......
/* /*
* bq2415x charger driver * bq2415x charger driver
* *
* Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com> * Copyright (C) 2011-2013 Pali Rohár <pali.rohar@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -31,46 +31,9 @@ ...@@ -31,46 +31,9 @@
* termination current. It it is less or equal to zero, configuring charge * termination current. It it is less or equal to zero, configuring charge
* and termination current will not be possible. * and termination current will not be possible.
* *
* Function set_mode_hook is needed for automode (setting correct current * For automode support is needed to provide name of power supply device
* limit when charger is connected/disconnected or setting boost mode). * in value notify_device. Device driver must immediately report property
* When is NULL, automode function is disabled. When is not NULL, it must * POWER_SUPPLY_PROP_CURRENT_MAX when current changed.
* have this prototype:
*
* int (*set_mode_hook)(
* void (*hook)(enum bq2415x_mode mode, void *data),
* void *data)
*
* hook is hook function (see below) and data is pointer to driver private
* data
*
* bq2415x driver will call it as:
*
* platform_data->set_mode_hook(bq2415x_hook_function, bq2415x_device);
*
* Board/platform function set_mode_hook return non zero value when hook
* function was successful registered. Platform code should call that hook
* function (which get from pointer, with data) every time when charger
* was connected/disconnected or require to enable boost mode. bq2415x
* driver then will set correct current limit, enable/disable charger or
* boost mode.
*
* Hook function has this prototype:
*
* void hook(enum bq2415x_mode mode, void *data);
*
* mode is bq2415x mode (charger or boost)
* data is pointer to driver private data (which get from
* set_charger_type_hook)
*
* When bq driver is being unloaded, it call function:
*
* platform_data->set_mode_hook(NULL, NULL);
*
* (hook function and driver private data are NULL)
*
* After that board/platform code must not call driver hook function! It
* is possible that pointer to hook function will not be valid and calling
* will cause undefined result.
*/ */
/* Supported modes with maximal current limit */ /* Supported modes with maximal current limit */
...@@ -89,8 +52,7 @@ struct bq2415x_platform_data { ...@@ -89,8 +52,7 @@ struct bq2415x_platform_data {
int charge_current; /* mA */ int charge_current; /* mA */
int termination_current; /* mA */ int termination_current; /* mA */
int resistor_sense; /* m ohm */ int resistor_sense; /* m ohm */
int (*set_mode_hook)(void (*hook)(enum bq2415x_mode mode, void *data), const char *notify_device; /* name */
void *data);
}; };
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment