dect
/
linux-2.6
Archived
13
0
Fork 0

Merge git://git.infradead.org/battery-2.6

* git://git.infradead.org/battery-2.6:
  gpio-charger: Fix checking return value of request_any_context_irq
  power_supply: MAX17042: Support additional properties
  max8903_charger: Allow platform data to be __initdata
  power_supply: Add charger driver for MAX8998/LP3974
  power_supply: Add charger driver for MAX8997/8966
  max17042_battery: Remove obsolete cleanup for clientdata
  twl4030_charger: Fix warnings
  wm831x_power: Support multiple instances
  wm831x_backup: Support multiple instances
  apm_power: Fix style error in macros
  s3c_adc_battery: Fix annotation for s3c_adc_battery_probe()
  bq20z75: Enable detection after registering
  bq20z75: Add support for external notification
This commit is contained in:
Linus Torvalds 2011-07-31 06:24:50 -10:00
commit f0d15c96d4
18 changed files with 806 additions and 103 deletions

View File

@ -39,6 +39,8 @@ static struct mfd_cell max8998_devs[] = {
.name = "max8998-pmic",
}, {
.name = "max8998-rtc",
}, {
.name = "max8998-battery",
},
};

View File

@ -235,4 +235,18 @@ config CHARGER_GPIO
This driver can be build as a module. If so, the module will be
called gpio-charger.
config CHARGER_MAX8997
tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
depends on MFD_MAX8997 && REGULATOR_MAX8997
help
Say Y to enable support for the battery charger control sysfs and
platform data of MAX8997/LP3974 PMICs.
config CHARGER_MAX8998
tristate "Maxim MAX8998/LP3974 PMIC battery charger driver"
depends on MFD_MAX8998 && REGULATOR_MAX8998
help
Say Y to enable support for the battery charger control sysfs and
platform data of MAX8998/LP3974 PMICs.
endif # POWER_SUPPLY

View File

@ -36,3 +36,5 @@ obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o

View File

@ -14,11 +14,11 @@
#include <linux/apm-emulation.h>
#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
POWER_SUPPLY_PROP_##prop, val)
#define PSY_PROP(psy, prop, val) (psy->get_property(psy, \
POWER_SUPPLY_PROP_##prop, val))
#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
prop, val)
#define _MPSY_PROP(prop, val) (main_battery->get_property(main_battery, \
prop, val))
#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)

View File

