Skip to contentSkip to conversation

BQ27000/BQ27200 battery monitoring driver for OMAP34xx

RFC/PATCH Madhusudhan Chikkature Rajashekar 2 participants 5 messages Apr 25, 2008 – Apr 29, 2008 W1 dallas's 1-wire bus

lore
Share & tools
lore
#0 lore raw

This patch provides the battery monitoring driver to monitor batteries with BQ27000(HDQ) or BQ27200(i2C) chips. On omap 3430 sdp BQ27000 battery is tested through the HDQ interface which uses the earlier posted HDQ and BQ slave drivers. The BQ27200 support is an extension to the BQ27000 driver as the register set between BQ27000 and BQ27200 is the same.

Thanks to Klaus.K Pedersen and Mikko Ylinen for the suggestions to add support for BQ27200 chip as part of this driver.

---
 drivers/power/Kconfig           |   21 +
 drivers/power/Makefile          |    1 
 drivers/power/bq27x00_battery.c |  556 ++++++++++++++++++++++++++++++++++++++++
 drivers/w1/slaves/w1_bq27000.c  |    2 
 4 files changed, 579 insertions(+), 1 deletion(-)
drivers/power/bq27x00_battery.c new file +556 -0
Index: linux-omap-2.6/drivers/power/bq27x00_battery.c
===================================================================
@@ -0,0 +1,556 @@
+/*
+ * linux/drivers/power/bq27x00_battery.c
+ *
+ * BQ27000/BQ27200 battery driver
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * Author: Texas Instruments
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#if defined(CONFIG_BATTERY_BQ27000)
+#define BATTERY_BQ27000
+#include "../w1/w1.h"
+#endif
+#if defined(CONFIG_BATTERY_BQ27200)
+#define BATTERY_BQ27200
+#include <linux/i2c.h>
+#endif
+
+#define BQ27x00_REG_TEMP		0x06
+#define BQ27x00_REG_VOLT		0x08
+#define BQ27x00_REG_RSOC		0x0B /* Relative State-of-Charge */
+#define BQ27x00_REG_AI			0x14
+#define BQ27x00_REG_FLAGS		0x0A
+#define HIGH_BYTE(A)			((A) << 8)
+
+#if defined(BATTERY_BQ27000)
+extern int w1_bq27000_read(struct device *dev, u8 reg);
+#endif
+
+struct bq27x00_device_info;
+struct bq27x00_access_methods {
+	int (*read)(u8 reg, int *rt_value, int b_single,
+		struct bq27x00_device_info *di);
+};
+
+struct bq27x00_device_info {
+	struct device 		*dev;
+#if defined(BATTERY_BQ27000)
+	struct device		*w1_dev;
+#endif
+#if defined(BATTERY_BQ27200)
+	struct i2c_client *client;
+#endif
+	unsigned long		update_time;
+	int			voltage_uV;
+	int			current_uA;
+	int			temp_C;
+	int			charge_rsoc;
+	struct bq27x00_access_methods	*bus;
+	struct power_supply	bat;
+	struct delayed_work	monitor_work;
+};
+
+static unsigned int cache_time = 60000;
+module_param(cache_time, uint, 0644);
+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
+
+static enum power_supply_property bq27x00_battery_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di);
+
+#if defined(BATTERY_BQ27000)
+static int bq27000_battery_probe(struct platform_device *dev);
+static int bq27000_battery_remove(struct platform_device *dev);
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *dev,
+	pm_message_t state);
+static int bq27000_battery_resume(struct platform_device *dev);
+#endif
+
+static struct platform_driver bq27000_battery_driver = {
+	.probe = bq27000_battery_probe,
+	.remove = bq27000_battery_remove,
+#ifdef CONFIG_PM
+	.suspend = bq27000_battery_suspend,
+	.resume = bq27000_battery_resume,
+#endif
+	.driver = {
+		.name = "bq27000-bat",
+	},
+};
+#endif
+
+#if defined(BATTERY_BQ27200)
+static int bq27200_battery_probe(struct i2c_client *client);
+static int bq27200_battery_remove(struct i2c_client *client);
+static int bq27200_battery_suspend(struct i2c_client *client,
+		pm_message_t mesg);
+static int bq27200_battery_resume(struct i2c_client *client);
+static struct i2c_driver bq27200_battery_driver = {
+	.driver = {
+		.name   = "bq27200-bat",
+	},
+	.probe  = bq27200_battery_probe,
+	.remove = bq27200_battery_remove,
+#ifdef CONFIG_PM
+	.suspend = bq27200_battery_suspend,
+	.resume = bq27200_battery_resume,
+#endif
+};
+#endif
+
+/*
+ * Return the battery temperature in Celcius degrees
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
+{
+	int ret, temp = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading temperature from the battery\n");
+		return ret;
+	}
+
+	return (temp >> 2) - 273;
+}
+
+/*
+ * Return the battery Voltage in milivolts
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
+{
+	int ret, volt = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery voltage from the battery\n");
+		return ret;
+	}
+
+	return volt;
+}
+
+/*
+ * Return the battery average current
+ * Note that current can be negative signed as well
+ * Or 0 if something fails.
+ */
+static int bq27x00_battery_current(struct bq27x00_device_info *di)
+{
+	int ret, curr = 0, flags = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading current from the battery\n");
+		return 0;
+	}
+	ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+	if (ret < 0) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery flags\n");
+		return 0;
+	}
+	if ((flags & (1 << 7)) != 0) {
+		pr_debug("Negative current\n");
+		return -curr;
+	} else {
+		return curr;
+	}
+}
+
+/*
+ * Return the battery Relative State-of-Charge
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
+{
+	int ret, rsoc = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery Relative"
+			"State-of-Charge\n");
+		return ret;
+	}
+	return rsoc;
+}
+
+#if defined(BATTERY_BQ27000)
+static int bq27000_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	u8 val;
+
+	val = w1_bq27000_read(di->w1_dev, reg);
+	*rt_value = val;
+
+	if (!b_single) {
+		val = 0;
+		val = w1_bq27000_read(di->w1_dev, reg + 1);
+		*rt_value +=  HIGH_BYTE((int) val);
+	}
+
+	return 0;
+}
+#else
+#define bq27000_read NULL
+#endif
+
+#if defined(BATTERY_BQ27200)
+static int bq27200_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	struct i2c_client *client = di->client;
+	struct i2c_msg msg[1];
+	unsigned char data[2];
+	int err;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 1;
+	msg->buf = data;
+
+	data[0] = reg;
+	err = i2c_transfer(client->adapter, msg, 1);
+
+	if (err >= 0) {
+		if (!b_single)
+			msg->len = 2;
+		else
+			msg->len = 1;
+
+		msg->flags = I2C_M_RD;
+		err = i2c_transfer(client->adapter, msg, 1);
+		if (err >= 0) {
+			if (!b_single)
+				*rt_value = data[1] | HIGH_BYTE(data[0]);
+			else
+				*rt_value = data[0];
+
+			return 0;
+		} else {
+			pr_err("BQ27200 I2C read failed\n");
+			return err;
+		}
+	} else {
+		pr_err("BQ27200 I2C write failed\n");
+		return err;
+	}
+}
+#else
+#define bq27200_read NULL
+#endif
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	int ret;
+
+	ret = di->bus->read(reg, rt_value, b_single, di);
+	return ret;
+}
+
+/*
+ * Read the battery temp, voltage, current and relative state of charge.
+ */
+static void bq27x00_battery_read_status(struct bq27x00_device_info *di)
+{
+	if (di->update_time && time_before(jiffies, di->update_time +
+					msecs_to_jiffies(cache_time)))
+		return;
+
+	di->temp_C = bq27x00_battery_temperature(di);
+	di->voltage_uV = bq27x00_battery_voltage(di);
+	di->current_uA = bq27x00_battery_current(di);
+	di->charge_rsoc = bq27x00_battery_rsoc(di);
+
+	di->update_time = jiffies;
+
+	return;
+}
+
+static void bq27x00_battery_work(struct delayed_work *work)
+{
+	struct bq27x00_device_info *di = container_of(work,
+		struct bq27x00_device_info, monitor_work);
+
+	bq27x00_battery_read_status(di);
+	schedule_delayed_work(&di->monitor_work, 100);
+	return;
+}
+
+#define to_bq27x00_device_info(x) container_of((x), \
+				struct bq27x00_device_info, bat);
+
+static int bq27x00_battery_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = di->voltage_uV;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = di->current_uA;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = di->charge_rsoc;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = di->temp_C;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = di->charge_rsoc;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		if (di->voltage_uV == 0)
+			val->intval = 0;
+		else
+			val->intval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
+{
+	di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat.properties = bq27x00_battery_props;
+	di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+	di->bat.get_property = bq27x00_battery_get_property;
+	di->bat.external_power_changed = NULL;
+	return;
+}
+
+#ifdef BATTERY_BQ27200
+static int bq27200_battery_probe(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di;
+	struct bq27x00_access_methods *bus;
+	int retval = 0;
+
+	di = kzalloc(sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate device info structure\n");
+		return -ENOMEM;
+	}
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate access method structure\n");
+		kfree(di);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, di);
+	di->dev = &client->dev;
+	di->bat.name = "bq27200";
+	bus->read = &bq27200_read;
+	di->bus = bus;
+	di->client = client;
+
+	bq27x00_powersupply_init(di);
+
+	retval = power_supply_register(&client->dev, &di->bat);
+	if (retval) {
+		pr_err("BQ27200 battery driver: Failed to register battery\n");
+		goto batt_failed;
+	}
+
+	INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+	schedule_delayed_work(&di->monitor_work, 100);
+
+	return 0;
+
+batt_failed:
+	kfree(bus);
+	kfree(di);
+	return retval;
+}
+
+static int bq27200_battery_remove(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->bat);
+	kfree(di);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27200_battery_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	cancel_delayed_work(&di->monitor_work);
+	return 0;
+}
+
+static int bq27200_battery_resume(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	schedule_delayed_work(&di->monitor_work, 0);
+	return 0;
+}
+#endif
+#endif
+
+#ifdef BATTERY_BQ27000
+static int bq27000_battery_probe(struct  platform_device *pdev)
+{
+	struct bq27x00_device_info *di;
+	struct bq27x00_access_methods *bus;
+	int retval = 0;
+
+	di = kzalloc(sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate device info structure\n");
+		return -ENOMEM;
+	}
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate access method structure\n");
+		kfree(di);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, di);
+
+	di->dev = &pdev->dev;
+	di->w1_dev = pdev->dev.parent;
+	di->bat.name = "bq27000";
+	bus->read = &bq27000_read;
+	di->bus = bus;
+
+	bq27x00_powersupply_init(di);
+
+	retval = power_supply_register(&pdev->dev, &di->bat);
+	if (retval) {
+		pr_err("BQ27000 battery driver: Failed to register battery\n");
+		goto batt_failed;
+	}
+
+	INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+	schedule_delayed_work(&di->monitor_work, 50);
+
+	return 0;
+
+batt_failed:
+	kfree(bus);
+	kfree(di);
+	return retval;
+}
+
+static int bq27000_battery_remove(struct  platform_device *pdev)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->bat);
+	platform_set_drvdata(pdev, NULL);
+	kfree(di);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	cancel_delayed_work(&di->monitor_work);
+	return 0;
+}
+
+static int bq27000_battery_resume(struct platform_device *pdev)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	schedule_delayed_work(&di->monitor_work, 0);
+	return 0;
+}
+#endif
+#endif
+
+static int __init bq27x00_battery_init(void)
+{
+	int status = 0;
+
+#if defined(BATTERY_BQ27000)
+	status = platform_driver_register(&bq27000_battery_driver);
+	if (status)
+		printk(KERN_ERR "Unable to register BQ27000 driver\n");
+#endif
+#if defined(BATTERY_BQ27200)
+	status = i2c_add_driver(&bq27200_battery_driver);
+		printk(KERN_ERR "Unable to register BQ27200 driver\n");
+#endif
+	return status;
+}
+
+static void __exit bq27x00_battery_exit(void)
+{
+#if defined(BATTERY_BQ27000)
+	platform_driver_unregister(&bq27000_battery_driver);
+#endif
+#if defined(BATTERY_BQ27200)
+	i2c_del_driver(&bq27200_battery_driver);
+#endif
+}
+
+module_init(bq27x00_battery_init);
+module_exit(bq27x00_battery_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("BQ27x00 battery moniter driver");
+MODULE_LICENSE("GPL");
drivers/power/Kconfig +21 -0
Index: linux-omap-2.6/drivers/power/Kconfig
===================================================================
@@ -49,4 +49,25 @@
 	help
 	  Say Y to enable support for the battery on the OLPC laptop.
 
+config BATTERY_BQ27x00
+	tristate "BQ27x00 battery driver"
+	help
+	  Say Y here to enable support for batteries with BQ27000 or BQ27200 chip.
+
+config BATTERY_BQ27000
+	bool "BQ27000 battery driver"
+	depends on BATTERY_BQ27x00
+	select W1
+	select W1_SLAVE_BQ27000
+	help
+	  Say Y here to enable support for batteries with BQ27000(HDQ) chip.
+
+config BATTERY_BQ27200
+	bool "BQ27200 battery driver"
+	depends on BATTERY_BQ27x00
+	select I2C
+	select I2C_OMAP
+	help
+	  Say Y here to enable support for batteries with BQ27200(I2C) chip.
+
 endif # POWER_SUPPLY
drivers/power/Makefile +1 -0
Index: linux-omap-2.6/drivers/power/Makefile
===================================================================
@@ -20,3 +20,4 @@
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
+obj-$(CONFIG_BATTERY_BQ27x00)   += bq27x00_battery.o
drivers/w1/slaves/w1_bq27000.c +1 -1
Index: linux-omap-2.6/drivers/w1/slaves/w1_bq27000.c
===================================================================
@@ -59,7 +59,7 @@
 	int id = 1;
 	struct platform_device *pdev;
 
-	pdev = platform_device_alloc("omap-bq2700-battery", id);
+	pdev = platform_device_alloc("bq27000-bat", id);
 	if (!pdev) {
 		ret = -ENOMEM;
 		return ret;
#1 lore raw

Some cosmetic comments below

Quoted 1 line · Madhusudhan Chikkature Rajashekar

This patch provides the battery monitoring driver to monitor batteries

with

Quoted 2 lines

BQ27000(HDQ) or BQ27200(i2C) chips.
On omap 3430 sdp BQ27000 battery is tested through the HDQ interface

which

Quoted 42 lines

uses the earlier posted HDQ and BQ slave drivers.
The BQ27200 support is an extension to the BQ27000 driver as the register set between BQ27000 and BQ27200 is the same.

Thanks to Klaus.K Pedersen and Mikko Ylinen for the suggestions to add support for BQ27200 chip as part of
this driver.

---
 drivers/power/Kconfig           |   21 +
 drivers/power/Makefile          |    1
 drivers/power/bq27x00_battery.c |  556
++++++++++++++++++++++++++++++++++++++++
 drivers/w1/slaves/w1_bq27000.c  |    2
 4 files changed, 579 insertions(+), 1 deletion(-)

Index: linux-omap-2.6/drivers/power/bq27x00_battery.c
===================================================================

drivers/power/bq27x00_battery.c new file +0 -0

10:50:53.631358952 +0530

drivers/power/bq27x00_battery.c new file +17 -0
@@ -0,0 +1,556 @@
+/*
+ * linux/drivers/power/bq27x00_battery.c
+ *
+ * BQ27000/BQ27200 battery driver
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * Author: Texas Instruments
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *

drivers/power/bq27x00_battery.c line 27

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+ */
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#if defined(CONFIG_BATTERY_BQ27000)

Here use ifdef

drivers/power/bq27x00_battery.c line 28

Quoted 1 line
drivers/power/bq27x00_battery.c new file +1 -0
+#define BATTERY_BQ27000

there's no need to add this one as you can use the Kconfig option

Quoted 17 lines
drivers/power/bq27x00_battery.c new file +17 -0
+#include "../w1/w1.h"
+#endif
+#if defined(CONFIG_BATTERY_BQ27200)
+#define BATTERY_BQ27200
+#include <linux/i2c.h>
+#endif
+
+#define BQ27x00_REG_TEMP		0x06
+#define BQ27x00_REG_VOLT		0x08
+#define BQ27x00_REG_RSOC		0x0B /* Relative State-of-Charge */
+#define BQ27x00_REG_AI			0x14
+#define BQ27x00_REG_FLAGS		0x0A
+#define HIGH_BYTE(A)			((A) << 8)
+
+#if defined(BATTERY_BQ27000)
+extern int w1_bq27000_read(struct device *dev, u8 reg);
+#endif

drivers/power/bq27x00_battery.c line 55

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+
+struct bq27x00_device_info;
+struct bq27x00_access_methods {
+	int (*read)(u8 reg, int *rt_value, int b_single,
+		struct bq27x00_device_info *di);
+};
+
+struct bq27x00_device_info {
+	struct device 		*dev;
+#if defined(BATTERY_BQ27000)

#ifdef CONFIG_BATERRY_BQ27000

drivers/power/bq27x00_battery.c line 58

Quoted 3 lines
drivers/power/bq27x00_battery.c new file +3 -0
+	struct device		*w1_dev;
+#endif
+#if defined(BATTERY_BQ27200)

#ifdef CONFIG_BATTERY_BQ27200

Quoted 161 lines
drivers/power/bq27x00_battery.c new file +161 -0
+	struct i2c_client *client;
+#endif
+	unsigned long		update_time;
+	int			voltage_uV;
+	int			current_uA;
+	int			temp_C;
+	int			charge_rsoc;
+	struct bq27x00_access_methods	*bus;
+	struct power_supply	bat;
+	struct delayed_work	monitor_work;
+};
+
+static unsigned int cache_time = 60000;
+module_param(cache_time, uint, 0644);
+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
+
+static enum power_supply_property bq27x00_battery_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di);
+
+#if defined(BATTERY_BQ27000)
+static int bq27000_battery_probe(struct platform_device *dev);
+static int bq27000_battery_remove(struct platform_device *dev);
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *dev,
+	pm_message_t state);
+static int bq27000_battery_resume(struct platform_device *dev);
+#endif
+
+static struct platform_driver bq27000_battery_driver = {
+	.probe = bq27000_battery_probe,
+	.remove = bq27000_battery_remove,
+#ifdef CONFIG_PM
+	.suspend = bq27000_battery_suspend,
+	.resume = bq27000_battery_resume,
+#endif
+	.driver = {
+		.name = "bq27000-bat",
+	},
+};
+#endif
+
+#if defined(BATTERY_BQ27200)
+static int bq27200_battery_probe(struct i2c_client *client);
+static int bq27200_battery_remove(struct i2c_client *client);
+static int bq27200_battery_suspend(struct i2c_client *client,
+		pm_message_t mesg);
+static int bq27200_battery_resume(struct i2c_client *client);
+static struct i2c_driver bq27200_battery_driver = {
+	.driver = {
+		.name   = "bq27200-bat",
+	},
+	.probe  = bq27200_battery_probe,
+	.remove = bq27200_battery_remove,
+#ifdef CONFIG_PM
+	.suspend = bq27200_battery_suspend,
+	.resume = bq27200_battery_resume,
+#endif
+};
+#endif
+
+/*
+ * Return the battery temperature in Celcius degrees
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
+{
+	int ret, temp = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading temperature from the battery\n");
+		return ret;
+	}
+
+	return (temp >> 2) - 273;
+}
+
+/*
+ * Return the battery Voltage in milivolts
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
+{
+	int ret, volt = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery voltage from the battery\n");
+		return ret;
+	}
+
+	return volt;
+}
+
+/*
+ * Return the battery average current
+ * Note that current can be negative signed as well
+ * Or 0 if something fails.
+ */
+static int bq27x00_battery_current(struct bq27x00_device_info *di)
+{
+	int ret, curr = 0, flags = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading current from the battery\n");
+		return 0;
+	}
+	ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+	if (ret < 0) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery flags\n");
+		return 0;
+	}
+	if ((flags & (1 << 7)) != 0) {
+		pr_debug("Negative current\n");
+		return -curr;
+	} else {
+		return curr;
+	}
+}
+
+/*
+ * Return the battery Relative State-of-Charge
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
+{
+	int ret, rsoc = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery Relative"
+			"State-of-Charge\n");
+		return ret;
+	}
+	return rsoc;
+}
+
+#if defined(BATTERY_BQ27000)
+static int bq27000_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	u8 val;
+
+	val = w1_bq27000_read(di->w1_dev, reg);
+	*rt_value = val;
+

drivers/power/bq27x00_battery.c line 229

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+	if (!b_single) {
+		val = 0;
+		val = w1_bq27000_read(di->w1_dev, reg + 1);
+		*rt_value +=  HIGH_BYTE((int) val);
+	}
+
+	return 0;
+}
+#else
+#define bq27000_read NULL

this should be defined as 0 or an static inline int [...] { return 0; }

Quoted 38 lines
drivers/power/bq27x00_battery.c new file +38 -0
+#endif
+
+#if defined(BATTERY_BQ27200)
+static int bq27200_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	struct i2c_client *client = di->client;
+	struct i2c_msg msg[1];
+	unsigned char data[2];
+	int err;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 1;
+	msg->buf = data;
+
+	data[0] = reg;
+	err = i2c_transfer(client->adapter, msg, 1);
+
+	if (err >= 0) {
+		if (!b_single)
+			msg->len = 2;
+		else
+			msg->len = 1;
+
+		msg->flags = I2C_M_RD;
+		err = i2c_transfer(client->adapter, msg, 1);
+		if (err >= 0) {
+			if (!b_single)
+				*rt_value = data[1] | HIGH_BYTE(data[0]);
+			else
+				*rt_value = data[0];
+
+			return 0;
+		} else {

drivers/power/bq27x00_battery.c line 277

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+			pr_err("BQ27200 I2C read failed\n");
+			return err;
+		}
+	} else {
+		pr_err("BQ27200 I2C write failed\n");
+		return err;
+	}
+}
+#else
+#define bq27200_read NULL

same here

Quoted 156 lines
drivers/power/bq27x00_battery.c new file +149 -0
+#endif
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	int ret;
+
+	ret = di->bus->read(reg, rt_value, b_single, di);
+	return ret;
+}
+
+/*
+ * Read the battery temp, voltage, current and relative state of charge.
+ */
+static void bq27x00_battery_read_status(struct bq27x00_device_info *di)
+{
+	if (di->update_time && time_before(jiffies, di->update_time +
+					msecs_to_jiffies(cache_time)))
+		return;
+
+	di->temp_C = bq27x00_battery_temperature(di);
+	di->voltage_uV = bq27x00_battery_voltage(di);
+	di->current_uA = bq27x00_battery_current(di);
+	di->charge_rsoc = bq27x00_battery_rsoc(di);
+
+	di->update_time = jiffies;
+
+	return;
+}
+
+static void bq27x00_battery_work(struct delayed_work *work)
+{
+	struct bq27x00_device_info *di = container_of(work,
+		struct bq27x00_device_info, monitor_work);
+
+	bq27x00_battery_read_status(di);
+	schedule_delayed_work(&di->monitor_work, 100);
+	return;
+}
+
+#define to_bq27x00_device_info(x) container_of((x), \
+				struct bq27x00_device_info, bat);
+
+static int bq27x00_battery_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = di->voltage_uV;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = di->current_uA;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = di->charge_rsoc;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = di->temp_C;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = di->charge_rsoc;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		if (di->voltage_uV == 0)
+			val->intval = 0;
+		else
+			val->intval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
+{
+	di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat.properties = bq27x00_battery_props;
+	di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+	di->bat.get_property = bq27x00_battery_get_property;
+	di->bat.external_power_changed = NULL;
+	return;
+}
+
+#ifdef BATTERY_BQ27200
+static int bq27200_battery_probe(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di;
+	struct bq27x00_access_methods *bus;
+	int retval = 0;
+
+	di = kzalloc(sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate device info structure\n");
+		return -ENOMEM;
+	}
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate access method structure\n");
+		kfree(di);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, di);
+	di->dev = &client->dev;
+	di->bat.name = "bq27200";
+	bus->read = &bq27200_read;
+	di->bus = bus;
+	di->client = client;
+
+	bq27x00_powersupply_init(di);
+
+	retval = power_supply_register(&client->dev, &di->bat);
+	if (retval) {
+		pr_err("BQ27200 battery driver: Failed to register battery\n");
+		goto batt_failed;
+	}
+
+	INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+	schedule_delayed_work(&di->monitor_work, 100);
+
+	return 0;
+
+batt_failed:
+	kfree(bus);
+	kfree(di);
+	return retval;
+}
+
+static int bq27200_battery_remove(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->bat);
+	kfree(di);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27200_battery_suspend(struct i2c_client *client,

pm_message_t mesg)

drivers/power/bq27x00_battery.c new file +6 -0
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	cancel_delayed_work(&di->monitor_work);
+	return 0;
+}

drivers/power/bq27x00_battery.c line 442

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+
+static int bq27200_battery_resume(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	schedule_delayed_work(&di->monitor_work, 0);
+	return 0;
+}
+#endif
+#endif

put a comment indicating which ifdef you're closing, like:

#endif /* CONFIG_PM */

Quoted 165 lines
drivers/power/bq27x00_battery.c new file +114 -0
+
+#ifdef BATTERY_BQ27000
+static int bq27000_battery_probe(struct  platform_device *pdev)
+{
+	struct bq27x00_device_info *di;
+	struct bq27x00_access_methods *bus;
+	int retval = 0;
+
+	di = kzalloc(sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate device info structure\n");
+		return -ENOMEM;
+	}
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate access method structure\n");
+		kfree(di);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, di);
+
+	di->dev = &pdev->dev;
+	di->w1_dev = pdev->dev.parent;
+	di->bat.name = "bq27000";
+	bus->read = &bq27000_read;
+	di->bus = bus;
+
+	bq27x00_powersupply_init(di);
+
+	retval = power_supply_register(&pdev->dev, &di->bat);
+	if (retval) {
+		pr_err("BQ27000 battery driver: Failed to register battery\n");
+		goto batt_failed;
+	}
+
+	INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+	schedule_delayed_work(&di->monitor_work, 50);
+
+	return 0;
+
+batt_failed:
+	kfree(bus);
+	kfree(di);
+	return retval;
+}
+
+static int bq27000_battery_remove(struct  platform_device *pdev)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->bat);
+	platform_set_drvdata(pdev, NULL);
+	kfree(di);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	cancel_delayed_work(&di->monitor_work);
+	return 0;
+}
+
+static int bq27000_battery_resume(struct platform_device *pdev)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	schedule_delayed_work(&di->monitor_work, 0);
+	return 0;
+}
+#endif
+#endif
+
+static int __init bq27x00_battery_init(void)
+{
+	int status = 0;
+
+#if defined(BATTERY_BQ27000)
+	status = platform_driver_register(&bq27000_battery_driver);
+	if (status)
+		printk(KERN_ERR "Unable to register BQ27000 driver\n");
+#endif
+#if defined(BATTERY_BQ27200)
+	status = i2c_add_driver(&bq27200_battery_driver);
+		printk(KERN_ERR "Unable to register BQ27200 driver\n");
+#endif
+	return status;
+}
+
+static void __exit bq27x00_battery_exit(void)
+{
+#if defined(BATTERY_BQ27000)
+	platform_driver_unregister(&bq27000_battery_driver);
+#endif
+#if defined(BATTERY_BQ27200)
+	i2c_del_driver(&bq27200_battery_driver);
+#endif
+}
+
+module_init(bq27x00_battery_init);
+module_exit(bq27x00_battery_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("BQ27x00 battery moniter driver");
+MODULE_LICENSE("GPL");

Index: linux-omap-2.6/drivers/power/Kconfig
===================================================================
--- linux-omap-2.6.orig/drivers/power/Kconfig 2008-04-08
17:15:04.000000000 +0530
+++ linux-omap-2.6/drivers/power/Kconfig 2008-04-21 08:25:00.000000000
+0530

drivers/power/bq27x00_battery.c new file +4 -0
@@ -49,4 +49,25 @@
 	help
 	  Say Y to enable support for the battery on the OLPC laptop.
 
+config BATTERY_BQ27x00
+	tristate "BQ27x00 battery driver"
+	help
+	  Say Y here to enable support for batteries with BQ27000 or BQ27200

chip.

drivers/power/bq27x00_battery.c new file +17 -0
+
+config BATTERY_BQ27000
+	bool "BQ27000 battery driver"
+	depends on BATTERY_BQ27x00
+	select W1
+	select W1_SLAVE_BQ27000
+	help
+	  Say Y here to enable support for batteries with BQ27000(HDQ) chip.
+
+config BATTERY_BQ27200
+	bool "BQ27200 battery driver"
+	depends on BATTERY_BQ27x00
+	select I2C
+	select I2C_OMAP
+	help
+	  Say Y here to enable support for batteries with BQ27200(I2C) chip.
+
 endif # POWER_SUPPLY

Index: linux-omap-2.6/drivers/power/Makefile
===================================================================
--- linux-omap-2.6.orig/drivers/power/Makefile 2008-04-08
17:15:04.000000000 +0530
+++ linux-omap-2.6/drivers/power/Makefile 2008-04-20 17:03:51.000000000
+0530

drivers/power/bq27x00_battery.c new file +1 -0
@@ -20,3 +20,4 @@
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
+obj-$(CONFIG_BATTERY_BQ27x00)   += bq27x00_battery.o

Index: linux-omap-2.6/drivers/w1/slaves/w1_bq27000.c
===================================================================
--- linux-omap-2.6.orig/drivers/w1/slaves/w1_bq27000.c 2008-04-08
17:15:05.000000000 +0530
+++ linux-omap-2.6/drivers/w1/slaves/w1_bq27000.c 2008-04-20
17:08:55.000000000 +0530

drivers/power/bq27x00_battery.c line 62

Quoted 5 lines
drivers/power/bq27x00_battery.c new file +1 -1
@@ -59,7 +59,7 @@
 	int id = 1;
 	struct platform_device *pdev;
 
-	pdev = platform_device_alloc("omap-bq2700-battery", id);
+	pdev = platform_device_alloc("bq27000-bat", id);

do you really need to change the name here?
It seems that this change doesn't belong to this patch.

Quoted 8 lines
drivers/power/bq27x00_battery.c new file +0 -1
 	if (!pdev) {
 		ret = -ENOMEM;
 		return ret;
 
--

To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 5 lines
Best Regards,

Felipe Balbi
http://felipebalbi.com
[email protected]
#2 lore raw

Hi Felipe,

Thanks for the comments. I will fix them and resend the patch.

Please note my view on the below point.

Quoted 5 lines

drivers/w1/slaves/w1_bq27000.c line 62

Quoted 2 lines
drivers/w1/slaves/w1_bq27000.c +1 -1
-	pdev = platform_device_alloc("omap-bq2700-battery", id);
+	pdev = platform_device_alloc("bq27000-bat", id);

do you really need to change the name here?
It seems that this change doesn't belong to this patch.

I will make this as a separate patch.As BQ27000 chip is not omap specific, I guess the above name is not correct. Hence I intend to make that change.

Regards,
Madhu

Quoted 724 lines

-----Original Message-----
From: Felipe Balbi [mailto:[email protected]]
Sent: Friday, April 25, 2008 4:20 PM
To: Madhusudhan Chikkature Rajashekar
Cc: Tony Lindgren; [email protected]
Subject: Re: [RFC/PATCH] BQ27000/BQ27200 battery monitoring driver for OMAP34xx

Some cosmetic comments below

Quoted 1 line · Madhusudhan Chikkature Rajashekar

This patch provides the battery monitoring driver to

monitor batteries
with

Quoted 2 lines

BQ27000(HDQ) or BQ27200(i2C) chips.
On omap 3430 sdp BQ27000 battery is tested through the HDQ interface

which

Quoted 2 lines

uses the earlier posted HDQ and BQ slave drivers. The BQ27200 support is an extension to the BQ27000 driver

as the register

Quoted 3 lines

set between BQ27000 and BQ27200 is the same.

Thanks to Klaus.K Pedersen and Mikko Ylinen for the

suggestions to add

Quoted 20 lines

support for BQ27200 chip as part of
this driver.

---
 drivers/power/Kconfig           |   21 +
 drivers/power/Makefile          |    1
 drivers/power/bq27x00_battery.c |  556
++++++++++++++++++++++++++++++++++++++++
 drivers/w1/slaves/w1_bq27000.c  |    2
 4 files changed, 579 insertions(+), 1 deletion(-)

Index: linux-omap-2.6/drivers/power/bq27x00_battery.c
===================================================================

drivers/power/bq27x00_battery.c new file +0 -0

10:50:53.631358952 +0530

drivers/power/bq27x00_battery.c line 10

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
@@ -0,0 +1,556 @@
+/*
+ * linux/drivers/power/bq27x00_battery.c
+ *
+ * BQ27000/BQ27200 battery driver
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * Author: Texas Instruments
+ *
+ * This package is free software; you can redistribute it 

and/or modify

drivers/power/bq27x00_battery.c line 11

Quoted 1 line
drivers/power/bq27x00_battery.c new file +1 -0
+ * it under the terms of the GNU General Public License 

version 2 as

drivers/power/bq27x00_battery.c

Quoted 5 lines
drivers/power/bq27x00_battery.c new file +5 -0
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A 

PARTICULAR PURPOSE.

drivers/power/bq27x00_battery.c line 27

Quoted 11 lines
drivers/power/bq27x00_battery.c new file +11 -0
+ *
+ */
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#if defined(CONFIG_BATTERY_BQ27000)

Here use ifdef

drivers/power/bq27x00_battery.c line 28

Quoted 1 line
drivers/power/bq27x00_battery.c new file +1 -0
+#define BATTERY_BQ27000

there's no need to add this one as you can use the Kconfig option

drivers/power/bq27x00_battery.c

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+#include "../w1/w1.h"
+#endif
+#if defined(CONFIG_BATTERY_BQ27200)
+#define BATTERY_BQ27200
+#include <linux/i2c.h>
+#endif
+
+#define BQ27x00_REG_TEMP		0x06
+#define BQ27x00_REG_VOLT		0x08
+#define BQ27x00_REG_RSOC		0x0B /* Relative 

State-of-Charge */

Quoted 7 lines
drivers/power/bq27x00_battery.c new file +7 -0
+#define BQ27x00_REG_AI			0x14
+#define BQ27x00_REG_FLAGS		0x0A
+#define HIGH_BYTE(A)			((A) << 8)
+
+#if defined(BATTERY_BQ27000)
+extern int w1_bq27000_read(struct device *dev, u8 reg);
+#endif

drivers/power/bq27x00_battery.c line 55

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+
+struct bq27x00_device_info;
+struct bq27x00_access_methods {
+	int (*read)(u8 reg, int *rt_value, int b_single,
+		struct bq27x00_device_info *di);
+};
+
+struct bq27x00_device_info {
+	struct device 		*dev;
+#if defined(BATTERY_BQ27000)

#ifdef CONFIG_BATERRY_BQ27000

drivers/power/bq27x00_battery.c line 58

Quoted 3 lines
drivers/power/bq27x00_battery.c new file +3 -0
+	struct device		*w1_dev;
+#endif
+#if defined(BATTERY_BQ27200)

#ifdef CONFIG_BATTERY_BQ27200

Quoted 64 lines
drivers/power/bq27x00_battery.c new file +64 -0
+	struct i2c_client *client;
+#endif
+	unsigned long		update_time;
+	int			voltage_uV;
+	int			current_uA;
+	int			temp_C;
+	int			charge_rsoc;
+	struct bq27x00_access_methods	*bus;
+	struct power_supply	bat;
+	struct delayed_work	monitor_work;
+};
+
+static unsigned int cache_time = 60000;
+module_param(cache_time, uint, 0644);
+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
+
+static enum power_supply_property bq27x00_battery_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di);
+
+#if defined(BATTERY_BQ27000)
+static int bq27000_battery_probe(struct platform_device *dev);
+static int bq27000_battery_remove(struct platform_device *dev);
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *dev,
+	pm_message_t state);
+static int bq27000_battery_resume(struct platform_device *dev);
+#endif
+
+static struct platform_driver bq27000_battery_driver = {
+	.probe = bq27000_battery_probe,
+	.remove = bq27000_battery_remove,
+#ifdef CONFIG_PM
+	.suspend = bq27000_battery_suspend,
+	.resume = bq27000_battery_resume,
+#endif
+	.driver = {
+		.name = "bq27000-bat",
+	},
+};
+#endif
+
+#if defined(BATTERY_BQ27200)
+static int bq27200_battery_probe(struct i2c_client *client);
+static int bq27200_battery_remove(struct i2c_client *client);
+static int bq27200_battery_suspend(struct i2c_client *client,
+		pm_message_t mesg);
+static int bq27200_battery_resume(struct i2c_client *client);
+static struct i2c_driver bq27200_battery_driver = {
+	.driver = {
+		.name   = "bq27200-bat",
+	},
+	.probe  = bq27200_battery_probe,
+	.remove = bq27200_battery_remove,
+#ifdef CONFIG_PM
+	.suspend = bq27200_battery_suspend,

drivers/power/bq27x00_battery.c

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+	.resume = bq27200_battery_resume,
+#endif
+};
+#endif
+
+/*
+ * Return the battery temperature in Celcius degrees
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_temperature(struct 

bq27x00_device_info *di)

Quoted 15 lines
drivers/power/bq27x00_battery.c new file +15 -0
+{
+	int ret, temp = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading temperature from the battery\n");
+		return ret;
+	}
+
+	return (temp >> 2) - 273;
+}
+
+/*
+ * Return the battery Voltage in milivolts

drivers/power/bq27x00_battery.c

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
+{
+	int ret, volt = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery voltage from the 

battery\n");

Quoted 62 lines
drivers/power/bq27x00_battery.c new file +62 -0
+		return ret;
+	}
+
+	return volt;
+}
+
+/*
+ * Return the battery average current
+ * Note that current can be negative signed as well
+ * Or 0 if something fails.
+ */
+static int bq27x00_battery_current(struct bq27x00_device_info *di)
+{
+	int ret, curr = 0, flags = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading current from the battery\n");
+		return 0;
+	}
+	ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+	if (ret < 0) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery flags\n");
+		return 0;
+	}
+	if ((flags & (1 << 7)) != 0) {
+		pr_debug("Negative current\n");
+		return -curr;
+	} else {
+		return curr;
+	}
+}
+
+/*
+ * Return the battery Relative State-of-Charge
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
+{
+	int ret, rsoc = 0;
+
+	ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
+	if (ret) {
+		pr_err("BQ27x00 battery driver:"
+			"Error reading battery Relative"
+			"State-of-Charge\n");
+		return ret;
+	}
+	return rsoc;
+}
+
+#if defined(BATTERY_BQ27000)
+static int bq27000_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	u8 val;
+
+	val = w1_bq27000_read(di->w1_dev, reg);
+	*rt_value = val;
+

drivers/power/bq27x00_battery.c line 229

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+	if (!b_single) {
+		val = 0;
+		val = w1_bq27000_read(di->w1_dev, reg + 1);
+		*rt_value +=  HIGH_BYTE((int) val);
+	}
+
+	return 0;
+}
+#else
+#define bq27000_read NULL

this should be defined as 0 or an static inline int [...] { return 0; }

Quoted 23 lines
drivers/power/bq27x00_battery.c new file +23 -0
+#endif
+
+#if defined(BATTERY_BQ27200)
+static int bq27200_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	struct i2c_client *client = di->client;
+	struct i2c_msg msg[1];
+	unsigned char data[2];
+	int err;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 1;
+	msg->buf = data;
+
+	data[0] = reg;
+	err = i2c_transfer(client->adapter, msg, 1);
+
+	if (err >= 0) {

drivers/power/bq27x00_battery.c

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+		if (!b_single)
+			msg->len = 2;
+		else
+			msg->len = 1;
+
+		msg->flags = I2C_M_RD;
+		err = i2c_transfer(client->adapter, msg, 1);
+		if (err >= 0) {
+			if (!b_single)
+				*rt_value = data[1] | 

HIGH_BYTE(data[0]);

Quoted 5 lines
drivers/power/bq27x00_battery.c new file +5 -0
+			else
+				*rt_value = data[0];
+
+			return 0;
+		} else {

drivers/power/bq27x00_battery.c line 277

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+			pr_err("BQ27200 I2C read failed\n");
+			return err;
+		}
+	} else {
+		pr_err("BQ27200 I2C write failed\n");
+		return err;
+	}
+}
+#else
+#define bq27200_read NULL

same here

drivers/power/bq27x00_battery.c

Quoted 13 lines
drivers/power/bq27x00_battery.c new file +13 -0
+#endif
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+	struct bq27x00_device_info *di)
+{
+	int ret;
+
+	ret = di->bus->read(reg, rt_value, b_single, di);
+	return ret;
+}
+
+/*
+ * Read the battery temp, voltage, current and relative 

state of charge.

drivers/power/bq27x00_battery.c line 292

Quoted 2 lines
drivers/power/bq27x00_battery.c new file +2 -0
+ */
+static void bq27x00_battery_read_status(struct 

bq27x00_device_info *di)

