Commit 56a9ccb7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.infradead.org/battery-2.6: (30 commits)
  bq20z75: Fix time and temp units
  bq20z75: Fix issues with present and suspend
  z2_battery: Fix count of properties
  s3c_adc_battery: Fix method names when PM not set
  z2_battery: Add MODULE_DEVICE_TABLE
  ds2782_battery: Add MODULE_DEVICE_TABLE
  bq20z75: Add MODULE_DEVICE_TABLE
  power_supply: Update power_supply_is_watt_property
  bq20z75: Add i2c retry mechanism
  bq20z75: Add optional battery detect gpio
  twl4030_charger: Make the driver atomic notifier safe
  bq27x00: Use single i2c_transfer call for property read
  bq27x00: Cleanup bq27x00_i2c_read
  bq27x00: Minor cleanups
  bq27x00: Give more specific reports on battery status
  bq27x00: Add MODULE_DEVICE_TABLE
  bq27x00: Add new properties
  bq27x00: Poll battery state
  bq27x00: Cache battery registers
  bq27x00: Add bq27000 support
  ...
parents 44bbd7ac 909a78b3
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -231,6 +231,26 @@ void led_trigger_event(struct led_trigger *trigger,
}
EXPORT_SYMBOL_GPL(led_trigger_event);

void led_trigger_blink(struct led_trigger *trigger,
		       unsigned long *delay_on,
		       unsigned long *delay_off)
{
	struct list_head *entry;

	if (!trigger)
		return;

	read_lock(&trigger->leddev_list_lock);
	list_for_each(entry, &trigger->led_cdevs) {
		struct led_classdev *led_cdev;

		led_cdev = list_entry(entry, struct led_classdev, trig_list);
		led_blink_set(led_cdev, delay_on, delay_off);
	}
	read_unlock(&trigger->leddev_list_lock);
}
EXPORT_SYMBOL_GPL(led_trigger_blink);

void led_trigger_register_simple(const char *name, struct led_trigger **tp)
{
	struct led_trigger *trigger;
+14 −0
Original line number Diff line number Diff line
@@ -117,10 +117,24 @@ config BATTERY_BQ20Z75

config BATTERY_BQ27x00
	tristate "BQ27x00 battery driver"
	help
	  Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips.

config BATTERY_BQ27X00_I2C
	bool "BQ27200/BQ27500 support"
	depends on BATTERY_BQ27x00
	depends on I2C
	default y
	help
	  Say Y here to enable support for batteries with BQ27x00 (I2C) chips.

config BATTERY_BQ27X00_PLATFORM
	bool "BQ27000 support"
	depends on BATTERY_BQ27x00
	default y
	help
	  Say Y here to enable support for batteries with BQ27000 (HDQ) chips.

config BATTERY_DA9030
	tristate "DA9030 battery driver"
	depends on PMIC_DA903X
+263 −47
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@
#include <linux/power_supply.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

#include <linux/power/bq20z75.h>

enum {
	REG_MANUFACTURER_DATA,
@@ -38,11 +42,22 @@ enum {
	REG_CYCLE_COUNT,
	REG_SERIAL_NUMBER,
	REG_REMAINING_CAPACITY,
	REG_REMAINING_CAPACITY_CHARGE,
	REG_FULL_CHARGE_CAPACITY,
	REG_FULL_CHARGE_CAPACITY_CHARGE,
	REG_DESIGN_CAPACITY,
	REG_DESIGN_CAPACITY_CHARGE,
	REG_DESIGN_VOLTAGE,
};

/* Battery Mode defines */
#define BATTERY_MODE_OFFSET		0x03
#define BATTERY_MODE_MASK		0x8000
enum bq20z75_battery_mode {
	BATTERY_MODE_AMPS,
	BATTERY_MODE_WATTS
};

/* manufacturer access defines */
#define MANUFACTURER_ACCESS_STATUS	0x0006
#define MANUFACTURER_ACCESS_SLEEP	0x0011
@@ -78,8 +93,12 @@ static const struct bq20z75_device_data {
		BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
	[REG_REMAINING_CAPACITY] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
	[REG_REMAINING_CAPACITY_CHARGE] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
	[REG_FULL_CHARGE_CAPACITY] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
	[REG_FULL_CHARGE_CAPACITY_CHARGE] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
	[REG_TIME_TO_EMPTY] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
			65535),
@@ -93,6 +112,9 @@ static const struct bq20z75_device_data {
	[REG_DESIGN_CAPACITY] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
			65535),
	[REG_DESIGN_CAPACITY_CHARGE] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0,
			65535),
	[REG_DESIGN_VOLTAGE] =
		BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
			65535),