@ -152,6 +152,10 @@ struct bq20z75_info {
bool gpio_detect;
bool enable_detection;
int irq;
int last_state;
int poll_time;
struct delayed_work work;
int ignore_changes;
};
static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
@ -279,6 +283,7 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
int reg_offset, enum power_supply_property psp,
union power_supply_propval *val)
{
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
s32 ret;
ret = bq20z75_read_word_data(client,
@ -293,15 +298,24 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
if (ret >= bq20z75_data[reg_offset].min_value &&
ret <= bq20z75_data[reg_offset].max_value) {
val->intval = ret;
if (psp == POWER_SUPPLY_PROP_STATUS) {
if (ret & BATTERY_FULL_CHARGED)
val->intval = POWER_SUPPLY_STATUS_FULL;
else if (ret & BATTERY_FULL_DISCHARGED)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else if (ret & BATTERY_DISCHARGING)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else
val->intval = POWER_SUPPLY_STATUS_CHARGING;
if (psp != POWER_SUPPLY_PROP_STATUS)
return 0;
if (ret & BATTERY_FULL_CHARGED)
val->intval = POWER_SUPPLY_STATUS_FULL;
else if (ret & BATTERY_FULL_DISCHARGED)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else if (ret & BATTERY_DISCHARGING)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else
val->intval = POWER_SUPPLY_STATUS_CHARGING;
if (bq20z75_device->poll_time == 0)
bq20z75_device->last_state = val->intval;
else if (bq20z75_device->last_state != val->intval) {
cancel_delayed_work_sync(&bq20z75_device->work);
power_supply_changed(&bq20z75_device->power_supply);
bq20z75_device->poll_time = 0;
}
} else {
if (psp == POWER_SUPPLY_PROP_STATUS)
@ -545,6 +559,60 @@ static irqreturn_t bq20z75_irq(int irq, void *devid)
return IRQ_HANDLED;
}
static void bq20z75_external_power_changed(struct power_supply *psy)
{
struct bq20z75_info *bq20z75_device;
bq20z75_device = container_of(psy, struct bq20z75_info, power_supply);
if (bq20z75_device->ignore_changes > 0) {
bq20z75_device->ignore_changes--;
return;
}
/* cancel outstanding work */
cancel_delayed_work_sync(&bq20z75_device->work);
schedule_delayed_work(&bq20z75_device->work, HZ);
bq20z75_device->poll_time = bq20z75_device->pdata->poll_retry_count;
}
static void bq20z75_delayed_work(struct work_struct *work)
{
struct bq20z75_info *bq20z75_device;
s32 ret;
bq20z75_device = container_of(work, struct bq20z75_info, work.work);
ret = bq20z75_read_word_data(bq20z75_device->client,
bq20z75_data[REG_STATUS].addr);
/* if the read failed, give up on this work */
if (ret < 0) {
bq20z75_device->poll_time = 0;
return;
}
if (ret & BATTERY_FULL_CHARGED)
ret = POWER_SUPPLY_STATUS_FULL;
else if (ret & BATTERY_FULL_DISCHARGED)
ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
else if (ret & BATTERY_DISCHARGING)
ret = POWER_SUPPLY_STATUS_DISCHARGING;
else
ret = POWER_SUPPLY_STATUS_CHARGING;
if (bq20z75_device->last_state != ret) {
bq20z75_device->poll_time = 0;
power_supply_changed(&bq20z75_device->power_supply);
return;
}
if (bq20z75_device->poll_time > 0) {
schedule_delayed_work(&bq20z75_device->work, HZ);
bq20z75_device->poll_time--;
return;
}
}
static int __devinit bq20z75_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -566,6 +634,13 @@ static int __devinit bq20z75_probe(struct i2c_client *client,
bq20z75_device->power_supply.num_properties =
ARRAY_SIZE(bq20z75_properties);
bq20z75_device->power_supply.get_property = bq20z75_get_property;
/* ignore first notification of external change, it is generated
* from the power_supply_register call back
*/
bq20z75_device->ignore_changes = 1;
bq20z75_device->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
bq20z75_device->power_supply.external_power_changed =
bq20z75_external_power_changed;
if (pdata) {
bq20z75_device->gpio_detect =
@ -625,6 +700,10 @@ skip_gpio:
dev_info(&client->dev,
"%s: battery gas gauge device registered\n", client->name);
INIT_DELAYED_WORK(&bq20z75_device->work, bq20z75_delayed_work);
bq20z75_device->enable_detection = true;
return 0;
exit_psupply:
@ -648,6 +727,9 @@ static int __devexit bq20z75_remove(struct i2c_client *client)
gpio_free(bq20z75_device->pdata->battery_detect);
power_supply_unregister(&bq20z75_device->power_supply);
cancel_delayed_work_sync(&bq20z75_device->work);
kfree(bq20z75_device);
bq20z75_device = NULL;
@ -661,6 +743,9 @@ static int bq20z75_suspend(struct i2c_client *client,
struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
s32 ret;
if (bq20z75_device->poll_time > 0)
cancel_delayed_work_sync(&bq20z75_device->work);
/* write to manufacturer access with sleep command */
ret = bq20z75_write_word_data(client,
bq20z75_data[REG_MANUFACTURER_DATA].addr,

View File

@ -127,7 +127,7 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev)
ret = request_any_context_irq(irq, gpio_charger_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
dev_name(&pdev->dev), charger);
if (ret)
if (ret < 0)
dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
else
gpio_charger->irq = irq;

View File

@ -29,74 +29,6 @@
#include <linux/power_supply.h>
#include <linux/power/max17042_battery.h>
enum max17042_register {
MAX17042_STATUS = 0x00,
MAX17042_VALRT_Th = 0x01,
MAX17042_TALRT_Th = 0x02,
MAX17042_SALRT_Th = 0x03,
MAX17042_AtRate = 0x04,
MAX17042_RepCap = 0x05,
MAX17042_RepSOC = 0x06,
MAX17042_Age = 0x07,
MAX17042_TEMP = 0x08,
MAX17042_VCELL = 0x09,
MAX17042_Current = 0x0A,
MAX17042_AvgCurrent = 0x0B,
MAX17042_Qresidual = 0x0C,
MAX17042_SOC = 0x0D,
MAX17042_AvSOC = 0x0E,
MAX17042_RemCap = 0x0F,
MAX17402_FullCAP = 0x10,
MAX17042_TTE = 0x11,
MAX17042_V_empty = 0x12,
MAX17042_RSLOW = 0x14,
MAX17042_AvgTA = 0x16,
MAX17042_Cycles = 0x17,
MAX17042_DesignCap = 0x18,
MAX17042_AvgVCELL = 0x19,
MAX17042_MinMaxTemp = 0x1A,
MAX17042_MinMaxVolt = 0x1B,
MAX17042_MinMaxCurr = 0x1C,
MAX17042_CONFIG = 0x1D,
MAX17042_ICHGTerm = 0x1E,
MAX17042_AvCap = 0x1F,
MAX17042_ManName = 0x20,
MAX17042_DevName = 0x21,
MAX17042_DevChem = 0x22,
MAX17042_TempNom = 0x24,
MAX17042_TempCold = 0x25,
MAX17042_TempHot = 0x26,
MAX17042_AIN = 0x27,
MAX17042_LearnCFG = 0x28,
MAX17042_SHFTCFG = 0x29,
MAX17042_RelaxCFG = 0x2A,
MAX17042_MiscCFG = 0x2B,
MAX17042_TGAIN = 0x2C,
MAx17042_TOFF = 0x2D,
MAX17042_CGAIN = 0x2E,
MAX17042_COFF = 0x2F,
MAX17042_Q_empty = 0x33,
MAX17042_T_empty = 0x34,
MAX17042_RCOMP0 = 0x38,
MAX17042_TempCo = 0x39,
MAX17042_Rx = 0x3A,
MAX17042_T_empty0 = 0x3B,
MAX17042_TaskPeriod = 0x3C,
MAX17042_FSTAT = 0x3D,
MAX17042_SHDNTIMER = 0x3F,
MAX17042_VFRemCap = 0x4A,
MAX17042_QH = 0x4D,
MAX17042_QL = 0x4E,
};
struct max17042_chip {
struct i2c_client *client;
struct power_supply battery;
@ -123,10 +55,27 @@ static int max17042_read_reg(struct i2c_client *client, u8 reg)
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[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
};
static int max17042_get_property(struct power_supply *psy,
@ -137,6 +86,30 @@ static int max17042_get_property(struct power_supply *psy,
struct max17042_chip, battery);
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
val->intval = max17042_read_reg(chip->client,
MAX17042_STATUS);
if (val->intval & MAX17042_STATUS_BattAbsent)
val->intval = 0;
else
val->intval = 1;
break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
val->intval = max17042_read_reg(chip->client,
MAX17042_Cycles);
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
val->intval = max17042_read_reg(chip->client,
MAX17042_MinMaxVolt);
val->intval >>= 8;
val->intval *= 20000; /* Units of LSB = 20mV */
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
val->intval = max17042_read_reg(chip->client,
MAX17042_V_empty);
val->intval >>= 7;
val->intval *= 10000; /* Units of LSB = 10mV */
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = max17042_read_reg(chip->client,
MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
@ -149,6 +122,57 @@ static int max17042_get_property(struct power_supply *psy,
val->intval = max17042_read_reg(chip->client,
MAX17042_SOC) / 256;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
val->intval = max17042_read_reg(chip->client,
MAX17042_RepSOC);
if ((val->intval / 256) >= MAX17042_BATTERY_FULL)
val->intval = 1;
else if (val->intval >= 0)
val->intval = 0;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = max17042_read_reg(chip->client,
MAX17042_TEMP);
/* The value is signed. */
if (val->intval & 0x8000) {
val->intval = (0x7fff & ~val->intval) + 1;
val->intval *= -1;
}
/* The value is converted into deci-centigrade scale */
/* Units of LSB = 1 / 256 degree Celsius */
val->intval = val->intval * 10 / 256;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
if (chip->pdata->enable_current_sense) {
val->intval = max17042_read_reg(chip->client,
MAX17042_Current);
if (val->intval & 0x8000) {
/* Negative */
val->intval = ~val->intval & 0x7fff;
val->intval++;
val->intval *= -1;
}
val->intval >>= 4;
val->intval *= 1000000 * 25 / chip->pdata->r_sns;
} else {
return -EINVAL;
}
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
if (chip->pdata->enable_current_sense) {
val->intval = max17042_read_reg(chip->client,
MAX17042_AvgCurrent);
if (val->intval & 0x8000) {
/* Negative */
val->intval = ~val->intval & 0x7fff;
val->intval++;
val->intval *= -1;
}
val->intval *= 1562500 / chip->pdata->r_sns;
} else {
return -EINVAL;
}
break;
default:
return -EINVAL;
}
@ -180,18 +204,30 @@ static int __devinit max17042_probe(struct i2c_client *client,
chip->battery.properties = max17042_battery_props;
chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props);
/* When current is not measured,
* CURRENT_NOW and CURRENT_AVG properties should be invisible. */
if (!chip->pdata->enable_current_sense)
chip->battery.num_properties -= 2;
ret = power_supply_register(&client->dev, &chip->battery);
if (ret) {
dev_err(&client->dev, "failed: power supply register\n");
i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
}
/* Initialize registers according to values from the platform data */
if (chip->pdata->init_data)
max17042_set_reg(client, chip->pdata->init_data,
chip->pdata->num_init_data);
if (!chip->pdata->enable_current_sense) {
max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
} else {
if (chip->pdata->r_sns == 0)
chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
}
return 0;
@ -202,7 +238,6 @@ static int __devexit max17042_remove(struct i2c_client *client)
struct max17042_chip *chip = i2c_get_clientdata(client);
power_supply_unregister(&chip->battery);
i2c_set_clientdata(client, NULL);
kfree(chip);
return 0;
}

View File

@ -28,7 +28,7 @@
#include <linux/power/max8903_charger.h>
struct max8903_data {
struct max8903_pdata *pdata;
struct max8903_pdata pdata;
struct device *dev;
struct power_supply psy;
bool fault;
@ -52,8 +52,8 @@ static int max8903_get_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
if (data->pdata->chg) {
if (gpio_get_value(data->pdata->chg) == 0)
if (data->pdata.chg) {
if (gpio_get_value(data->pdata.chg) == 0)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (data->usb_in || data->ta_in)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@ -80,7 +80,7 @@ static int max8903_get_property(struct power_supply *psy,
static irqreturn_t max8903_dcin(int irq, void *_data)
{
struct max8903_data *data = _data;
struct max8903_pdata *pdata = data->pdata;
struct max8903_pdata *pdata = &data->pdata;
bool ta_in;
enum power_supply_type old_type;
@ -121,7 +121,7 @@ static irqreturn_t max8903_dcin(int irq, void *_data)
static irqreturn_t max8903_usbin(int irq, void *_data)
{
struct max8903_data *data = _data;
struct max8903_pdata *pdata = data->pdata;
struct max8903_pdata *pdata = &data->pdata;
bool usb_in;
enum power_supply_type old_type;
@ -160,7 +160,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data)
static irqreturn_t max8903_fault(int irq, void *_data)
{
struct max8903_data *data = _data;
struct max8903_pdata *pdata = data->pdata;
struct max8903_pdata *pdata = &data->pdata;
bool fault;
fault = gpio_get_value(pdata->flt) ? false : true;
@ -193,7 +193,7 @@ static __devinit int max8903_probe(struct platform_device *pdev)
dev_err(dev, "Cannot allocate memory.\n");
return -ENOMEM;
}
data->pdata = pdata;
memcpy(&data->pdata, pdata, sizeof(struct max8903_pdata));
data->dev = dev;
platform_set_drvdata(pdev, data);
@ -349,7 +349,7 @@ static __devexit int max8903_remove(struct platform_device *pdev)
struct max8903_data *data = platform_get_drvdata(pdev);
if (data) {
struct max8903_pdata *pdata = data->pdata;
struct max8903_pdata *pdata = &data->pdata;
if (pdata->flt)
free_irq(gpio_to_irq(pdata->flt), data);

View File

@ -0,0 +1,206 @@
/*
* max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.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
* 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
*/
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
struct charger_data {
struct device *dev;
struct max8997_dev *iodev;
struct power_supply battery;
};
static enum power_supply_property max8997_battery_props[] = {
POWER_SUPPLY_PROP_STATUS, /* "FULL" or "NOT FULL" only. */
POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
};
/* Note that the charger control is done by a current regulator "CHARGER" */
static int max8997_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct charger_data *charger = container_of(psy,
struct charger_data, battery);
struct i2c_client *i2c = charger->iodev->i2c;
int ret;
u8 reg;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = 0;
ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
if (ret)
return ret;
if ((reg & (1 << 0)) == 0x1)
val->intval = POWER_SUPPLY_STATUS_FULL;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 0;
ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
if (ret)
return ret;
if ((reg & (1 << 2)) == 0x0)
val->intval = 1;
break;
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
if (ret)
return ret;
/* DCINOK */
if (reg & (1 << 1))
val->intval = 1;
break;
default:
return -EINVAL;
}
return 0;
}
static __devinit int max8997_battery_probe(struct platform_device *pdev)
{
int ret = 0;
struct charger_data *charger;
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
if (!pdata)
return -EINVAL;
if (pdata->eoc_mA) {
u8 val = (pdata->eoc_mA - 50) / 10;
if (val < 0)
val = 0;
if (val > 0xf)
val = 0xf;
ret = max8997_update_reg(iodev->i2c,
MAX8997_REG_MBCCTRL5, val, 0xf);
if (ret < 0) {
dev_err(&pdev->dev, "Cannot use i2c bus.\n");
return ret;
}
}
switch (pdata->timeout) {
case 5:
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
0x2 << 4, 0x7 << 4);
break;
case 6:
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
0x3 << 4, 0x7 << 4);
break;
case 7:
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
0x4 << 4, 0x7 << 4);
break;
case 0:
ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
0x7 << 4, 0x7 << 4);
break;
default:
dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
pdata->timeout);
return -EINVAL;
}
if (ret < 0) {
dev_err(&pdev->dev, "Cannot use i2c bus.\n");
return ret;
}
charger = kzalloc(sizeof(struct charger_data), GFP_KERNEL);
if (charger == NULL) {
dev_err(&pdev->dev, "Cannot allocate memory.\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, charger);
charger->battery.name = "max8997_pmic";
charger->battery.type = POWER_SUPPLY_TYPE_BATTERY;
charger->battery.get_property = max8997_battery_get_property;
charger->battery.properties = max8997_battery_props;
charger->battery.num_properties = ARRAY_SIZE(max8997_battery_props);
charger->dev = &pdev->dev;
charger->iodev = iodev;
ret = power_supply_register(&pdev->dev, &charger->battery);
if (ret) {
dev_err(&pdev->dev, "failed: power supply register\n");
goto err;
}
return 0;
err:
kfree(charger);
return ret;
}
static int __devexit max8997_battery_remove(struct platform_device *pdev)
{
struct charger_data *charger = platform_get_drvdata(pdev);
power_supply_unregister(&charger->battery);
kfree(charger);
return 0;
}
static const struct platform_device_id max8997_battery_id[] = {
{ "max8997-battery", 0 },
};
static struct platform_driver max8997_battery_driver = {
.driver = {
.name = "max8997-battery",
.owner = THIS_MODULE,
},
.probe = max8997_battery_probe,
.remove = __devexit_p(max8997_battery_remove),
.id_table = max8997_battery_id,
};
static int __init max8997_battery_init(void)
{
return platform_driver_register(&max8997_battery_driver);
}
subsys_initcall(max8997_battery_init);
static void __exit max8997_battery_cleanup(void)
{
platform_driver_unregister(&max8997_battery_driver);
}
module_exit(max8997_battery_cleanup);
MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,218 @@
/*
* max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974
*
* Copyright (C) 2009-2010 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.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
* 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
*/
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/mfd/max8998.h>
#include <linux/mfd/max8998-private.h>
struct max8998_battery_data {
struct device *dev;
struct max8998_dev *iodev;
struct power_supply battery;
};
static enum power_supply_property max8998_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
};
/* Note that the charger control is done by a current regulator "CHARGER" */
static int max8998_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct max8998_battery_data *max8998 = container_of(psy,
struct max8998_battery_data, battery);
struct i2c_client *i2c = max8998->iodev->i2c;
int ret;
u8 reg;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, &reg);
if (ret)
return ret;
if (reg & (1 << 4))
val->intval = 0;
else
val->intval = 1;
break;
case POWER_SUPPLY_PROP_ONLINE:
ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, &reg);
if (ret)
return ret;
if (reg & (1 << 3))
val->intval = 0;
else
val->intval = 1;
break;
default:
return -EINVAL;
}
return 0;
}
static __devinit int max8998_battery_probe(struct platform_device *pdev)
{
struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
struct max8998_battery_data *max8998;
struct i2c_client *i2c;
int ret = 0;
if (!pdata) {
dev_err(pdev->dev.parent, "No platform init data supplied\n");
return -ENODEV;
}
max8998 = kzalloc(sizeof(struct max8998_battery_data), GFP_KERNEL);
if (!max8998)
return -ENOMEM;
max8998->dev = &pdev->dev;
max8998->iodev = iodev;
platform_set_drvdata(pdev, max8998);
i2c = max8998->iodev->i2c;
/* Setup "End of Charge" */
/* If EOC value equals 0,
* remain value set from bootloader or default value */
if (pdata->eoc >= 10 && pdata->eoc <= 45) {
max8998_update_reg(i2c, MAX8998_REG_CHGR1,
(pdata->eoc / 5 - 2) << 5, 0x7 << 5);
} else if (pdata->eoc == 0) {
dev_dbg(max8998->dev,
"EOC value not set: leave it unchanged.\n");
} else {
dev_err(max8998->dev, "Invalid EOC value\n");
ret = -EINVAL;
goto err;
}
/* Setup Charge Restart Level */
switch (pdata->restart) {
case 100:
max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x1 << 3, 0x3 << 3);
break;
case 150:
max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x0 << 3, 0x3 << 3);
break;
case 200:
max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x2 << 3, 0x3 << 3);
break;
case -1:
max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x3 << 3, 0x3 << 3);
break;
case 0:
dev_dbg(max8998->dev,
"Restart Level not set: leave it unchanged.\n");
break;
default:
dev_err(max8998->dev, "Invalid Restart Level\n");
ret = -EINVAL;
goto err;
}
/* Setup Charge Full Timeout */
switch (pdata->timeout) {
case 5:
max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x0 << 4, 0x3 << 4);
break;
case 6:
max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x1 << 4, 0x3 << 4);
break;
case 7:
max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x2 << 4, 0x3 << 4);
break;
case -1:
max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x3 << 4, 0x3 << 4);
break;
case 0:
dev_dbg(max8998->dev,
"Full Timeout not set: leave it unchanged.\n");
default:
dev_err(max8998->dev, "Invalid Full Timeout value\n");
ret = -EINVAL;
goto err;
}
max8998->battery.name = "max8998_pmic";
max8998->battery.type = POWER_SUPPLY_TYPE_BATTERY;
max8998->battery.get_property = max8998_battery_get_property;
max8998->battery.properties = max8998_battery_props;
max8998->battery.num_properties = ARRAY_SIZE(max8998_battery_props);
ret = power_supply_register(max8998->dev, &max8998->battery);
if (ret) {
dev_err(max8998->dev, "failed: power supply register\n");
goto err;
}
return 0;
err:
kfree(max8998);
return ret;
}
static int __devexit max8998_battery_remove(struct platform_device *pdev)
{
struct max8998_battery_data *max8998 = platform_get_drvdata(pdev);
power_supply_unregister(&max8998->battery);
kfree(max8998);
return 0;
}
static const struct platform_device_id max8998_battery_id[] = {
{ "max8998-battery", TYPE_MAX8998 },
};
static struct platform_driver max8998_battery_driver = {
.driver = {
.name = "max8998-battery",
.owner = THIS_MODULE,
},
.probe = max8998_battery_probe,
.remove = __devexit_p(max8998_battery_remove),
.id_table = max8998_battery_id,
};
static int __init max8998_battery_init(void)
{
return platform_driver_register(&max8998_battery_driver);
}
module_init(max8998_battery_init);
static void __exit max8998_battery_cleanup(void)
{
platform_driver_unregister(&max8998_battery_driver);
}
module_exit(max8998_battery_cleanup);
MODULE_DESCRIPTION("MAXIM 8998 battery control driver");
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:max8998-battery");