Quoted 54 lines
drivers/power/bq27x00_battery.c new file +54 -0
+{
+	if (di->update_time && time_before(jiffies, di->update_time +
+					msecs_to_jiffies(cache_time)))
+		return;
+
+	di->temp_C = bq27x00_battery_temperature(di);
+	di->voltage_uV = bq27x00_battery_voltage(di);
+	di->current_uA = bq27x00_battery_current(di);
+	di->charge_rsoc = bq27x00_battery_rsoc(di);
+
+	di->update_time = jiffies;
+
+	return;
+}
+
+static void bq27x00_battery_work(struct delayed_work *work)
+{
+	struct bq27x00_device_info *di = container_of(work,
+		struct bq27x00_device_info, monitor_work);
+
+	bq27x00_battery_read_status(di);
+	schedule_delayed_work(&di->monitor_work, 100);
+	return;
+}
+
+#define to_bq27x00_device_info(x) container_of((x), \
+				struct bq27x00_device_info, bat);
+
+static int bq27x00_battery_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = di->voltage_uV;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = di->current_uA;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = di->charge_rsoc;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = di->temp_C;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = di->charge_rsoc;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		if (di->voltage_uV == 0)
+			val->intval = 0;
+		else

drivers/power/bq27x00_battery.c

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+			val->intval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void bq27x00_powersupply_init(struct 

bq27x00_device_info *di)