@@ -117,39 +139,72 @@ static enum power_supply_property bq20z75_properties[] = {
	POWER_SUPPLY_PROP_ENERGY_NOW,
	POWER_SUPPLY_PROP_ENERGY_FULL,
	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
	POWER_SUPPLY_PROP_CHARGE_NOW,
	POWER_SUPPLY_PROP_CHARGE_FULL,
	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};

struct bq20z75_info {
	struct i2c_client		*client;
	struct power_supply		power_supply;
	struct bq20z75_platform_data	*pdata;
	bool				is_present;
	bool				gpio_detect;
	bool				enable_detection;
	int				irq;
};

static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
{
	s32 ret;
	struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
	s32 ret = 0;
	int retries = 1;

	if (bq20z75_device->pdata)
		retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);

	while (retries > 0) {
		ret = i2c_smbus_read_word_data(client, address);
		if (ret >= 0)
			break;
		retries--;
	}

	if (ret < 0) {
		dev_err(&client->dev,
		dev_dbg(&client->dev,
			"%s: i2c read at address 0x%x failed\n",
			__func__, address);
		return ret;
	}

	return le16_to_cpu(ret);
}

static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
	u16 value)
{
	s32 ret;
	struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
	s32 ret = 0;
	int retries = 1;

	if (bq20z75_device->pdata)
		retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);

	while (retries > 0) {
		ret = i2c_smbus_write_word_data(client, address,
			le16_to_cpu(value));
		if (ret >= 0)
			break;
		retries--;
	}

	ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value));
	if (ret < 0) {
		dev_err(&client->dev,
		dev_dbg(&client->dev,
			"%s: i2c write to address 0x%x failed\n",
			__func__, address);
		return ret;
	}

	return 0;
}

@@ -158,6 +213,19 @@ static int bq20z75_get_battery_presence_and_health(
	union power_supply_propval *val)
{
	s32 ret;
	struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);

	if (psp == POWER_SUPPLY_PROP_PRESENT &&
		bq20z75_device->gpio_detect) {
		ret = gpio_get_value(
			bq20z75_device->pdata->battery_detect);
		if (ret == bq20z75_device->pdata->battery_detect_present)
			val->intval = 1;
		else
			val->intval = 0;
		bq20z75_device->is_present = val->intval;
		return ret;
	}

	/* Write to ManufacturerAccess with
	 * ManufacturerAccess command and then
@@ -165,9 +233,11 @@ static int bq20z75_get_battery_presence_and_health(
	ret = bq20z75_write_word_data(client,
		bq20z75_data[REG_MANUFACTURER_DATA].addr,
		MANUFACTURER_ACCESS_STATUS);
	if (ret < 0)
	if (ret < 0) {
		if (psp == POWER_SUPPLY_PROP_PRESENT)
			val->intval = 0; /* battery removed */
		return ret;

	}

	ret = bq20z75_read_word_data(client,
		bq20z75_data[REG_MANUFACTURER_DATA].addr);
@@ -248,30 +318,39 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
{
#define BASE_UNIT_CONVERSION		1000
#define BATTERY_MODE_CAP_MULT_WATT	(10 * BASE_UNIT_CONVERSION)
#define TIME_UNIT_CONVERSION		600
#define TEMP_KELVIN_TO_CELCIUS		2731
#define TIME_UNIT_CONVERSION		60
#define TEMP_KELVIN_TO_CELSIUS		2731
	switch (psp) {
	case POWER_SUPPLY_PROP_ENERGY_NOW:
	case POWER_SUPPLY_PROP_ENERGY_FULL:
	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
		/* bq20z75 provides energy in units of 10mWh.
		 * Convert to µWh
		 */
		val->intval *= BATTERY_MODE_CAP_MULT_WATT;
		break;

	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
	case POWER_SUPPLY_PROP_CURRENT_NOW:
	case POWER_SUPPLY_PROP_CHARGE_NOW:
	case POWER_SUPPLY_PROP_CHARGE_FULL:
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		val->intval *= BASE_UNIT_CONVERSION;
		break;

	case POWER_SUPPLY_PROP_TEMP:
		/* bq20z75 provides battery tempreture in 0.1°K
		 * so convert it to 0.1°C */
		val->intval -= TEMP_KELVIN_TO_CELCIUS;
		val->intval *= 10;
		/* bq20z75 provides battery temperature in 0.1K
		 * so convert it to 0.1°C
		 */
		val->intval -= TEMP_KELVIN_TO_CELSIUS;
		break;

	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
		/* bq20z75 provides time to empty and time to full in minutes.
		 * Convert to seconds
		 */
		val->intval *= TIME_UNIT_CONVERSION;
		break;

@@ -281,11 +360,44 @@ static void bq20z75_unit_adjustment(struct i2c_client *client,
	}
}

static enum bq20z75_battery_mode
bq20z75_set_battery_mode(struct i2c_client *client,
	enum bq20z75_battery_mode mode)
{
	int ret, original_val;

	original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET);
	if (original_val < 0)
		return original_val;

	if ((original_val & BATTERY_MODE_MASK) == mode)
		return mode;

	if (mode == BATTERY_MODE_AMPS)
		ret = original_val & ~BATTERY_MODE_MASK;
	else
		ret = original_val | BATTERY_MODE_MASK;

	ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret);
	if (ret < 0)
		return ret;

	return original_val & BATTERY_MODE_MASK;
}