View File

@ -266,7 +266,7 @@ static irqreturn_t s3c_adc_bat_charged(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int __init s3c_adc_bat_probe(struct platform_device *pdev)
static int __devinit s3c_adc_bat_probe(struct platform_device *pdev)
{
struct s3c_adc_client *client;
struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;

View File

@ -62,7 +62,7 @@
#define TWL4030_MSTATEC_COMPLETE4 0x0e
static bool allow_usb;
module_param(allow_usb, bool, 1);
module_param(allow_usb, bool, 0644);
MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
struct twl4030_bci {
@ -425,7 +425,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
{
struct twl4030_bci *bci;
int ret;
int reg;
u32 reg;
bci = kzalloc(sizeof(*bci), GFP_KERNEL);
if (bci == NULL)
@ -486,7 +486,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
}
/* Enable interrupts now. */
reg = ~(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
TWL4030_TBATOR1 | TWL4030_BATSTS);
ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
TWL4030_INTERRUPTS_BCIIMR1A);
@ -495,7 +495,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
goto fail_unmask_interrupts;
}
reg = ~(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
TWL4030_INTERRUPTS_BCIIMR2A);
if (ret < 0)
@ -572,7 +572,7 @@ static void __exit twl4030_bci_exit(void)
}
module_exit(twl4030_bci_exit);
MODULE_AUTHOR("Gražydas Ignotas");
MODULE_AUTHOR("Gražvydas Ignotas");
MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:twl4030_bci");

