提交 a709bd58 编写于 作者: L Linus Torvalds

Merge tag 'for-v3.13' of git://git.infradead.org/battery-2.6

Pull battery updates from Anton Vorontsov:
 "Highlights:
   - A new driver for TI BQ24735 Battery Chargers, courtesy of NVidia.
   - Device tree bindings for TWL4030 chips.
   - Random fixes and cleanups"

* tag 'for-v3.13' of git://git.infradead.org/battery-2.6:
  pm2301-charger: Remove unneeded NULL checks
  twl4030_charger: Add devicetree support
  power_supply: Fix documentation for TEMP_*ALERT* properties
  max17042_battery: Support regmap to access device's registers
  max17042_battery: Use SIMPLE_DEV_PM_OPS
  charger-manager : Replace kzalloc to devm_kzalloc and remove uneccessary code
  bq2415x_charger: Fix max battery regulation voltage
  tps65090-charger: Use "IS_ENABLED(CONFIG_OF)" for DT code
  tps65090-charger: Drop devm_free_irq of devm_ allocated irq
  power_supply: Add support for bq24735 charger
  pm2301-charger: Staticize pm2xxx_charger_die_therm_mngt
  pm2301-charger: Check return value of regulator_enable
  ab8500-charger: Remove redundant break
  ab8500-charger: Check return value of regulator_enable
  isp1704_charger: Fix driver to work with changes introduced in v3.5