Quoted 33 lines
drivers/power/bq27x00_battery.c new file +33 -0
+{
+	di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat.properties = bq27x00_battery_props;
+	di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+	di->bat.get_property = bq27x00_battery_get_property;
+	di->bat.external_power_changed = NULL;
+	return;
+}
+
+#ifdef BATTERY_BQ27200
+static int bq27200_battery_probe(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di;
+	struct bq27x00_access_methods *bus;
+	int retval = 0;
+
+	di = kzalloc(sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate device info structure\n");
+		return -ENOMEM;
+	}
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate access method structure\n");
+		kfree(di);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, di);
+	di->dev = &client->dev;

drivers/power/bq27x00_battery.c

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+	di->bat.name = "bq27200";
+	bus->read = &bq27200_read;
+	di->bus = bus;
+	di->client = client;
+
+	bq27x00_powersupply_init(di);
+
+	retval = power_supply_register(&client->dev, &di->bat);
+	if (retval) {
+		pr_err("BQ27200 battery driver: Failed to 

register battery\n");

Quoted 34 lines
drivers/power/bq27x00_battery.c new file +27 -0
+		goto batt_failed;
+	}
+
+	INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+	schedule_delayed_work(&di->monitor_work, 100);
+
+	return 0;
+
+batt_failed:
+	kfree(bus);
+	kfree(di);
+	return retval;
+}
+
+static int bq27200_battery_remove(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->bat);
+	kfree(di);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27200_battery_suspend(struct i2c_client *client,

pm_message_t mesg)