static int bq20z75_get_battery_capacity(struct i2c_client *client,
	int reg_offset, enum power_supply_property psp,
	union power_supply_propval *val)
{
	s32 ret;
	enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS;

	if (power_supply_is_amp_property(psp))
		mode = BATTERY_MODE_AMPS;

	mode = bq20z75_set_battery_mode(client, mode);
	if (mode < 0)
		return mode;

	ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
	if (ret < 0)
@@ -298,6 +410,10 @@ static int bq20z75_get_battery_capacity(struct i2c_client *client,
	} else
		val->intval = ret;

	ret = bq20z75_set_battery_mode(client, mode);
	if (ret < 0)
		return ret;

	return 0;
}

@@ -318,12 +434,25 @@ static int bq20z75_get_battery_serial_number(struct i2c_client *client,
	return 0;
}

static int bq20z75_get_property_index(struct i2c_client *client,
	enum power_supply_property psp)
{
	int count;
	for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++)
		if (psp == bq20z75_data[count].psp)
			return count;

	dev_warn(&client->dev,
		"%s: Invalid Property - %d\n", __func__, psp);

	return -EINVAL;
}

static int bq20z75_get_property(struct power_supply *psy,
	enum power_supply_property psp,
	union power_supply_propval *val)
{
	int count;
	int ret;
	int ret = 0;
	struct bq20z75_info *bq20z75_device = container_of(psy,
				struct bq20z75_info, power_supply);
	struct i2c_client *client = bq20z75_device->client;
@@ -332,8 +461,8 @@ static int bq20z75_get_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_PRESENT:
	case POWER_SUPPLY_PROP_HEALTH:
		ret = bq20z75_get_battery_presence_and_health(client, psp, val);
		if (ret)
			return ret;
		if (psp == POWER_SUPPLY_PROP_PRESENT)
			return 0;
		break;

	case POWER_SUPPLY_PROP_TECHNOLOGY:
@@ -343,22 +472,19 @@ static int bq20z75_get_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_ENERGY_NOW:
	case POWER_SUPPLY_PROP_ENERGY_FULL:
	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
	case POWER_SUPPLY_PROP_CHARGE_NOW:
	case POWER_SUPPLY_PROP_CHARGE_FULL:
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
	case POWER_SUPPLY_PROP_CAPACITY:
		for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
			if (psp == bq20z75_data[count].psp)
		ret = bq20z75_get_property_index(client, psp);
		if (ret < 0)
			break;
		}

		ret = bq20z75_get_battery_capacity(client, count, psp, val);
		if (ret)
			return ret;

		ret = bq20z75_get_battery_capacity(client, ret, psp, val);
		break;

	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
		ret = bq20z75_get_battery_serial_number(client, val);
		if (ret)
			return ret;
		break;

	case POWER_SUPPLY_PROP_STATUS:
@@ -369,15 +495,11 @@ static int bq20z75_get_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
		for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
			if (psp == bq20z75_data[count].psp)
		ret = bq20z75_get_property_index(client, psp);
		if (ret < 0)
			break;
		}

		ret = bq20z75_get_battery_property(client, count, psp, val);
		if (ret)
			return ret;

		ret = bq20z75_get_battery_property(client, ret, psp, val);
		break;

	default:
@@ -386,26 +508,58 @@ static int bq20z75_get_property(struct power_supply *psy,
		return -EINVAL;
	}

	if (!bq20z75_device->enable_detection)
		goto done;

	if (!bq20z75_device->gpio_detect &&
		bq20z75_device->is_present != (ret >= 0)) {
		bq20z75_device->is_present = (ret >= 0);
		power_supply_changed(&bq20z75_device->power_supply);
	}

done:
	if (!ret) {
		/* Convert units to match requirements for power supply class */
		bq20z75_unit_adjustment(client, psp, val);
	}

	dev_dbg(&client->dev,
		"%s: property = %d, value = %d\n", __func__, psp, val->intval);
		"%s: property = %d, value = %x\n", __func__, psp, val->intval);

	if (ret && bq20z75_device->is_present)
		return ret;

	/* battery not present, so return NODATA for properties */
	if (ret)
		return -ENODATA;

	return 0;
}

static int bq20z75_probe(struct i2c_client *client,
static irqreturn_t bq20z75_irq(int irq, void *devid)
{
	struct power_supply *battery = devid;

	power_supply_changed(battery);

	return IRQ_HANDLED;
}

static int __devinit bq20z75_probe(struct i2c_client *client,
	const struct i2c_device_id *id)
{
	struct bq20z75_info *bq20z75_device;
	struct bq20z75_platform_data *pdata = client->dev.platform_data;
	int rc;
	int irq;

	bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
	if (!bq20z75_device)
		return -ENOMEM;

	bq20z75_device->client = client;
	bq20z75_device->enable_detection = false;
	bq20z75_device->gpio_detect = false;
	bq20z75_device->power_supply.name = "battery";
	bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
	bq20z75_device->power_supply.properties = bq20z75_properties;
@@ -413,26 +567,86 @@ static int bq20z75_probe(struct i2c_client *client,
		ARRAY_SIZE(bq20z75_properties);
	bq20z75_device->power_supply.get_property = bq20z75_get_property;

	if (pdata) {
		bq20z75_device->gpio_detect =
			gpio_is_valid(pdata->battery_detect);
		bq20z75_device->pdata = pdata;
	}

	i2c_set_clientdata(client, bq20z75_device);

	if (!bq20z75_device->gpio_detect)
		goto skip_gpio;

	rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
	if (rc) {
		dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
		bq20z75_device->gpio_detect = false;
		goto skip_gpio;
	}

	rc = gpio_direction_input(pdata->battery_detect);
	if (rc) {
		dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
		gpio_free(pdata->battery_detect);
		bq20z75_device->gpio_detect = false;
		goto skip_gpio;
	}

	irq = gpio_to_irq(pdata->battery_detect);
	if (irq <= 0) {
		dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
		gpio_free(pdata->battery_detect);
		bq20z75_device->gpio_detect = false;
		goto skip_gpio;
	}

	rc = request_irq(irq, bq20z75_irq,
		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
		dev_name(&client->dev), &bq20z75_device->power_supply);
	if (rc) {
		dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
		gpio_free(pdata->battery_detect);
		bq20z75_device->gpio_detect = false;
		goto skip_gpio;
	}

	bq20z75_device->irq = irq;

skip_gpio:

	rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
	if (rc) {
		dev_err(&client->dev,
			"%s: Failed to register power supply\n", __func__);
		kfree(bq20z75_device);
		return rc;
		goto exit_psupply;
	}

	dev_info(&client->dev,
		"%s: battery gas gauge device registered\n", client->name);

	return 0;

exit_psupply:
	if (bq20z75_device->irq)
		free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
	if (bq20z75_device->gpio_detect)
		gpio_free(pdata->battery_detect);

	kfree(bq20z75_device);

	return rc;
}

static int bq20z75_remove(struct i2c_client *client)
static int __devexit bq20z75_remove(struct i2c_client *client)
{
	struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);

	if (bq20z75_device->irq)
		free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
	if (bq20z75_device->gpio_detect)
		gpio_free(bq20z75_device->pdata->battery_detect);

	power_supply_unregister(&bq20z75_device->power_supply);
	kfree(bq20z75_device);
	bq20z75_device = NULL;
@@ -444,13 +658,14 @@ static int bq20z75_remove(struct i2c_client *client)
static int bq20z75_suspend(struct i2c_client *client,
	pm_message_t state)
{
	struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
	s32 ret;

	/* write to manufacturer access with sleep command */
	ret = bq20z75_write_word_data(client,
		bq20z75_data[REG_MANUFACTURER_DATA].addr,
		MANUFACTURER_ACCESS_SLEEP);
	if (ret < 0)
	if (bq20z75_device->is_present && ret < 0)
		return ret;

	return 0;
@@ -465,10 +680,11 @@ static const struct i2c_device_id bq20z75_id[] = {
	{ "bq20z75", 0 },
	{}
};
MODULE_DEVICE_TABLE(i2c, bq20z75_id);

static struct i2c_driver bq20z75_battery_driver = {
	.probe		= bq20z75_probe,
	.remove		= bq20z75_remove,
	.remove		= __devexit_p(bq20z75_remove),
	.suspend	= bq20z75_suspend,
	.resume		= bq20z75_resume,
	.id_table	= bq20z75_id,
Loading