TWL BCI (Battery Charger Interface)
Required properties:
- compatible:
- "ti,twl4030-bci"
- interrupts: two interrupt lines from the TWL SIH (secondary
interrupt handler) - interrupts 9 and 2.
Optional properties:
- ti,bb-uvolt: microvolts for charging the backup battery.
- ti,bb-uamp: microamps for charging the backup battery.
Examples:
bci {
compatible = "ti,twl4030-bci";
interrupts = <9>, <2>;
ti,bb-uvolt = <3200000>;
ti,bb-uamp = <150>;
};
TI BQ24735 Charge Controller
~~~~~~~~~~
Required properties :
- compatible : "ti,bq24735"
Optional properties :
- interrupts : Specify the interrupt to be used to trigger when the AC
adapter is either plugged in or removed.
- ti,ac-detect-gpios : This GPIO is optionally used to read the AC adapter
presence. This is a Host GPIO that is configured as an input and
connected to the bq24735.
- ti,charge-current : Used to control and set the charging current. This value
must be between 128mA and 8.128A with a 64mA step resolution. The POR value
is 0x0000h. This number is in mA (e.g. 8192), see spec for more information
about the ChargeCurrent (0x14h) register.
- ti,charge-voltage : Used to control and set the charging voltage. This value
must be between 1.024V and 19.2V with a 16mV step resolution. The POR value
is 0x0000h. This number is in mV (e.g. 19200), see spec for more information
about the ChargeVoltage (0x15h) register.
- ti,input-current : Used to control and set the charger input current. This
value must be between 128mA and 8.064A with a 128mA step resolution. The
POR value is 0x1000h. This number is in mA (e.g. 8064), see the spec for
more information about the InputCurrent (0x3fh) register.
Example:
bq24735@9 {
compatible = "ti,bq24735";
reg = <0x9>;
ti,ac-detect-gpios = <&gpio 72 0x1>;
}
......@@ -135,11 +135,11 @@ CAPACITY_LEVEL - capacity level. This corresponds to
POWER_SUPPLY_CAPACITY_LEVEL_*.
TEMP - temperature of the power supply.
TEMP_ALERT_MIN - minimum battery temperature alert value in milli centigrade.
TEMP_ALERT_MAX - maximum battery temperature alert value in milli centigrade.
TEMP_ALERT_MIN - minimum battery temperature alert.
TEMP_ALERT_MAX - maximum battery temperature alert.
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.
TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert.
TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert.
TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e.
while battery powers a load)
......
......@@ -19,6 +19,12 @@ rtc {
interrupts = <11>;
};
charger: bci {
compatible = "ti,twl4030-bci";
interrupts = <9>, <2>;
bci3v1-supply = <&vusb3v1>;
};
watchdog {
compatible = "ti,twl4030-wdt";
};
......
......@@ -346,6 +346,12 @@ config CHARGER_BQ24190
help
Say Y to enable support for the TI BQ24190 battery charger.
config CHARGER_BQ24735
tristate "TI BQ24735 battery charger support"
depends on I2C && GPIOLIB
help
Say Y to enable support for the TI BQ24735 battery charger.
config CHARGER_SMB347
tristate "Summit Microelectronics SMB347 Battery Charger"
depends on I2C
......
......@@ -52,6 +52,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o
obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
......
......@@ -766,7 +766,6 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
ret = -ENXIO;
break;
}
break;
case USB_STAT_CARKIT_1:
case USB_STAT_CARKIT_2:
case USB_STAT_ACA_DOCK_CHARGER:
......@@ -1387,8 +1386,12 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
* the GPADC module independant of the AB8500 chargers
*/
if (!di->vddadc_en_ac) {
regulator_enable(di->regu);
di->vddadc_en_ac = true;
ret = regulator_enable(di->regu);
if (ret)
dev_warn(di->dev,
"Failed to enable regulator\n");
else
di->vddadc_en_ac = true;
}
/* Check if the requested voltage or current is valid */
......@@ -1556,8 +1559,12 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
* the GPADC module independant of the AB8500 chargers
*/
if (!di->vddadc_en_usb) {
regulator_enable(di->regu);
di->vddadc_en_usb = true;
ret = regulator_enable(di->regu);
if (ret)
dev_warn(di->dev,
"Failed to enable regulator\n");
else
di->vddadc_en_usb = true;
}
/* Enable USB charging */
......
......@@ -605,9 +605,13 @@ static int bq2415x_set_battery_regulation_voltage(struct bq2415x_device *bq,
{
int val = (mV/10 - 350) / 2;
/*
* According to datasheet, maximum battery regulation voltage is
* 4440mV which is b101111 = 47.
*/
if (val < 0)
val = 0;
else if (val > 94) /* FIXME: Max is 94 or 122 ? Set max value ? */
else if (val > 47)
return -EINVAL;
return bq2415x_i2c_write_mask(bq, BQ2415X_REG_VOLTAGE, val,
......
/*
* 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 i2c_client *client;
struct bq24735_platform *pdata;
};
static inline struct bq24735 *to_bq24735(struct power_supply *psy)
{
return container_of(psy, struct bq24735, charger);
}
static enum power_supply_property bq24735_charger_properties[] = {
POWER_SUPPLY_PROP_ONLINE,
};
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));
}
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);
}
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);
}
static inline int bq24735_enable_charging(struct bq24735 *charger)
{
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
~BQ24735_CHG_OPT_CHARGE_DISABLE);
}
static inline int bq24735_disable_charging(struct bq24735 *charger)
{
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
BQ24735_CHG_OPT_CHARGE_DISABLE);
}
static int bq24735_config_charger(struct bq24735 *charger)
{
struct bq24735_platform *pdata = charger->pdata;
int ret;
u16 value;
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;
}
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;
}
static irqreturn_t bq24735_charger_isr(int irq, void *devid)
{
struct power_supply *psy = devid;
struct bq24735 *charger = to_bq24735(psy);
if (bq24735_charger_is_present(charger))
bq24735_enable_charging(charger);
else
bq24735_disable_charging(charger);
power_supply_changed(psy);
return IRQ_HANDLED;
}
static int bq24735_charger_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct bq24735 *charger;
charger = container_of(psy, struct bq24735, charger);
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
break;
default:
return -EINVAL;
}
return 0;
}
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;
return pdata;
}
static int bq24735_charger_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct bq24735 *charger;
struct power_supply *supply;
char *name;
charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL);
if (!charger)
return -ENOMEM;
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 = kasprintf(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 = &charger->charger;
supply->name = name;
supply->type = POWER_SUPPLY_TYPE_MAINS;
supply->properties = bq24735_charger_properties;
supply->num_properties = ARRAY_SIZE(bq24735_charger_properties);
supply->get_property = bq24735_charger_get_property;
supply->supplied_to = charger->pdata->supplied_to;
supply->num_supplicants = charger->pdata->num_supplicants;
supply->of_node = client->dev.of_node;
i2c_set_clientdata(client, charger);
ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
ret);
goto err_free_name;
} else if (ret != 0x0040) {
dev_err(&client->dev,
"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
ret = -ENODEV;
goto err_free_name;
}
ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read device id : %d\n", ret);
goto err_free_name;
} else if (ret != 0x000B) {
dev_err(&client->dev,
"device id mismatch. 0x000b != 0x%04x\n", ret);
ret = -ENODEV;
goto err_free_name;
}
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;
}
ret = bq24735_config_charger(charger);
if (ret < 0) {
dev_err(&client->dev, "failed in configuring charger");
goto err_free_name;
}
/* 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");
goto err_free_name;
}
}
ret = power_supply_register(&client->dev, supply);
if (ret < 0) {
dev_err(&client->dev, "Failed to register power supply: %d\n",
ret);
goto err_free_name;
}
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->name, supply);
if (ret) {
dev_err(&client->dev,
"Unable to register IRQ %d err %d\n",
client->irq, ret);
goto err_unregister_supply;
}
}
return 0;
err_unregister_supply:
power_supply_unregister(supply);
err_free_name:
if (name != charger->pdata->name)
kfree(name);
return ret;
}
static int bq24735_charger_remove(struct i2c_client *client)
{
struct bq24735 *charger = i2c_get_clientdata(client);
if (charger->client->irq)
devm_free_irq(&charger->client->dev, charger->client->irq,
&charger->charger);
power_supply_unregister(&charger->charger);
if (charger->charger.name != charger->pdata->name)
kfree(charger->charger.name);
return 0;
}
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",
.owner = THIS_MODULE,
.of_match_table = bq24735_match_ids,
},
.probe = bq24735_charger_probe,
.remove = bq24735_charger_remove,
.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");
......@@ -1378,7 +1378,8 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
charger = &desc->charger_regulators[i];
snprintf(buf, 10, "charger.%d", i);
str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
str = devm_kzalloc(cm->dev,
sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
if (!str) {
ret = -ENOMEM;
goto err;
......@@ -1452,30 +1453,23 @@ static int charger_manager_probe(struct platform_device *pdev)
rtc_dev = NULL;
dev_err(&pdev->dev, "Cannot get RTC %s\n",
g_desc->rtc_name);
ret = -ENODEV;
goto err_alloc;
return -ENODEV;
}
}
if (!desc) {
dev_err(&pdev->dev, "No platform data (desc) found\n");
ret = -ENODEV;
goto err_alloc;
return -ENODEV;
}
cm = kzalloc(sizeof(struct charger_manager), GFP_KERNEL);
if (!cm) {
ret = -ENOMEM;
goto err_alloc;
}
cm = devm_kzalloc(&pdev->dev,
sizeof(struct charger_manager), GFP_KERNEL);
if (!cm)
return -ENOMEM;
/* Basic Values. Unspecified are Null or 0 */
cm->dev = &pdev->dev;
cm->desc = kmemdup(desc, sizeof(struct charger_desc), GFP_KERNEL);
if (!cm->desc) {
ret = -ENOMEM;
goto err_alloc_desc;
}
cm->desc = desc;
cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */
/*
......@@ -1498,27 +1492,23 @@ static int charger_manager_probe(struct platform_device *pdev)
}
if (!desc->charger_regulators || desc->num_charger_regulators < 1) {
ret = -EINVAL;
dev_err(&pdev->dev, "charger_regulators undefined\n");
goto err_no_charger;
return -EINVAL;
}
if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) {
dev_err(&pdev->dev, "No power supply defined\n");
ret = -EINVAL;
goto err_no_charger_stat;
return -EINVAL;
}
/* Counting index only */
while (desc->psy_charger_stat[i])
i++;
cm->charger_stat = kzalloc(sizeof(struct power_supply *) * (i + 1),
GFP_KERNEL);
if (!cm->charger_stat) {
ret = -ENOMEM;
goto err_no_charger_stat;
}
cm->charger_stat = devm_kzalloc(&pdev->dev,
sizeof(struct power_supply *) * i, GFP_KERNEL);
if (!cm->charger_stat)
return -ENOMEM;
for (i = 0; desc->psy_charger_stat[i]; i++) {
cm->charger_stat[i] = power_supply_get_by_name(
......@@ -1526,8 +1516,7 @@ static int charger_manager_probe(struct platform_device *pdev)
if (!cm->charger_stat[i]) {
dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
desc->psy_charger_stat[i]);
ret = -ENODEV;
goto err_chg_stat;
return -ENODEV;
}
}
......@@ -1535,21 +1524,18 @@ static int charger_manager_probe(struct platform_device *pdev)
if (!cm->fuel_gauge) {
dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
desc->psy_fuel_gauge);
ret = -ENODEV;
goto err_chg_stat;
return -ENODEV;
}
if (desc->polling_interval_ms == 0 ||
msecs_to_jiffies(desc->polling_interval_ms) <= CM_JIFFIES_SMALL) {
dev_err(&pdev->dev, "polling_interval_ms is too small\n");
ret = -EINVAL;
goto err_chg_stat;
return -EINVAL;
}
if (!desc->temperature_out_of_range) {
dev_err(&pdev->dev, "there is no temperature_out_of_range\n");
ret = -EINVAL;
goto err_chg_stat;
return -EINVAL;
}
if (!desc->charging_max_duration_ms ||
......@@ -1570,14 +1556,13 @@ static int charger_manager_probe(struct platform_device *pdev)
cm->charger_psy.name = cm->psy_name_buf;
/* Allocate for psy properties because they may vary */
cm->charger_psy.properties = kzalloc(sizeof(enum power_supply_property)
cm->charger_psy.properties = devm_kzalloc(&pdev->dev,
sizeof(enum power_supply_property)
* (ARRAY_SIZE(default_charger_props) +
NUM_CHARGER_PSY_OPTIONAL),
GFP_KERNEL);
if (!cm->charger_psy.properties) {
ret = -ENOMEM;
goto err_chg_stat;
}
NUM_CHARGER_PSY_OPTIONAL), GFP_KERNEL);
if (!cm->charger_psy.properties)
return -ENOMEM;
memcpy(cm->charger_psy.properties, default_charger_props,
sizeof(enum power_supply_property) *
ARRAY_SIZE(default_charger_props));
......@@ -1614,7 +1599,7 @@ static int charger_manager_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "Cannot register charger-manager with name \"%s\"\n",
cm->charger_psy.name);
goto err_register;
return ret;
}
/* Register extcon device for charger cable */
......@@ -1655,8 +1640,6 @@ static int charger_manager_probe(struct platform_device *pdev)
charger = &desc->charger_regulators[i];
sysfs_remove_group(&cm->charger_psy.dev->kobj,
&charger->attr_g);
kfree(charger->attr_g.name);
}
err_reg_extcon:
for (i = 0; i < desc->num_charger_regulators; i++) {
......@@ -1674,16 +1657,7 @@ static int charger_manager_probe(struct platform_device *pdev)
}
power_supply_unregister(&cm->charger_psy);
err_register:
kfree(cm->charger_psy.properties);
err_chg_stat:
kfree(cm->charger_stat);
err_no_charger_stat:
err_no_charger:
kfree(cm->desc);
err_alloc_desc:
kfree(cm);
err_alloc:
return ret;
}
......@@ -1718,11 +1692,6 @@ static int charger_manager_remove(struct platform_device *pdev)
try_charger_enable(cm, false);
kfree(cm->charger_psy.properties);
kfree(cm->charger_stat);
kfree(cm->desc);
kfree(cm);
return 0;
}
......
......@@ -2,6 +2,7 @@
* ISP1704 USB Charger Detection driver
*
* Copyright (C) 2010 Nokia Corporation
* Copyright (C) 2012 - 2013 Pali Rohár <pali.rohar@gmail.com>
*
* 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
......@@ -65,10 +66,6 @@ struct isp1704_charger {
unsigned present:1;
unsigned online:1;
unsigned current_max;
/* temp storage variables */
unsigned long event;
unsigned max_power;
};
static inline int isp1704_read(struct isp1704_charger *isp, u32 reg)
......@@ -231,56 +228,59 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
return ret;
}
static inline int isp1704_charger_detect_dcp(struct isp1704_charger *isp)
{
if (isp1704_charger_detect(isp) &&
isp1704_charger_type(isp) == POWER_SUPPLY_TYPE_USB_DCP)
return true;
else
return false;
}
static void isp1704_charger_work(struct work_struct *data)
{
int detect;
unsigned long event;
unsigned power;
struct isp1704_charger *isp =
container_of(data, struct isp1704_charger, work);
static DEFINE_MUTEX(lock);
event = isp->event;
power = isp->max_power;
mutex_lock(&lock);
if (event != USB_EVENT_NONE)
isp1704_charger_set_power(isp, 1);
switch (event) {
switch (isp->phy->last_event) {
case USB_EVENT_VBUS:
isp->online = true;
/* do not call wall charger detection more times */
if (!isp->present) {
isp->online = true;
isp->present = 1;
isp1704_charger_set_power(isp, 1);
/* detect wall charger */
if (isp1704_charger_detect_dcp(isp)) {
isp->psy.type = POWER_SUPPLY_TYPE_USB_DCP;
isp->current_max = 1800;
} else {
isp->psy.type = POWER_SUPPLY_TYPE_USB;
isp->current_max = 500;
}
/* detect charger */
detect = isp1704_charger_detect(isp);
if (detect) {
isp->present = detect;
isp->psy.type = isp1704_charger_type(isp);
/* enable data pullups */
if (isp->phy->otg->gadget)
usb_gadget_connect(isp->phy->otg->gadget);
}
switch (isp->psy.type) {
case POWER_SUPPLY_TYPE_USB_DCP:
isp->current_max = 1800;
break;
case POWER_SUPPLY_TYPE_USB_CDP:
if (isp->psy.type != POWER_SUPPLY_TYPE_USB_DCP) {
/*
* Only 500mA here or high speed chirp
* handshaking may break
*/
isp->current_max = 500;
/* FALLTHROUGH */
case POWER_SUPPLY_TYPE_USB:
default:
/* enable data pullups */
if (isp->phy->otg->gadget)
usb_gadget_connect(isp->phy->otg->gadget);
if (isp->current_max > 500)
isp->current_max = 500;
if (isp->current_max > 100)
isp->psy.type = POWER_SUPPLY_TYPE_USB_CDP;
}
break;
case USB_EVENT_NONE:
isp->online = false;
isp->current_max = 0;
isp->present = 0;
isp->current_max = 0;
isp->psy.type = POWER_SUPPLY_TYPE_USB;
......@@ -298,12 +298,6 @@ static void isp1704_charger_work(struct work_struct *data)
isp1704_charger_set_power(isp, 0);
break;
case USB_EVENT_ENUMERATED:
if (isp->present)
isp->current_max = 1800;
else
isp->current_max = power;
break;
default:
goto out;
}
......@@ -314,16 +308,11 @@ static void isp1704_charger_work(struct work_struct *data)
}
static int isp1704_notifier_call(struct notifier_block *nb,
unsigned long event, void *power)
unsigned long val, void *v)
{
struct isp1704_charger *isp =
container_of(nb, struct isp1704_charger, nb);
isp->event = event;
if (power)
isp->max_power = *((unsigned *)power);
schedule_work(&isp->work);
return NOTIFY_OK;
......@@ -462,13 +451,13 @@ static int isp1704_charger_probe(struct platform_device *pdev)
if (isp->phy->otg->gadget)
usb_gadget_disconnect(isp->phy->otg->gadget);
if (isp->phy->last_event == USB_EVENT_NONE)
isp1704_charger_set_power(isp, 0);
/* Detect charger if VBUS is valid (the cable was already plugged). */
ret = isp1704_read(isp, ULPI_USB_INT_STS);
isp1704_charger_set_power(isp, 0);
if ((ret & ULPI_INT_VBUS_VALID) && !isp->phy->otg->default_a) {
isp->event = USB_EVENT_VBUS;
if (isp->phy->last_event == USB_EVENT_VBUS &&
!isp->phy->otg->default_a)
schedule_work(&isp->work);
}
return 0;
fail2:
......
此差异已折叠。
......@@ -205,7 +205,7 @@ static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val)
}
int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
static int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
{
queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
......@@ -722,8 +722,12 @@ static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
if (!pm2->vddadc_en_ac) {
regulator_enable(pm2->regu);
pm2->vddadc_en_ac = true;
ret = regulator_enable(pm2->regu);
if (ret)
dev_warn(pm2->dev,
"Failed to enable vddadc regulator\n");
else
pm2->vddadc_en_ac = true;
}
ret = pm2xxx_charging_init(pm2);
......@@ -953,37 +957,24 @@ static int pm2xxx_runtime_suspend(struct device *dev)
{
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
int ret = 0;
pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
if (!pm2) {
dev_err(pm2->dev, "no pm2xxx_charger data supplied\n");
ret = -EINVAL;
return ret;
}
clear_lpn_pin(pm2);
return ret;
return 0;
}
static int pm2xxx_runtime_resume(struct device *dev)
{
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
int ret = 0;
pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
if (!pm2) {
dev_err(pm2->dev, "no pm2xxx_charger data supplied\n");
ret = -EINVAL;
return ret;
}
if (gpio_is_valid(pm2->lpn_pin) && gpio_get_value(pm2->lpn_pin) == 0)
set_lpn_pin(pm2);
return ret;
return 0;
}
#endif
......
......@@ -15,15 +15,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/mfd/tps65090.h>
#define TPS65090_REG_INTR_STS 0x00
......@@ -185,10 +187,6 @@ static irqreturn_t tps65090_charger_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
#if defined(CONFIG_OF)
#include <linux/of_device.h>
static struct tps65090_platform_data *
tps65090_parse_dt_charger_data(struct platform_device *pdev)
{
......@@ -210,13 +208,6 @@ static struct tps65090_platform_data *
return pdata;
}
#else
static struct tps65090_platform_data *
tps65090_parse_dt_charger_data(struct platform_device *pdev)
{
return NULL;
}
#endif
static int tps65090_charger_probe(struct platform_device *pdev)
{
......@@ -228,7 +219,7 @@ static int tps65090_charger_probe(struct platform_device *pdev)
pdata = dev_get_platdata(pdev->dev.parent);
if (!pdata && pdev->dev.of_node)
if (IS_ENABLED(CONFIG_OF) && !pdata && pdev->dev.of_node)
pdata = tps65090_parse_dt_charger_data(pdev);
if (!pdata) {
......@@ -277,13 +268,13 @@ static int tps65090_charger_probe(struct platform_device *pdev)
if (ret) {
dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq,
ret);
goto fail_free_irq;
goto fail_unregister_supply;
}
ret = tps65090_config_charger(cdata);
if (ret < 0) {
dev_err(&pdev->dev, "charger config failed, err %d\n", ret);
goto fail_free_irq;
goto fail_unregister_supply;
}
/* Check for charger presence */
......@@ -292,14 +283,14 @@ static int tps65090_charger_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__,
TPS65090_REG_CG_STATUS1);
goto fail_free_irq;
goto fail_unregister_supply;
}
if (status1 != 0) {
ret = tps65090_enable_charging(cdata);
if (ret < 0) {
dev_err(cdata->dev, "error enabling charger\n");
goto fail_free_irq;
goto fail_unregister_supply;
}
cdata->ac_online = 1;
power_supply_changed(&cdata->ac);
......@@ -307,8 +298,6 @@ static int tps65090_charger_probe(struct platform_device *pdev)
return 0;
fail_free_irq:
devm_free_irq(cdata->dev, irq, cdata);
fail_unregister_supply:
power_supply_unregister(&cdata->ac);
......@@ -319,7 +308,6 @@ static int tps65090_charger_remove(struct platform_device *pdev)
{
struct tps65090_charger *cdata = platform_get_drvdata(pdev);
devm_free_irq(cdata->dev, cdata->irq, cdata);
power_supply_unregister(&cdata->ac);
return 0;
......
......@@ -495,10 +495,38 @@ static enum power_supply_property twl4030_charger_props[] = {
POWER_SUPPLY_PROP_CURRENT_NOW,
};
#ifdef CONFIG_OF
static const struct twl4030_bci_platform_data *
twl4030_bci_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
struct twl4030_bci_platform_data *pdata;
u32 num;
if (!np)
return NULL;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return pdata;
if (of_property_read_u32(np, "ti,bb-uvolt", &num) == 0)
pdata->bb_uvolt = num;
if (of_property_read_u32(np, "ti,bb-uamp", &num) == 0)
pdata->bb_uamp = num;
return pdata;
}
#else
static inline const struct twl4030_bci_platform_data *
twl4030_bci_parse_dt(struct device *dev)
{
return NULL;
}
#endif
static int __init twl4030_bci_probe(struct platform_device *pdev)
{
struct twl4030_bci *bci;
struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
const struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
int ret;
u32 reg;
......@@ -506,6 +534,9 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
if (bci == NULL)
return -ENOMEM;
if (!pdata)
pdata = twl4030_bci_parse_dt(&pdev->dev);
bci->dev = &pdev->dev;
bci->irq_chg = platform_get_irq(pdev, 0);
bci->irq_bci = platform_get_irq(pdev, 1);
......@@ -581,8 +612,11 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
twl4030_charger_enable_ac(true);
twl4030_charger_enable_usb(bci, true);
twl4030_charger_enable_backup(pdata->bb_uvolt,
pdata->bb_uamp);
if (pdata)
twl4030_charger_enable_backup(pdata->bb_uvolt,
pdata->bb_uamp);
else
twl4030_charger_enable_backup(0, 0);
return 0;
......@@ -631,10 +665,17 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id twl_bci_of_match[] = {
{.compatible = "ti,twl4030-bci", },
{ }
};
MODULE_DEVICE_TABLE(of, twl_bci_of_match);
static struct platform_driver twl4030_bci_driver = {
.driver = {
.name = "twl4030_bci",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(twl_bci_of_match),
},
.remove = __exit_p(twl4030_bci_remove),
};
......
/*
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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
*/
#ifndef __CHARGER_BQ24735_H_
#define __CHARGER_BQ24735_H_
#include <linux/types.h>
#include <linux/power_supply.h>
struct bq24735_platform {
uint32_t charge_current;
uint32_t charge_voltage;
uint32_t input_current;
const char *name;
int status_gpio;
int status_gpio_active_low;
bool status_gpio_valid;
char **supplied_to;
size_t num_supplicants;
};
#endif /* __CHARGER_BQ24735_H_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册