drivers/power/bq27x00_battery.c new file +6 -0
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	cancel_delayed_work(&di->monitor_work);
+	return 0;
+}

drivers/power/bq27x00_battery.c line 442

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+
+static int bq27200_battery_resume(struct i2c_client *client)
+{
+	struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+	schedule_delayed_work(&di->monitor_work, 0);
+	return 0;
+}
+#endif
+#endif

put a comment indicating which ifdef you're closing, like:

#endif /* CONFIG_PM */

Quoted 26 lines
drivers/power/bq27x00_battery.c new file +26 -0
+
+#ifdef BATTERY_BQ27000
+static int bq27000_battery_probe(struct  platform_device *pdev)
+{
+	struct bq27x00_device_info *di;
+	struct bq27x00_access_methods *bus;
+	int retval = 0;
+
+	di = kzalloc(sizeof(*di), GFP_KERNEL);
+	if (!di) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate device info structure\n");
+		return -ENOMEM;
+	}
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus) {
+		pr_err("BQ27000 battery driver:"
+			"Failed to allocate access method structure\n");
+		kfree(di);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, di);
+
+	di->dev = &pdev->dev;

drivers/power/bq27x00_battery.c

Quoted 10 lines
drivers/power/bq27x00_battery.c new file +10 -0
+	di->w1_dev = pdev->dev.parent;
+	di->bat.name = "bq27000";
+	bus->read = &bq27000_read;
+	di->bus = bus;
+
+	bq27x00_powersupply_init(di);
+
+	retval = power_supply_register(&pdev->dev, &di->bat);
+	if (retval) {
+		pr_err("BQ27000 battery driver: Failed to 

register battery\n");

Quoted 78 lines
drivers/power/bq27x00_battery.c new file +78 -0
+		goto batt_failed;
+	}
+
+	INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+	schedule_delayed_work(&di->monitor_work, 50);
+
+	return 0;
+
+batt_failed:
+	kfree(bus);
+	kfree(di);
+	return retval;
+}
+
+static int bq27000_battery_remove(struct  platform_device *pdev)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	flush_scheduled_work();
+	power_supply_unregister(&di->bat);
+	platform_set_drvdata(pdev, NULL);
+	kfree(di);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	cancel_delayed_work(&di->monitor_work);
+	return 0;
+}
+
+static int bq27000_battery_resume(struct platform_device *pdev)
+{
+	struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+	schedule_delayed_work(&di->monitor_work, 0);
+	return 0;
+}
+#endif
+#endif
+
+static int __init bq27x00_battery_init(void)
+{
+	int status = 0;
+
+#if defined(BATTERY_BQ27000)
+	status = platform_driver_register(&bq27000_battery_driver);
+	if (status)
+		printk(KERN_ERR "Unable to register BQ27000 driver\n");
+#endif
+#if defined(BATTERY_BQ27200)
+	status = i2c_add_driver(&bq27200_battery_driver);
+		printk(KERN_ERR "Unable to register BQ27200 driver\n");
+#endif
+	return status;
+}
+
+static void __exit bq27x00_battery_exit(void)
+{
+#if defined(BATTERY_BQ27000)
+	platform_driver_unregister(&bq27000_battery_driver);
+#endif
+#if defined(BATTERY_BQ27200)
+	i2c_del_driver(&bq27200_battery_driver);
+#endif
+}
+
+module_init(bq27x00_battery_init);
+module_exit(bq27x00_battery_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("BQ27x00 battery moniter driver");
+MODULE_LICENSE("GPL");
Quoted 5 lines

Index: linux-omap-2.6/drivers/power/Kconfig
===================================================================
--- linux-omap-2.6.orig/drivers/power/Kconfig 2008-04-08
17:15:04.000000000 +0530
+++ linux-omap-2.6/drivers/power/Kconfig 2008-04-21

08:25:00.000000000

drivers/power/bq27x00_battery.c line 55

Quoted 9 lines

+0530

drivers/power/bq27x00_battery.c new file +4 -0
@@ -49,4 +49,25 @@
 	help
 	  Say Y to enable support for the battery on the OLPC laptop.
 
+config BATTERY_BQ27x00
+	tristate "BQ27x00 battery driver"
+	help
+	  Say Y here to enable support for batteries with 

BQ27000 or BQ27200

drivers/power/bq27x00_battery.c

Quoted 9 lines

chip.

drivers/power/bq27x00_battery.c new file +8 -0
+
+config BATTERY_BQ27000
+	bool "BQ27000 battery driver"
+	depends on BATTERY_BQ27x00
+	select W1
+	select W1_SLAVE_BQ27000
+	help
+	  Say Y here to enable support for batteries with 

BQ27000(HDQ) chip.

drivers/power/bq27x00_battery.c

Quoted 8 lines
drivers/power/bq27x00_battery.c new file +8 -0
+
+config BATTERY_BQ27200
+	bool "BQ27200 battery driver"
+	depends on BATTERY_BQ27x00
+	select I2C
+	select I2C_OMAP
+	help
+	  Say Y here to enable support for batteries with 

BQ27200(I2C) chip.

Quoted 7 lines

+
endif # POWER_SUPPLY
Index: linux-omap-2.6/drivers/power/Makefile
===================================================================
--- linux-omap-2.6.orig/drivers/power/Makefile 2008-04-08
17:15:04.000000000 +0530
+++ linux-omap-2.6/drivers/power/Makefile 2008-04-20

17:03:51.000000000

Quoted 9 lines

+0530

drivers/power/bq27x00_battery.c new file +1 -0
@@ -20,3 +20,4 @@
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
+obj-$(CONFIG_BATTERY_BQ27x00)   += bq27x00_battery.o

Index: linux-omap-2.6/drivers/w1/slaves/w1_bq27000.c
===================================================================
--- linux-omap-2.6.orig/drivers/w1/slaves/w1_bq27000.c

2008-04-08

drivers/power/bq27x00_battery.c line 62

Quoted 9 lines

17:15:05.000000000 +0530
+++ linux-omap-2.6/drivers/w1/slaves/w1_bq27000.c 2008-04-20
17:08:55.000000000 +0530

drivers/power/bq27x00_battery.c new file +1 -1
@@ -59,7 +59,7 @@
 	int id = 1;
 	struct platform_device *pdev;
 
-	pdev = platform_device_alloc("omap-bq2700-battery", id);
+	pdev = platform_device_alloc("bq27000-bat", id);

do you really need to change the name here?
It seems that this change doesn't belong to this patch.

Quoted 6 lines
drivers/power/bq27x00_battery.c new file +0 -1
 	if (!pdev) {
 		ret = -ENOMEM;
 		return ret;
 
--

To unsubscribe from this list: send the line "unsubscribe

linux-omap" in

Quoted 2 lines

the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 5 lines
Best Regards,

Felipe Balbi
http://felipebalbi.com
[email protected]
#3 lore raw
Quoted 6 lines · Madhusudhan Chikkature Rajashekar

Hi Felipe,

Thanks for the comments. I will fix them and resend the patch.

Please note my view on the below point.

Quoted 7 lines
Quoted 5 lines

drivers/w1/slaves/w1_bq27000.c line 62

Quoted 2 lines
drivers/w1/slaves/w1_bq27000.c +1 -1
-	pdev = platform_device_alloc("omap-bq2700-battery", id);
+	pdev = platform_device_alloc("bq27000-bat", id);

do you really need to change the name here?
It seems that this change doesn't belong to this patch.

I will make this as a separate patch.As BQ27000 chip is not omap

specific,

Quoted 1 line

I guess the above name is not correct. Hence I intend to make that

change.

Ok, works for me :-)

I guess bq2700-battery is ok, just remove omap- from the previous name??

Signature · 5 lines
Best Regards,

Felipe Balbi
http://felipebalbi.com
[email protected]
#4 lore raw
Quoted 28 lines

-----Original Message-----
From: Felipe Balbi [mailto:[email protected]]
Sent: Monday, April 28, 2008 5:17 PM
To: Madhusudhan Chikkature Rajashekar
Cc: Tony Lindgren; [email protected]
Subject: RE: [RFC/PATCH] BQ27000/BQ27200 battery monitoring driver for OMAP34xx

Quoted 6 lines · Madhusudhan Chikkature Rajashekar

Hi Felipe,

Thanks for the comments. I will fix them and resend the patch.

Please note my view on the below point.

Quoted 7 lines
Quoted 5 lines

drivers/w1/slaves/w1_bq27000.c line 62

Quoted 2 lines
drivers/w1/slaves/w1_bq27000.c +1 -1
-	pdev = platform_device_alloc("omap-bq2700-battery", id);
+	pdev = platform_device_alloc("bq27000-bat", id);

do you really need to change the name here?
It seems that this change doesn't belong to this patch.

I will make this as a separate patch.As BQ27000 chip is not omap

Quoted 8 lines

specific,

Quoted 1 line

I guess the above name is not correct. Hence I intend to make that

change.

Ok, works for me :-)

I guess bq2700-battery is ok, just remove omap- from the previous name??

Yes. I will correct the name and resend the patch. I will send this one as a separate patch and followed by it will be the battery driver patch.

Quoted 10 lines
Signature · 6 lines
-- 
Best Regards,

Felipe Balbi
http://felipebalbi.com
[email protected]