All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
@ 2014-02-01 22:23 ` Vladimir Barinov
  0 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree
  Cc: mk7.kang, k.kozlowski, mark.rutland

Hello.

This adds the folowing:
- Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips
- Document DT bindings
- Remove superseded Maxim MAX17040 gauge driver

Vladimir Barinov (3):
 [1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
 [2/3] dt: Document ModelGauge gauge bindings
 [3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge

---
This patchset is against the 'kernel/git/torvalds/linux.git' repo.

Changes since v1:
- switched to REGMAP API
- replaced request_threaded_irq with devm_request_threaded_irq
- replaced cancel_delayed_work with _sync version
- moved "empty_alert_threshold, soc_change_alert, hibernate_threshold,
  active_threshold, undervoltage, overvoltage, resetvoltage" parameters
  out from platform_data and DT
- removed unused parameters "empty_adjustment, empty_adjustment"
- added return value checks for of_property_read_XX functions
- removed irrelevant bindings
- fixed dt properties naming in documentation
- added binding size description in documentation
- removed satelite include file include/linux/max17040_battery.h

 Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt |   61 
 drivers/power/Kconfig                                                 |   17 
 drivers/power/Makefile                                                |    2 
 drivers/power/max17040_battery.c                                      |  297 ---
 drivers/power/modelgauge_battery.c                                    |  838 ++++++++++
 include/linux/max17040_battery.h                                      |   19 
 include/linux/platform_data/battery-modelgauge.h                      |   31 
 7 files changed, 940 insertions(+), 325 deletions(-)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
@ 2014-02-01 22:23 ` Vladimir Barinov
  0 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree
  Cc: mk7.kang, k.kozlowski, mark.rutland

Hello.

This adds the folowing:
- Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips
- Document DT bindings
- Remove superseded Maxim MAX17040 gauge driver

