Commit a709bd58 authored by Linus Torvalds's avatar 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
parents 3ea369ee c8024234
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 ...@@ -135,11 +135,11 @@ CAPACITY_LEVEL - capacity level. This corresponds to
POWER_SUPPLY_CAPACITY_LEVEL_*. POWER_SUPPLY_CAPACITY_LEVEL_*.
TEMP - temperature of the power supply. TEMP - temperature of the power supply.
TEMP_ALERT_MIN - minimum battery temperature alert value in milli centigrade. TEMP_ALERT_MIN - minimum battery temperature alert.
TEMP_ALERT_MAX - maximum battery temperature alert value in milli centigrade. TEMP_ALERT_MAX - maximum battery temperature alert.
TEMP_AMBIENT - ambient temperature. TEMP_AMBIENT - ambient temperature.
TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert value in milli centigrade. TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert.
TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert value in milli centigrade. TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert.
TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e. TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e.
while battery powers a load) while battery powers a load)
......
...@@ -19,6 +19,12 @@ rtc { ...@@ -19,6 +19,12 @@ rtc {
interrupts = <11>; interrupts = <11>;
}; };
charger: bci {
compatible = "ti,twl4030-bci";
interrupts = <9>, <2>;
bci3v1-supply = <&vusb3v1>;
};
watchdog { watchdog {
compatible = "ti,twl4030-wdt"; compatible = "ti,twl4030-wdt";
}; };
......
...@@ -346,6 +346,12 @@ config CHARGER_BQ24190 ...@@ -346,6 +346,12 @@ config CHARGER_BQ24190
help help
Say Y to enable support for the TI BQ24190 battery charger. 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 config CHARGER_SMB347
tristate "Summit Microelectronics SMB347 Battery Charger" tristate "Summit Microelectronics SMB347 Battery Charger"
depends on I2C depends on I2C
......
...@@ -52,6 +52,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o ...@@ -52,6 +52,7 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o
obj-$(CONFIG_POWER_AVS) += avs/ obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
......
...@@ -766,7 +766,6 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, ...@@ -766,7 +766,6 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
ret = -ENXIO; ret = -ENXIO;
break; break;
} }
break;
case USB_STAT_CARKIT_1: case USB_STAT_CARKIT_1:
case USB_STAT_CARKIT_2: case USB_STAT_CARKIT_2:
case USB_STAT_ACA_DOCK_CHARGER: case USB_STAT_ACA_DOCK_CHARGER:
...@@ -1387,7 +1386,11 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, ...@@ -1387,7 +1386,11 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
* the GPADC module independant of the AB8500 chargers * the GPADC module independant of the AB8500 chargers
*/ */
if (!di->vddadc_en_ac) { if (!di->vddadc_en_ac) {
regulator_enable(di->regu); ret = regulator_enable(di->regu);
if (ret)
dev_warn(di->dev,
"Failed to enable regulator\n");
else
di->vddadc_en_ac = true; di->vddadc_en_ac = true;
} }
...@@ -1556,7 +1559,11 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, ...@@ -1556,7 +1559,11 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
* the GPADC module independant of the AB8500 chargers * the GPADC module independant of the AB8500 chargers
*/ */
if (!di->vddadc_en_usb) { if (!di->vddadc_en_usb) {
regulator_enable(di->regu); ret = regulator_enable(di->regu);
if (ret)
dev_warn(di->dev,
"Failed to enable regulator\n");
else
di->vddadc_en_usb = true; di->vddadc_en_usb = true;
} }
......
...@@ -605,9 +605,13 @@ static int bq2415x_set_battery_regulation_voltage(struct bq2415x_device *bq, ...@@ -605,9 +605,13 @@ static int bq2415x_set_battery_regulation_voltage(struct bq2415x_device *bq,
{ {
int val = (mV/10 - 350) / 2; int val = (mV/10 - 350) / 2;
/*
* According to datasheet, maximum battery regulation voltage is
* 4440mV which is b101111 = 47.
*/
if (val < 0) if (val < 0)
val = 0; val = 0;
else if (val > 94) /* FIXME: Max is 94 or 122 ? Set max value ? */ else if (val > 47)
return -EINVAL; return -EINVAL;
return bq2415x_i2c_write_mask(bq, BQ2415X_REG_VOLTAGE, val, 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) ...@@ -1378,7 +1378,8 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
charger = &desc->charger_regulators[i]; charger = &desc->charger_regulators[i];
snprintf(buf, 10, "charger.%d", 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) { if (!str) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
...@@ -1452,30 +1453,23 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1452,30 +1453,23 @@ static int charger_manager_probe(struct platform_device *pdev)
rtc_dev = NULL; rtc_dev = NULL;
dev_err(&pdev->dev, "Cannot get RTC %s\n", dev_err(&pdev->dev, "Cannot get RTC %s\n",
g_desc->rtc_name); g_desc->rtc_name);
ret = -ENODEV; return -ENODEV;
goto err_alloc;
} }
} }
if (!desc) { if (!desc) {
dev_err(&pdev->dev, "No platform data (desc) found\n"); dev_err(&pdev->dev, "No platform data (desc) found\n");
ret = -ENODEV; return -ENODEV;
goto err_alloc;
} }
cm = kzalloc(sizeof(struct charger_manager), GFP_KERNEL); cm = devm_kzalloc(&pdev->dev,
if (!cm) { sizeof(struct charger_manager), GFP_KERNEL);
ret = -ENOMEM; if (!cm)
goto err_alloc; return -ENOMEM;
}
/* Basic Values. Unspecified are Null or 0 */ /* Basic Values. Unspecified are Null or 0 */
cm->dev = &pdev->dev; cm->dev = &pdev->dev;
cm->desc = kmemdup(desc, sizeof(struct charger_desc), GFP_KERNEL); cm->desc = desc;
if (!cm->desc) {
ret = -ENOMEM;
goto err_alloc_desc;
}
cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */
/* /*
...@@ -1498,27 +1492,23 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1498,27 +1492,23 @@ static int charger_manager_probe(struct platform_device *pdev)
} }
if (!desc->charger_regulators || desc->num_charger_regulators < 1) { if (!desc->charger_regulators || desc->num_charger_regulators < 1) {
ret = -EINVAL;
dev_err(&pdev->dev, "charger_regulators undefined\n"); dev_err(&pdev->dev, "charger_regulators undefined\n");
goto err_no_charger; return -EINVAL;
} }
if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) { if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) {
dev_err(&pdev->dev, "No power supply defined\n"); dev_err(&pdev->dev, "No power supply defined\n");
ret = -EINVAL; return -EINVAL;
goto err_no_charger_stat;
} }
/* Counting index only */ /* Counting index only */
while (desc->psy_charger_stat[i]) while (desc->psy_charger_stat[i])
i++; i++;
cm->charger_stat = kzalloc(sizeof(struct power_supply *) * (i + 1), cm->charger_stat = devm_kzalloc(&pdev->dev,
GFP_KERNEL); sizeof(struct power_supply *) * i, GFP_KERNEL);
if (!cm->charger_stat) { if (!cm->charger_stat)
ret = -ENOMEM; return -ENOMEM;
goto err_no_charger_stat;
}
for (i = 0; desc->psy_charger_stat[i]; i++) { for (i = 0; desc->psy_charger_stat[i]; i++) {
cm->charger_stat[i] = power_supply_get_by_name( cm->charger_stat[i] = power_supply_get_by_name(
...@@ -1526,8 +1516,7 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1526,8 +1516,7 @@ static int charger_manager_probe(struct platform_device *pdev)
if (!cm->charger_stat[i]) { if (!cm->charger_stat[i]) {
dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
desc->psy_charger_stat[i]); desc->psy_charger_stat[i]);
ret = -ENODEV; return -ENODEV;
goto err_chg_stat;
} }
} }
...@@ -1535,21 +1524,18 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1535,21 +1524,18 @@ static int charger_manager_probe(struct platform_device *pdev)
if (!cm->fuel_gauge) { if (!cm->fuel_gauge) {
dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
desc->psy_fuel_gauge); desc->psy_fuel_gauge);
ret = -ENODEV; return -ENODEV;
goto err_chg_stat;
} }
if (desc->polling_interval_ms == 0 || if (desc->polling_interval_ms == 0 ||
msecs_to_jiffies(desc->polling_interval_ms) <= CM_JIFFIES_SMALL) { msecs_to_jiffies(desc->polling_interval_ms) <= CM_JIFFIES_SMALL) {
dev_err(&pdev->dev, "polling_interval_ms is too small\n"); dev_err(&pdev->dev, "polling_interval_ms is too small\n");
ret = -EINVAL; return -EINVAL;
goto err_chg_stat;
} }
if (!desc->temperature_out_of_range) { if (!desc->temperature_out_of_range) {
dev_err(&pdev->dev, "there is no temperature_out_of_range\n"); dev_err(&pdev->dev, "there is no temperature_out_of_range\n");
ret = -EINVAL; return -EINVAL;
goto err_chg_stat;
} }
if (!desc->charging_max_duration_ms || if (!desc->charging_max_duration_ms ||
...@@ -1570,14 +1556,13 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1570,14 +1556,13 @@ static int charger_manager_probe(struct platform_device *pdev)
cm->charger_psy.name = cm->psy_name_buf; cm->charger_psy.name = cm->psy_name_buf;
/* Allocate for psy properties because they may vary */ /* 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) + * (ARRAY_SIZE(default_charger_props) +
NUM_CHARGER_PSY_OPTIONAL), NUM_CHARGER_PSY_OPTIONAL), GFP_KERNEL);
GFP_KERNEL); if (!cm->charger_psy.properties)
if (!cm->charger_psy.properties) { return -ENOMEM;
ret = -ENOMEM;
goto err_chg_stat;
}
memcpy(cm->charger_psy.properties, default_charger_props, memcpy(cm->charger_psy.properties, default_charger_props,
sizeof(enum power_supply_property) * sizeof(enum power_supply_property) *
ARRAY_SIZE(default_charger_props)); ARRAY_SIZE(default_charger_props));
...@@ -1614,7 +1599,7 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1614,7 +1599,7 @@ static int charger_manager_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(&pdev->dev, "Cannot register charger-manager with name \"%s\"\n", dev_err(&pdev->dev, "Cannot register charger-manager with name \"%s\"\n",
cm->charger_psy.name); cm->charger_psy.name);
goto err_register; return ret;
} }
/* Register extcon device for charger cable */ /* Register extcon device for charger cable */
...@@ -1655,8 +1640,6 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1655,8 +1640,6 @@ static int charger_manager_probe(struct platform_device *pdev)
charger = &desc->charger_regulators[i]; charger = &desc->charger_regulators[i];
sysfs_remove_group(&cm->charger_psy.dev->kobj, sysfs_remove_group(&cm->charger_psy.dev->kobj,
&charger->attr_g); &charger->attr_g);
kfree(charger->attr_g.name);
} }
err_reg_extcon: err_reg_extcon:
for (i = 0; i < desc->num_charger_regulators; i++) { for (i = 0; i < desc->num_charger_regulators; i++) {
...@@ -1674,16 +1657,7 @@ static int charger_manager_probe(struct platform_device *pdev) ...@@ -1674,16 +1657,7 @@ static int charger_manager_probe(struct platform_device *pdev)
} }
power_supply_unregister(&cm->charger_psy); 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; return ret;
} }
...@@ -1718,11 +1692,6 @@ static int charger_manager_remove(struct platform_device *pdev) ...@@ -1718,11 +1692,6 @@ static int charger_manager_remove(struct platform_device *pdev)
try_charger_enable(cm, false); try_charger_enable(cm, false);
kfree(cm->charger_psy.properties);
kfree(cm->charger_stat);
kfree(cm->desc);
kfree(cm);
return 0; return 0;
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* ISP1704 USB Charger Detection driver * ISP1704 USB Charger Detection driver
* *
* Copyright (C) 2010 Nokia Corporation * 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 * 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
...@@ -65,10 +66,6 @@ struct isp1704_charger { ...@@ -65,10 +66,6 @@ struct isp1704_charger {
unsigned present:1; unsigned present:1;
unsigned online:1; unsigned online:1;
unsigned current_max; unsigned current_max;
/* temp storage variables */
unsigned long event;
unsigned max_power;
}; };
static inline int isp1704_read(struct isp1704_charger *isp, u32 reg) 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) ...@@ -231,56 +228,59 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
return ret; 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) static void isp1704_charger_work(struct work_struct *data)
{ {
int detect;
unsigned long event;
unsigned power;
struct isp1704_charger *isp = struct isp1704_charger *isp =
container_of(data, struct isp1704_charger, work); container_of(data, struct isp1704_charger, work);
static DEFINE_MUTEX(lock); static DEFINE_MUTEX(lock);
event = isp->event;
power = isp->max_power;
mutex_lock(&lock); mutex_lock(&lock);
if (event != USB_EVENT_NONE) switch (isp->phy->last_event) {
isp1704_charger_set_power(isp, 1);
switch (event) {
case USB_EVENT_VBUS: case USB_EVENT_VBUS:
/* do not call wall charger detection more times */
if (!isp->present) {
isp->online = true; isp->online = true;
isp->present = 1;
isp1704_charger_set_power(isp, 1);
/* detect charger */ /* detect wall charger */
detect = isp1704_charger_detect(isp); 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;
}
if (detect) { /* enable data pullups */
isp->present = detect; if (isp->phy->otg->gadget)
isp->psy.type = isp1704_charger_type(isp); usb_gadget_connect(isp->phy->otg->gadget);
} }
switch (isp->psy.type) { if (isp->psy.type != POWER_SUPPLY_TYPE_USB_DCP) {
case POWER_SUPPLY_TYPE_USB_DCP:
isp->current_max = 1800;
break;
case POWER_SUPPLY_TYPE_USB_CDP:
/* /*
* Only 500mA here or high speed chirp * Only 500mA here or high speed chirp
* handshaking may break * handshaking may break
*/ */
if (isp->current_max > 500)
isp->current_max = 500; isp->current_max = 500;
/* FALLTHROUGH */
case POWER_SUPPLY_TYPE_USB: if (isp->current_max > 100)
default: isp->psy.type = POWER_SUPPLY_TYPE_USB_CDP;
/* enable data pullups */
if (isp->phy->otg->gadget)
usb_gadget_connect(isp->phy->otg->gadget);
} }
break; break;
case USB_EVENT_NONE: case USB_EVENT_NONE:
isp->online = false; isp->online = false;
isp->current_max = 0;
isp->present = 0; isp->present = 0;
isp->current_max = 0; isp->current_max = 0;
isp->psy.type = POWER_SUPPLY_TYPE_USB; isp->psy.type = POWER_SUPPLY_TYPE_USB;
...@@ -298,12 +298,6 @@ static void isp1704_charger_work(struct work_struct *data) ...@@ -298,12 +298,6 @@ static void isp1704_charger_work(struct work_struct *data)
isp1704_charger_set_power(isp, 0); isp1704_charger_set_power(isp, 0);
break; break;
case USB_EVENT_ENUMERATED:
if (isp->present)
isp->current_max = 1800;
else
isp->current_max = power;
break;
default: default:
goto out; goto out;
} }
...@@ -314,16 +308,11 @@ static void isp1704_charger_work(struct work_struct *data) ...@@ -314,16 +308,11 @@ static void isp1704_charger_work(struct work_struct *data)
} }
static int isp1704_notifier_call(struct notifier_block *nb, static int isp1704_notifier_call(struct notifier_block *nb,
unsigned long event, void *power) unsigned long val, void *v)
{ {
struct isp1704_charger *isp = struct isp1704_charger *isp =
container_of(nb, struct isp1704_charger, nb); container_of(nb, struct isp1704_charger, nb);
isp->event = event;
if (power)
isp->max_power = *((unsigned *)power);
schedule_work(&isp->work); schedule_work(&isp->work);
return NOTIFY_OK; return NOTIFY_OK;
...@@ -462,13 +451,13 @@ static int isp1704_charger_probe(struct platform_device *pdev) ...@@ -462,13 +451,13 @@ static int isp1704_charger_probe(struct platform_device *pdev)
if (isp->phy->otg->gadget) if (isp->phy->otg->gadget)
usb_gadget_disconnect(isp->phy->otg->gadget); usb_gadget_disconnect(isp->phy->otg->gadget);
/* Detect charger if VBUS is valid (the cable was already plugged). */ if (isp->phy->last_event == USB_EVENT_NONE)
ret = isp1704_read(isp, ULPI_USB_INT_STS);
isp1704_charger_set_power(isp, 0); isp1704_charger_set_power(isp, 0);
if ((ret & ULPI_INT_VBUS_VALID) && !isp->phy->otg->default_a) {
isp->event = USB_EVENT_VBUS; /* Detect charger if VBUS is valid (the cable was already plugged). */
if (isp->phy->last_event == USB_EVENT_VBUS &&
!isp->phy->otg->default_a)
schedule_work(&isp->work); schedule_work(&isp->work);
}
return 0; return 0;
fail2: fail2:
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/power/max17042_battery.h> #include <linux/power/max17042_battery.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/regmap.h>
/* Status register bits */ /* Status register bits */
#define STATUS_POR_BIT (1 << 1) #define STATUS_POR_BIT (1 << 1)
...@@ -67,6 +68,7 @@ ...@@ -67,6 +68,7 @@
struct max17042_chip { struct max17042_chip {
struct i2c_client *client; struct i2c_client *client;
struct regmap *regmap;
struct power_supply battery; struct power_supply battery;
enum max170xx_chip_type chip_type; enum max170xx_chip_type chip_type;
struct max17042_platform_data *pdata; struct max17042_platform_data *pdata;
...@@ -74,35 +76,6 @@ struct max17042_chip { ...@@ -74,35 +76,6 @@ struct max17042_chip {
int init_complete; int init_complete;
}; };
static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
{
int ret = i2c_smbus_write_word_data(client, reg, value);
if (ret < 0)
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
return ret;
}
static int max17042_read_reg(struct i2c_client *client, u8 reg)
{
int ret = i2c_smbus_read_word_data(client, reg);
if (ret < 0)
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
return ret;
}
static void max17042_set_reg(struct i2c_client *client,
struct max17042_reg_data *data, int size)
{
int i;
for (i = 0; i < size; i++)
max17042_write_reg(client, data[i].addr, data[i].data);
}
static enum power_supply_property max17042_battery_props[] = { static enum power_supply_property max17042_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CYCLE_COUNT,
...@@ -125,96 +98,98 @@ static int max17042_get_property(struct power_supply *psy, ...@@ -125,96 +98,98 @@ static int max17042_get_property(struct power_supply *psy,
{ {
struct max17042_chip *chip = container_of(psy, struct max17042_chip *chip = container_of(psy,
struct max17042_chip, battery); struct max17042_chip, battery);
struct regmap *map = chip->regmap;
int ret; int ret;
u32 data;
if (!chip->init_complete) if (!chip->init_complete)
return -EAGAIN; return -EAGAIN;
switch (psp) { switch (psp) {
case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_PRESENT:
ret = max17042_read_reg(chip->client, MAX17042_STATUS); ret = regmap_read(map, MAX17042_STATUS, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret & MAX17042_STATUS_BattAbsent) if (data & MAX17042_STATUS_BattAbsent)
val->intval = 0; val->intval = 0;
else else
val->intval = 1; val->intval = 1;
break; break;
case POWER_SUPPLY_PROP_CYCLE_COUNT: case POWER_SUPPLY_PROP_CYCLE_COUNT:
ret = max17042_read_reg(chip->client, MAX17042_Cycles); ret = regmap_read(map, MAX17042_Cycles, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret; val->intval = data;
break; break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX: case POWER_SUPPLY_PROP_VOLTAGE_MAX:
ret = max17042_read_reg(chip->client, MAX17042_MinMaxVolt); ret = regmap_read(map, MAX17042_MinMaxVolt, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret >> 8; val->intval = data >> 8;
val->intval *= 20000; /* Units of LSB = 20mV */ val->intval *= 20000; /* Units of LSB = 20mV */
break; break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
if (chip->chip_type == MAX17042) if (chip->chip_type == MAX17042)
ret = max17042_read_reg(chip->client, MAX17042_V_empty); ret = regmap_read(map, MAX17042_V_empty, &data);
else else
ret = max17042_read_reg(chip->client, MAX17047_V_empty); ret = regmap_read(map, MAX17047_V_empty, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret >> 7; val->intval = data >> 7;
val->intval *= 10000; /* Units of LSB = 10mV */ val->intval *= 10000; /* Units of LSB = 10mV */
break; break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = max17042_read_reg(chip->client, MAX17042_VCELL); ret = regmap_read(map, MAX17042_VCELL, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret * 625 / 8; val->intval = data * 625 / 8;
break; break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG: case POWER_SUPPLY_PROP_VOLTAGE_AVG:
ret = max17042_read_reg(chip->client, MAX17042_AvgVCELL); ret = regmap_read(map, MAX17042_AvgVCELL, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret * 625 / 8; val->intval = data * 625 / 8;
break; break;
case POWER_SUPPLY_PROP_VOLTAGE_OCV: case POWER_SUPPLY_PROP_VOLTAGE_OCV:
ret = max17042_read_reg(chip->client, MAX17042_OCVInternal); ret = regmap_read(map, MAX17042_OCVInternal, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret * 625 / 8; val->intval = data * 625 / 8;
break; break;
case POWER_SUPPLY_PROP_CAPACITY: case POWER_SUPPLY_PROP_CAPACITY:
ret = max17042_read_reg(chip->client, MAX17042_RepSOC); ret = regmap_read(map, MAX17042_RepSOC, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret >> 8; val->intval = data >> 8;
break; break;
case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_FULL:
ret = max17042_read_reg(chip->client, MAX17042_FullCAP); ret = regmap_read(map, MAX17042_FullCAP, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret * 1000 / 2; val->intval = data * 1000 / 2;
break; break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER: case POWER_SUPPLY_PROP_CHARGE_COUNTER:
ret = max17042_read_reg(chip->client, MAX17042_QH); ret = regmap_read(map, MAX17042_QH, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret * 1000 / 2; val->intval = data * 1000 / 2;
break; break;
case POWER_SUPPLY_PROP_TEMP: case POWER_SUPPLY_PROP_TEMP:
ret = max17042_read_reg(chip->client, MAX17042_TEMP); ret = regmap_read(map, MAX17042_TEMP, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret; val->intval = data;
/* The value is signed. */ /* The value is signed. */
if (val->intval & 0x8000) { if (val->intval & 0x8000) {
val->intval = (0x7fff & ~val->intval) + 1; val->intval = (0x7fff & ~val->intval) + 1;
...@@ -226,11 +201,11 @@ static int max17042_get_property(struct power_supply *psy, ...@@ -226,11 +201,11 @@ static int max17042_get_property(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_CURRENT_NOW:
if (chip->pdata->enable_current_sense) { if (chip->pdata->enable_current_sense) {
ret = max17042_read_reg(chip->client, MAX17042_Current); ret = regmap_read(map, MAX17042_Current, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret; val->intval = data;
if (val->intval & 0x8000) { if (val->intval & 0x8000) {
/* Negative */ /* Negative */
val->intval = ~val->intval & 0x7fff; val->intval = ~val->intval & 0x7fff;
...@@ -244,12 +219,11 @@ static int max17042_get_property(struct power_supply *psy, ...@@ -244,12 +219,11 @@ static int max17042_get_property(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_CURRENT_AVG: case POWER_SUPPLY_PROP_CURRENT_AVG:
if (chip->pdata->enable_current_sense) { if (chip->pdata->enable_current_sense) {
ret = max17042_read_reg(chip->client, ret = regmap_read(map, MAX17042_AvgCurrent, &data);
MAX17042_AvgCurrent);
if (ret < 0) if (ret < 0)
return ret; return ret;
val->intval = ret; val->intval = data;
if (val->intval & 0x8000) { if (val->intval & 0x8000) {
/* Negative */ /* Negative */
val->intval = ~val->intval & 0x7fff; val->intval = ~val->intval & 0x7fff;
...@@ -267,16 +241,15 @@ static int max17042_get_property(struct power_supply *psy, ...@@ -267,16 +241,15 @@ static int max17042_get_property(struct power_supply *psy,
return 0; return 0;
} }
static int max17042_write_verify_reg(struct i2c_client *client, static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value)
u8 reg, u16 value)
{ {
int retries = 8; int retries = 8;
int ret; int ret;
u16 read_value; u32 read_value;
do { do {
ret = i2c_smbus_write_word_data(client, reg, value); ret = regmap_write(map, reg, value);
read_value = max17042_read_reg(client, reg); regmap_read(map, reg, &read_value);
if (read_value != value) { if (read_value != value) {
ret = -EIO; ret = -EIO;
retries--; retries--;
...@@ -284,50 +257,51 @@ static int max17042_write_verify_reg(struct i2c_client *client, ...@@ -284,50 +257,51 @@ static int max17042_write_verify_reg(struct i2c_client *client,
} while (retries && read_value != value); } while (retries && read_value != value);
if (ret < 0) if (ret < 0)
dev_err(&client->dev, "%s: err %d\n", __func__, ret); pr_err("%s: err %d\n", __func__, ret);
return ret; return ret;
} }
static inline void max17042_override_por( static inline void max17042_override_por(struct regmap *map,
struct i2c_client *client, u8 reg, u16 value) u8 reg, u16 value)
{ {
if (value) if (value)
max17042_write_reg(client, reg, value); regmap_write(map, reg, value);
} }
static inline void max10742_unlock_model(struct max17042_chip *chip) static inline void max10742_unlock_model(struct max17042_chip *chip)
{ {
struct i2c_client *client = chip->client; struct regmap *map = chip->regmap;
max17042_write_reg(client, MAX17042_MLOCKReg1, MODEL_UNLOCK1); regmap_write(map, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
max17042_write_reg(client, MAX17042_MLOCKReg2, MODEL_UNLOCK2); regmap_write(map, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
} }
static inline void max10742_lock_model(struct max17042_chip *chip) static inline void max10742_lock_model(struct max17042_chip *chip)
{ {
struct i2c_client *client = chip->client; struct regmap *map = chip->regmap;
max17042_write_reg(client, MAX17042_MLOCKReg1, MODEL_LOCK1);
max17042_write_reg(client, MAX17042_MLOCKReg2, MODEL_LOCK2); regmap_write(map, MAX17042_MLOCKReg1, MODEL_LOCK1);
regmap_write(map, MAX17042_MLOCKReg2, MODEL_LOCK2);
} }
static inline void max17042_write_model_data(struct max17042_chip *chip, static inline void max17042_write_model_data(struct max17042_chip *chip,
u8 addr, int size) u8 addr, int size)
{ {
struct i2c_client *client = chip->client; struct regmap *map = chip->regmap;
int i; int i;
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
max17042_write_reg(client, addr + i, regmap_write(map, addr + i,
chip->pdata->config_data->cell_char_tbl[i]); chip->pdata->config_data->cell_char_tbl[i]);
} }
static inline void max17042_read_model_data(struct max17042_chip *chip, static inline void max17042_read_model_data(struct max17042_chip *chip,
u8 addr, u16 *data, int size) u8 addr, u32 *data, int size)
{ {
struct i2c_client *client = chip->client; struct regmap *map = chip->regmap;
int i; int i;
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
data[i] = max17042_read_reg(client, addr + i); regmap_read(map, addr + i, &data[i]);
} }
static inline int max17042_model_data_compare(struct max17042_chip *chip, static inline int max17042_model_data_compare(struct max17042_chip *chip,
...@@ -350,7 +324,7 @@ static int max17042_init_model(struct max17042_chip *chip) ...@@ -350,7 +324,7 @@ static int max17042_init_model(struct max17042_chip *chip)
{ {
int ret; int ret;
int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
u16 *temp_data; u32 *temp_data;
temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
if (!temp_data) if (!temp_data)
...@@ -365,7 +339,7 @@ static int max17042_init_model(struct max17042_chip *chip) ...@@ -365,7 +339,7 @@ static int max17042_init_model(struct max17042_chip *chip)
ret = max17042_model_data_compare( ret = max17042_model_data_compare(
chip, chip,
chip->pdata->config_data->cell_char_tbl, chip->pdata->config_data->cell_char_tbl,
temp_data, (u16 *)temp_data,
table_size); table_size);
max10742_lock_model(chip); max10742_lock_model(chip);
...@@ -378,7 +352,7 @@ static int max17042_verify_model_lock(struct max17042_chip *chip) ...@@ -378,7 +352,7 @@ static int max17042_verify_model_lock(struct max17042_chip *chip)
{ {
int i; int i;
int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
u16 *temp_data; u32 *temp_data;
int ret = 0; int ret = 0;
temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
...@@ -398,40 +372,38 @@ static int max17042_verify_model_lock(struct max17042_chip *chip) ...@@ -398,40 +372,38 @@ static int max17042_verify_model_lock(struct max17042_chip *chip)
static void max17042_write_config_regs(struct max17042_chip *chip) static void max17042_write_config_regs(struct max17042_chip *chip)
{ {
struct max17042_config_data *config = chip->pdata->config_data; struct max17042_config_data *config = chip->pdata->config_data;
struct regmap *map = chip->regmap;
max17042_write_reg(chip->client, MAX17042_CONFIG, config->config); regmap_write(map, MAX17042_CONFIG, config->config);
max17042_write_reg(chip->client, MAX17042_LearnCFG, config->learn_cfg); regmap_write(map, MAX17042_LearnCFG, config->learn_cfg);
max17042_write_reg(chip->client, MAX17042_FilterCFG, regmap_write(map, MAX17042_FilterCFG,
config->filter_cfg); config->filter_cfg);
max17042_write_reg(chip->client, MAX17042_RelaxCFG, config->relax_cfg); regmap_write(map, MAX17042_RelaxCFG, config->relax_cfg);
if (chip->chip_type == MAX17047) if (chip->chip_type == MAX17047)
max17042_write_reg(chip->client, MAX17047_FullSOCThr, regmap_write(map, MAX17047_FullSOCThr,
config->full_soc_thresh); config->full_soc_thresh);
} }
static void max17042_write_custom_regs(struct max17042_chip *chip) static void max17042_write_custom_regs(struct max17042_chip *chip)
{ {
struct max17042_config_data *config = chip->pdata->config_data; struct max17042_config_data *config = chip->pdata->config_data;
struct regmap *map = chip->regmap;
max17042_write_verify_reg(chip->client, MAX17042_RCOMP0, max17042_write_verify_reg(map, MAX17042_RCOMP0, config->rcomp0);
config->rcomp0); max17042_write_verify_reg(map, MAX17042_TempCo, config->tcompc0);
max17042_write_verify_reg(chip->client, MAX17042_TempCo, max17042_write_verify_reg(map, MAX17042_ICHGTerm, config->ichgt_term);
config->tcompc0);
max17042_write_verify_reg(chip->client, MAX17042_ICHGTerm,
config->ichgt_term);
if (chip->chip_type == MAX17042) { if (chip->chip_type == MAX17042) {
max17042_write_reg(chip->client, MAX17042_EmptyTempCo, regmap_write(map, MAX17042_EmptyTempCo, config->empty_tempco);
config->empty_tempco); max17042_write_verify_reg(map, MAX17042_K_empty0,
max17042_write_verify_reg(chip->client, MAX17042_K_empty0,
config->kempty0); config->kempty0);
} else { } else {
max17042_write_verify_reg(chip->client, MAX17047_QRTbl00, max17042_write_verify_reg(map, MAX17047_QRTbl00,
config->qrtbl00); config->qrtbl00);
max17042_write_verify_reg(chip->client, MAX17047_QRTbl10, max17042_write_verify_reg(map, MAX17047_QRTbl10,
config->qrtbl10); config->qrtbl10);
max17042_write_verify_reg(chip->client, MAX17047_QRTbl20, max17042_write_verify_reg(map, MAX17047_QRTbl20,
config->qrtbl20); config->qrtbl20);
max17042_write_verify_reg(chip->client, MAX17047_QRTbl30, max17042_write_verify_reg(map, MAX17047_QRTbl30,
config->qrtbl30); config->qrtbl30);
} }
} }
...@@ -439,58 +411,60 @@ static void max17042_write_custom_regs(struct max17042_chip *chip) ...@@ -439,58 +411,60 @@ static void max17042_write_custom_regs(struct max17042_chip *chip)
static void max17042_update_capacity_regs(struct max17042_chip *chip) static void max17042_update_capacity_regs(struct max17042_chip *chip)
{ {
struct max17042_config_data *config = chip->pdata->config_data; struct max17042_config_data *config = chip->pdata->config_data;
struct regmap *map = chip->regmap;
max17042_write_verify_reg(chip->client, MAX17042_FullCAP, max17042_write_verify_reg(map, MAX17042_FullCAP,
config->fullcap); config->fullcap);
max17042_write_reg(chip->client, MAX17042_DesignCap, regmap_write(map, MAX17042_DesignCap, config->design_cap);
config->design_cap); max17042_write_verify_reg(map, MAX17042_FullCAPNom,
max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom,
config->fullcapnom); config->fullcapnom);
} }
static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip) static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip)
{ {
u16 vfSoc; unsigned int vfSoc;
struct regmap *map = chip->regmap;
vfSoc = max17042_read_reg(chip->client, MAX17042_VFSOC); regmap_read(map, MAX17042_VFSOC, &vfSoc);
max17042_write_reg(chip->client, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK); regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK);
max17042_write_verify_reg(chip->client, MAX17042_VFSOC0, vfSoc); max17042_write_verify_reg(map, MAX17042_VFSOC0, vfSoc);
max17042_write_reg(chip->client, MAX17042_VFSOC0Enable, VFSOC0_LOCK); regmap_write(map, MAX17042_VFSOC0Enable, VFSOC0_LOCK);
} }
static void max17042_load_new_capacity_params(struct max17042_chip *chip) static void max17042_load_new_capacity_params(struct max17042_chip *chip)
{ {
u16 full_cap0, rep_cap, dq_acc, vfSoc; u32 full_cap0, rep_cap, dq_acc, vfSoc;
u32 rem_cap; u32 rem_cap;
struct max17042_config_data *config = chip->pdata->config_data; struct max17042_config_data *config = chip->pdata->config_data;
struct regmap *map = chip->regmap;
full_cap0 = max17042_read_reg(chip->client, MAX17042_FullCAP0); regmap_read(map, MAX17042_FullCAP0, &full_cap0);
vfSoc = max17042_read_reg(chip->client, MAX17042_VFSOC); regmap_read(map, MAX17042_VFSOC, &vfSoc);
/* fg_vfSoc needs to shifted by 8 bits to get the /* fg_vfSoc needs to shifted by 8 bits to get the
* perc in 1% accuracy, to get the right rem_cap multiply * perc in 1% accuracy, to get the right rem_cap multiply
* full_cap0, fg_vfSoc and devide by 100 * full_cap0, fg_vfSoc and devide by 100
*/ */
rem_cap = ((vfSoc >> 8) * full_cap0) / 100; rem_cap = ((vfSoc >> 8) * full_cap0) / 100;
max17042_write_verify_reg(chip->client, MAX17042_RemCap, (u16)rem_cap); max17042_write_verify_reg(map, MAX17042_RemCap, rem_cap);
rep_cap = (u16)rem_cap; rep_cap = rem_cap;
max17042_write_verify_reg(chip->client, MAX17042_RepCap, rep_cap); max17042_write_verify_reg(map, MAX17042_RepCap, rep_cap);
/* Write dQ_acc to 200% of Capacity and dP_acc to 200% */ /* Write dQ_acc to 200% of Capacity and dP_acc to 200% */
dq_acc = config->fullcap / dQ_ACC_DIV; dq_acc = config->fullcap / dQ_ACC_DIV;
max17042_write_verify_reg(chip->client, MAX17042_dQacc, dq_acc); max17042_write_verify_reg(map, MAX17042_dQacc, dq_acc);
max17042_write_verify_reg(chip->client, MAX17042_dPacc, dP_ACC_200); max17042_write_verify_reg(map, MAX17042_dPacc, dP_ACC_200);
max17042_write_verify_reg(chip->client, MAX17042_FullCAP, max17042_write_verify_reg(map, MAX17042_FullCAP,
config->fullcap); config->fullcap);
max17042_write_reg(chip->client, MAX17042_DesignCap, regmap_write(map, MAX17042_DesignCap,
config->design_cap); config->design_cap);
max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom, max17042_write_verify_reg(map, MAX17042_FullCAPNom,
config->fullcapnom); config->fullcapnom);
/* Update SOC register with new SOC */ /* Update SOC register with new SOC */
max17042_write_reg(chip->client, MAX17042_RepSOC, vfSoc); regmap_write(map, MAX17042_RepSOC, vfSoc);
} }
/* /*
...@@ -500,59 +474,60 @@ static void max17042_load_new_capacity_params(struct max17042_chip *chip) ...@@ -500,59 +474,60 @@ static void max17042_load_new_capacity_params(struct max17042_chip *chip)
*/ */
static inline void max17042_override_por_values(struct max17042_chip *chip) static inline void max17042_override_por_values(struct max17042_chip *chip)
{ {
struct i2c_client *client = chip->client; struct regmap *map = chip->regmap;
struct max17042_config_data *config = chip->pdata->config_data; struct max17042_config_data *config = chip->pdata->config_data;
max17042_override_por(client, MAX17042_TGAIN, config->tgain); max17042_override_por(map, MAX17042_TGAIN, config->tgain);
max17042_override_por(client, MAx17042_TOFF, config->toff); max17042_override_por(map, MAx17042_TOFF, config->toff);
max17042_override_por(client, MAX17042_CGAIN, config->cgain); max17042_override_por(map, MAX17042_CGAIN, config->cgain);
max17042_override_por(client, MAX17042_COFF, config->coff); max17042_override_por(map, MAX17042_COFF, config->coff);
max17042_override_por(client, MAX17042_VALRT_Th, config->valrt_thresh); max17042_override_por(map, MAX17042_VALRT_Th, config->valrt_thresh);
max17042_override_por(client, MAX17042_TALRT_Th, config->talrt_thresh); max17042_override_por(map, MAX17042_TALRT_Th, config->talrt_thresh);
max17042_override_por(client, MAX17042_SALRT_Th, max17042_override_por(map, MAX17042_SALRT_Th,
config->soc_alrt_thresh); config->soc_alrt_thresh);
max17042_override_por(client, MAX17042_CONFIG, config->config); max17042_override_por(map, MAX17042_CONFIG, config->config);
max17042_override_por(client, MAX17042_SHDNTIMER, config->shdntimer); max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer);
max17042_override_por(client, MAX17042_DesignCap, config->design_cap); max17042_override_por(map, MAX17042_DesignCap, config->design_cap);
max17042_override_por(client, MAX17042_ICHGTerm, config->ichgt_term); max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term);
max17042_override_por(client, MAX17042_AtRate, config->at_rate); max17042_override_por(map, MAX17042_AtRate, config->at_rate);
max17042_override_por(client, MAX17042_LearnCFG, config->learn_cfg); max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg);
max17042_override_por(client, MAX17042_FilterCFG, config->filter_cfg); max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg);
max17042_override_por(client, MAX17042_RelaxCFG, config->relax_cfg); max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg);
max17042_override_por(client, MAX17042_MiscCFG, config->misc_cfg); max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg);
max17042_override_por(client, MAX17042_MaskSOC, config->masksoc); max17042_override_por(map, MAX17042_MaskSOC, config->masksoc);
max17042_override_por(client, MAX17042_FullCAP, config->fullcap); max17042_override_por(map, MAX17042_FullCAP, config->fullcap);
max17042_override_por(client, MAX17042_FullCAPNom, config->fullcapnom); max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom);
if (chip->chip_type == MAX17042) if (chip->chip_type == MAX17042)
max17042_override_por(client, MAX17042_SOC_empty, max17042_override_por(map, MAX17042_SOC_empty,
config->socempty); config->socempty);
max17042_override_por(client, MAX17042_LAvg_empty, config->lavg_empty); max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty);
max17042_override_por(client, MAX17042_dQacc, config->dqacc); max17042_override_por(map, MAX17042_dQacc, config->dqacc);
max17042_override_por(client, MAX17042_dPacc, config->dpacc); max17042_override_por(map, MAX17042_dPacc, config->dpacc);
if (chip->chip_type == MAX17042) if (chip->chip_type == MAX17042)
max17042_override_por(client, MAX17042_V_empty, config->vempty); max17042_override_por(map, MAX17042_V_empty, config->vempty);
else else
max17042_override_por(client, MAX17047_V_empty, config->vempty); max17042_override_por(map, MAX17047_V_empty, config->vempty);
max17042_override_por(client, MAX17042_TempNom, config->temp_nom); max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
max17042_override_por(client, MAX17042_TempLim, config->temp_lim); max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
max17042_override_por(client, MAX17042_FCTC, config->fctc); max17042_override_por(map, MAX17042_FCTC, config->fctc);
max17042_override_por(client, MAX17042_RCOMP0, config->rcomp0); max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0);
max17042_override_por(client, MAX17042_TempCo, config->tcompc0); max17042_override_por(map, MAX17042_TempCo, config->tcompc0);
if (chip->chip_type) { if (chip->chip_type) {
max17042_override_por(client, MAX17042_EmptyTempCo, max17042_override_por(map, MAX17042_EmptyTempCo,
config->empty_tempco); config->empty_tempco);
max17042_override_por(client, MAX17042_K_empty0, max17042_override_por(map, MAX17042_K_empty0,
config->kempty0); config->kempty0);
} }
} }
static int max17042_init_chip(struct max17042_chip *chip) static int max17042_init_chip(struct max17042_chip *chip)
{ {
struct regmap *map = chip->regmap;
int ret; int ret;
int val; int val;
...@@ -597,31 +572,32 @@ static int max17042_init_chip(struct max17042_chip *chip) ...@@ -597,31 +572,32 @@ static int max17042_init_chip(struct max17042_chip *chip)
max17042_load_new_capacity_params(chip); max17042_load_new_capacity_params(chip);
/* Init complete, Clear the POR bit */ /* Init complete, Clear the POR bit */
val = max17042_read_reg(chip->client, MAX17042_STATUS); regmap_read(map, MAX17042_STATUS, &val);
max17042_write_reg(chip->client, MAX17042_STATUS, regmap_write(map, MAX17042_STATUS, val & (~STATUS_POR_BIT));
val & (~STATUS_POR_BIT));
return 0; return 0;
} }
static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off) static void max17042_set_soc_threshold(struct max17042_chip *chip, u16 off)
{ {
u16 soc, soc_tr; struct regmap *map = chip->regmap;
u32 soc, soc_tr;
/* program interrupt thesholds such that we should /* program interrupt thesholds such that we should
* get interrupt for every 'off' perc change in the soc * get interrupt for every 'off' perc change in the soc
*/ */
soc = max17042_read_reg(chip->client, MAX17042_RepSOC) >> 8; regmap_read(map, MAX17042_RepSOC, &soc);
soc >>= 8;
soc_tr = (soc + off) << 8; soc_tr = (soc + off) << 8;
soc_tr |= (soc - off); soc_tr |= (soc - off);
max17042_write_reg(chip->client, MAX17042_SALRT_Th, soc_tr); regmap_write(map, MAX17042_SALRT_Th, soc_tr);
} }
static irqreturn_t max17042_thread_handler(int id, void *dev) static irqreturn_t max17042_thread_handler(int id, void *dev)
{ {
struct max17042_chip *chip = dev; struct max17042_chip *chip = dev;
u16 val; u32 val;
val = max17042_read_reg(chip->client, MAX17042_STATUS); regmap_read(chip->regmap, MAX17042_STATUS, &val);
if ((val & STATUS_INTR_SOCMIN_BIT) || if ((val & STATUS_INTR_SOCMIN_BIT) ||
(val & STATUS_INTR_SOCMAX_BIT)) { (val & STATUS_INTR_SOCMAX_BIT)) {
dev_info(&chip->client->dev, "SOC threshold INTR\n"); dev_info(&chip->client->dev, "SOC threshold INTR\n");
...@@ -682,13 +658,20 @@ max17042_get_pdata(struct device *dev) ...@@ -682,13 +658,20 @@ max17042_get_pdata(struct device *dev)
} }
#endif #endif
static struct regmap_config max17042_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
};
static int max17042_probe(struct i2c_client *client, static int max17042_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct max17042_chip *chip; struct max17042_chip *chip;
int ret; int ret;
int reg; int i;
u32 val;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EIO; return -EIO;
...@@ -698,6 +681,12 @@ static int max17042_probe(struct i2c_client *client, ...@@ -698,6 +681,12 @@ static int max17042_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
chip->client = client; chip->client = client;
chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
if (IS_ERR(chip->regmap)) {
dev_err(&client->dev, "Failed to initialize regmap\n");
return -EINVAL;
}
chip->pdata = max17042_get_pdata(&client->dev); chip->pdata = max17042_get_pdata(&client->dev);
if (!chip->pdata) { if (!chip->pdata) {
dev_err(&client->dev, "no platform data provided\n"); dev_err(&client->dev, "no platform data provided\n");
...@@ -706,15 +695,15 @@ static int max17042_probe(struct i2c_client *client, ...@@ -706,15 +695,15 @@ static int max17042_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip); i2c_set_clientdata(client, chip);
ret = max17042_read_reg(chip->client, MAX17042_DevName); regmap_read(chip->regmap, MAX17042_DevName, &val);
if (ret == MAX17042_IC_VERSION) { if (val == MAX17042_IC_VERSION) {
dev_dbg(&client->dev, "chip type max17042 detected\n"); dev_dbg(&client->dev, "chip type max17042 detected\n");
chip->chip_type = MAX17042; chip->chip_type = MAX17042;
} else if (ret == MAX17047_IC_VERSION) { } else if (val == MAX17047_IC_VERSION) {
dev_dbg(&client->dev, "chip type max17047/50 detected\n"); dev_dbg(&client->dev, "chip type max17047/50 detected\n");
chip->chip_type = MAX17047; chip->chip_type = MAX17047;
} else { } else {
dev_err(&client->dev, "device version mismatch: %x\n", ret); dev_err(&client->dev, "device version mismatch: %x\n", val);
return -EIO; return -EIO;
} }
...@@ -733,13 +722,15 @@ static int max17042_probe(struct i2c_client *client, ...@@ -733,13 +722,15 @@ static int max17042_probe(struct i2c_client *client,
chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
if (chip->pdata->init_data) if (chip->pdata->init_data)
max17042_set_reg(client, chip->pdata->init_data, for (i = 0; i < chip->pdata->num_init_data; i++)
chip->pdata->num_init_data); regmap_write(chip->regmap,
chip->pdata->init_data[i].addr,
chip->pdata->init_data[i].data);
if (!chip->pdata->enable_current_sense) { if (!chip->pdata->enable_current_sense) {
max17042_write_reg(client, MAX17042_CGAIN, 0x0000); regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000);
max17042_write_reg(client, MAX17042_MiscCFG, 0x0003); regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003);
max17042_write_reg(client, MAX17042_LearnCFG, 0x0007); regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007);
} }
ret = power_supply_register(&client->dev, &chip->battery); ret = power_supply_register(&client->dev, &chip->battery);
...@@ -754,9 +745,9 @@ static int max17042_probe(struct i2c_client *client, ...@@ -754,9 +745,9 @@ static int max17042_probe(struct i2c_client *client,
IRQF_TRIGGER_FALLING, IRQF_TRIGGER_FALLING,
chip->battery.name, chip); chip->battery.name, chip);
if (!ret) { if (!ret) {
reg = max17042_read_reg(client, MAX17042_CONFIG); regmap_read(chip->regmap, MAX17042_CONFIG, &val);
reg |= CONFIG_ALRT_BIT_ENBL; val |= CONFIG_ALRT_BIT_ENBL;
max17042_write_reg(client, MAX17042_CONFIG, reg); regmap_write(chip->regmap, MAX17042_CONFIG, val);
max17042_set_soc_threshold(chip, 1); max17042_set_soc_threshold(chip, 1);
} else { } else {
client->irq = 0; client->irq = 0;
...@@ -765,8 +756,8 @@ static int max17042_probe(struct i2c_client *client, ...@@ -765,8 +756,8 @@ static int max17042_probe(struct i2c_client *client,
} }
} }
reg = max17042_read_reg(chip->client, MAX17042_STATUS); regmap_read(chip->regmap, MAX17042_STATUS, &val);
if (reg & STATUS_POR_BIT) { if (val & STATUS_POR_BIT) {
INIT_WORK(&chip->work, max17042_init_worker); INIT_WORK(&chip->work, max17042_init_worker);
schedule_work(&chip->work); schedule_work(&chip->work);
} else { } else {
...@@ -786,7 +777,7 @@ static int max17042_remove(struct i2c_client *client) ...@@ -786,7 +777,7 @@ static int max17042_remove(struct i2c_client *client)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int max17042_suspend(struct device *dev) static int max17042_suspend(struct device *dev)
{ {
struct max17042_chip *chip = dev_get_drvdata(dev); struct max17042_chip *chip = dev_get_drvdata(dev);
...@@ -816,17 +807,11 @@ static int max17042_resume(struct device *dev) ...@@ -816,17 +807,11 @@ static int max17042_resume(struct device *dev)
return 0; return 0;
} }
static const struct dev_pm_ops max17042_pm_ops = {
.suspend = max17042_suspend,
.resume = max17042_resume,
};
#define MAX17042_PM_OPS (&max17042_pm_ops)
#else
#define MAX17042_PM_OPS NULL
#endif #endif
static SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend,
max17042_resume);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id max17042_dt_match[] = { static const struct of_device_id max17042_dt_match[] = {
{ .compatible = "maxim,max17042" }, { .compatible = "maxim,max17042" },
...@@ -849,7 +834,7 @@ static struct i2c_driver max17042_i2c_driver = { ...@@ -849,7 +834,7 @@ static struct i2c_driver max17042_i2c_driver = {
.driver = { .driver = {
.name = "max17042", .name = "max17042",
.of_match_table = of_match_ptr(max17042_dt_match), .of_match_table = of_match_ptr(max17042_dt_match),
.pm = MAX17042_PM_OPS, .pm = &max17042_pm_ops,
}, },
.probe = max17042_probe, .probe = max17042_probe,
.remove = max17042_remove, .remove = max17042_remove,
......
...@@ -205,7 +205,7 @@ static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val) ...@@ -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); queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
...@@ -722,7 +722,11 @@ static int pm2xxx_charger_ac_en(struct ux500_charger *charger, ...@@ -722,7 +722,11 @@ static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset); dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
if (!pm2->vddadc_en_ac) { if (!pm2->vddadc_en_ac) {
regulator_enable(pm2->regu); ret = regulator_enable(pm2->regu);
if (ret)
dev_warn(pm2->dev,
"Failed to enable vddadc regulator\n");
else
pm2->vddadc_en_ac = true; pm2->vddadc_en_ac = true;
} }
...@@ -953,37 +957,24 @@ static int pm2xxx_runtime_suspend(struct device *dev) ...@@ -953,37 +957,24 @@ static int pm2xxx_runtime_suspend(struct device *dev)
{ {
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev); struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2; struct pm2xxx_charger *pm2;
int ret = 0;
pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client); 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); clear_lpn_pin(pm2);
return ret; return 0;
} }
static int pm2xxx_runtime_resume(struct device *dev) static int pm2xxx_runtime_resume(struct device *dev)
{ {
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev); struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2; struct pm2xxx_charger *pm2;
int ret = 0;
pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client); 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) if (gpio_is_valid(pm2->lpn_pin) && gpio_get_value(pm2->lpn_pin) == 0)
set_lpn_pin(pm2); set_lpn_pin(pm2);
return ret; return 0;
} }
#endif #endif
......
...@@ -15,15 +15,17 @@ ...@@ -15,15 +15,17 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/mfd/tps65090.h> #include <linux/mfd/tps65090.h>
#define TPS65090_REG_INTR_STS 0x00 #define TPS65090_REG_INTR_STS 0x00
...@@ -185,10 +187,6 @@ static irqreturn_t tps65090_charger_isr(int irq, void *dev_id) ...@@ -185,10 +187,6 @@ static irqreturn_t tps65090_charger_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#if defined(CONFIG_OF)
#include <linux/of_device.h>
static struct tps65090_platform_data * static struct tps65090_platform_data *
tps65090_parse_dt_charger_data(struct platform_device *pdev) tps65090_parse_dt_charger_data(struct platform_device *pdev)
{ {
...@@ -210,13 +208,6 @@ static struct tps65090_platform_data * ...@@ -210,13 +208,6 @@ static struct tps65090_platform_data *
return pdata; 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) static int tps65090_charger_probe(struct platform_device *pdev)
{ {
...@@ -228,7 +219,7 @@ 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); 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); pdata = tps65090_parse_dt_charger_data(pdev);
if (!pdata) { if (!pdata) {
...@@ -277,13 +268,13 @@ static int tps65090_charger_probe(struct platform_device *pdev) ...@@ -277,13 +268,13 @@ static int tps65090_charger_probe(struct platform_device *pdev)
if (ret) { if (ret) {
dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq, dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq,
ret); ret);
goto fail_free_irq; goto fail_unregister_supply;
} }
ret = tps65090_config_charger(cdata); ret = tps65090_config_charger(cdata);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "charger config failed, err %d\n", ret); dev_err(&pdev->dev, "charger config failed, err %d\n", ret);
goto fail_free_irq; goto fail_unregister_supply;
} }
/* Check for charger presence */ /* Check for charger presence */
...@@ -292,14 +283,14 @@ static int tps65090_charger_probe(struct platform_device *pdev) ...@@ -292,14 +283,14 @@ static int tps65090_charger_probe(struct platform_device *pdev)
if (ret < 0) { if (ret < 0) {
dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__, dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__,
TPS65090_REG_CG_STATUS1); TPS65090_REG_CG_STATUS1);
goto fail_free_irq; goto fail_unregister_supply;
} }
if (status1 != 0) { if (status1 != 0) {
ret = tps65090_enable_charging(cdata); ret = tps65090_enable_charging(cdata);
if (ret < 0) { if (ret < 0) {
dev_err(cdata->dev, "error enabling charger\n"); dev_err(cdata->dev, "error enabling charger\n");
goto fail_free_irq; goto fail_unregister_supply;
} }
cdata->ac_online = 1; cdata->ac_online = 1;
power_supply_changed(&cdata->ac); power_supply_changed(&cdata->ac);
...@@ -307,8 +298,6 @@ static int tps65090_charger_probe(struct platform_device *pdev) ...@@ -307,8 +298,6 @@ static int tps65090_charger_probe(struct platform_device *pdev)
return 0; return 0;
fail_free_irq:
devm_free_irq(cdata->dev, irq, cdata);
fail_unregister_supply: fail_unregister_supply:
power_supply_unregister(&cdata->ac); power_supply_unregister(&cdata->ac);
...@@ -319,7 +308,6 @@ static int tps65090_charger_remove(struct platform_device *pdev) ...@@ -319,7 +308,6 @@ static int tps65090_charger_remove(struct platform_device *pdev)
{ {
struct tps65090_charger *cdata = platform_get_drvdata(pdev); struct tps65090_charger *cdata = platform_get_drvdata(pdev);
devm_free_irq(cdata->dev, cdata->irq, cdata);
power_supply_unregister(&cdata->ac); power_supply_unregister(&cdata->ac);
return 0; return 0;
......
...@@ -495,10 +495,38 @@ static enum power_supply_property twl4030_charger_props[] = { ...@@ -495,10 +495,38 @@ static enum power_supply_property twl4030_charger_props[] = {
POWER_SUPPLY_PROP_CURRENT_NOW, 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) static int __init twl4030_bci_probe(struct platform_device *pdev)
{ {
struct twl4030_bci *bci; 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; int ret;
u32 reg; u32 reg;
...@@ -506,6 +534,9 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) ...@@ -506,6 +534,9 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
if (bci == NULL) if (bci == NULL)
return -ENOMEM; return -ENOMEM;
if (!pdata)
pdata = twl4030_bci_parse_dt(&pdev->dev);
bci->dev = &pdev->dev; bci->dev = &pdev->dev;
bci->irq_chg = platform_get_irq(pdev, 0); bci->irq_chg = platform_get_irq(pdev, 0);
bci->irq_bci = platform_get_irq(pdev, 1); bci->irq_bci = platform_get_irq(pdev, 1);
...@@ -581,8 +612,11 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) ...@@ -581,8 +612,11 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
twl4030_charger_enable_ac(true); twl4030_charger_enable_ac(true);
twl4030_charger_enable_usb(bci, true); twl4030_charger_enable_usb(bci, true);
if (pdata)
twl4030_charger_enable_backup(pdata->bb_uvolt, twl4030_charger_enable_backup(pdata->bb_uvolt,
pdata->bb_uamp); pdata->bb_uamp);
else
twl4030_charger_enable_backup(0, 0);
return 0; return 0;
...@@ -631,10 +665,17 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) ...@@ -631,10 +665,17 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
return 0; 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 = { static struct platform_driver twl4030_bci_driver = {
.driver = { .driver = {
.name = "twl4030_bci", .name = "twl4030_bci",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(twl_bci_of_match),
}, },
.remove = __exit_p(twl4030_bci_remove), .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%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment