Release 4.7 drivers/power/bq24735-charger.c
/*
* Battery charger driver for TI BQ24735
*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* 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;
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/power/bq24735-charger.h>
#define BQ24735_CHG_OPT 0x12
#define BQ24735_CHG_OPT_CHARGE_DISABLE (1 << 0)
#define BQ24735_CHG_OPT_AC_PRESENT (1 << 4)
#define BQ24735_CHARGE_CURRENT 0x14
#define BQ24735_CHARGE_CURRENT_MASK 0x1fc0
#define BQ24735_CHARGE_VOLTAGE 0x15
#define BQ24735_CHARGE_VOLTAGE_MASK 0x7ff0
#define BQ24735_INPUT_CURRENT 0x3f
#define BQ24735_INPUT_CURRENT_MASK 0x1f80
#define BQ24735_MANUFACTURER_ID 0xfe
#define BQ24735_DEVICE_ID 0xff
struct bq24735 {
struct power_supply *charger;
struct power_supply_desc charger_desc;
struct i2c_client *client;
struct bq24735_platform *pdata;
struct mutex lock;
bool charging;
};
static inline struct bq24735 *to_bq24735(struct power_supply *psy)
{
return power_supply_get_drvdata(psy);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 19 | 95.00% | 1 | 50.00% |
krzysztof kozlowski | krzysztof kozlowski | 1 | 5.00% | 1 | 50.00% |
| Total | 20 | 100.00% | 2 | 100.00% |
static enum power_supply_property bq24735_charger_properties[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
};
static int bq24735_charger_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
return 1;
default:
break;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
peter rosin | peter rosin | 32 | 100.00% | 1 | 100.00% |
| Total | 32 | 100.00% | 1 | 100.00% |
static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
u16 value)
{
return i2c_smbus_write_word_data(client, reg, le16_to_cpu(value));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 31 | 100.00% | 1 | 100.00% |
| Total | 31 | 100.00% | 1 | 100.00% |
static inline int bq24735_read_word(struct i2c_client *client, u8 reg)
{
s32 ret = i2c_smbus_read_word_data(client, reg);
return ret < 0 ? ret : le16_to_cpu(ret);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 37 | 100.00% | 1 | 100.00% |
| Total | 37 | 100.00% | 1 | 100.00% |
static int bq24735_update_word(struct i2c_client *client, u8 reg,
u16 mask, u16 value)
{
unsigned int tmp;
int ret;
ret = bq24735_read_word(client, reg);
if (ret < 0)
return ret;
tmp = ret & ~mask;
tmp |= value & mask;
return bq24735_write_word(client, reg, tmp);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 68 | 100.00% | 1 | 100.00% |
| Total | 68 | 100.00% | 1 | 100.00% |
static inline int bq24735_enable_charging(struct bq24735 *charger)
{
if (charger->pdata->ext_control)
return 0;
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
~BQ24735_CHG_OPT_CHARGE_DISABLE);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 27 | 71.05% | 1 | 50.00% |
jonathan tinkham | jonathan tinkham | 11 | 28.95% | 1 | 50.00% |
| Total | 38 | 100.00% | 2 | 100.00% |
static inline int bq24735_disable_charging(struct bq24735 *charger)
{
if (charger->pdata->ext_control)
return 0;
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
BQ24735_CHG_OPT_CHARGE_DISABLE);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 26 | 70.27% | 1 | 50.00% |
jonathan tinkham | jonathan tinkham | 11 | 29.73% | 1 | 50.00% |
| Total | 37 | 100.00% | 2 | 100.00% |
static int bq24735_config_charger(struct bq24735 *charger)
{
struct bq24735_platform *pdata = charger->pdata;
int ret;
u16 value;
if (pdata->ext_control)
return 0;
if (pdata->charge_current) {
value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
ret = bq24735_write_word(charger->client,
BQ24735_CHARGE_CURRENT, value);
if (ret < 0) {
dev_err(&charger->client->dev,
"Failed to write charger current : %d\n",
ret);
return ret;
}
}
if (pdata->charge_voltage) {
value = pdata->charge_voltage & BQ24735_CHARGE_VOLTAGE_MASK;
ret = bq24735_write_word(charger->client,
BQ24735_CHARGE_VOLTAGE, value);
if (ret < 0) {
dev_err(&charger->client->dev,
"Failed to write charger voltage : %d\n",
ret);
return ret;
}
}
if (pdata->input_current) {
value = pdata->input_current & BQ24735_INPUT_CURRENT_MASK;
ret = bq24735_write_word(charger->client,
BQ24735_INPUT_CURRENT, value);
if (ret < 0) {
dev_err(&charger->client->dev,
"Failed to write input current : %d\n",
ret);
return ret;
}
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 191 | 95.50% | 1 | 50.00% |
jonathan tinkham | jonathan tinkham | 9 | 4.50% | 1 | 50.00% |
| Total | 200 | 100.00% | 2 | 100.00% |
static bool bq24735_charger_is_present(struct bq24735 *charger)
{
struct bq24735_platform *pdata = charger->pdata;
int ret;
if (pdata->status_gpio_valid) {
ret = gpio_get_value_cansleep(pdata->status_gpio);
return ret ^= pdata->status_gpio_active_low == 0;
} else {
int ac = 0;
ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
if (ac < 0) {
dev_err(&charger->client->dev,
"Failed to read charger options : %d\n",
ac);
return false;
}
return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false;
}
return false;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 107 | 100.00% | 1 | 100.00% |
| Total | 107 | 100.00% | 1 | 100.00% |
static int bq24735_charger_is_charging(struct bq24735 *charger)
{
int ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
if (ret < 0)
return ret;
return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
peter rosin | peter rosin | 40 | 100.00% | 1 | 100.00% |
| Total | 40 | 100.00% | 1 | 100.00% |
static irqreturn_t bq24735_charger_isr(int irq, void *devid)
{
struct power_supply *psy = devid;
struct bq24735 *charger = to_bq24735(psy);
mutex_lock(&charger->lock);
if (charger->charging && bq24735_charger_is_present(charger))
bq24735_enable_charging(charger);
else
bq24735_disable_charging(charger);
mutex_unlock(&charger->lock);
power_supply_changed(psy);
return IRQ_HANDLED;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 56 | 73.68% | 1 | 50.00% |
peter rosin | peter rosin | 20 | 26.32% | 1 | 50.00% |
| Total | 76 | 100.00% | 2 | 100.00% |
static int bq24735_charger_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct bq24735 *charger = to_bq24735(psy);
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
break;
case POWER_SUPPLY_PROP_STATUS:
switch (bq24735_charger_is_charging(charger)) {
case 1:
val->intval = POWER_SUPPLY_STATUS_CHARGING;
break;
case 0:
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
default:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
}
break;
default:
return -EINVAL;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 58 | 56.86% | 1 | 33.33% |
peter rosin | peter rosin | 41 | 40.20% | 1 | 33.33% |
krzysztof kozlowski | krzysztof kozlowski | 3 | 2.94% | 1 | 33.33% |
| Total | 102 | 100.00% | 3 | 100.00% |
static int bq24735_charger_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct bq24735 *charger = to_bq24735(psy);
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
switch (val->intval) {
case POWER_SUPPLY_STATUS_CHARGING:
mutex_lock(&charger->lock);
charger->charging = true;
ret = bq24735_enable_charging(charger);
mutex_unlock(&charger->lock);
if (ret)
return ret;
bq24735_config_charger(charger);
break;
case POWER_SUPPLY_STATUS_DISCHARGING:
case POWER_SUPPLY_STATUS_NOT_CHARGING:
mutex_lock(&charger->lock);
charger->charging = false;
ret = bq24735_disable_charging(charger);
mutex_unlock(&charger->lock);
if (ret)
return ret;
break;
default:
return -EINVAL;
}
power_supply_changed(psy);
break;
default:
return -EPERM;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
peter rosin | peter rosin | 158 | 100.00% | 1 | 100.00% |
| Total | 158 | 100.00% | 1 | 100.00% |
static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
{
struct bq24735_platform *pdata;
struct device_node *np = client->dev.of_node;
u32 val;
int ret;
enum of_gpio_flags flags;
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&client->dev,
"Memory alloc for bq24735 pdata failed\n");
return NULL;
}
pdata->status_gpio = of_get_named_gpio_flags(np, "ti,ac-detect-gpios",
0, &flags);
if (flags & OF_GPIO_ACTIVE_LOW)
pdata->status_gpio_active_low = 1;
ret = of_property_read_u32(np, "ti,charge-current", &val);
if (!ret)
pdata->charge_current = val;
ret = of_property_read_u32(np, "ti,charge-voltage", &val);
if (!ret)
pdata->charge_voltage = val;
ret = of_property_read_u32(np, "ti,input-current", &val);
if (!ret)
pdata->input_current = val;
pdata->ext_control = of_property_read_bool(np, "ti,external-control");
return pdata;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 177 | 94.15% | 1 | 50.00% |
jonathan tinkham | jonathan tinkham | 11 | 5.85% | 1 | 50.00% |
| Total | 188 | 100.00% | 2 | 100.00% |
static int bq24735_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct bq24735 *charger;
struct power_supply_desc *supply_desc;
struct power_supply_config psy_cfg = {};
char *name;
charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL);
if (!charger)
return -ENOMEM;
mutex_init(&charger->lock);
charger->charging = true;
charger->pdata = client->dev.platform_data;
if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
charger->pdata = bq24735_parse_dt_data(client);
if (!charger->pdata) {
dev_err(&client->dev, "no platform data provided\n");
return -EINVAL;
}
name = (char *)charger->pdata->name;
if (!name) {
name = devm_kasprintf(&client->dev, GFP_KERNEL,
"bq24735@%s",
dev_name(&client->dev));
if (!name) {
dev_err(&client->dev, "Failed to alloc device name\n");
return -ENOMEM;
}
}
charger->client = client;
supply_desc = &charger->charger_desc;
supply_desc->name = name;
supply_desc->type = POWER_SUPPLY_TYPE_MAINS;
supply_desc->properties = bq24735_charger_properties;
supply_desc->num_properties = ARRAY_SIZE(bq24735_charger_properties);
supply_desc->get_property = bq24735_charger_get_property;
supply_desc->set_property = bq24735_charger_set_property;
supply_desc->property_is_writeable =
bq24735_charger_property_is_writeable;
psy_cfg.supplied_to = charger->pdata->supplied_to;
psy_cfg.num_supplicants = charger->pdata->num_supplicants;
psy_cfg.of_node = client->dev.of_node;
psy_cfg.drv_data = charger;
i2c_set_clientdata(client, charger);
if (gpio_is_valid(charger->pdata->status_gpio)) {
ret = devm_gpio_request(&client->dev,
charger->pdata->status_gpio,
name);
if (ret) {
dev_err(&client->dev,
"Failed GPIO request for GPIO %d: %d\n",
charger->pdata->status_gpio, ret);
}
charger->pdata->status_gpio_valid = !ret;
}
if (!charger->pdata->status_gpio_valid
|| bq24735_charger_is_present(charger)) {
ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
ret);
return ret;
} else if (ret != 0x0040) {
dev_err(&client->dev,
"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
return -ENODEV;
}
ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read device id : %d\n", ret);
return ret;
} else if (ret != 0x000B) {
dev_err(&client->dev,
"device id mismatch. 0x000b != 0x%04x\n", ret);
return -ENODEV;
}
}
ret = bq24735_config_charger(charger);
if (ret < 0) {
dev_err(&client->dev, "failed in configuring charger");
return ret;
}
/* check for AC adapter presence */
if (bq24735_charger_is_present(charger)) {
ret = bq24735_enable_charging(charger);
if (ret < 0) {
dev_err(&client->dev, "Failed to enable charging\n");
return ret;
}
}
charger->charger = devm_power_supply_register(&client->dev, supply_desc,
&psy_cfg);
if (IS_ERR(charger->charger)) {
ret = PTR_ERR(charger->charger);
dev_err(&client->dev, "Failed to register power supply: %d\n",
ret);
return ret;
}
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, bq24735_charger_isr,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
supply_desc->name,
charger->charger);
if (ret) {
dev_err(&client->dev,
"Unable to register IRQ %d err %d\n",
client->irq, ret);
return ret;
}
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 499 | 72.95% | 1 | 16.67% |
jonathan tinkham | jonathan tinkham | 79 | 11.55% | 1 | 16.67% |
krzysztof kozlowski | krzysztof kozlowski | 53 | 7.75% | 2 | 33.33% |
vaishali thakkar | vaishali thakkar | 27 | 3.95% | 1 | 16.67% |
peter rosin | peter rosin | 26 | 3.80% | 1 | 16.67% |
| Total | 684 | 100.00% | 6 | 100.00% |
static const struct i2c_device_id bq24735_charger_id[] = {
{ "bq24735-charger", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, bq24735_charger_id);
static const struct of_device_id bq24735_match_ids[] = {
{ .compatible = "ti,bq24735", },
{ /* end */ }
};
MODULE_DEVICE_TABLE(of, bq24735_match_ids);
static struct i2c_driver bq24735_charger_driver = {
.driver = {
.name = "bq24735-charger",
.of_match_table = bq24735_match_ids,
},
.probe = bq24735_charger_probe,
.id_table = bq24735_charger_id,
};
module_i2c_driver(bq24735_charger_driver);
MODULE_DESCRIPTION("bq24735 battery charging driver");
MODULE_AUTHOR("Darbha Sriharsha <dsriharsha@nvidia.com>");
MODULE_LICENSE("GPL v2");
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
darbha sriharsha | darbha sriharsha | 1509 | 73.79% | 1 | 14.29% |
peter rosin | peter rosin | 326 | 15.94% | 1 | 14.29% |
jonathan tinkham | jonathan tinkham | 121 | 5.92% | 2 | 28.57% |
krzysztof kozlowski | krzysztof kozlowski | 62 | 3.03% | 2 | 28.57% |
vaishali thakkar | vaishali thakkar | 27 | 1.32% | 1 | 14.29% |
| Total | 2045 | 100.00% | 7 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.