Vladimir Barinov (3):
 [1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
 [2/3] dt: Document ModelGauge gauge bindings
 [3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge

---
This patchset is against the 'kernel/git/torvalds/linux.git' repo.

Changes since v1:
- switched to REGMAP API
- replaced request_threaded_irq with devm_request_threaded_irq
- replaced cancel_delayed_work with _sync version
- moved "empty_alert_threshold, soc_change_alert, hibernate_threshold,
  active_threshold, undervoltage, overvoltage, resetvoltage" parameters
  out from platform_data and DT
- removed unused parameters "empty_adjustment, empty_adjustment"
- added return value checks for of_property_read_XX functions
- removed irrelevant bindings
- fixed dt properties naming in documentation
- added binding size description in documentation
- removed satelite include file include/linux/max17040_battery.h

 Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt |   61 
 drivers/power/Kconfig                                                 |   17 
 drivers/power/Makefile                                                |    2 
 drivers/power/max17040_battery.c                                      |  297 ---
 drivers/power/modelgauge_battery.c                                    |  838 ++++++++++
 include/linux/max17040_battery.h                                      |   19 
 include/linux/platform_data/battery-modelgauge.h                      |   31 
 7 files changed, 940 insertions(+), 325 deletions(-)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
  2014-02-01 22:23 ` Vladimir Barinov
@ 2014-02-01 22:23     ` Vladimir Barinov
  -1 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: mk7.kang-Sze3O3UU22JBDgjK7y7TUQ,
	k.kozlowski-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland-5wv7dgnIgG8

Add Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips

Signed-off-by: Vladimir Barinov <vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

---
 drivers/power/Kconfig                            |    9 
 drivers/power/Makefile                           |    1 
 drivers/power/modelgauge_battery.c               |  838 +++++++++++++++++++++++
 include/linux/platform_data/battery-modelgauge.h |   31 
 4 files changed, 879 insertions(+)

Index: battery-2.6/drivers/power/Kconfig
===================================================================
--- battery-2.6.orig/drivers/power/Kconfig	2014-02-02 01:29:07.434614235 +0400
+++ battery-2.6/drivers/power/Kconfig	2014-02-02 01:29:29.070614750 +0400
@@ -205,6 +205,15 @@
 	  with MAX17042. This driver also supports max17047/50 chips which are
 	  improved version of max17042.
 
+config BATTERY_MODELGAUGE
+	tristate "Maxim ModelGauge ICs fuel gauge"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  ModelGauge(TM) is a Maxim algorithm incorporated in
+	  MAX17040/41/43/44/48/49/58/59 fuel-gauges for lithium-ion (Li+)
+	  batteries.
+
 config BATTERY_Z2
 	tristate "Z2 battery driver"
 	depends on I2C && MACH_ZIPIT2
Index: battery-2.6/drivers/power/Makefile
===================================================================
--- battery-2.6.orig/drivers/power/Makefile	2014-02-02 01:29:07.462614237 +0400
+++ battery-2.6/drivers/power/Makefile	2014-02-02 01:29:12.978614368 +0400
@@ -32,6 +32,7 @@
 obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
+obj-$(CONFIG_BATTERY_MODELGAUGE)	+= modelgauge_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
 obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
 obj-$(CONFIG_BATTERY_TWL4030_MADC)	+= twl4030_madc_battery.o
Index: battery-2.6/drivers/power/modelgauge_battery.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ battery-2.6/drivers/power/modelgauge_battery.c	2014-02-02 01:29:34.314614874 +0400
@@ -0,0 +1,838 @@
+/*
+ * Maxim ModelGauge ICs fuel gauge driver
+ *
+ * Author: Vladimir Barinov <source-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/battery-modelgauge.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define DRV_NAME "modelgauge"
+
+/* Register offsets for ModelGauge ICs */
+#define MODELGAUGE_VCELL_REG		0x02
+#define MODELGAUGE_SOC_REG		0x04
+#define MODELGAUGE_MODE_REG		0x06
+#define MODELGAUGE_VERSION_REG		0x08
+#define MODELGAUGE_HIBRT_REG		0x0A
+#define MODELGAUGE_CONFIG_REG		0x0C
+#define MODELGAUGE_OCV_REG		0x0E
+#define MODELGAUGE_VALRT_REG		0x14
+#define MODELGAUGE_CRATE_REG		0x16
+#define MODELGAUGE_VRESETID_REG		0x18
+#define MODELGAUGE_STATUS_REG		0x1A
+#define MODELGAUGE_UNLOCK_REG		0x3E
+#define MODELGAUGE_TABLE_REG		0x40
+#define MODELGAUGE_RCOMPSEG_REG		0x80
+#define MODELGAUGE_CMD_REG		0xFE
+
+/* MODE register bits */
+#define MODELGAUGE_MODE_QUICKSTART	(1 << 14)
+#define MODELGAUGE_MODE_ENSLEEP		(1 << 13)
+#define MODELGAUGE_MODE_HIBSTAT		(1 << 12)
+
+/* CONFIG register bits */
+#define MODELGAUGE_CONFIG_SLEEP		(1 << 7)
+#define MODELGAUGE_CONFIG_ALSC		(1 << 6)
+#define MODELGAUGE_CONFIG_ALRT		(1 << 5)
+#define MODELGAUGE_CONFIG_ATHD_MASK	0x1f
+
+/* STATUS register bits */
+#define MODELGAUGE_STATUS_ENVR		(1 << 14)
+#define MODELGAUGE_STATUS_SC		(1 << 13)
+#define MODELGAUGE_STATUS_HD		(1 << 12)
+#define MODELGAUGE_STATUS_VR		(1 << 11)
+#define MODELGAUGE_STATUS_VL		(1 << 10)
+#define MODELGAUGE_STATUS_VH		(1 << 9)
+#define MODELGAUGE_STATUS_RI		(1 << 8)
+
+/* VRESETID register bits */
+#define MODELGAUGE_VRESETID_DIS		(1 << 8)
+
+#define MODELGAUGE_UNLOCK_VALUE		0x4a57
+#define MODELGAUGE_RESET_VALUE		0x5400
+
+#define MODELGAUGE_RCOMP_UPDATE_DELAY	60000
+
+/* Capacity threshold where an interrupt is generated on the ALRT pin */
+#define MODELGAUGE_EMPTY_ATHD		15
+/* Enable alert for 1% soc change */
+#define MODELGAUGE_SOC_CHANGE_ALERT	1
+/* Hibernate threshold (crate), where IC enters hibernate mode */
+#define MODELGAUGE_HIBRT_THD		20
+/* Active threshold (mV), where IC exits hibernate mode */
+#define MODELGAUGE_ACTIVE_THD		60
+/* Voltage (mV), when IC alerts if battery voltage less then undervoltage */
+#define MODELGAUGE_UV			0
+/* Voltage (mV), when IC alerts if battery voltage greater then overvoltage */
+#define MODELGAUGE_OV			5120
+/*
+ * Voltage threshold (mV) below which the IC resets itself.
+ * Used to detect battery removal and reinsertion
+ */
+#define MODELGAUGE_RV			0
+
+enum chip_id {
+	ID_MAX17040,
+	ID_MAX17041,
+	ID_MAX17043,
+	ID_MAX17044,
+	ID_MAX17048,
+	ID_MAX17049,
+	ID_MAX17058,
+	ID_MAX17059,
+};
+
+struct modelgauge_priv {
+	struct device			*dev;
+	struct regmap			*regmap;
+	struct power_supply		battery;
+	struct modelgauge_platform_data	*pdata;
+	enum chip_id			chip;
+	struct work_struct		load_work;
+	struct delayed_work		rcomp_work;
+	int				soc_shift;
+};
+
+static void modelgauge_write_block(struct regmap *regmap, u8 adr, u8 size,
+				   u16 *data)
+{
+	int k;
+
+	/* RAM has different endianness then registers */
+	for (k = 0; k < size; k += 2, adr += 2, data++)
+		regmap_write(regmap, adr, cpu_to_be16(*data));
+}
+
+static int modelgauge_lsb_to_uvolts(struct modelgauge_priv *priv, int lsb)
+{
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17043:
+		return (lsb >> 4) * 1250; /* 1.25mV per bit */
+	case ID_MAX17041:
+	case ID_MAX17044:
+		return (lsb >> 4) * 2500; /* 2.5mV per bit */
+	case ID_MAX17048:
+	case ID_MAX17058:
+		return lsb * 625 / 8; /* 78.125uV per bit */
+	case ID_MAX17049:
+	case ID_MAX17059:
+		return lsb * 625 / 4; /* 156.25uV per bit */
+	default:
+		return -EINVAL;
+	}
+}
+
+static enum power_supply_property modelgauge_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static int modelgauge_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct modelgauge_priv *priv = container_of(psy,
+						    struct modelgauge_priv,
+						    battery);
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int reg;
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (pdata && pdata->get_charging_status)
+			val->intval = pdata->get_charging_status();
+		else
+			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = regmap_read(regmap, MODELGAUGE_VCELL_REG, &reg);
+		if (ret < 0)
+			return ret;
+
+		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		/* Unlock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+			     MODELGAUGE_UNLOCK_VALUE);
+		ret = regmap_read(regmap, MODELGAUGE_OCV_REG, &reg);
+		/* Lock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0);
+		if (ret < 0)
+			return ret;
+
+		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = regmap_read(regmap, MODELGAUGE_SOC_REG, &reg);
+		if (ret < 0)
+			return ret;
+
+		val->intval = reg / (1 << priv->soc_shift);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		if (pdata && pdata->get_temperature)
+			val->intval = pdata->get_temperature();
+		else
+			val->intval = 25;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void modelgauge_update_rcomp(struct modelgauge_priv *priv)
+{
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	u16 rcomp;
+	int temp;
+
+	if (pdata->get_temperature)
+		temp = pdata->get_temperature();
+	else
+		temp = 25;
+
+	if (!pdata->temp_co_up)
+		pdata->temp_co_up = -500;
+	if (!pdata->temp_co_down)
+		pdata->temp_co_down = -5000;
+
+	rcomp = pdata->rcomp0;
+	if (temp > 20)
+		rcomp += (temp - 20) * pdata->temp_co_up / 1000;
+	else
+		rcomp += (temp - 20) * pdata->temp_co_down / 1000;
+
+	/* Update RCOMP */
+	regmap_update_bits(regmap, MODELGAUGE_CONFIG_REG, 0xff, rcomp << 8);
+}
+
+static void modelgauge_update_rcomp_work(struct work_struct *work)
+{
+	struct modelgauge_priv *priv = container_of(work,
+						    struct modelgauge_priv,
+						    rcomp_work.work);
+
+	modelgauge_update_rcomp(priv);
+	schedule_delayed_work(&priv->rcomp_work,
+			      msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY));
+}
+
+static int modelgauge_load_model(struct modelgauge_priv *priv)
+{
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int ret = -EINVAL;
+	int timeout, k;
+	int ocv, config, soc;
+
+	/* Save CONFIG */
+	regmap_read(regmap, MODELGAUGE_CONFIG_REG, &config);
+
+	for (timeout = 0; timeout < 100; timeout++) {
+		/* Unlock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+			     MODELGAUGE_UNLOCK_VALUE);
+
+		/* Read OCV */
+		regmap_read(regmap, MODELGAUGE_OCV_REG, &ocv);
+		if (ocv != 0xffff)
+			break;
+	}
+
+	if (timeout >= 100) {
+		dev_err(priv->dev, "timeout to unlock model access\n");
+		ret = -EIO;
+		goto exit;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Reset chip transaction does not provide ACK */
+		regmap_write(regmap, MODELGAUGE_CMD_REG,
+			     MODELGAUGE_RESET_VALUE);
+		msleep(150);
+
+		for (timeout = 0; timeout < 100; timeout++) {
+			int reg;
+
+			/* Unlock Model Access */
+			regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+
+			/* Read OCV */
+			regmap_read(regmap, MODELGAUGE_OCV_REG, &reg);
+			if (reg != 0xffff)
+				break;
+		}
+
+		if (timeout >= 100) {
+			dev_err(priv->dev, "timeout to unlock model access\n");
+			ret = -EIO;
+			goto exit;
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+	case ID_MAX17043:
+	case ID_MAX17044:
+		/* Write OCV */
+		regmap_write(regmap, MODELGAUGE_OCV_REG, pdata->ocvtest);
+		/* Write RCOMP to its maximum value */
+		regmap_write(regmap, MODELGAUGE_CONFIG_REG, 0xff00);
+		break;
+	default:
+		break;
+	}
+
+	/* Write the model */
+	modelgauge_write_block(regmap, MODELGAUGE_TABLE_REG,
+			       MODELGAUGE_TABLE_SIZE,
+			       (u16 *)pdata->model_data);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049: {
+			u16 buf[16];
+
+			if (!pdata->rcomp_seg)
+				pdata->rcomp_seg = 0x80;
+
+			for (k = 0; k < 16; k++)
+				*buf = pdata->rcomp_seg;
+
+			/* Write RCOMPSeg */
+			modelgauge_write_block(regmap, MODELGAUGE_RCOMPSEG_REG,
+					       32, buf);
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+	case ID_MAX17043:
+	case ID_MAX17044:
+		/* Delay at least 150ms */
+		msleep(150);
+		break;
+	default:
+		break;
+	}
+
+	/* Write OCV */
+	regmap_write(regmap, MODELGAUGE_OCV_REG, pdata->ocvtest);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Disable Hibernate */
+		regmap_write(regmap, MODELGAUGE_HIBRT_REG, 0);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Lock Model Access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0);
+		break;
+	default:
+		break;
+	}
+
+	/* Delay between 150ms and 600ms */
+	msleep(200);
+
+	/* Read SOC Register and compare to expected result */
+	regmap_read(regmap, MODELGAUGE_SOC_REG, &soc);
+	soc >>= 8;
+	if (soc >= pdata->soc_check_a && soc <= pdata->soc_check_b)
+		ret = 0;
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Unlock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+			     MODELGAUGE_UNLOCK_VALUE);
+		break;
+	default:
+		break;
+	}
+
+	/* Restore CONFIG and OCV */
+	regmap_write(regmap, MODELGAUGE_CONFIG_REG, config);
+	regmap_write(regmap, MODELGAUGE_OCV_REG, ocv);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Restore Hibernate */
+		regmap_write(regmap, MODELGAUGE_HIBRT_REG,
+			     (MODELGAUGE_HIBRT_THD << 8) |
+			     MODELGAUGE_ACTIVE_THD);
+		break;
+	default:
+		break;
+	}
+
+exit:
+	/* Lock model access */
+	regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0);
+
+	/* Wait 150ms minimum */
+	msleep(150);
+
+	return ret;
+}
+
+static void modelgauge_load_model_work(struct work_struct *work)
+{
+	struct modelgauge_priv *priv = container_of(work,
+						    struct modelgauge_priv,
+						    load_work);
+	struct regmap *regmap = priv->regmap;
+	int ret;
+	int timeout;
+
+	for (timeout = 0; timeout < 10; timeout++) {
+		/* Load custom model data */
+		ret = modelgauge_load_model(priv);
+		if (!ret)
+			break;
+	}
+
+	if (timeout >= 10) {
+		dev_info(priv->dev, "failed to load custom model\n");
+		return;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Clear reset indicator bit */
+		regmap_update_bits(regmap, MODELGAUGE_STATUS_REG,
+				   MODELGAUGE_STATUS_RI, 0);
+		break;
+	default:
+		break;
+	}
+}
+
+static irqreturn_t modelgauge_irq_handler(int id, void *dev)
+{
+	struct modelgauge_priv *priv = dev;
+
+	/* clear alert status bit */
+	regmap_update_bits(priv->regmap, MODELGAUGE_CONFIG_REG,
+			   MODELGAUGE_CONFIG_ALRT, 0);
+
+	power_supply_changed(&priv->battery);
+	return IRQ_HANDLED;
+}
+
+static int modelgauge_init(struct modelgauge_priv *priv)
+{
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int ret;
+	int reg;
+
+	ret = regmap_read(regmap, MODELGAUGE_VERSION_REG, &reg);
+	if (ret < 0)
+		return -ENODEV;
+
+	dev_info(priv->dev, "IC production version 0x%04x\n", reg);
+
+	/* SOC=0 means unrecoverable IC fault, reset is a workaround */
+	regmap_read(regmap, MODELGAUGE_SOC_REG, &reg);
+	if (!reg) {
+		dev_info(priv->dev, "Reset chip, SOC measurement stall\n");
+		/* Reset chip transaction does not provide ACK */
+		regmap_write(regmap, MODELGAUGE_CMD_REG,
+			     MODELGAUGE_RESET_VALUE);
+		msleep(150);
+	}
+
+	/* Default model uses 8 bits per percent */
+	priv->soc_shift = 8;
+
+	if (!priv->pdata) {
+		dev_info(priv->dev, "no platform data provided\n");
+		return 0;
+	}
+
+	switch (pdata->bits) {
+	case 19:
+		priv->soc_shift = 9;
+		break;
+	case 18:
+	default:
+		priv->soc_shift = 8;
+		break;
+	}
+
+	/* Set RCOMP */
+	modelgauge_update_rcomp(priv);
+	if (pdata->get_temperature) {
+		/* Schedule update RCOMP */
+		schedule_delayed_work(&priv->rcomp_work,
+			    msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY));
+	}
+
+	/* Clear alert status bit, wake-up, set alert threshold */
+	reg = 0;
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		reg |= MODELGAUGE_SOC_CHANGE_ALERT ? MODELGAUGE_CONFIG_ALSC : 0;
+		/* fall-through */
+	case ID_MAX17043:
+	case ID_MAX17044:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		reg |= 32 - (MODELGAUGE_EMPTY_ATHD << (priv->soc_shift - 8));
+		break;
+	default:
+		break;
+	}
+	regmap_update_bits(regmap, MODELGAUGE_CONFIG_REG,
+			   MODELGAUGE_CONFIG_ALRT | MODELGAUGE_CONFIG_SLEEP |
+			   MODELGAUGE_CONFIG_ALSC | MODELGAUGE_CONFIG_ATHD_MASK,
+			   reg);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Set Hibernate thresholds */
+		reg = (MODELGAUGE_HIBRT_THD * 125 / 26) & 0xff;
+		reg <<= 8;
+		reg |= (MODELGAUGE_ACTIVE_THD * 4 / 5) & 0xff;
+		regmap_write(regmap, MODELGAUGE_HIBRT_REG, reg);
+
+		/* Set undervoltage/overvoltage alerts */
+		reg = (MODELGAUGE_UV / 20) & 0xff;
+		reg <<= 8;
+		reg |= (MODELGAUGE_OV / 20) & 0xff;
+		regmap_write(regmap, MODELGAUGE_VALRT_REG, reg);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Disable sleep mode and quick start */
+		regmap_write(regmap, MODELGAUGE_MODE_REG, 0);
+
+		/* Setup reset voltage threshold */
+		if (MODELGAUGE_RV)
+			reg = ((MODELGAUGE_RV / 40) & 0x7f) << 9;
+		else
+			reg = MODELGAUGE_VRESETID_DIS;
+		regmap_write(regmap, MODELGAUGE_VRESETID_REG, reg);
+
+		/* Skip load model if reset indicator cleared */
+		regmap_read(regmap, MODELGAUGE_STATUS_REG, &reg);
+		/* Skip load custom model */
+		if (!(reg & MODELGAUGE_STATUS_RI))
+			return 0;
+		break;
+	default:
+		break;
+	}
+
+	/* Schedule load custom model work */
+	if (pdata->model_data)
+		schedule_work(&priv->load_work);
+
+	return 0;
+}
+
+static struct modelgauge_platform_data *modelgauge_parse_dt(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct modelgauge_platform_data *pdata;
+	struct property *prop;
+	int ret;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	ret = of_property_read_u8(np, "maxim,rcomp0", &pdata->rcomp0);
+	if (ret)
+		pdata->rcomp0 = 25;
+
+	ret = of_property_read_u32(np, "maxim,temp-co-up", &pdata->temp_co_up);
+	if (ret)
+		pdata->temp_co_up = -500;
+
+	ret = of_property_read_u32(np, "maxim,temp-co-down",
+				   &pdata->temp_co_down);
+	if (ret)
+		pdata->temp_co_down = -5000;
+
+	ret = of_property_read_u16(np, "maxim,ocvtest", &pdata->ocvtest);
+	if (ret)
+		pdata->ocvtest = 0;
+
+	ret = of_property_read_u8(np, "maxim,soc-check-a", &pdata->soc_check_a);
+	if (ret)
+		pdata->soc_check_a = 0;
+
+	ret = of_property_read_u8(np, "maxim,soc-check-b", &pdata->soc_check_b);
+	if (ret)
+		pdata->soc_check_b = 0;
+
+	ret = of_property_read_u8(np, "maxim,bits", &pdata->bits);
+	if (ret)
+		pdata->bits = 18;
+
+	ret = of_property_read_u16(np, "maxim,rcomp-seg", &pdata->rcomp_seg);
+	if (ret)
+		pdata->rcomp_seg = 0;
+
+	prop = of_find_property(np, "maxim,model-data", NULL);
+	if (prop && prop->length == MODELGAUGE_TABLE_SIZE) {
+		pdata->model_data = devm_kzalloc(dev, MODELGAUGE_TABLE_SIZE,
+						 GFP_KERNEL);
+		if (!pdata->model_data)
+			goto out;
+
+		ret = of_property_read_u8_array(np, "maxim,model-data",
+						pdata->model_data,
+						MODELGAUGE_TABLE_SIZE);
+		if (ret) {
+			dev_warn(dev, "failed to get model_data %d\n", ret);
+			devm_kfree(dev, pdata->model_data);
+			pdata->model_data = NULL;
+		}
+	}
+
+out:
+	return pdata;
+}
+
+static const struct regmap_config modelgauge_regmap = {
+	.reg_bits	= 8,
+	.val_bits	= 16,
+};
+
+static int modelgauge_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct modelgauge_priv *priv;
+	int ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -EIO;
+
+	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (client->dev.of_node)
+		priv->pdata = modelgauge_parse_dt(&client->dev);
+	else
+		priv->pdata = client->dev.platform_data;
+
+	priv->dev	= &client->dev;
+	priv->chip	= id->driver_data;
+
+	i2c_set_clientdata(client, priv);
+
+	priv->regmap = devm_regmap_init_i2c(client, &modelgauge_regmap);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	priv->battery.name		= "modelgauge_battery";
+	priv->battery.type		= POWER_SUPPLY_TYPE_BATTERY;
+	priv->battery.get_property	= modelgauge_get_property;
+	priv->battery.properties	= modelgauge_battery_props;
+	priv->battery.num_properties	= ARRAY_SIZE(modelgauge_battery_props);
+
+	INIT_WORK(&priv->load_work, modelgauge_load_model_work);
+	INIT_DELAYED_WORK(&priv->rcomp_work, modelgauge_update_rcomp_work);
+
+	ret = modelgauge_init(priv);
+	if (ret)
+		return ret;
+
+	ret = power_supply_register(&client->dev, &priv->battery);
+	if (ret) {
+		dev_err(priv->dev, "failed: power supply register\n");
+		goto err_supply;
+	}
+
+	if (client->irq) {
+		switch (priv->chip) {
+		case ID_MAX17040:
+		case ID_MAX17041:
+			dev_err(priv->dev, "alert line is not supported\n");
+			ret = -EINVAL;
+			goto err_irq;
+		default:
+			ret = devm_request_threaded_irq(priv->dev, client->irq,
+							NULL,
+							modelgauge_irq_handler,
+							IRQF_TRIGGER_FALLING,
+							priv->battery.name,
+							priv);
+			if (ret) {
+				dev_err(priv->dev, "failed to request irq %d\n",
+					client->irq);
+				goto err_irq;
+			}
+		}
+	}
+
+	return 0;
+
+err_irq:
+	power_supply_unregister(&priv->battery);
+err_supply:
+	cancel_work_sync(&priv->load_work);
+	cancel_delayed_work_sync(&priv->rcomp_work);
+	return ret;
+}
+
+static int modelgauge_remove(struct i2c_client *client)
+{
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+
+	cancel_work_sync(&priv->load_work);
+	cancel_delayed_work_sync(&priv->rcomp_work);
+
+	power_supply_unregister(&priv->battery);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int modelgauge_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+	struct modelgauge_platform_data *pdata = priv->pdata;
+
+	if (pdata && pdata->get_temperature)
+		cancel_delayed_work_sync(&priv->rcomp_work);
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+		return 0;
+	default:
+		if (client->irq) {
+			disable_irq(client->irq);
+			enable_irq_wake(client->irq);
+		}
+	}
+
+	return 0;
+}
+
+static int modelgauge_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+	struct modelgauge_platform_data *pdata = priv->pdata;
+
+	if (pdata && pdata->get_temperature)
+		schedule_delayed_work(&priv->rcomp_work,
+			    msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY));
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+		return 0;
+	default:
+		if (client->irq) {
+			disable_irq_wake(client->irq);
+			enable_irq(client->irq);
+		}
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(modelgauge_pm_ops,
+			 modelgauge_suspend, modelgauge_resume);
+#define MODELGAUGE_PM_OPS (&modelgauge_pm_ops)
+#else
+#define MODELGAUGE_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct of_device_id modelgauge_match[] = {
+	{ .compatible = "maxim,max17040" },
+	{ .compatible = "maxim,max17041" },
+	{ .compatible = "maxim,max17043" },
+	{ .compatible = "maxim,max17044" },
+	{ .compatible = "maxim,max17048" },
+	{ .compatible = "maxim,max17049" },
+	{ .compatible = "maxim,max17058" },
+	{ .compatible = "maxim,max17059" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, modelgauge_match);
+
+static const struct i2c_device_id modelgauge_id[] = {
+	{ "max17040", ID_MAX17040 },
+	{ "max17041", ID_MAX17041 },
+	{ "max17043", ID_MAX17043 },
+	{ "max17044", ID_MAX17044 },
+	{ "max17048", ID_MAX17048 },
+	{ "max17049", ID_MAX17049 },
+	{ "max17058", ID_MAX17058 },
+	{ "max17059", ID_MAX17059 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, modelgauge_id);
+
+static struct i2c_driver modelgauge_i2c_driver = {
+	.driver	= {
+		.name		= DRV_NAME,
+		.of_match_table	= of_match_ptr(modelgauge_match),
+		.pm		= MODELGAUGE_PM_OPS,
+	},
+	.probe		= modelgauge_probe,
+	.remove		= modelgauge_remove,
+	.id_table	= modelgauge_id,
+};
+module_i2c_driver(modelgauge_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("Maxim ModelGauge fuel gauge");
Index: battery-2.6/include/linux/platform_data/battery-modelgauge.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ battery-2.6/include/linux/platform_data/battery-modelgauge.h	2014-02-02 01:29:34.314614874 +0400
@@ -0,0 +1,31 @@
+/*
+ * Maxim ModelGauge ICs fuel gauge driver header file
+ *
+ * Author: Vladimir Barinov <source-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __BATTERY_MODELGAUGE_H_
+#define __BATTERY_MODELGAUGE_H_
+
+#define MODELGAUGE_TABLE_SIZE	64
+
+struct modelgauge_platform_data {
+	u8	rcomp0;
+	int	temp_co_up;
+	int	temp_co_down;
+	u16	ocvtest;
+	u8	soc_check_a;
+	u8	soc_check_b;
+	u8	bits;
+	u16	rcomp_seg;
+	u8	*model_data;
+	int	(*get_temperature)(void);
+	int	(*get_charging_status)(void);
+};
+#endif
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
@ 2014-02-01 22:23     ` Vladimir Barinov
  0 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree
  Cc: mk7.kang, k.kozlowski, mark.rutland

Add Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips

Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>

---
 drivers/power/Kconfig                            |    9 
 drivers/power/Makefile                           |    1 
 drivers/power/modelgauge_battery.c               |  838 +++++++++++++++++++++++
 include/linux/platform_data/battery-modelgauge.h |   31 
 4 files changed, 879 insertions(+)

Index: battery-2.6/drivers/power/Kconfig
===================================================================
--- battery-2.6.orig/drivers/power/Kconfig	2014-02-02 01:29:07.434614235 +0400
+++ battery-2.6/drivers/power/Kconfig	2014-02-02 01:29:29.070614750 +0400
@@ -205,6 +205,15 @@
 	  with MAX17042. This driver also supports max17047/50 chips which are
 	  improved version of max17042.
 
+config BATTERY_MODELGAUGE
+	tristate "Maxim ModelGauge ICs fuel gauge"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  ModelGauge(TM) is a Maxim algorithm incorporated in
+	  MAX17040/41/43/44/48/49/58/59 fuel-gauges for lithium-ion (Li+)
+	  batteries.
+
 config BATTERY_Z2
 	tristate "Z2 battery driver"
 	depends on I2C && MACH_ZIPIT2
Index: battery-2.6/drivers/power/Makefile
===================================================================
--- battery-2.6.orig/drivers/power/Makefile	2014-02-02 01:29:07.462614237 +0400
+++ battery-2.6/drivers/power/Makefile	2014-02-02 01:29:12.978614368 +0400
@@ -32,6 +32,7 @@
 obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
+obj-$(CONFIG_BATTERY_MODELGAUGE)	+= modelgauge_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
 obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
 obj-$(CONFIG_BATTERY_TWL4030_MADC)	+= twl4030_madc_battery.o
Index: battery-2.6/drivers/power/modelgauge_battery.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ battery-2.6/drivers/power/modelgauge_battery.c	2014-02-02 01:29:34.314614874 +0400
@@ -0,0 +1,838 @@
+/*
+ * Maxim ModelGauge ICs fuel gauge driver
+ *
+ * Author: Vladimir Barinov <source@cogentembedded.com>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/battery-modelgauge.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define DRV_NAME "modelgauge"
+
+/* Register offsets for ModelGauge ICs */
+#define MODELGAUGE_VCELL_REG		0x02
+#define MODELGAUGE_SOC_REG		0x04
+#define MODELGAUGE_MODE_REG		0x06
+#define MODELGAUGE_VERSION_REG		0x08
+#define MODELGAUGE_HIBRT_REG		0x0A
+#define MODELGAUGE_CONFIG_REG		0x0C
+#define MODELGAUGE_OCV_REG		0x0E
+#define MODELGAUGE_VALRT_REG		0x14
+#define MODELGAUGE_CRATE_REG		0x16
+#define MODELGAUGE_VRESETID_REG		0x18
+#define MODELGAUGE_STATUS_REG		0x1A
+#define MODELGAUGE_UNLOCK_REG		0x3E
+#define MODELGAUGE_TABLE_REG		0x40
+#define MODELGAUGE_RCOMPSEG_REG		0x80
+#define MODELGAUGE_CMD_REG		0xFE
+
+/* MODE register bits */
+#define MODELGAUGE_MODE_QUICKSTART	(1 << 14)
+#define MODELGAUGE_MODE_ENSLEEP		(1 << 13)
+#define MODELGAUGE_MODE_HIBSTAT		(1 << 12)
+
+/* CONFIG register bits */
+#define MODELGAUGE_CONFIG_SLEEP		(1 << 7)
+#define MODELGAUGE_CONFIG_ALSC		(1 << 6)
+#define MODELGAUGE_CONFIG_ALRT		(1 << 5)
+#define MODELGAUGE_CONFIG_ATHD_MASK	0x1f
+
+/* STATUS register bits */
+#define MODELGAUGE_STATUS_ENVR		(1 << 14)
+#define MODELGAUGE_STATUS_SC		(1 << 13)
+#define MODELGAUGE_STATUS_HD		(1 << 12)
+#define MODELGAUGE_STATUS_VR		(1 << 11)
+#define MODELGAUGE_STATUS_VL		(1 << 10)
+#define MODELGAUGE_STATUS_VH		(1 << 9)
+#define MODELGAUGE_STATUS_RI		(1 << 8)
+
+/* VRESETID register bits */
+#define MODELGAUGE_VRESETID_DIS		(1 << 8)
+
+#define MODELGAUGE_UNLOCK_VALUE		0x4a57
+#define MODELGAUGE_RESET_VALUE		0x5400
+
+#define MODELGAUGE_RCOMP_UPDATE_DELAY	60000
+
+/* Capacity threshold where an interrupt is generated on the ALRT pin */
+#define MODELGAUGE_EMPTY_ATHD		15
+/* Enable alert for 1% soc change */
+#define MODELGAUGE_SOC_CHANGE_ALERT	1
+/* Hibernate threshold (crate), where IC enters hibernate mode */
+#define MODELGAUGE_HIBRT_THD		20
+/* Active threshold (mV), where IC exits hibernate mode */
+#define MODELGAUGE_ACTIVE_THD		60
+/* Voltage (mV), when IC alerts if battery voltage less then undervoltage */
+#define MODELGAUGE_UV			0
+/* Voltage (mV), when IC alerts if battery voltage greater then overvoltage */
+#define MODELGAUGE_OV			5120
+/*
+ * Voltage threshold (mV) below which the IC resets itself.
+ * Used to detect battery removal and reinsertion
+ */
+#define MODELGAUGE_RV			0
+
+enum chip_id {
+	ID_MAX17040,
+	ID_MAX17041,
+	ID_MAX17043,
+	ID_MAX17044,
+	ID_MAX17048,
+	ID_MAX17049,
+	ID_MAX17058,
+	ID_MAX17059,
+};
+
+struct modelgauge_priv {
+	struct device			*dev;
+	struct regmap			*regmap;
+	struct power_supply		battery;
+	struct modelgauge_platform_data	*pdata;
+	enum chip_id			chip;
+	struct work_struct		load_work;
+	struct delayed_work		rcomp_work;
+	int				soc_shift;
+};
+
+static void modelgauge_write_block(struct regmap *regmap, u8 adr, u8 size,
+				   u16 *data)
+{
+	int k;
+
+	/* RAM has different endianness then registers */
+	for (k = 0; k < size; k += 2, adr += 2, data++)
+		regmap_write(regmap, adr, cpu_to_be16(*data));
+}
+
+static int modelgauge_lsb_to_uvolts(struct modelgauge_priv *priv, int lsb)
+{
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17043:
+		return (lsb >> 4) * 1250; /* 1.25mV per bit */
+	case ID_MAX17041:
+	case ID_MAX17044:
+		return (lsb >> 4) * 2500; /* 2.5mV per bit */
+	case ID_MAX17048:
+	case ID_MAX17058:
+		return lsb * 625 / 8; /* 78.125uV per bit */
+	case ID_MAX17049:
+	case ID_MAX17059:
+		return lsb * 625 / 4; /* 156.25uV per bit */
+	default:
+		return -EINVAL;
+	}
+}
+
+static enum power_supply_property modelgauge_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static int modelgauge_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct modelgauge_priv *priv = container_of(psy,
+						    struct modelgauge_priv,
+						    battery);
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int reg;
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (pdata && pdata->get_charging_status)
+			val->intval = pdata->get_charging_status();
+		else
+			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = regmap_read(regmap, MODELGAUGE_VCELL_REG, &reg);
+		if (ret < 0)
+			return ret;
+
+		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		/* Unlock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+			     MODELGAUGE_UNLOCK_VALUE);
+		ret = regmap_read(regmap, MODELGAUGE_OCV_REG, &reg);
+		/* Lock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0);
+		if (ret < 0)
+			return ret;
+
+		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = regmap_read(regmap, MODELGAUGE_SOC_REG, &reg);
+		if (ret < 0)
+			return ret;
+
+		val->intval = reg / (1 << priv->soc_shift);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		if (pdata && pdata->get_temperature)
+			val->intval = pdata->get_temperature();
+		else
+			val->intval = 25;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void modelgauge_update_rcomp(struct modelgauge_priv *priv)
+{
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	u16 rcomp;
+	int temp;
+
+	if (pdata->get_temperature)
+		temp = pdata->get_temperature();
+	else
+		temp = 25;
+
+	if (!pdata->temp_co_up)
+		pdata->temp_co_up = -500;
+	if (!pdata->temp_co_down)
+		pdata->temp_co_down = -5000;
+
+	rcomp = pdata->rcomp0;
+	if (temp > 20)
+		rcomp += (temp - 20) * pdata->temp_co_up / 1000;
+	else
+		rcomp += (temp - 20) * pdata->temp_co_down / 1000;
+
+	/* Update RCOMP */
+	regmap_update_bits(regmap, MODELGAUGE_CONFIG_REG, 0xff, rcomp << 8);
+}
+
+static void modelgauge_update_rcomp_work(struct work_struct *work)
+{
+	struct modelgauge_priv *priv = container_of(work,
+						    struct modelgauge_priv,
+						    rcomp_work.work);
+
+	modelgauge_update_rcomp(priv);
+	schedule_delayed_work(&priv->rcomp_work,
+			      msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY));
+}
+
+static int modelgauge_load_model(struct modelgauge_priv *priv)
+{
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int ret = -EINVAL;
+	int timeout, k;
+	int ocv, config, soc;
+
+	/* Save CONFIG */
+	regmap_read(regmap, MODELGAUGE_CONFIG_REG, &config);
+
+	for (timeout = 0; timeout < 100; timeout++) {
+		/* Unlock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+			     MODELGAUGE_UNLOCK_VALUE);
+
+		/* Read OCV */
+		regmap_read(regmap, MODELGAUGE_OCV_REG, &ocv);
+		if (ocv != 0xffff)
+			break;
+	}
+
+	if (timeout >= 100) {
+		dev_err(priv->dev, "timeout to unlock model access\n");
+		ret = -EIO;
+		goto exit;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Reset chip transaction does not provide ACK */
+		regmap_write(regmap, MODELGAUGE_CMD_REG,
+			     MODELGAUGE_RESET_VALUE);
+		msleep(150);
+
+		for (timeout = 0; timeout < 100; timeout++) {
+			int reg;
+
+			/* Unlock Model Access */
+			regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+
+			/* Read OCV */
+			regmap_read(regmap, MODELGAUGE_OCV_REG, &reg);
+			if (reg != 0xffff)
+				break;
+		}
+
+		if (timeout >= 100) {
+			dev_err(priv->dev, "timeout to unlock model access\n");
+			ret = -EIO;
+			goto exit;
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+	case ID_MAX17043:
+	case ID_MAX17044:
+		/* Write OCV */
+		regmap_write(regmap, MODELGAUGE_OCV_REG, pdata->ocvtest);
+		/* Write RCOMP to its maximum value */
+		regmap_write(regmap, MODELGAUGE_CONFIG_REG, 0xff00);
+		break;
+	default:
+		break;
+	}
+
+	/* Write the model */
+	modelgauge_write_block(regmap, MODELGAUGE_TABLE_REG,
+			       MODELGAUGE_TABLE_SIZE,
+			       (u16 *)pdata->model_data);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049: {
+			u16 buf[16];
+
+			if (!pdata->rcomp_seg)
+				pdata->rcomp_seg = 0x80;
+
+			for (k = 0; k < 16; k++)
+				*buf = pdata->rcomp_seg;
+
+			/* Write RCOMPSeg */
+			modelgauge_write_block(regmap, MODELGAUGE_RCOMPSEG_REG,
+					       32, buf);
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+	case ID_MAX17043:
+	case ID_MAX17044:
+		/* Delay at least 150ms */
+		msleep(150);
+		break;
+	default:
+		break;
+	}
+
+	/* Write OCV */
+	regmap_write(regmap, MODELGAUGE_OCV_REG, pdata->ocvtest);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Disable Hibernate */
+		regmap_write(regmap, MODELGAUGE_HIBRT_REG, 0);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Lock Model Access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0);
+		break;
+	default:
+		break;
+	}
+
+	/* Delay between 150ms and 600ms */
+	msleep(200);
+
+	/* Read SOC Register and compare to expected result */
+	regmap_read(regmap, MODELGAUGE_SOC_REG, &soc);
+	soc >>= 8;
+	if (soc >= pdata->soc_check_a && soc <= pdata->soc_check_b)
+		ret = 0;
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Unlock model access */
+		regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
+			     MODELGAUGE_UNLOCK_VALUE);
+		break;
+	default:
+		break;
+	}
+
+	/* Restore CONFIG and OCV */
+	regmap_write(regmap, MODELGAUGE_CONFIG_REG, config);
+	regmap_write(regmap, MODELGAUGE_OCV_REG, ocv);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Restore Hibernate */
+		regmap_write(regmap, MODELGAUGE_HIBRT_REG,
+			     (MODELGAUGE_HIBRT_THD << 8) |
+			     MODELGAUGE_ACTIVE_THD);
+		break;
+	default:
+		break;
+	}
+
+exit:
+	/* Lock model access */
+	regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0);
+
+	/* Wait 150ms minimum */
+	msleep(150);
+
+	return ret;
+}
+
+static void modelgauge_load_model_work(struct work_struct *work)
+{
+	struct modelgauge_priv *priv = container_of(work,
+						    struct modelgauge_priv,
+						    load_work);
+	struct regmap *regmap = priv->regmap;
+	int ret;
+	int timeout;
+
+	for (timeout = 0; timeout < 10; timeout++) {
+		/* Load custom model data */
+		ret = modelgauge_load_model(priv);
+		if (!ret)
+			break;
+	}
+
+	if (timeout >= 10) {
+		dev_info(priv->dev, "failed to load custom model\n");
+		return;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Clear reset indicator bit */
+		regmap_update_bits(regmap, MODELGAUGE_STATUS_REG,
+				   MODELGAUGE_STATUS_RI, 0);
+		break;
+	default:
+		break;
+	}
+}
+
+static irqreturn_t modelgauge_irq_handler(int id, void *dev)
+{
+	struct modelgauge_priv *priv = dev;
+
+	/* clear alert status bit */
+	regmap_update_bits(priv->regmap, MODELGAUGE_CONFIG_REG,
+			   MODELGAUGE_CONFIG_ALRT, 0);
+
+	power_supply_changed(&priv->battery);
+	return IRQ_HANDLED;
+}
+
+static int modelgauge_init(struct modelgauge_priv *priv)
+{
+	struct regmap *regmap = priv->regmap;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int ret;
+	int reg;
+
+	ret = regmap_read(regmap, MODELGAUGE_VERSION_REG, &reg);
+	if (ret < 0)
+		return -ENODEV;
+
+	dev_info(priv->dev, "IC production version 0x%04x\n", reg);
+
+	/* SOC=0 means unrecoverable IC fault, reset is a workaround */
+	regmap_read(regmap, MODELGAUGE_SOC_REG, &reg);
+	if (!reg) {
+		dev_info(priv->dev, "Reset chip, SOC measurement stall\n");
+		/* Reset chip transaction does not provide ACK */
+		regmap_write(regmap, MODELGAUGE_CMD_REG,
+			     MODELGAUGE_RESET_VALUE);
+		msleep(150);
+	}
+
+	/* Default model uses 8 bits per percent */
+	priv->soc_shift = 8;
+
+	if (!priv->pdata) {
+		dev_info(priv->dev, "no platform data provided\n");
+		return 0;
+	}
+
+	switch (pdata->bits) {
+	case 19:
+		priv->soc_shift = 9;
+		break;
+	case 18:
+	default:
+		priv->soc_shift = 8;
+		break;
+	}
+
+	/* Set RCOMP */
+	modelgauge_update_rcomp(priv);
+	if (pdata->get_temperature) {
+		/* Schedule update RCOMP */
+		schedule_delayed_work(&priv->rcomp_work,
+			    msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY));
+	}
+
+	/* Clear alert status bit, wake-up, set alert threshold */
+	reg = 0;
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		reg |= MODELGAUGE_SOC_CHANGE_ALERT ? MODELGAUGE_CONFIG_ALSC : 0;
+		/* fall-through */
+	case ID_MAX17043:
+	case ID_MAX17044:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		reg |= 32 - (MODELGAUGE_EMPTY_ATHD << (priv->soc_shift - 8));
+		break;
+	default:
+		break;
+	}
+	regmap_update_bits(regmap, MODELGAUGE_CONFIG_REG,
+			   MODELGAUGE_CONFIG_ALRT | MODELGAUGE_CONFIG_SLEEP |
+			   MODELGAUGE_CONFIG_ALSC | MODELGAUGE_CONFIG_ATHD_MASK,
+			   reg);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Set Hibernate thresholds */
+		reg = (MODELGAUGE_HIBRT_THD * 125 / 26) & 0xff;
+		reg <<= 8;
+		reg |= (MODELGAUGE_ACTIVE_THD * 4 / 5) & 0xff;
+		regmap_write(regmap, MODELGAUGE_HIBRT_REG, reg);
+
+		/* Set undervoltage/overvoltage alerts */
+		reg = (MODELGAUGE_UV / 20) & 0xff;
+		reg <<= 8;
+		reg |= (MODELGAUGE_OV / 20) & 0xff;
+		regmap_write(regmap, MODELGAUGE_VALRT_REG, reg);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Disable sleep mode and quick start */
+		regmap_write(regmap, MODELGAUGE_MODE_REG, 0);
+
+		/* Setup reset voltage threshold */
+		if (MODELGAUGE_RV)
+			reg = ((MODELGAUGE_RV / 40) & 0x7f) << 9;
+		else
+			reg = MODELGAUGE_VRESETID_DIS;
+		regmap_write(regmap, MODELGAUGE_VRESETID_REG, reg);
+
+		/* Skip load model if reset indicator cleared */
+		regmap_read(regmap, MODELGAUGE_STATUS_REG, &reg);
+		/* Skip load custom model */
+		if (!(reg & MODELGAUGE_STATUS_RI))
+			return 0;
+		break;
+	default:
+		break;
+	}
+
+	/* Schedule load custom model work */
+	if (pdata->model_data)
+		schedule_work(&priv->load_work);
+
+	return 0;
+}
+
+static struct modelgauge_platform_data *modelgauge_parse_dt(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct modelgauge_platform_data *pdata;
+	struct property *prop;
+	int ret;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	ret = of_property_read_u8(np, "maxim,rcomp0", &pdata->rcomp0);
+	if (ret)
+		pdata->rcomp0 = 25;
+
+	ret = of_property_read_u32(np, "maxim,temp-co-up", &pdata->temp_co_up);
+	if (ret)
+		pdata->temp_co_up = -500;
+
+	ret = of_property_read_u32(np, "maxim,temp-co-down",
+				   &pdata->temp_co_down);
+	if (ret)
+		pdata->temp_co_down = -5000;
+
+	ret = of_property_read_u16(np, "maxim,ocvtest", &pdata->ocvtest);
+	if (ret)
+		pdata->ocvtest = 0;
+
+	ret = of_property_read_u8(np, "maxim,soc-check-a", &pdata->soc_check_a);
+	if (ret)
+		pdata->soc_check_a = 0;
+
+	ret = of_property_read_u8(np, "maxim,soc-check-b", &pdata->soc_check_b);
+	if (ret)
+		pdata->soc_check_b = 0;
+
+	ret = of_property_read_u8(np, "maxim,bits", &pdata->bits);
+	if (ret)
+		pdata->bits = 18;
+
+	ret = of_property_read_u16(np, "maxim,rcomp-seg", &pdata->rcomp_seg);
+	if (ret)
+		pdata->rcomp_seg = 0;
+
+	prop = of_find_property(np, "maxim,model-data", NULL);
+	if (prop && prop->length == MODELGAUGE_TABLE_SIZE) {
+		pdata->model_data = devm_kzalloc(dev, MODELGAUGE_TABLE_SIZE,
+						 GFP_KERNEL);
+		if (!pdata->model_data)
+			goto out;
+
+		ret = of_property_read_u8_array(np, "maxim,model-data",
+						pdata->model_data,
+						MODELGAUGE_TABLE_SIZE);
+		if (ret) {
+			dev_warn(dev, "failed to get model_data %d\n", ret);
+			devm_kfree(dev, pdata->model_data);
+			pdata->model_data = NULL;
+		}
+	}
+
+out:
+	return pdata;
+}
+
+static const struct regmap_config modelgauge_regmap = {
+	.reg_bits	= 8,
+	.val_bits	= 16,
+};
+
+static int modelgauge_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct modelgauge_priv *priv;
+	int ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -EIO;
+
+	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (client->dev.of_node)
+		priv->pdata = modelgauge_parse_dt(&client->dev);
+	else
+		priv->pdata = client->dev.platform_data;
+
+	priv->dev	= &client->dev;
+	priv->chip	= id->driver_data;
+
+	i2c_set_clientdata(client, priv);
+
+	priv->regmap = devm_regmap_init_i2c(client, &modelgauge_regmap);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	priv->battery.name		= "modelgauge_battery";
+	priv->battery.type		= POWER_SUPPLY_TYPE_BATTERY;
+	priv->battery.get_property	= modelgauge_get_property;
+	priv->battery.properties	= modelgauge_battery_props;
+	priv->battery.num_properties	= ARRAY_SIZE(modelgauge_battery_props);
+
+	INIT_WORK(&priv->load_work, modelgauge_load_model_work);
+	INIT_DELAYED_WORK(&priv->rcomp_work, modelgauge_update_rcomp_work);
+
+	ret = modelgauge_init(priv);
+	if (ret)
+		return ret;
+
+	ret = power_supply_register(&client->dev, &priv->battery);
+	if (ret) {
+		dev_err(priv->dev, "failed: power supply register\n");
+		goto err_supply;
+	}
+
+	if (client->irq) {
+		switch (priv->chip) {
+		case ID_MAX17040:
+		case ID_MAX17041:
+			dev_err(priv->dev, "alert line is not supported\n");
+			ret = -EINVAL;
+			goto err_irq;
+		default:
+			ret = devm_request_threaded_irq(priv->dev, client->irq,
+							NULL,
+							modelgauge_irq_handler,
+							IRQF_TRIGGER_FALLING,
+							priv->battery.name,
+							priv);
+			if (ret) {
+				dev_err(priv->dev, "failed to request irq %d\n",
+					client->irq);
+				goto err_irq;
+			}
+		}
+	}
+
+	return 0;
+
+err_irq:
+	power_supply_unregister(&priv->battery);
+err_supply:
+	cancel_work_sync(&priv->load_work);
+	cancel_delayed_work_sync(&priv->rcomp_work);
+	return ret;
+}
+
+static int modelgauge_remove(struct i2c_client *client)
+{
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+
+	cancel_work_sync(&priv->load_work);
+	cancel_delayed_work_sync(&priv->rcomp_work);
+
+	power_supply_unregister(&priv->battery);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int modelgauge_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+	struct modelgauge_platform_data *pdata = priv->pdata;
+
+	if (pdata && pdata->get_temperature)
+		cancel_delayed_work_sync(&priv->rcomp_work);
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+		return 0;
+	default:
+		if (client->irq) {
+			disable_irq(client->irq);
+			enable_irq_wake(client->irq);
+		}
+	}
+
+	return 0;
+}
+
+static int modelgauge_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+	struct modelgauge_platform_data *pdata = priv->pdata;
+
+	if (pdata && pdata->get_temperature)
+		schedule_delayed_work(&priv->rcomp_work,
+			    msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY));
+
+	switch (priv->chip) {
+	case ID_MAX17040:
+	case ID_MAX17041:
+		return 0;
+	default:
+		if (client->irq) {
+			disable_irq_wake(client->irq);
+			enable_irq(client->irq);
+		}
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(modelgauge_pm_ops,
+			 modelgauge_suspend, modelgauge_resume);
+#define MODELGAUGE_PM_OPS (&modelgauge_pm_ops)
+#else
+#define MODELGAUGE_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct of_device_id modelgauge_match[] = {
+	{ .compatible = "maxim,max17040" },
+	{ .compatible = "maxim,max17041" },
+	{ .compatible = "maxim,max17043" },
+	{ .compatible = "maxim,max17044" },
+	{ .compatible = "maxim,max17048" },
+	{ .compatible = "maxim,max17049" },
+	{ .compatible = "maxim,max17058" },
+	{ .compatible = "maxim,max17059" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, modelgauge_match);
+
+static const struct i2c_device_id modelgauge_id[] = {
+	{ "max17040", ID_MAX17040 },
+	{ "max17041", ID_MAX17041 },
+	{ "max17043", ID_MAX17043 },
+	{ "max17044", ID_MAX17044 },
+	{ "max17048", ID_MAX17048 },
+	{ "max17049", ID_MAX17049 },
+	{ "max17058", ID_MAX17058 },
+	{ "max17059", ID_MAX17059 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, modelgauge_id);
+
+static struct i2c_driver modelgauge_i2c_driver = {
+	.driver	= {
+		.name		= DRV_NAME,
+		.of_match_table	= of_match_ptr(modelgauge_match),
+		.pm		= MODELGAUGE_PM_OPS,
+	},
+	.probe		= modelgauge_probe,
+	.remove		= modelgauge_remove,
+	.id_table	= modelgauge_id,
+};
+module_i2c_driver(modelgauge_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("Maxim ModelGauge fuel gauge");
Index: battery-2.6/include/linux/platform_data/battery-modelgauge.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ battery-2.6/include/linux/platform_data/battery-modelgauge.h	2014-02-02 01:29:34.314614874 +0400
@@ -0,0 +1,31 @@
+/*
+ * Maxim ModelGauge ICs fuel gauge driver header file
+ *
+ * Author: Vladimir Barinov <source@cogentembedded.com>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __BATTERY_MODELGAUGE_H_
+#define __BATTERY_MODELGAUGE_H_
+
+#define MODELGAUGE_TABLE_SIZE	64
+
+struct modelgauge_platform_data {
+	u8	rcomp0;
+	int	temp_co_up;
+	int	temp_co_down;
+	u16	ocvtest;
+	u8	soc_check_a;
+	u8	soc_check_b;
+	u8	bits;
+	u16	rcomp_seg;
+	u8	*model_data;
+	int	(*get_temperature)(void);
+	int	(*get_charging_status)(void);
+};
+#endif

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 2/3] dt: Document ModelGauge gauge bindings
  2014-02-01 22:23 ` Vladimir Barinov
@ 2014-02-01 22:23     ` Vladimir Barinov
  -1 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: mk7.kang-Sze3O3UU22JBDgjK7y7TUQ,
	k.kozlowski-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland-5wv7dgnIgG8

These bindings can be used to register Maxim ModelGauge ICs fuel gauge
(MAX17040/41/43/44/48/49/58/59)

Signed-off-by: Vladimir Barinov <vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

---
 Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt |   61 ++++++++++
 1 file changed, 61 insertions(+)

Index: battery-2.6/Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ battery-2.6/Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt	2014-02-02 01:36:12.638624341 +0400
@@ -0,0 +1,61 @@
+modelgauge_battery
+~~~~~~~~~~~~~~~~~~
+
+Required properties:
+ - compatible		: should contain one of the following:
+			  - "maxim,max17040" for MAX17040
+			  - "maxim,max17041" for MAX17041
+			  - "maxim,max17043" for MAX17043
+			  - "maxim,max17044" for MAX17044
+			  - "maxim,max17048" for MAX17048
+			  - "maxim,max17049" for MAX17049
+			  - "maxim,max17058" for MAX17058
+			  - "maxim,max17059" for MAX17059
+
+Optional properties:
+ - maxim,rcomp0			: ModelGauge RCOMP parameter, used for
+				  temperature compensation (u8);
+ - maxim,temp-co-up		: ModelGauge TempCoUp parameter, used for
+				  temperature compensation (signed);
+ - maxim,temp-co-down		: ModelGauge TempCoDown parameter, used for
+				  temperature compensation (signed);
+ - maxim,ocvtest		: ModelGauge OCVTest parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM (u16);
+ - maxim,soc-check-a		: ModelGauge SOCCheckA parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM (u8);
+ - maxim,soc-check-b		: ModelGauge SOCCheckB parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM (u8);
+ - maxim,bits			: ModelGauge Bits parameter, used as
+				  scaling parameter in Custom Model algorithm (u8);
+ - maxim,model-data		: ModelGauge ModelData data,
+				  Custom Model calibration data (array_u8[64]).
+
+Example:
+
+modelgauge@36 {
+	compatible = "maxim,max17058";
+	reg = <0x36>;
+	interrupt-parent = <&msmgpio>;
+	interrupts = <107 0x2>;
+
+	maxim,rcomp0 = /bits/ 8 <175>;
+	maxim,temp-co-up = <(-1100)>;
+	maxim,temp-co-down = <(-4000)>;
+	maxim,ocvtest = /bits/ 16 <56144>;
+	maxim,soc-check-a = /bits/ 8 <241>;
+	maxim,soc-check-b = /bits/ 8 <243>;
+	maxim,bits = /bits/ 8 <19>;
+
+	maxim,model-data = /bits/ 8 <
+		0x9B 0x70 0xAB 0x30 0xB5 0xA0 0xB9 0xD0
+		0xBB 0xA0 0xBC 0x00 0xBC 0xB0 0xBD 0x00
+		0xBD 0x60 0xBE 0x40 0xBF 0x40 0xC1 0xF0
+		0xC5 0x60 0xC8 0xA0 0xCD 0x00 0xD1 0x50
+		0x00 0xE0 0x01 0x80 0x18 0x60 0x1C 0x20
+		0x54 0x00 0x6A 0xC0 0x79 0x20 0x65 0xC0
+		0x0B 0xE0 0x2A 0xC0 0x1D 0x00 0x17 0xE0
+		0x15 0xE0 0x11 0xE0 0x11 0x00 0x11 0x00>;
+};
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 2/3] dt: Document ModelGauge gauge bindings
@ 2014-02-01 22:23     ` Vladimir Barinov
  0 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree
  Cc: mk7.kang, k.kozlowski, mark.rutland

These bindings can be used to register Maxim ModelGauge ICs fuel gauge
(MAX17040/41/43/44/48/49/58/59)

Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>

---
 Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt |   61 ++++++++++
 1 file changed, 61 insertions(+)

Index: battery-2.6/Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ battery-2.6/Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt	2014-02-02 01:36:12.638624341 +0400
@@ -0,0 +1,61 @@
+modelgauge_battery
+~~~~~~~~~~~~~~~~~~
+
+Required properties:
+ - compatible		: should contain one of the following:
+			  - "maxim,max17040" for MAX17040
+			  - "maxim,max17041" for MAX17041
+			  - "maxim,max17043" for MAX17043
+			  - "maxim,max17044" for MAX17044
+			  - "maxim,max17048" for MAX17048
+			  - "maxim,max17049" for MAX17049
+			  - "maxim,max17058" for MAX17058
+			  - "maxim,max17059" for MAX17059
+
+Optional properties:
+ - maxim,rcomp0			: ModelGauge RCOMP parameter, used for
+				  temperature compensation (u8);
+ - maxim,temp-co-up		: ModelGauge TempCoUp parameter, used for
+				  temperature compensation (signed);
+ - maxim,temp-co-down		: ModelGauge TempCoDown parameter, used for
+				  temperature compensation (signed);
+ - maxim,ocvtest		: ModelGauge OCVTest parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM (u16);
+ - maxim,soc-check-a		: ModelGauge SOCCheckA parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM (u8);
+ - maxim,soc-check-b		: ModelGauge SOCCheckB parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM (u8);
+ - maxim,bits			: ModelGauge Bits parameter, used as
+				  scaling parameter in Custom Model algorithm (u8);
+ - maxim,model-data		: ModelGauge ModelData data,
+				  Custom Model calibration data (array_u8[64]).
+
+Example:
+
+modelgauge@36 {
+	compatible = "maxim,max17058";
+	reg = <0x36>;
+	interrupt-parent = <&msmgpio>;
+	interrupts = <107 0x2>;
+
+	maxim,rcomp0 = /bits/ 8 <175>;
+	maxim,temp-co-up = <(-1100)>;
+	maxim,temp-co-down = <(-4000)>;
+	maxim,ocvtest = /bits/ 16 <56144>;
+	maxim,soc-check-a = /bits/ 8 <241>;
+	maxim,soc-check-b = /bits/ 8 <243>;
+	maxim,bits = /bits/ 8 <19>;
+
+	maxim,model-data = /bits/ 8 <
+		0x9B 0x70 0xAB 0x30 0xB5 0xA0 0xB9 0xD0
+		0xBB 0xA0 0xBC 0x00 0xBC 0xB0 0xBD 0x00
+		0xBD 0x60 0xBE 0x40 0xBF 0x40 0xC1 0xF0
+		0xC5 0x60 0xC8 0xA0 0xCD 0x00 0xD1 0x50
+		0x00 0xE0 0x01 0x80 0x18 0x60 0x1C 0x20
+		0x54 0x00 0x6A 0xC0 0x79 0x20 0x65 0xC0
+		0x0B 0xE0 0x2A 0xC0 0x1D 0x00 0x17 0xE0
+		0x15 0xE0 0x11 0xE0 0x11 0x00 0x11 0x00>;
+};

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge
  2014-02-01 22:23 ` Vladimir Barinov
@ 2014-02-01 22:23   ` Vladimir Barinov
  -1 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree
  Cc: mk7.kang, k.kozlowski, mark.rutland

Remove Maxim MAX17040 gauge driver since it is superseded by full-functional
Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips

Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>

---
 drivers/power/Kconfig            |    8 -
 drivers/power/Makefile           |    1 
 drivers/power/max17040_battery.c |  297 ---------------------------------------
 include/linux/max17040_battery.h |   19 --
 4 files changed, 325 deletions(-)

Index: linux-2.6.torvalds/drivers/power/Kconfig
===================================================================
--- linux-2.6.torvalds.orig/drivers/power/Kconfig	2014-02-02 01:37:35.374626307 +0400
+++ linux-2.6.torvalds/drivers/power/Kconfig	2014-02-02 01:38:21.966627415 +0400
@@ -185,14 +185,6 @@
 	  Say Y here to enable support for batteries charger integrated into
 	  DA9052 PMIC.
 
-config BATTERY_MAX17040
-	tristate "Maxim MAX17040 Fuel Gauge"
-	depends on I2C
-	help
-	  MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
-	  in handheld and portable equipment. The MAX17040 is configured
-	  to operate with a single lithium cell
-
 config BATTERY_MAX17042
 	tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
 	depends on I2C
Index: linux-2.6.torvalds/drivers/power/Makefile
===================================================================
--- linux-2.6.torvalds.orig/drivers/power/Makefile	2014-02-02 01:37:35.000000000 +0400
+++ linux-2.6.torvalds/drivers/power/Makefile	2014-02-02 01:38:21.966627415 +0400
@@ -30,7 +30,6 @@
 obj-$(CONFIG_BATTERY_BQ27x00)	+= bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
 obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
-obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
 obj-$(CONFIG_BATTERY_MODELGAUGE)	+= modelgauge_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
Index: linux-2.6.torvalds/drivers/power/max17040_battery.c
===================================================================
--- linux-2.6.torvalds.orig/drivers/power/max17040_battery.c	2014-02-02 01:38:29.614627597 +0400
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,297 +0,0 @@
-/*
- *  max17040_battery.c
- *  fuel-gauge systems for lithium-ion (Li+) batteries
- *
- *  Copyright (C) 2009 Samsung Electronics
- *  Minkyu Kang <mk7.kang@samsung.com>
- *
- * This program 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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/power_supply.h>
-#include <linux/max17040_battery.h>
-#include <linux/slab.h>
-
-#define MAX17040_VCELL_MSB	0x02
-#define MAX17040_VCELL_LSB	0x03
-#define MAX17040_SOC_MSB	0x04
-#define MAX17040_SOC_LSB	0x05
-#define MAX17040_MODE_MSB	0x06
-#define MAX17040_MODE_LSB	0x07
-#define MAX17040_VER_MSB	0x08
-#define MAX17040_VER_LSB	0x09
-#define MAX17040_RCOMP_MSB	0x0C
-#define MAX17040_RCOMP_LSB	0x0D
-#define MAX17040_CMD_MSB	0xFE
-#define MAX17040_CMD_LSB	0xFF
-
-#define MAX17040_DELAY		1000
-#define MAX17040_BATTERY_FULL	95
-
-struct max17040_chip {
-	struct i2c_client		*client;
-	struct delayed_work		work;
-	struct power_supply		battery;
-	struct max17040_platform_data	*pdata;
-
-	/* State Of Connect */
-	int online;
-	/* battery voltage */
-	int vcell;
-	/* battery capacity */
-	int soc;
-	/* State Of Charge */
-	int status;
-};
-
-static int max17040_get_property(struct power_supply *psy,
-			    enum power_supply_property psp,
-			    union power_supply_propval *val)
-{
-	struct max17040_chip *chip = container_of(psy,
-				struct max17040_chip, battery);
-
-	switch (psp) {
-	case POWER_SUPPLY_PROP_STATUS:
-		val->intval = chip->status;
-		break;
-	case POWER_SUPPLY_PROP_ONLINE:
-		val->intval = chip->online;
-		break;
-	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		val->intval = chip->vcell;
-		break;
-	case POWER_SUPPLY_PROP_CAPACITY:
-		val->intval = chip->soc;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int max17040_write_reg(struct i2c_client *client, int reg, u8 value)
-{
-	int ret;
-
-	ret = i2c_smbus_write_byte_data(client, reg, value);
-
-	if (ret < 0)
-		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
-	return ret;
-}
-
-static int max17040_read_reg(struct i2c_client *client, int reg)
-{
-	int ret;
-
-	ret = i2c_smbus_read_byte_data(client, reg);
-
-	if (ret < 0)
-		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
-	return ret;
-}
-
-static void max17040_reset(struct i2c_client *client)
-{
-	max17040_write_reg(client, MAX17040_CMD_MSB, 0x54);
-	max17040_write_reg(client, MAX17040_CMD_LSB, 0x00);
-}
-
-static void max17040_get_vcell(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-	u8 msb;
-	u8 lsb;
-
-	msb = max17040_read_reg(client, MAX17040_VCELL_MSB);
-	lsb = max17040_read_reg(client, MAX17040_VCELL_LSB);
-
-	chip->vcell = (msb << 4) + (lsb >> 4);
-}
-
-static void max17040_get_soc(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-	u8 msb;
-	u8 lsb;
-
-	msb = max17040_read_reg(client, MAX17040_SOC_MSB);
-	lsb = max17040_read_reg(client, MAX17040_SOC_LSB);
-
-	chip->soc = msb;
-}
-
-static void max17040_get_version(struct i2c_client *client)
-{
-	u8 msb;
-	u8 lsb;
-
-	msb = max17040_read_reg(client, MAX17040_VER_MSB);
-	lsb = max17040_read_reg(client, MAX17040_VER_LSB);
-
-	dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb);
-}
-
-static void max17040_get_online(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	if (chip->pdata->battery_online)
-		chip->online = chip->pdata->battery_online();
-	else
-		chip->online = 1;
-}
-
-static void max17040_get_status(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	if (!chip->pdata->charger_online || !chip->pdata->charger_enable) {
-		chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
-		return;
-	}
-
-	if (chip->pdata->charger_online()) {
-		if (chip->pdata->charger_enable())
-			chip->status = POWER_SUPPLY_STATUS_CHARGING;
-		else
-			chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-	} else {
-		chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
-	}
-
-	if (chip->soc > MAX17040_BATTERY_FULL)
-		chip->status = POWER_SUPPLY_STATUS_FULL;
-}
-
-static void max17040_work(struct work_struct *work)
-{
-	struct max17040_chip *chip;
-
-	chip = container_of(work, struct max17040_chip, work.work);
-
-	max17040_get_vcell(chip->client);
-	max17040_get_soc(chip->client);
-	max17040_get_online(chip->client);
-	max17040_get_status(chip->client);
-
-	schedule_delayed_work(&chip->work, MAX17040_DELAY);
-}
-
-static enum power_supply_property max17040_battery_props[] = {
-	POWER_SUPPLY_PROP_STATUS,
-	POWER_SUPPLY_PROP_ONLINE,
-	POWER_SUPPLY_PROP_VOLTAGE_NOW,
-	POWER_SUPPLY_PROP_CAPACITY,
-};
-
-static int max17040_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
-{
-	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct max17040_chip *chip;
-	int ret;
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
-		return -EIO;
-
-	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
-	if (!chip)
-		return -ENOMEM;
-
-	chip->client = client;
-	chip->pdata = client->dev.platform_data;
-
-	i2c_set_clientdata(client, chip);
-
-	chip->battery.name		= "battery";
-	chip->battery.type		= POWER_SUPPLY_TYPE_BATTERY;
-	chip->battery.get_property	= max17040_get_property;
-	chip->battery.properties	= max17040_battery_props;
-	chip->battery.num_properties	= ARRAY_SIZE(max17040_battery_props);
-
-	ret = power_supply_register(&client->dev, &chip->battery);
-	if (ret) {
-		dev_err(&client->dev, "failed: power supply register\n");
-		return ret;
-	}
-
-	max17040_reset(client);
-	max17040_get_version(client);
-
-	INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
-	schedule_delayed_work(&chip->work, MAX17040_DELAY);
-
-	return 0;
-}
-
-static int max17040_remove(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	power_supply_unregister(&chip->battery);
-	cancel_delayed_work(&chip->work);
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-static int max17040_suspend(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	cancel_delayed_work(&chip->work);
-	return 0;
-}
-
-static int max17040_resume(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	schedule_delayed_work(&chip->work, MAX17040_DELAY);
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
-#define MAX17040_PM_OPS (&max17040_pm_ops)
-
-#else
-
-#define MAX17040_PM_OPS NULL
-
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct i2c_device_id max17040_id[] = {
-	{ "max17040", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, max17040_id);
-
-static struct i2c_driver max17040_i2c_driver = {
-	.driver	= {
-		.name	= "max17040",
-		.pm	= MAX17040_PM_OPS,
-	},
-	.probe		= max17040_probe,
-	.remove		= max17040_remove,
-	.id_table	= max17040_id,
-};
-module_i2c_driver(max17040_i2c_driver);
-
-MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
-MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
-MODULE_LICENSE("GPL");
Index: linux-2.6.torvalds/include/linux/max17040_battery.h
===================================================================
--- linux-2.6.torvalds.orig/include/linux/max17040_battery.h	2014-01-15 14:11:22.000000000 +0400
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-/*
- *  Copyright (C) 2009 Samsung Electronics
- *  Minkyu Kang <mk7.kang@samsung.com>
- *
- * This program 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.
- */
-
-#ifndef __MAX17040_BATTERY_H_
-#define __MAX17040_BATTERY_H_
-
-struct max17040_platform_data {
-	int (*battery_online)(void);
-	int (*charger_online)(void);
-	int (*charger_enable)(void);
-};
-
-#endif

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge
@ 2014-02-01 22:23   ` Vladimir Barinov
  0 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree
  Cc: mk7.kang, k.kozlowski, mark.rutland

Remove Maxim MAX17040 gauge driver since it is superseded by full-functional
Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips

Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>

---
 drivers/power/Kconfig            |    8 -
 drivers/power/Makefile           |    1 
 drivers/power/max17040_battery.c |  297 ---------------------------------------
 include/linux/max17040_battery.h |   19 --
 4 files changed, 325 deletions(-)

Index: linux-2.6.torvalds/drivers/power/Kconfig
===================================================================
--- linux-2.6.torvalds.orig/drivers/power/Kconfig	2014-02-02 01:37:35.374626307 +0400
+++ linux-2.6.torvalds/drivers/power/Kconfig	2014-02-02 01:38:21.966627415 +0400
@@ -185,14 +185,6 @@
 	  Say Y here to enable support for batteries charger integrated into
 	  DA9052 PMIC.
 
-config BATTERY_MAX17040
-	tristate "Maxim MAX17040 Fuel Gauge"
-	depends on I2C
-	help
-	  MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries
-	  in handheld and portable equipment. The MAX17040 is configured
-	  to operate with a single lithium cell
-
 config BATTERY_MAX17042
 	tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
 	depends on I2C
Index: linux-2.6.torvalds/drivers/power/Makefile
===================================================================
--- linux-2.6.torvalds.orig/drivers/power/Makefile	2014-02-02 01:37:35.000000000 +0400
+++ linux-2.6.torvalds/drivers/power/Makefile	2014-02-02 01:38:21.966627415 +0400
@@ -30,7 +30,6 @@
 obj-$(CONFIG_BATTERY_BQ27x00)	+= bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
 obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
-obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
 obj-$(CONFIG_BATTERY_MODELGAUGE)	+= modelgauge_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
Index: linux-2.6.torvalds/drivers/power/max17040_battery.c
===================================================================
--- linux-2.6.torvalds.orig/drivers/power/max17040_battery.c	2014-02-02 01:38:29.614627597 +0400
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,297 +0,0 @@
-/*
- *  max17040_battery.c
- *  fuel-gauge systems for lithium-ion (Li+) batteries
- *
- *  Copyright (C) 2009 Samsung Electronics
- *  Minkyu Kang <mk7.kang@samsung.com>
- *
- * This program 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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/power_supply.h>
-#include <linux/max17040_battery.h>
-#include <linux/slab.h>
-
-#define MAX17040_VCELL_MSB	0x02
-#define MAX17040_VCELL_LSB	0x03
-#define MAX17040_SOC_MSB	0x04
-#define MAX17040_SOC_LSB	0x05
-#define MAX17040_MODE_MSB	0x06
-#define MAX17040_MODE_LSB	0x07
-#define MAX17040_VER_MSB	0x08
-#define MAX17040_VER_LSB	0x09
-#define MAX17040_RCOMP_MSB	0x0C
-#define MAX17040_RCOMP_LSB	0x0D
-#define MAX17040_CMD_MSB	0xFE
-#define MAX17040_CMD_LSB	0xFF
-
-#define MAX17040_DELAY		1000
-#define MAX17040_BATTERY_FULL	95
-
-struct max17040_chip {
-	struct i2c_client		*client;
-	struct delayed_work		work;
-	struct power_supply		battery;
-	struct max17040_platform_data	*pdata;
-
-	/* State Of Connect */
-	int online;
-	/* battery voltage */
-	int vcell;
-	/* battery capacity */
-	int soc;
-	/* State Of Charge */
-	int status;
-};
-
-static int max17040_get_property(struct power_supply *psy,
-			    enum power_supply_property psp,
-			    union power_supply_propval *val)
-{
-	struct max17040_chip *chip = container_of(psy,
-				struct max17040_chip, battery);
-
-	switch (psp) {
-	case POWER_SUPPLY_PROP_STATUS:
-		val->intval = chip->status;
-		break;
-	case POWER_SUPPLY_PROP_ONLINE:
-		val->intval = chip->online;
-		break;
-	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		val->intval = chip->vcell;
-		break;
-	case POWER_SUPPLY_PROP_CAPACITY:
-		val->intval = chip->soc;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int max17040_write_reg(struct i2c_client *client, int reg, u8 value)
-{
-	int ret;
-
-	ret = i2c_smbus_write_byte_data(client, reg, value);
-
-	if (ret < 0)
-		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
-	return ret;
-}
-
-static int max17040_read_reg(struct i2c_client *client, int reg)
-{
-	int ret;
-
-	ret = i2c_smbus_read_byte_data(client, reg);
-
-	if (ret < 0)
-		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-
-	return ret;
-}
-
-static void max17040_reset(struct i2c_client *client)
-{
-	max17040_write_reg(client, MAX17040_CMD_MSB, 0x54);
-	max17040_write_reg(client, MAX17040_CMD_LSB, 0x00);
-}
-
-static void max17040_get_vcell(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-	u8 msb;
-	u8 lsb;
-
-	msb = max17040_read_reg(client, MAX17040_VCELL_MSB);
-	lsb = max17040_read_reg(client, MAX17040_VCELL_LSB);
-
-	chip->vcell = (msb << 4) + (lsb >> 4);
-}
-
-static void max17040_get_soc(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-	u8 msb;
-	u8 lsb;
-
-	msb = max17040_read_reg(client, MAX17040_SOC_MSB);
-	lsb = max17040_read_reg(client, MAX17040_SOC_LSB);
-
-	chip->soc = msb;
-}
-
-static void max17040_get_version(struct i2c_client *client)
-{
-	u8 msb;
-	u8 lsb;
-
-	msb = max17040_read_reg(client, MAX17040_VER_MSB);
-	lsb = max17040_read_reg(client, MAX17040_VER_LSB);
-
-	dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb);
-}
-
-static void max17040_get_online(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	if (chip->pdata->battery_online)
-		chip->online = chip->pdata->battery_online();
-	else
-		chip->online = 1;
-}
-
-static void max17040_get_status(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	if (!chip->pdata->charger_online || !chip->pdata->charger_enable) {
-		chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
-		return;
-	}
-
-	if (chip->pdata->charger_online()) {
-		if (chip->pdata->charger_enable())
-			chip->status = POWER_SUPPLY_STATUS_CHARGING;
-		else
-			chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-	} else {
-		chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
-	}
-
-	if (chip->soc > MAX17040_BATTERY_FULL)
-		chip->status = POWER_SUPPLY_STATUS_FULL;
-}
-
-static void max17040_work(struct work_struct *work)
-{
-	struct max17040_chip *chip;
-
-	chip = container_of(work, struct max17040_chip, work.work);
-
-	max17040_get_vcell(chip->client);
-	max17040_get_soc(chip->client);
-	max17040_get_online(chip->client);
-	max17040_get_status(chip->client);
-
-	schedule_delayed_work(&chip->work, MAX17040_DELAY);
-}
-
-static enum power_supply_property max17040_battery_props[] = {
-	POWER_SUPPLY_PROP_STATUS,
-	POWER_SUPPLY_PROP_ONLINE,
-	POWER_SUPPLY_PROP_VOLTAGE_NOW,
-	POWER_SUPPLY_PROP_CAPACITY,
-};
-
-static int max17040_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
-{
-	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct max17040_chip *chip;
-	int ret;
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
-		return -EIO;
-
-	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
-	if (!chip)
-		return -ENOMEM;
-
-	chip->client = client;
-	chip->pdata = client->dev.platform_data;
-
-	i2c_set_clientdata(client, chip);
-
-	chip->battery.name		= "battery";
-	chip->battery.type		= POWER_SUPPLY_TYPE_BATTERY;
-	chip->battery.get_property	= max17040_get_property;
-	chip->battery.properties	= max17040_battery_props;
-	chip->battery.num_properties	= ARRAY_SIZE(max17040_battery_props);
-
-	ret = power_supply_register(&client->dev, &chip->battery);
-	if (ret) {
-		dev_err(&client->dev, "failed: power supply register\n");
-		return ret;
-	}
-
-	max17040_reset(client);
-	max17040_get_version(client);
-
-	INIT_DEFERRABLE_WORK(&chip->work, max17040_work);
-	schedule_delayed_work(&chip->work, MAX17040_DELAY);
-
-	return 0;
-}
-
-static int max17040_remove(struct i2c_client *client)
-{
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	power_supply_unregister(&chip->battery);
-	cancel_delayed_work(&chip->work);
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-static int max17040_suspend(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	cancel_delayed_work(&chip->work);
-	return 0;
-}
-
-static int max17040_resume(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct max17040_chip *chip = i2c_get_clientdata(client);
-
-	schedule_delayed_work(&chip->work, MAX17040_DELAY);
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
-#define MAX17040_PM_OPS (&max17040_pm_ops)
-
-#else
-
-#define MAX17040_PM_OPS NULL
-
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct i2c_device_id max17040_id[] = {
-	{ "max17040", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, max17040_id);
-
-static struct i2c_driver max17040_i2c_driver = {
-	.driver	= {
-		.name	= "max17040",
-		.pm	= MAX17040_PM_OPS,
-	},
-	.probe		= max17040_probe,
-	.remove		= max17040_remove,
-	.id_table	= max17040_id,
-};
-module_i2c_driver(max17040_i2c_driver);
-
-MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
-MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
-MODULE_LICENSE("GPL");
Index: linux-2.6.torvalds/include/linux/max17040_battery.h
===================================================================
--- linux-2.6.torvalds.orig/include/linux/max17040_battery.h	2014-01-15 14:11:22.000000000 +0400
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-/*
- *  Copyright (C) 2009 Samsung Electronics
- *  Minkyu Kang <mk7.kang@samsung.com>
- *
- * This program 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.
- */
-
-#ifndef __MAX17040_BATTERY_H_
-#define __MAX17040_BATTERY_H_
-
-struct max17040_platform_data {
-	int (*battery_online)(void);
-	int (*charger_online)(void);
-	int (*charger_enable)(void);
-};
-
-#endif

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
  2014-02-01 22:23 ` Vladimir Barinov
                   ` (2 preceding siblings ...)
  (?)
@ 2014-02-26 10:21 ` Vladimir Barinov
  -1 siblings, 0 replies; 11+ messages in thread
From: Vladimir Barinov @ 2014-02-26 10:21 UTC (permalink / raw)
  To: dbaryshkov
  Cc: anton@enomsg.org, dwmw2, linux-kernel, devicetree, mk7.kang,
	k.kozlowski, mark.rutland

Hello Dmitry,

In accordance to this change you've taken the responsibility for power 
supply maintainership.
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/MAINTAINERS?id=573189354b7c97cd2256b87cf083ee435584594e

It passed almost month and no answer from you.
Does it make sense to apply this patch series?

Regards,
Vladimir

On 02/02/2014 02:23 AM, Vladimir Barinov wrote:
> Hello.
>
> This adds the folowing:
> - Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips
> - Document DT bindings
> - Remove superseded Maxim MAX17040 gauge driver
>
> Vladimir Barinov (3):
>   [1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
>   [2/3] dt: Document ModelGauge gauge bindings
>   [3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge
>
> ---
> This patchset is against the 'kernel/git/torvalds/linux.git' repo.
>
> Changes since v1:
> - switched to REGMAP API
> - replaced request_threaded_irq with devm_request_threaded_irq
> - replaced cancel_delayed_work with _sync version
> - moved "empty_alert_threshold, soc_change_alert, hibernate_threshold,
>    active_threshold, undervoltage, overvoltage, resetvoltage" parameters
>    out from platform_data and DT
> - removed unused parameters "empty_adjustment, empty_adjustment"
> - added return value checks for of_property_read_XX functions
> - removed irrelevant bindings
> - fixed dt properties naming in documentation
> - added binding size description in documentation
> - removed satelite include file include/linux/max17040_battery.h
>
>   Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt |   61
>   drivers/power/Kconfig                                                 |   17
>   drivers/power/Makefile                                                |    2
>   drivers/power/max17040_battery.c                                      |  297 ---
>   drivers/power/modelgauge_battery.c                                    |  838 ++++++++++
>   include/linux/max17040_battery.h                                      |   19
>   include/linux/platform_data/battery-modelgauge.h                      |   31
>   7 files changed, 940 insertions(+), 325 deletions(-)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
  2014-02-01 22:23     ` Vladimir Barinov
  (?)
@ 2014-03-04 10:48     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 11+ messages in thread
From: Krzysztof Kozlowski @ 2014-03-04 10:48 UTC (permalink / raw)
  To: Vladimir Barinov
  Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang, mark.rutland

Hi,

On Sun, 2014-02-02 at 02:23 +0400, Vladimir Barinov wrote:
> Index: battery-2.6/drivers/power/modelgauge_battery.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ battery-2.6/drivers/power/modelgauge_battery.c	2014-02-02 01:29:34.314614874 +0400
> @@ -0,0 +1,838 @@
> +/*
> + * Maxim ModelGauge ICs fuel gauge driver
> + *
> + * Author: Vladimir Barinov <source@cogentembedded.com>
> + * Copyright (C) 2013 Cogent Embedded, Inc.
> + *
> + * 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.
> + */

(...)

> +static int modelgauge_probe(struct i2c_client *client,
> +			    const struct i2c_device_id *id)
> +{
> +	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> +	struct modelgauge_priv *priv;
> +	int ret;
> +
> +	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
> +		return -EIO;
> +
> +	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	if (client->dev.of_node)
> +		priv->pdata = modelgauge_parse_dt(&client->dev);
> +	else
> +		priv->pdata = client->dev.platform_data;
> +
> +	priv->dev	= &client->dev;
> +	priv->chip	= id->driver_data;
> +
> +	i2c_set_clientdata(client, priv);
> +
> +	priv->regmap = devm_regmap_init_i2c(client, &modelgauge_regmap);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	priv->battery.name		= "modelgauge_battery";
> +	priv->battery.type		= POWER_SUPPLY_TYPE_BATTERY;
> +	priv->battery.get_property	= modelgauge_get_property;
> +	priv->battery.properties	= modelgauge_battery_props;
> +	priv->battery.num_properties	= ARRAY_SIZE(modelgauge_battery_props);
> +
> +	INIT_WORK(&priv->load_work, modelgauge_load_model_work);
> +	INIT_DELAYED_WORK(&priv->rcomp_work, modelgauge_update_rcomp_work);
> +
> +	ret = modelgauge_init(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = power_supply_register(&client->dev, &priv->battery);
> +	if (ret) {
> +		dev_err(priv->dev, "failed: power supply register\n");
> +		goto err_supply;
> +	}
> +
> +	if (client->irq) {
> +		switch (priv->chip) {
> +		case ID_MAX17040:
> +		case ID_MAX17041:
> +			dev_err(priv->dev, "alert line is not supported\n");
> +			ret = -EINVAL;
> +			goto err_irq;
> +		default:
> +			ret = devm_request_threaded_irq(priv->dev, client->irq,
> +							NULL,
> +							modelgauge_irq_handler,
> +							IRQF_TRIGGER_FALLING,
> +							priv->battery.name,
> +							priv);

Shouldn't it be also IRQF_ONESHOT? Without this you may get an error:
genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq

> +			if (ret) {
> +				dev_err(priv->dev, "failed to request irq %d\n",
> +					client->irq);
> +				goto err_irq;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +
> +err_irq:
> +	power_supply_unregister(&priv->battery);
> +err_supply:
> +	cancel_work_sync(&priv->load_work);
> +	cancel_delayed_work_sync(&priv->rcomp_work);
> +	return ret;
> +}
> +
> +static int modelgauge_remove(struct i2c_client *client)
> +{
> +	struct modelgauge_priv *priv = i2c_get_clientdata(client);
> +
> +	cancel_work_sync(&priv->load_work);
> +	cancel_delayed_work_sync(&priv->rcomp_work);
> +
> +	power_supply_unregister(&priv->battery);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int modelgauge_suspend(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct modelgauge_priv *priv = i2c_get_clientdata(client);
> +	struct modelgauge_platform_data *pdata = priv->pdata;
> +
> +	if (pdata && pdata->get_temperature)
> +		cancel_delayed_work_sync(&priv->rcomp_work);
> +
> +	switch (priv->chip) {
> +	case ID_MAX17040:
> +	case ID_MAX17041:
> +		return 0;
> +	default:
> +		if (client->irq) {
> +			disable_irq(client->irq);
> +			enable_irq_wake(client->irq);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int modelgauge_resume(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct modelgauge_priv *priv = i2c_get_clientdata(client);
> +	struct modelgauge_platform_data *pdata = priv->pdata;
> +
> +	if (pdata && pdata->get_temperature)
> +		schedule_delayed_work(&priv->rcomp_work,
> +			    msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY));
> +
> +	switch (priv->chip) {
> +	case ID_MAX17040:
> +	case ID_MAX17041:
> +		return 0;
> +	default:
> +		if (client->irq) {
> +			disable_irq_wake(client->irq);
> +			enable_irq(client->irq);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(modelgauge_pm_ops,
> +			 modelgauge_suspend, modelgauge_resume);
> +#define MODELGAUGE_PM_OPS (&modelgauge_pm_ops)
> +#else
> +#define MODELGAUGE_PM_OPS NULL
> +#endif /* CONFIG_PM_SLEEP */

You can simplify this into:
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(modelgauge_pm_ops,
+			 modelgauge_suspend, modelgauge_resume);

And later:
+static struct i2c_driver modelgauge_i2c_driver = {
+	.driver	= {
+		.name		= DRV_NAME,
+		.of_match_table	= of_match_ptr(modelgauge_match),
+		.pm		= &modelgauge_pm_ops,


Anyway, I like the idea of merging these drivers so I'm happy to test it
further.


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
  2014-02-01 22:23     ` Vladimir Barinov
  (?)
  (?)
@ 2014-03-04 12:05     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 11+ messages in thread
From: Krzysztof Kozlowski @ 2014-03-04 12:05 UTC (permalink / raw)
  To: Vladimir Barinov
  Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang, mark.rutland

And one more comment:

On Sun, 2014-02-02 at 02:23 +0400, Vladimir Barinov wrote:
> +static int modelgauge_get_property(struct power_supply *psy,
> +				   enum power_supply_property psp,
> +				   union power_supply_propval *val)
> +{
> +	struct modelgauge_priv *priv = container_of(psy,
> +						    struct modelgauge_priv,
> +						    battery);
> +	struct regmap *regmap = priv->regmap;
> +	struct modelgauge_platform_data *pdata = priv->pdata;
> +	int reg;
> +	int ret;
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_STATUS:
> +		if (pdata && pdata->get_charging_status)
> +			val->intval = pdata->get_charging_status();
> +		else
> +			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +		ret = regmap_read(regmap, MODELGAUGE_VCELL_REG, &reg);
> +		if (ret < 0)
> +			return ret;
> +
> +		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
> +		/* Unlock model access */
> +		regmap_write(regmap, MODELGAUGE_UNLOCK_REG,
> +			     MODELGAUGE_UNLOCK_VALUE);
> +		ret = regmap_read(regmap, MODELGAUGE_OCV_REG, &reg);
> +		/* Lock model access */
> +		regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0);
> +		if (ret < 0)
> +			return ret;
> +
> +		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
> +		break;
> +	case POWER_SUPPLY_PROP_CAPACITY:
> +		ret = regmap_read(regmap, MODELGAUGE_SOC_REG, &reg);
> +		if (ret < 0)
> +			return ret;
> +
> +		val->intval = reg / (1 << priv->soc_shift);
> +		break;
> +	case POWER_SUPPLY_PROP_TEMP:
> +		if (pdata && pdata->get_temperature)
> +			val->intval = pdata->get_temperature();
> +		else
> +			val->intval = 25;

If pdata->get_temperature() is not supplied then probably the driver
should not support POWER_SUPPLY_PROP_TEMP at all. I think it is better
not to report any temperature than to report a wrong one.


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2014-03-04 12:05 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-01 22:23 [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov
2014-02-01 22:23 ` Vladimir Barinov
     [not found] ` <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
2014-02-01 22:23   ` [PATCH v2 1/3] power_supply: modelgauge_battery: " Vladimir Barinov
2014-02-01 22:23     ` Vladimir Barinov
2014-03-04 10:48     ` Krzysztof Kozlowski
2014-03-04 12:05     ` Krzysztof Kozlowski
2014-02-01 22:23   ` [PATCH v2 2/3] dt: Document ModelGauge gauge bindings Vladimir Barinov
2014-02-01 22:23     ` Vladimir Barinov
2014-02-01 22:23 ` [PATCH v2 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge Vladimir Barinov
2014-02-01 22:23   ` Vladimir Barinov
2014-02-26 10:21 ` [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.