View File

@ -22,6 +22,7 @@
struct wm831x_backup {
struct wm831x *wm831x;
struct power_supply backup;
char name[20];
};
static int wm831x_backup_read_voltage(struct wm831x *wm831x,
@ -163,6 +164,7 @@ static enum power_supply_property wm831x_backup_props[] = {
static __devinit int wm831x_backup_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
struct wm831x_backup *devdata;
struct power_supply *backup;
int ret;
@ -182,7 +184,14 @@ static __devinit int wm831x_backup_probe(struct platform_device *pdev)
*/
wm831x_config_backup(wm831x);
backup->name = "wm831x-backup";
if (wm831x_pdata && wm831x_pdata->wm831x_num)
snprintf(devdata->name, sizeof(devdata->name),
"wm831x-backup.%d", wm831x_pdata->wm831x_num);
else
snprintf(devdata->name, sizeof(devdata->name),
"wm831x-backup");
backup->name = devdata->name;
backup->type = POWER_SUPPLY_TYPE_BATTERY;
backup->properties = wm831x_backup_props;
backup->num_properties = ARRAY_SIZE(wm831x_backup_props);
@ -203,6 +212,7 @@ static __devexit int wm831x_backup_remove(struct platform_device *pdev)
struct wm831x_backup *devdata = platform_get_drvdata(pdev);
power_supply_unregister(&devdata->backup);
kfree(devdata->backup.name);
kfree(devdata);
return 0;

View File

@ -24,6 +24,9 @@ struct wm831x_power {
struct power_supply wall;
struct power_supply usb;
struct power_supply battery;
char wall_name[20];
char usb_name[20];
char battery_name[20];
};
static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
@ -486,6 +489,7 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
static __devinit int wm831x_power_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
struct wm831x_power *power;
struct power_supply *usb;
struct power_supply *battery;
@ -503,12 +507,28 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
battery = &power->battery;
wall = &power->wall;
if (wm831x_pdata && wm831x_pdata->wm831x_num) {
snprintf(power->wall_name, sizeof(power->wall_name),
"wm831x-wall.%d", wm831x_pdata->wm831x_num);
snprintf(power->battery_name, sizeof(power->wall_name),
"wm831x-battery.%d", wm831x_pdata->wm831x_num);
snprintf(power->usb_name, sizeof(power->wall_name),
"wm831x-usb.%d", wm831x_pdata->wm831x_num);
} else {
snprintf(power->wall_name, sizeof(power->wall_name),
"wm831x-wall");
snprintf(power->battery_name, sizeof(power->wall_name),
"wm831x-battery");
snprintf(power->usb_name, sizeof(power->wall_name),
"wm831x-usb");
}
/* We ignore configuration failures since we can still read back
* the status without enabling the charger.
*/
wm831x_config_battery(wm831x);
wall->name = "wm831x-wall";
wall->name = power->wall_name;
wall->type = POWER_SUPPLY_TYPE_MAINS;
wall->properties = wm831x_wall_props;
wall->num_properties = ARRAY_SIZE(wm831x_wall_props);
@ -517,7 +537,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
if (ret)
goto err_kmalloc;
battery->name = "wm831x-battery";
battery->name = power->battery_name;
battery->properties = wm831x_bat_props;
battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
battery->get_property = wm831x_bat_get_prop;
@ -526,7 +546,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
if (ret)
goto err_wall;
usb->name = "wm831x-usb",
usb->name = power->usb_name,
usb->type = POWER_SUPPLY_TYPE_USB;
usb->properties = wm831x_usb_props;
usb->num_properties = ARRAY_SIZE(wm831x_usb_props);

View File

@ -107,11 +107,16 @@ struct max8997_platform_data {
unsigned int buck5_voltage[8];
bool buck5_gpiodvs;
/* ---- Charger control ---- */
/* eoc stands for 'end of charge' */
int eoc_mA; /* 50 ~ 200mA by 10mA step */
/* charge Full Timeout */
int timeout; /* 0 (no timeout), 5, 6, 7 hours */
/* MUIC: Not implemented */
/* HAPTIC: Not implemented */
/* RTC: Not implemented */
/* Flash: Not implemented */
/* Charger control: Not implemented */
};
#endif /* __LINUX_MFD_MAX8998_H */

View File

@ -87,6 +87,15 @@ struct max8998_regulator_data {
* @wakeup: Allow to wake up from suspend
* @rtc_delay: LP3974 RTC chip bug that requires delay after a register
* write before reading it.
* @eoc: End of Charge Level in percent: 10% ~ 45% by 5% step
* If it equals 0, leave it unchanged.
* Otherwise, it is a invalid value.
* @restart: Restart Level in mV: 100, 150, 200, and -1 for disable.
* If it equals 0, leave it unchanged.
* Otherwise, it is a invalid value.
* @timeout: Full Timeout in hours: 5, 6, 7, and -1 for disable.
* If it equals 0, leave it unchanged.
* Otherwise, leave it unchanged.
*/
struct max8998_platform_data {
struct max8998_regulator_data *regulators;
@ -107,6 +116,9 @@ struct max8998_platform_data {
int buck2_default_idx;
bool wakeup;
bool rtc_delay;
int eoc;
int restart;
int timeout;
};
#endif /* __LINUX_MFD_MAX8998_H */

View File

@ -29,11 +29,14 @@
* @battery_detect: GPIO which is used to detect battery presence
* @battery_detect_present: gpio state when battery is present (0 / 1)
* @i2c_retry_count: # of times to retry on i2c IO failure
* @poll_retry_count: # of times to retry looking for new status after
* external change notification
*/
struct bq20z75_platform_data {
int battery_detect;
int battery_detect_present;
int i2c_retry_count;
int poll_retry_count;
};
#endif

View File

@ -23,8 +23,99 @@
#ifndef __MAX17042_BATTERY_H_
#define __MAX17042_BATTERY_H_
#define MAX17042_STATUS_BattAbsent (1 << 3)
#define MAX17042_BATTERY_FULL (100)
#define MAX17042_DEFAULT_SNS_RESISTOR (10000)
enum max17042_register {
MAX17042_STATUS = 0x00,
MAX17042_VALRT_Th = 0x01,
MAX17042_TALRT_Th = 0x02,
MAX17042_SALRT_Th = 0x03,
MAX17042_AtRate = 0x04,
MAX17042_RepCap = 0x05,
MAX17042_RepSOC = 0x06,
MAX17042_Age = 0x07,
MAX17042_TEMP = 0x08,
MAX17042_VCELL = 0x09,
MAX17042_Current = 0x0A,
MAX17042_AvgCurrent = 0x0B,
MAX17042_Qresidual = 0x0C,
MAX17042_SOC = 0x0D,
MAX17042_AvSOC = 0x0E,
MAX17042_RemCap = 0x0F,
MAX17402_FullCAP = 0x10,
MAX17042_TTE = 0x11,
MAX17042_V_empty = 0x12,
MAX17042_RSLOW = 0x14,
MAX17042_AvgTA = 0x16,
MAX17042_Cycles = 0x17,
MAX17042_DesignCap = 0x18,
MAX17042_AvgVCELL = 0x19,
MAX17042_MinMaxTemp = 0x1A,
MAX17042_MinMaxVolt = 0x1B,
MAX17042_MinMaxCurr = 0x1C,
MAX17042_CONFIG = 0x1D,
MAX17042_ICHGTerm = 0x1E,
MAX17042_AvCap = 0x1F,
MAX17042_ManName = 0x20,
MAX17042_DevName = 0x21,
MAX17042_DevChem = 0x22,
MAX17042_TempNom = 0x24,
MAX17042_TempCold = 0x25,
MAX17042_TempHot = 0x26,
MAX17042_AIN = 0x27,
MAX17042_LearnCFG = 0x28,
MAX17042_SHFTCFG = 0x29,
MAX17042_RelaxCFG = 0x2A,
MAX17042_MiscCFG = 0x2B,
MAX17042_TGAIN = 0x2C,
MAx17042_TOFF = 0x2D,
MAX17042_CGAIN = 0x2E,
MAX17042_COFF = 0x2F,
MAX17042_Q_empty = 0x33,
MAX17042_T_empty = 0x34,
MAX17042_RCOMP0 = 0x38,
MAX17042_TempCo = 0x39,
MAX17042_Rx = 0x3A,
MAX17042_T_empty0 = 0x3B,
MAX17042_TaskPeriod = 0x3C,
MAX17042_FSTAT = 0x3D,
MAX17042_SHDNTIMER = 0x3F,
MAX17042_VFRemCap = 0x4A,
MAX17042_QH = 0x4D,
MAX17042_QL = 0x4E,
};
/*
* used for setting a register to a desired value
* addr : address for a register
* data : setting value for the register
*/
struct max17042_reg_data {
u8 addr;
u16 data;
};
struct max17042_platform_data {
struct max17042_reg_data *init_data;
int num_init_data; /* Number of enties in init_data array */
bool enable_current_sense;
/*
* R_sns in micro-ohms.
* default 10000 (if r_sns = 0) as it is the recommended value by
* the datasheet although it can be changed by board designers.
*/
unsigned int r_sns;
};
#endif /* __MAX17042_BATTERY_H_ */