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

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

---
 Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt |   82 
 drivers/power/Kconfig                                                 |   16 
 drivers/power/Makefile                                                |    2 
 drivers/power/max17040_battery.c                                      |  297 ---
 drivers/power/modelgauge_battery.c                                    |  875 ++++++++++
 include/linux/platform_data/battery-modelgauge.h                      |   44 
 6 files changed, 1010 insertions(+), 306 deletions(-)

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

* [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
@ 2014-01-09 16:49 ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-09 16:49 UTC (permalink / raw)
  To: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: mk7.kang-Sze3O3UU22JBDgjK7y7TUQ

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

---
 Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt |   82 
 drivers/power/Kconfig                                                 |   16 
 drivers/power/Makefile                                                |    2 
 drivers/power/max17040_battery.c                                      |  297 ---
 drivers/power/modelgauge_battery.c                                    |  875 ++++++++++
 include/linux/platform_data/battery-modelgauge.h                      |   44 
 6 files changed, 1010 insertions(+), 306 deletions(-)
--
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] 27+ messages in thread

* [PATCH 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
@ 2014-01-09 16:49   ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-09 16:49 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree; +Cc: mk7.kang

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                            |    8 
 drivers/power/Makefile                           |    1 
 drivers/power/modelgauge_battery.c               |  875 +++++++++++++++++++++++
 include/linux/platform_data/battery-modelgauge.h |   44 +
 4 files changed, 928 insertions(+)

Index: battery-2.6/drivers/power/Kconfig
===================================================================
--- battery-2.6.orig/drivers/power/Kconfig	2014-01-09 15:09:31.455138730 +0400
+++ battery-2.6/drivers/power/Kconfig	2014-01-09 15:09:36.331138847 +0400
@@ -204,6 +204,14 @@
 	  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
+	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-01-09 15:09:31.483138731 +0400
+++ battery-2.6/drivers/power/Makefile	2014-01-09 15:09:36.331138847 +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_CHARGER_88PM860X)	+= 88pm860x_charger.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-01-09 15:09:36.335138846 +0400
@@ -0,0 +1,875 @@
+/*
+ * 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/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
+
+enum chip_id {
+	ID_MAX17040,
+	ID_MAX17041,
+	ID_MAX17043,
+	ID_MAX17044,
+	ID_MAX17048,
+	ID_MAX17049,
+	ID_MAX17058,
+	ID_MAX17059,
+};
+
+struct modelgauge_priv {
+	struct i2c_client		*client;
+	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 int modelgauge_read_reg(struct i2c_client *client, u8 reg, u16 *value)
+{
+	int ret = i2c_smbus_read_word_data(client, reg);
+
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+		return ret;
+	}
+
+	*value = be16_to_cpu(ret);
+	return 0;
+}
+
+static int modelgauge_write_reg(struct i2c_client *client, u8 reg, u16 value)
+{
+	int ret = i2c_smbus_write_word_data(client, reg, cpu_to_be16(value));
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static void modelgauge_write_block(struct i2c_client *client, u8 adr, u8 size,
+				   u16 *data)
+{
+	int k;
+
+	for (k = 0; k < size; k += 2, adr += 2, data++)
+		i2c_smbus_write_word_data(client, adr, *data);
+}
+
+static void modelgauge_reset(struct i2c_client *client)
+{
+	/* Reset chip transaction does not provide ACK */
+	i2c_smbus_write_word_data(client, MODELGAUGE_CMD_REG,
+				  cpu_to_be16(MODELGAUGE_RESET_VALUE));
+}
+
+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_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
+	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 i2c_client *client = priv->client;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	u16 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_CHARGE_FULL_DESIGN:
+		if (pdata && pdata->model)
+			val->intval = pdata->model->full_adjustment;
+		else
+			val->intval = 100;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
+		if (pdata && pdata->model)
+			val->intval = pdata->model->empty_adjustment;
+		else
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = modelgauge_read_reg(client, 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 */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+		ret = modelgauge_read_reg(client, MODELGAUGE_OCV_REG, &reg);
+		/* Lock model access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG, 0);
+		if (ret < 0)
+			return ret;
+
+		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = modelgauge_read_reg(client, 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 i2c_client *client = priv->client;
+	struct modelgauge_custom_model *model = priv->pdata->model;
+	u16 rcomp, reg;
+	int temp;
+
+	if (priv->pdata->get_temperature)
+		temp = priv->pdata->get_temperature();
+	else
+		temp = 25;
+
+	if (!model->temp_co_up)
+		model->temp_co_up = -500;
+	if (!model->temp_co_down)
+		model->temp_co_down = -5000;
+
+	rcomp = model->rcomp0;
+	if (temp > 20)
+		rcomp += (temp - 20) * model->temp_co_up / 1000;
+	else
+		rcomp += (temp - 20) * model->temp_co_down / 1000;
+
+	/* Update RCOMP */
+	modelgauge_read_reg(client, MODELGAUGE_CONFIG_REG, &reg);
+	reg &= 0xff;
+	reg |= rcomp << 8;
+	modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, reg);
+}
+
+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 i2c_client *client = priv->client;
+	struct modelgauge_custom_model *model = priv->pdata->model;
+	int ret = -EINVAL;
+	int timeout, k;
+	u16 ocv, config, soc;
+
+	/* Save CONFIG */
+	modelgauge_read_reg(client, MODELGAUGE_CONFIG_REG, &config);
+
+	for (timeout = 0; timeout < 100; timeout++) {
+		/* Unlock model access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+
+		/* Read OCV */
+		modelgauge_read_reg(client, MODELGAUGE_OCV_REG, &ocv);
+		if (ocv != 0xffff)
+			break;
+	}
+
+	if (timeout >= 100) {
+		dev_err(&client->dev, "timeout to unlock model access\n");
+		ret = -EIO;
+		goto exit;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Reset chip */
+		modelgauge_reset(client);
+		msleep(150);
+
+		for (timeout = 0; timeout < 100; timeout++) {
+			u16 reg;
+
+			/* Unlock Model Access */
+			modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+						     MODELGAUGE_UNLOCK_VALUE);
+
+			/* Read OCV */
+			modelgauge_read_reg(client, MODELGAUGE_OCV_REG, &reg);
+			if (reg != 0xffff)
+				break;
+		}
+
+		if (timeout >= 100) {
+			dev_err(&client->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 */
+		modelgauge_write_reg(client, MODELGAUGE_OCV_REG,
+				     model->ocvtest);
+		/* Write RCOMP to its maximum value */
+		modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, 0xff00);
+		break;
+	default:
+		break;
+	}
+
+	/* Write the model */
+	modelgauge_write_block(client, MODELGAUGE_TABLE_REG,
+			       MODELGAUGE_TABLE_SIZE,
+			       (u16 *)model->model_data);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049: {
+			u16 buf[16];
+
+			if (!model->rcomp_seg)
+				model->rcomp_seg = 0x80;
+
+			for (k = 0; k < 16; k++)
+				*buf = model->rcomp_seg;
+
+			/* Write RCOMPSeg */
+			modelgauge_write_block(client, 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 */
+	modelgauge_write_reg(client, MODELGAUGE_OCV_REG, model->ocvtest);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Disable Hibernate */
+		modelgauge_write_reg(client, MODELGAUGE_HIBRT_REG, 0);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Lock Model Access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG, 0);
+		break;
+	default:
+		break;
+	}
+
+	/* Delay between 150ms and 600ms */
+	msleep(200);
+
+	/* Read SOC Register and compare to expected result */
+	modelgauge_read_reg(client, MODELGAUGE_SOC_REG, &soc);
+	soc >>= 8;
+	if (soc >= model->soc_check_a && soc <= model->soc_check_b)
+		ret = 0;
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Unlock model access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+		break;
+	default:
+		break;
+	}
+
+	/* Restore CONFIG and OCV */
+	modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, config);
+	modelgauge_write_reg(client, MODELGAUGE_OCV_REG, ocv);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Restore Hibernate */
+		modelgauge_write_reg(client, MODELGAUGE_HIBRT_REG,
+				     (priv->pdata->hibernate_threshold << 8) |
+				     priv->pdata->active_threshold);
+		break;
+	default:
+		break;
+	}
+
+exit:
+	/* Lock model access */
+	modelgauge_write_reg(client, 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 i2c_client *client = priv->client;
+	int ret;
+	u16 reg;
+	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(&client->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 */
+		modelgauge_read_reg(client, MODELGAUGE_STATUS_REG, &reg);
+		reg &= ~MODELGAUGE_STATUS_RI;
+		modelgauge_write_reg(client, MODELGAUGE_STATUS_REG, reg);
+		break;
+	default:
+		break;
+	}
+}
+
+static irqreturn_t modelgauge_irq_handler(int id, void *dev)
+{
+	struct modelgauge_priv *priv = dev;
+	u16 config;
+
+	/* clear alert status bit */
+	modelgauge_read_reg(priv->client, MODELGAUGE_CONFIG_REG, &config);
+	config &= ~MODELGAUGE_CONFIG_ALRT;
+	modelgauge_write_reg(priv->client, MODELGAUGE_CONFIG_REG, config);
+
+	power_supply_changed(&priv->battery);
+	return IRQ_HANDLED;
+}
+
+static int modelgauge_init(struct modelgauge_priv *priv)
+{
+	struct i2c_client *client = priv->client;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int ret;
+	u16 reg;
+
+	ret = modelgauge_read_reg(client, MODELGAUGE_VERSION_REG, &reg);
+	if (ret < 0)
+		return -ENODEV;
+
+	dev_info(&client->dev, "IC production version 0x%04x\n", reg);
+
+	/* SOC=0 means unrecoverable IC fault, reset is a workaround */
+	modelgauge_read_reg(client, MODELGAUGE_SOC_REG, &reg);
+	if (!reg) {
+		dev_info(&client->dev, "Reset chip, SOC measurement stall\n");
+		modelgauge_reset(client);
+		msleep(150);
+	}
+
+	/* Default model uses 8 bits per percent */
+	priv->soc_shift = 8;
+
+	if (!priv->pdata) {
+		dev_info(&client->dev, "no platform data provided\n");
+		return 0;
+	}
+
+	if (pdata->model) {
+		switch (pdata->model->bits) {
+		case 19:
+			priv->soc_shift = 9;
+			break;
+		case 18:
+		default:
+			priv->soc_shift = 8;
+			break;
+		}
+	}
+
+	/* Set RCOMP */
+	if (pdata->model)
+		modelgauge_update_rcomp(priv);
+	if (pdata->model && 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 */
+	modelgauge_read_reg(client, MODELGAUGE_CONFIG_REG, &reg);
+	reg &= ~(MODELGAUGE_CONFIG_ALRT | MODELGAUGE_CONFIG_SLEEP |
+		 MODELGAUGE_CONFIG_ALSC);
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		reg |= pdata->soc_change_alert ? MODELGAUGE_CONFIG_ALSC : 0;
+		/* fall-through */
+	case ID_MAX17043:
+	case ID_MAX17044:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		reg &= ~MODELGAUGE_CONFIG_ATHD_MASK;
+		reg |= 32 -
+		       (pdata->empty_alert_threshold << (priv->soc_shift - 8));
+		break;
+	default:
+		break;
+	}
+	modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, reg);
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Set Hibernate thresholds */
+		reg = (pdata->hibernate_threshold * 125 / 26) & 0xff;
+		reg <<= 8;
+		reg |= (pdata->active_threshold * 4 / 5) & 0xff;
+		modelgauge_write_reg(client, MODELGAUGE_HIBRT_REG, reg);
+
+		/* Set undervoltage/overvoltage alerts */
+		reg = (pdata->undervoltage / 20) & 0xff;
+		reg <<= 8;
+		reg |= (pdata->overvoltage / 20) & 0xff;
+		modelgauge_write_reg(client, MODELGAUGE_VALRT_REG, reg);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Disable sleep mode and quick start */
+		modelgauge_write_reg(client, MODELGAUGE_MODE_REG, 0);
+
+		/* Setup reset voltage threshold */
+		if (pdata->resetvoltage)
+			reg = ((pdata->resetvoltage / 40) & 0x7f) << 9;
+		else
+			reg = MODELGAUGE_VRESETID_DIS;
+		modelgauge_write_reg(client, MODELGAUGE_VRESETID_REG, reg);
+
+		/* Skip load model if reset indicator cleared */
+		modelgauge_read_reg(client, 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 && pdata->model->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;
+
+	if (!of_get_property(np, "maxim,empty_alert_threshold", NULL) &&
+	    !of_get_property(np, "maxim,soc_change_alert", NULL) &&
+	    !of_get_property(np, "maxim,hibernate_threshold", NULL) &&
+	    !of_get_property(np, "maxim,active_threshold", NULL) &&
+	    !of_get_property(np, "maxim,undervoltage", NULL) &&
+	    !of_get_property(np, "maxim,overvoltage", NULL) &&
+	    !of_get_property(np, "maxim,resetvoltage", NULL))
+		return NULL;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	of_property_read_u8(np, "maxim,empty_alert_threshold",
+			    &pdata->empty_alert_threshold);
+	pdata->soc_change_alert =
+			of_property_read_bool(np, "maxim,soc_change_alert");
+	of_property_read_u8(np, "maxim,hibernate_threshold",
+			    &pdata->hibernate_threshold);
+	of_property_read_u8(np, "maxim,active_threshold",
+			    &pdata->active_threshold);
+	of_property_read_u16(np, "maxim,undervoltage", &pdata->undervoltage);
+	of_property_read_u16(np, "maxim,overvoltage", &pdata->overvoltage);
+	of_property_read_u16(np, "maxim,resetvoltage", &pdata->resetvoltage);
+
+	prop = of_find_property(np, "maxim,ocvtest", NULL);
+	if (prop) {
+		pdata->model = devm_kzalloc(dev, sizeof(*pdata->model),
+					    GFP_KERNEL);
+		if (!pdata->model)
+			return NULL;
+
+		of_property_read_u8(np, "maxim,empty_adjustment",
+				    &pdata->model->empty_adjustment);
+		of_property_read_u8(np, "maxim,full_adjustment",
+				    &pdata->model->full_adjustment);
+		of_property_read_u8(np, "maxim,rcomp0",
+				    &pdata->model->rcomp0);
+		prop = of_find_property(np, "maxim,temp_co_up", NULL);
+		if (prop)
+			pdata->model->temp_co_up = be32_to_cpup(prop->value);
+		prop = of_find_property(np, "maxim,temp_co_down", NULL);
+		if (prop)
+			pdata->model->temp_co_down = be32_to_cpup(prop->value);
+		of_property_read_u16(np, "maxim,ocvtest",
+				     &pdata->model->ocvtest);
+		of_property_read_u8(np, "maxim,soc_check_a",
+				    &pdata->model->soc_check_a);
+		of_property_read_u8(np, "maxim,soc_check_b",
+				    &pdata->model->soc_check_b);
+		of_property_read_u8(np, "maxim,bits",
+				    &pdata->model->bits);
+		of_property_read_u16(np, "maxim,rcomp_seg",
+				     &pdata->model->rcomp_seg);
+	}
+
+	prop = of_find_property(np, "maxim,model_data", NULL);
+	if (prop && prop->length == MODELGAUGE_TABLE_SIZE) {
+		pdata->model->model_data = devm_kzalloc(dev,
+							MODELGAUGE_TABLE_SIZE,
+							GFP_KERNEL);
+		if (!pdata->model->model_data)
+			return NULL;
+
+		of_property_read_u8_array(np, "maxim,model_data",
+					  pdata->model->model_data,
+					  MODELGAUGE_TABLE_SIZE);
+	}
+
+	return pdata;
+}
+
+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->client	= client;
+	priv->chip	= id->driver_data;
+
+	i2c_set_clientdata(client, priv);
+
+	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(&client->dev, "failed: power supply register\n");
+		goto err_supply;
+	}
+
+	if (client->irq) {
+		switch (priv->chip) {
+		case ID_MAX17040:
+		case ID_MAX17041:
+			dev_err(&client->dev, "alert line is not supported\n");
+			ret = -EINVAL;
+			goto err_irq;
+		default:
+			ret = request_threaded_irq(client->irq, NULL,
+						   modelgauge_irq_handler,
+						   IRQF_TRIGGER_FALLING,
+						   priv->battery.name, priv);
+			if (ret) {
+				dev_err(&client->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(&priv->rcomp_work);
+	return ret;
+}
+
+static int modelgauge_remove(struct i2c_client *client)
+{
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+
+	if (client->irq)
+		free_irq(client->irq, priv);
+
+	cancel_work_sync(&priv->load_work);
+	cancel_delayed_work(&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->model && pdata->get_temperature)
+		cancel_delayed_work(&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->model && 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-01-09 15:09:36.335138846 +0400
@@ -0,0 +1,44 @@
+/*
+ * 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_custom_model {
+	u8	empty_adjustment;
+	u8	full_adjustment;
+	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;
+};
+
+struct modelgauge_platform_data {
+	u8	empty_alert_threshold;	/* soc alert range 1..32 */
+	bool	soc_change_alert;	/* alert for 1% soc change */
+	u8	hibernate_threshold;	/* soc per hour */
+	u8	active_threshold;	/* mV */
+	u16	undervoltage;		/* mV */
+	u16	overvoltage;		/* mV */
+	u16	resetvoltage;		/* mV */
+	struct modelgauge_custom_model *model; /* custom battery data */
+	int	(*get_temperature)(void); /* C */
+	int	(*get_charging_status)(void);
+};
+#endif

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

* [PATCH 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
@ 2014-01-09 16:49   ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-09 16:49 UTC (permalink / raw)
  To: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: mk7.kang-Sze3O3UU22JBDgjK7y7TUQ

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                            |    8 
 drivers/power/Makefile                           |    1 
 drivers/power/modelgauge_battery.c               |  875 +++++++++++++++++++++++
 include/linux/platform_data/battery-modelgauge.h |   44 +
 4 files changed, 928 insertions(+)

Index: battery-2.6/drivers/power/Kconfig
===================================================================
--- battery-2.6.orig/drivers/power/Kconfig	2014-01-09 15:09:31.455138730 +0400
+++ battery-2.6/drivers/power/Kconfig	2014-01-09 15:09:36.331138847 +0400
@@ -204,6 +204,14 @@
 	  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
+	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-01-09 15:09:31.483138731 +0400
+++ battery-2.6/drivers/power/Makefile	2014-01-09 15:09:36.331138847 +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_CHARGER_88PM860X)	+= 88pm860x_charger.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-01-09 15:09:36.335138846 +0400
@@ -0,0 +1,875 @@
+/*
+ * 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/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
+
+enum chip_id {
+	ID_MAX17040,
+	ID_MAX17041,
+	ID_MAX17043,
+	ID_MAX17044,
+	ID_MAX17048,
+	ID_MAX17049,
+	ID_MAX17058,
+	ID_MAX17059,
+};
+
+struct modelgauge_priv {
+	struct i2c_client		*client;
+	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 int modelgauge_read_reg(struct i2c_client *client, u8 reg, u16 *value)
+{
+	int ret = i2c_smbus_read_word_data(client, reg);
+
+	if (ret < 0) {
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+		return ret;
+	}
+
+	*value = be16_to_cpu(ret);
+	return 0;
+}
+
+static int modelgauge_write_reg(struct i2c_client *client, u8 reg, u16 value)
+{
+	int ret = i2c_smbus_write_word_data(client, reg, cpu_to_be16(value));
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static void modelgauge_write_block(struct i2c_client *client, u8 adr, u8 size,
+				   u16 *data)
+{
+	int k;
+
+	for (k = 0; k < size; k += 2, adr += 2, data++)
+		i2c_smbus_write_word_data(client, adr, *data);
+}
+
+static void modelgauge_reset(struct i2c_client *client)
+{
+	/* Reset chip transaction does not provide ACK */
+	i2c_smbus_write_word_data(client, MODELGAUGE_CMD_REG,
+				  cpu_to_be16(MODELGAUGE_RESET_VALUE));
+}
+
+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_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
+	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 i2c_client *client = priv->client;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	u16 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_CHARGE_FULL_DESIGN:
+		if (pdata && pdata->model)
+			val->intval = pdata->model->full_adjustment;
+		else
+			val->intval = 100;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
+		if (pdata && pdata->model)
+			val->intval = pdata->model->empty_adjustment;
+		else
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = modelgauge_read_reg(client, 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 */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+		ret = modelgauge_read_reg(client, MODELGAUGE_OCV_REG, &reg);
+		/* Lock model access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG, 0);
+		if (ret < 0)
+			return ret;
+
+		val->intval = modelgauge_lsb_to_uvolts(priv, reg);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = modelgauge_read_reg(client, 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 i2c_client *client = priv->client;
+	struct modelgauge_custom_model *model = priv->pdata->model;
+	u16 rcomp, reg;
+	int temp;
+
+	if (priv->pdata->get_temperature)
+		temp = priv->pdata->get_temperature();
+	else
+		temp = 25;
+
+	if (!model->temp_co_up)
+		model->temp_co_up = -500;
+	if (!model->temp_co_down)
+		model->temp_co_down = -5000;
+
+	rcomp = model->rcomp0;
+	if (temp > 20)
+		rcomp += (temp - 20) * model->temp_co_up / 1000;
+	else
+		rcomp += (temp - 20) * model->temp_co_down / 1000;
+
+	/* Update RCOMP */
+	modelgauge_read_reg(client, MODELGAUGE_CONFIG_REG, &reg);
+	reg &= 0xff;
+	reg |= rcomp << 8;
+	modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, reg);
+}
+
+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 i2c_client *client = priv->client;
+	struct modelgauge_custom_model *model = priv->pdata->model;
+	int ret = -EINVAL;
+	int timeout, k;
+	u16 ocv, config, soc;
+
+	/* Save CONFIG */
+	modelgauge_read_reg(client, MODELGAUGE_CONFIG_REG, &config);
+
+	for (timeout = 0; timeout < 100; timeout++) {
+		/* Unlock model access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+
+		/* Read OCV */
+		modelgauge_read_reg(client, MODELGAUGE_OCV_REG, &ocv);
+		if (ocv != 0xffff)
+			break;
+	}
+
+	if (timeout >= 100) {
+		dev_err(&client->dev, "timeout to unlock model access\n");
+		ret = -EIO;
+		goto exit;
+	}
+
+	switch (priv->chip) {
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Reset chip */
+		modelgauge_reset(client);
+		msleep(150);
+
+		for (timeout = 0; timeout < 100; timeout++) {
+			u16 reg;
+
+			/* Unlock Model Access */
+			modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+						     MODELGAUGE_UNLOCK_VALUE);
+
+			/* Read OCV */
+			modelgauge_read_reg(client, MODELGAUGE_OCV_REG, &reg);
+			if (reg != 0xffff)
+				break;
+		}
+
+		if (timeout >= 100) {
+			dev_err(&client->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 */
+		modelgauge_write_reg(client, MODELGAUGE_OCV_REG,
+				     model->ocvtest);
+		/* Write RCOMP to its maximum value */
+		modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, 0xff00);
+		break;
+	default:
+		break;
+	}
+
+	/* Write the model */
+	modelgauge_write_block(client, MODELGAUGE_TABLE_REG,
+			       MODELGAUGE_TABLE_SIZE,
+			       (u16 *)model->model_data);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049: {
+			u16 buf[16];
+
+			if (!model->rcomp_seg)
+				model->rcomp_seg = 0x80;
+
+			for (k = 0; k < 16; k++)
+				*buf = model->rcomp_seg;
+
+			/* Write RCOMPSeg */
+			modelgauge_write_block(client, 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 */
+	modelgauge_write_reg(client, MODELGAUGE_OCV_REG, model->ocvtest);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Disable Hibernate */
+		modelgauge_write_reg(client, MODELGAUGE_HIBRT_REG, 0);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Lock Model Access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG, 0);
+		break;
+	default:
+		break;
+	}
+
+	/* Delay between 150ms and 600ms */
+	msleep(200);
+
+	/* Read SOC Register and compare to expected result */
+	modelgauge_read_reg(client, MODELGAUGE_SOC_REG, &soc);
+	soc >>= 8;
+	if (soc >= model->soc_check_a && soc <= model->soc_check_b)
+		ret = 0;
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Unlock model access */
+		modelgauge_write_reg(client, MODELGAUGE_UNLOCK_REG,
+				     MODELGAUGE_UNLOCK_VALUE);
+		break;
+	default:
+		break;
+	}
+
+	/* Restore CONFIG and OCV */
+	modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, config);
+	modelgauge_write_reg(client, MODELGAUGE_OCV_REG, ocv);
+
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Restore Hibernate */
+		modelgauge_write_reg(client, MODELGAUGE_HIBRT_REG,
+				     (priv->pdata->hibernate_threshold << 8) |
+				     priv->pdata->active_threshold);
+		break;
+	default:
+		break;
+	}
+
+exit:
+	/* Lock model access */
+	modelgauge_write_reg(client, 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 i2c_client *client = priv->client;
+	int ret;
+	u16 reg;
+	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(&client->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 */
+		modelgauge_read_reg(client, MODELGAUGE_STATUS_REG, &reg);
+		reg &= ~MODELGAUGE_STATUS_RI;
+		modelgauge_write_reg(client, MODELGAUGE_STATUS_REG, reg);
+		break;
+	default:
+		break;
+	}
+}
+
+static irqreturn_t modelgauge_irq_handler(int id, void *dev)
+{
+	struct modelgauge_priv *priv = dev;
+	u16 config;
+
+	/* clear alert status bit */
+	modelgauge_read_reg(priv->client, MODELGAUGE_CONFIG_REG, &config);
+	config &= ~MODELGAUGE_CONFIG_ALRT;
+	modelgauge_write_reg(priv->client, MODELGAUGE_CONFIG_REG, config);
+
+	power_supply_changed(&priv->battery);
+	return IRQ_HANDLED;
+}
+
+static int modelgauge_init(struct modelgauge_priv *priv)
+{
+	struct i2c_client *client = priv->client;
+	struct modelgauge_platform_data *pdata = priv->pdata;
+	int ret;
+	u16 reg;
+
+	ret = modelgauge_read_reg(client, MODELGAUGE_VERSION_REG, &reg);
+	if (ret < 0)
+		return -ENODEV;
+
+	dev_info(&client->dev, "IC production version 0x%04x\n", reg);
+
+	/* SOC=0 means unrecoverable IC fault, reset is a workaround */
+	modelgauge_read_reg(client, MODELGAUGE_SOC_REG, &reg);
+	if (!reg) {
+		dev_info(&client->dev, "Reset chip, SOC measurement stall\n");
+		modelgauge_reset(client);
+		msleep(150);
+	}
+
+	/* Default model uses 8 bits per percent */
+	priv->soc_shift = 8;
+
+	if (!priv->pdata) {
+		dev_info(&client->dev, "no platform data provided\n");
+		return 0;
+	}
+
+	if (pdata->model) {
+		switch (pdata->model->bits) {
+		case 19:
+			priv->soc_shift = 9;
+			break;
+		case 18:
+		default:
+			priv->soc_shift = 8;
+			break;
+		}
+	}
+
+	/* Set RCOMP */
+	if (pdata->model)
+		modelgauge_update_rcomp(priv);
+	if (pdata->model && 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 */
+	modelgauge_read_reg(client, MODELGAUGE_CONFIG_REG, &reg);
+	reg &= ~(MODELGAUGE_CONFIG_ALRT | MODELGAUGE_CONFIG_SLEEP |
+		 MODELGAUGE_CONFIG_ALSC);
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		reg |= pdata->soc_change_alert ? MODELGAUGE_CONFIG_ALSC : 0;
+		/* fall-through */
+	case ID_MAX17043:
+	case ID_MAX17044:
+	case ID_MAX17058:
+	case ID_MAX17059:
+		reg &= ~MODELGAUGE_CONFIG_ATHD_MASK;
+		reg |= 32 -
+		       (pdata->empty_alert_threshold << (priv->soc_shift - 8));
+		break;
+	default:
+		break;
+	}
+	modelgauge_write_reg(client, MODELGAUGE_CONFIG_REG, reg);
+	switch (priv->chip) {
+	case ID_MAX17048:
+	case ID_MAX17049:
+		/* Set Hibernate thresholds */
+		reg = (pdata->hibernate_threshold * 125 / 26) & 0xff;
+		reg <<= 8;
+		reg |= (pdata->active_threshold * 4 / 5) & 0xff;
+		modelgauge_write_reg(client, MODELGAUGE_HIBRT_REG, reg);
+
+		/* Set undervoltage/overvoltage alerts */
+		reg = (pdata->undervoltage / 20) & 0xff;
+		reg <<= 8;
+		reg |= (pdata->overvoltage / 20) & 0xff;
+		modelgauge_write_reg(client, MODELGAUGE_VALRT_REG, reg);
+		/* fall-through */
+	case ID_MAX17058:
+	case ID_MAX17059:
+		/* Disable sleep mode and quick start */
+		modelgauge_write_reg(client, MODELGAUGE_MODE_REG, 0);
+
+		/* Setup reset voltage threshold */
+		if (pdata->resetvoltage)
+			reg = ((pdata->resetvoltage / 40) & 0x7f) << 9;
+		else
+			reg = MODELGAUGE_VRESETID_DIS;
+		modelgauge_write_reg(client, MODELGAUGE_VRESETID_REG, reg);
+
+		/* Skip load model if reset indicator cleared */
+		modelgauge_read_reg(client, 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 && pdata->model->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;
+
+	if (!of_get_property(np, "maxim,empty_alert_threshold", NULL) &&
+	    !of_get_property(np, "maxim,soc_change_alert", NULL) &&
+	    !of_get_property(np, "maxim,hibernate_threshold", NULL) &&
+	    !of_get_property(np, "maxim,active_threshold", NULL) &&
+	    !of_get_property(np, "maxim,undervoltage", NULL) &&
+	    !of_get_property(np, "maxim,overvoltage", NULL) &&
+	    !of_get_property(np, "maxim,resetvoltage", NULL))
+		return NULL;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	of_property_read_u8(np, "maxim,empty_alert_threshold",
+			    &pdata->empty_alert_threshold);
+	pdata->soc_change_alert =
+			of_property_read_bool(np, "maxim,soc_change_alert");
+	of_property_read_u8(np, "maxim,hibernate_threshold",
+			    &pdata->hibernate_threshold);
+	of_property_read_u8(np, "maxim,active_threshold",
+			    &pdata->active_threshold);
+	of_property_read_u16(np, "maxim,undervoltage", &pdata->undervoltage);
+	of_property_read_u16(np, "maxim,overvoltage", &pdata->overvoltage);
+	of_property_read_u16(np, "maxim,resetvoltage", &pdata->resetvoltage);
+
+	prop = of_find_property(np, "maxim,ocvtest", NULL);
+	if (prop) {
+		pdata->model = devm_kzalloc(dev, sizeof(*pdata->model),
+					    GFP_KERNEL);
+		if (!pdata->model)
+			return NULL;
+
+		of_property_read_u8(np, "maxim,empty_adjustment",
+				    &pdata->model->empty_adjustment);
+		of_property_read_u8(np, "maxim,full_adjustment",
+				    &pdata->model->full_adjustment);
+		of_property_read_u8(np, "maxim,rcomp0",
+				    &pdata->model->rcomp0);
+		prop = of_find_property(np, "maxim,temp_co_up", NULL);
+		if (prop)
+			pdata->model->temp_co_up = be32_to_cpup(prop->value);
+		prop = of_find_property(np, "maxim,temp_co_down", NULL);
+		if (prop)
+			pdata->model->temp_co_down = be32_to_cpup(prop->value);
+		of_property_read_u16(np, "maxim,ocvtest",
+				     &pdata->model->ocvtest);
+		of_property_read_u8(np, "maxim,soc_check_a",
+				    &pdata->model->soc_check_a);
+		of_property_read_u8(np, "maxim,soc_check_b",
+				    &pdata->model->soc_check_b);
+		of_property_read_u8(np, "maxim,bits",
+				    &pdata->model->bits);
+		of_property_read_u16(np, "maxim,rcomp_seg",
+				     &pdata->model->rcomp_seg);
+	}
+
+	prop = of_find_property(np, "maxim,model_data", NULL);
+	if (prop && prop->length == MODELGAUGE_TABLE_SIZE) {
+		pdata->model->model_data = devm_kzalloc(dev,
+							MODELGAUGE_TABLE_SIZE,
+							GFP_KERNEL);
+		if (!pdata->model->model_data)
+			return NULL;
+
+		of_property_read_u8_array(np, "maxim,model_data",
+					  pdata->model->model_data,
+					  MODELGAUGE_TABLE_SIZE);
+	}
+
+	return pdata;
+}
+
+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->client	= client;
+	priv->chip	= id->driver_data;
+
+	i2c_set_clientdata(client, priv);
+
+	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(&client->dev, "failed: power supply register\n");
+		goto err_supply;
+	}
+
+	if (client->irq) {
+		switch (priv->chip) {
+		case ID_MAX17040:
+		case ID_MAX17041:
+			dev_err(&client->dev, "alert line is not supported\n");
+			ret = -EINVAL;
+			goto err_irq;
+		default:
+			ret = request_threaded_irq(client->irq, NULL,
+						   modelgauge_irq_handler,
+						   IRQF_TRIGGER_FALLING,
+						   priv->battery.name, priv);
+			if (ret) {
+				dev_err(&client->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(&priv->rcomp_work);
+	return ret;
+}
+
+static int modelgauge_remove(struct i2c_client *client)
+{
+	struct modelgauge_priv *priv = i2c_get_clientdata(client);
+
+	if (client->irq)
+		free_irq(client->irq, priv);
+
+	cancel_work_sync(&priv->load_work);
+	cancel_delayed_work(&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->model && pdata->get_temperature)
+		cancel_delayed_work(&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->model && 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-01-09 15:09:36.335138846 +0400
@@ -0,0 +1,44 @@
+/*
+ * 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_custom_model {
+	u8	empty_adjustment;
+	u8	full_adjustment;
+	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;
+};
+
+struct modelgauge_platform_data {
+	u8	empty_alert_threshold;	/* soc alert range 1..32 */
+	bool	soc_change_alert;	/* alert for 1% soc change */
+	u8	hibernate_threshold;	/* soc per hour */
+	u8	active_threshold;	/* mV */
+	u16	undervoltage;		/* mV */
+	u16	overvoltage;		/* mV */
+	u16	resetvoltage;		/* mV */
+	struct modelgauge_custom_model *model; /* custom battery data */
+	int	(*get_temperature)(void); /* C */
+	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] 27+ messages in thread

* [PATCH 2/3] dt: Document ModelGauge gauge bindings
  2014-01-09 16:49 ` Vladimir Barinov
@ 2014-01-09 16:49   ` Vladimir Barinov
  -1 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-09 16:49 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree; +Cc: mk7.kang

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 |   82 ++++++++++
 1 file changed, 82 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-01-09 15:09:38.035138887 +0400
@@ -0,0 +1,82 @@
+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,empty_alert_threshold	: Capacity threshold where an interrupt is
+				  generated on the ALRT pin;
+
+ - soc_change_alert		: /* alert for 1% soc change */
+ - hibernate_threshold		: Hibernate threshold (crate), where IC
+				  enters hibernate mode
+ - active_threshold		: Active threshold (mV), where IC exits
+				  hibernate mode
+ - undervoltage			: Voltage (mV), when IC alerts while battery
+				  voltage less then undervoltage
+ - overvoltage			: Voltage (mV), when IC alerts while battery
+				  voltage greater then overvoltage
+ - maxim,resetvoltage		: Voltage threshold (mV) below which the IC
+				  resets itself. Used to detect battery removal
+				  and reinsertion;
+ - maxim,empty_adjustment	: Capacity charge empty design value;
+ - maxim,full_adjustment	: Capacity charge full design value;
+ - maxim,rcomp0			: ModelGauge RCOMP parameter, used for
+				  temperature compensation;
+ - maxim,temp_co_up		: ModelGauge TempCoUp parameter, used for
+				  temperature compensation;
+ - maxim,temp_co_down		: ModelGauge TempCoDown parameter, used for
+				  temperature compensation;
+ - maxim,ocvtest		: ModelGauge OCVTest parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM;
+ - maxim,soc_check_a		: ModelGauge SOCCheckA parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM;
+ - maxim,soc_check_b		: ModelGauge SOCCheckB parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM;
+ - maxim,bits			: ModelGauge Bits parameter, used as
+				  scaling parameter in Custom Model algorithm;
+ - maxim,model_data		: ModelGauge ModelData data,
+				  Custom Model calibration data.
+
+Example:
+
+modelgauge@36 {
+	compatible = "maxim,max17058";
+	reg = <0x36>;
+	interrupt-parent = <&msmgpio>;
+	interrupts = <107 0x2>;
+
+	maxim,empty_alert_threshold = /bits/ 8 <15>;
+	maxim,resetvoltage = /bits/ 16 <0>;
+	maxim,empty_adjustment = /bits/ 8 <0>;
+	maxim,full_adjustment = /bits/ 8 <100>;
+	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] 27+ messages in thread

* [PATCH 2/3] dt: Document ModelGauge gauge bindings
@ 2014-01-09 16:49   ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-09 16:49 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree; +Cc: mk7.kang

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 |   82 ++++++++++
 1 file changed, 82 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-01-09 15:09:38.035138887 +0400
@@ -0,0 +1,82 @@
+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,empty_alert_threshold	: Capacity threshold where an interrupt is
+				  generated on the ALRT pin;
+
+ - soc_change_alert		: /* alert for 1% soc change */
+ - hibernate_threshold		: Hibernate threshold (crate), where IC
+				  enters hibernate mode
+ - active_threshold		: Active threshold (mV), where IC exits
+				  hibernate mode
+ - undervoltage			: Voltage (mV), when IC alerts while battery
+				  voltage less then undervoltage
+ - overvoltage			: Voltage (mV), when IC alerts while battery
+				  voltage greater then overvoltage
+ - maxim,resetvoltage		: Voltage threshold (mV) below which the IC
+				  resets itself. Used to detect battery removal
+				  and reinsertion;
+ - maxim,empty_adjustment	: Capacity charge empty design value;
+ - maxim,full_adjustment	: Capacity charge full design value;
+ - maxim,rcomp0			: ModelGauge RCOMP parameter, used for
+				  temperature compensation;
+ - maxim,temp_co_up		: ModelGauge TempCoUp parameter, used for
+				  temperature compensation;
+ - maxim,temp_co_down		: ModelGauge TempCoDown parameter, used for
+				  temperature compensation;
+ - maxim,ocvtest		: ModelGauge OCVTest parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM;
+ - maxim,soc_check_a		: ModelGauge SOCCheckA parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM;
+ - maxim,soc_check_b		: ModelGauge SOCCheckB parameter, used for
+				  verification of Custom Model calibration data
+				  loaded into IC RAM;
+ - maxim,bits			: ModelGauge Bits parameter, used as
+				  scaling parameter in Custom Model algorithm;
+ - maxim,model_data		: ModelGauge ModelData data,
+				  Custom Model calibration data.
+
+Example:
+
+modelgauge@36 {
+	compatible = "maxim,max17058";
+	reg = <0x36>;
+	interrupt-parent = <&msmgpio>;
+	interrupts = <107 0x2>;
+
+	maxim,empty_alert_threshold = /bits/ 8 <15>;
+	maxim,resetvoltage = /bits/ 16 <0>;
+	maxim,empty_adjustment = /bits/ 8 <0>;
+	maxim,full_adjustment = /bits/ 8 <100>;
+	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] 27+ messages in thread

* [PATCH 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge
@ 2014-01-09 16:49   ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-09 16:49 UTC (permalink / raw)
  To: anton, dwmw2, linux-kernel, devicetree; +Cc: mk7.kang

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 ---------------------------------------
 3 files changed, 306 deletions(-)

Index: battery-2.6/drivers/power/Kconfig
===================================================================
--- battery-2.6.orig/drivers/power/Kconfig	2014-01-09 15:09:36.331138847 +0400
+++ battery-2.6/drivers/power/Kconfig	2014-01-09 15:09:39.523138923 +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: battery-2.6/drivers/power/Makefile
===================================================================
--- battery-2.6.orig/drivers/power/Makefile	2014-01-09 15:09:36.331138847 +0400
+++ battery-2.6/drivers/power/Makefile	2014-01-09 15:09:39.523138923 +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: battery-2.6/drivers/power/max17040_battery.c
===================================================================
--- battery-2.6.orig/drivers/power/max17040_battery.c	2014-01-09 15:09:31.163138723 +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");

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

* [PATCH 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge
@ 2014-01-09 16:49   ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-09 16:49 UTC (permalink / raw)
  To: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: mk7.kang-Sze3O3UU22JBDgjK7y7TUQ

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-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>

---
 drivers/power/Kconfig            |    8 -
 drivers/power/Makefile           |    1 
 drivers/power/max17040_battery.c |  297 ---------------------------------------
 3 files changed, 306 deletions(-)

Index: battery-2.6/drivers/power/Kconfig
===================================================================
--- battery-2.6.orig/drivers/power/Kconfig	2014-01-09 15:09:36.331138847 +0400
+++ battery-2.6/drivers/power/Kconfig	2014-01-09 15:09:39.523138923 +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: battery-2.6/drivers/power/Makefile
===================================================================
--- battery-2.6.orig/drivers/power/Makefile	2014-01-09 15:09:36.331138847 +0400
+++ battery-2.6/drivers/power/Makefile	2014-01-09 15:09:39.523138923 +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: battery-2.6/drivers/power/max17040_battery.c
===================================================================
--- battery-2.6.orig/drivers/power/max17040_battery.c	2014-01-09 15:09:31.163138723 +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-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
- *
- * 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-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
-MODULE_DESCRIPTION("MAX17040 Fuel Gauge");
-MODULE_LICENSE("GPL");
--
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] 27+ messages in thread

* Re: [PATCH 2/3] dt: Document ModelGauge gauge bindings
@ 2014-01-10  1:00     ` Kyungmin Park
  0 siblings, 0 replies; 27+ messages in thread
From: Kyungmin Park @ 2014-01-10  1:00 UTC (permalink / raw)
  To: Vladimir Barinov
  Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang, Krzysztof Kozlowski

On Fri, Jan 10, 2014 at 1:49 AM, Vladimir Barinov
<vladimir.barinov@cogentembedded.com> wrote:
> 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 |   82 ++++++++++
>  1 file changed, 82 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-01-09 15:09:38.035138887 +0400
> @@ -0,0 +1,82 @@
> +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,empty_alert_threshold : Capacity threshold where an interrupt is
> +                                 generated on the ALRT pin;
> +
> + - soc_change_alert            : /* alert for 1% soc change */
> + - hibernate_threshold         : Hibernate threshold (crate), where IC
> +                                 enters hibernate mode
> + - active_threshold            : Active threshold (mV), where IC exits
> +                                 hibernate mode
> + - undervoltage                        : Voltage (mV), when IC alerts while battery
> +                                 voltage less then undervoltage
> + - overvoltage                 : Voltage (mV), when IC alerts while battery
> +                                 voltage greater then overvoltage
> + - maxim,resetvoltage          : Voltage threshold (mV) below which the IC
> +                                 resets itself. Used to detect battery removal
> +                                 and reinsertion;
> + - maxim,empty_adjustment      : Capacity charge empty design value;
> + - maxim,full_adjustment       : Capacity charge full design value;
> + - maxim,rcomp0                        : ModelGauge RCOMP parameter, used for
> +                                 temperature compensation;
> + - maxim,temp_co_up            : ModelGauge TempCoUp parameter, used for
> +                                 temperature compensation;
> + - maxim,temp_co_down          : ModelGauge TempCoDown parameter, used for
> +                                 temperature compensation;
> + - maxim,ocvtest               : ModelGauge OCVTest parameter, used for
> +                                 verification of Custom Model calibration data
> +                                 loaded into IC RAM;
> + - maxim,soc_check_a           : ModelGauge SOCCheckA parameter, used for
> +                                 verification of Custom Model calibration data
> +                                 loaded into IC RAM;
> + - maxim,soc_check_b           : ModelGauge SOCCheckB parameter, used for
> +                                 verification of Custom Model calibration data
> +                                 loaded into IC RAM;
> + - maxim,bits                  : ModelGauge Bits parameter, used as
> +                                 scaling parameter in Custom Model algorithm;
> + - maxim,model_data            : ModelGauge ModelData data,
> +                                 Custom Model calibration data.
Dose it open to vendor? we're using this chip. we don't need to setup
it at all. most of property except "rcomp" doesn't used.

Thank you,
Kyungmin Park
> +
> +Example:
> +
> +modelgauge@36 {
> +       compatible = "maxim,max17058";
> +       reg = <0x36>;
> +       interrupt-parent = <&msmgpio>;
> +       interrupts = <107 0x2>;
> +
> +       maxim,empty_alert_threshold = /bits/ 8 <15>;
> +       maxim,resetvoltage = /bits/ 16 <0>;
> +       maxim,empty_adjustment = /bits/ 8 <0>;
> +       maxim,full_adjustment = /bits/ 8 <100>;
> +       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 linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH 2/3] dt: Document ModelGauge gauge bindings
@ 2014-01-10  1:00     ` Kyungmin Park
  0 siblings, 0 replies; 27+ messages in thread
From: Kyungmin Park @ 2014-01-10  1:00 UTC (permalink / raw)
  To: Vladimir Barinov
  Cc: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	mk7.kang-Sze3O3UU22JBDgjK7y7TUQ, Krzysztof Kozlowski

On Fri, Jan 10, 2014 at 1:49 AM, Vladimir Barinov
<vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> wrote:
> 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 |   82 ++++++++++
>  1 file changed, 82 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-01-09 15:09:38.035138887 +0400
> @@ -0,0 +1,82 @@
> +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,empty_alert_threshold : Capacity threshold where an interrupt is
> +                                 generated on the ALRT pin;
> +
> + - soc_change_alert            : /* alert for 1% soc change */
> + - hibernate_threshold         : Hibernate threshold (crate), where IC
> +                                 enters hibernate mode
> + - active_threshold            : Active threshold (mV), where IC exits
> +                                 hibernate mode
> + - undervoltage                        : Voltage (mV), when IC alerts while battery
> +                                 voltage less then undervoltage
> + - overvoltage                 : Voltage (mV), when IC alerts while battery
> +                                 voltage greater then overvoltage
> + - maxim,resetvoltage          : Voltage threshold (mV) below which the IC
> +                                 resets itself. Used to detect battery removal
> +                                 and reinsertion;
> + - maxim,empty_adjustment      : Capacity charge empty design value;
> + - maxim,full_adjustment       : Capacity charge full design value;
> + - maxim,rcomp0                        : ModelGauge RCOMP parameter, used for
> +                                 temperature compensation;
> + - maxim,temp_co_up            : ModelGauge TempCoUp parameter, used for
> +                                 temperature compensation;
> + - maxim,temp_co_down          : ModelGauge TempCoDown parameter, used for
> +                                 temperature compensation;
> + - maxim,ocvtest               : ModelGauge OCVTest parameter, used for
> +                                 verification of Custom Model calibration data
> +                                 loaded into IC RAM;
> + - maxim,soc_check_a           : ModelGauge SOCCheckA parameter, used for
> +                                 verification of Custom Model calibration data
> +                                 loaded into IC RAM;
> + - maxim,soc_check_b           : ModelGauge SOCCheckB parameter, used for
> +                                 verification of Custom Model calibration data
> +                                 loaded into IC RAM;
> + - maxim,bits                  : ModelGauge Bits parameter, used as
> +                                 scaling parameter in Custom Model algorithm;
> + - maxim,model_data            : ModelGauge ModelData data,
> +                                 Custom Model calibration data.
Dose it open to vendor? we're using this chip. we don't need to setup
it at all. most of property except "rcomp" doesn't used.

Thank you,
Kyungmin Park
> +
> +Example:
> +
> +modelgauge@36 {
> +       compatible = "maxim,max17058";
> +       reg = <0x36>;
> +       interrupt-parent = <&msmgpio>;
> +       interrupts = <107 0x2>;
> +
> +       maxim,empty_alert_threshold = /bits/ 8 <15>;
> +       maxim,resetvoltage = /bits/ 16 <0>;
> +       maxim,empty_adjustment = /bits/ 8 <0>;
> +       maxim,full_adjustment = /bits/ 8 <100>;
> +       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 linux-kernel" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
--
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] 27+ messages in thread

* Re: [PATCH 2/3] dt: Document ModelGauge gauge bindings
@ 2014-01-10 10:56     ` Mark Rutland
  0 siblings, 0 replies; 27+ messages in thread
From: Mark Rutland @ 2014-01-10 10:56 UTC (permalink / raw)
  To: Vladimir Barinov; +Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang

On Thu, Jan 09, 2014 at 04:49:04PM +0000, Vladimir Barinov wrote:
> 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 |   82 ++++++++++
>  1 file changed, 82 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-01-09 15:09:38.035138887 +0400
> @@ -0,0 +1,82 @@
> +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,empty_alert_threshold	: Capacity threshold where an interrupt is
> +				  generated on the ALRT pin;

s/_/-/ in proeprty names please.

Why is this property in the dt at all?

Surely the driver can choose the value it wants.

The driver can choose a sensible value, surely?

> +
> + - soc_change_alert		: /* alert for 1% soc change */

Likewise, surely the driver should decide if it wants this?

> + - hibernate_threshold		: Hibernate threshold (crate), where IC
> +				  enters hibernate mode
> + - active_threshold		: Active threshold (mV), where IC exits
> +				  hibernate mode
> + - undervoltage			: Voltage (mV), when IC alerts while battery
> +				  voltage less then undervoltage
> + - overvoltage			: Voltage (mV), when IC alerts while battery
> +				  voltage greater then overvoltage
> + - maxim,resetvoltage		: Voltage threshold (mV) below which the IC
> +				  resets itself. Used to detect battery removal
> +				  and reinsertion;

Could you elaborate on what these are for. How variable are these
between batteries?

> + - maxim,empty_adjustment	: Capacity charge empty design value;
> + - maxim,full_adjustment	: Capacity charge full design value;

These names are a bit odd.

How about maxim,charge-empty and maxim,charge-full (perhaps
maxim,charge-empty-design).

> + - maxim,rcomp0			: ModelGauge RCOMP parameter, used for
> +				  temperature compensation;
> + - maxim,temp_co_up		: ModelGauge TempCoUp parameter, used for
> +				  temperature compensation;
> + - maxim,temp_co_down		: ModelGauge TempCoDown parameter, used for
> +				  temperature compensation;
> + - maxim,ocvtest		: ModelGauge OCVTest parameter, used for
> +				  verification of Custom Model calibration data
> +				  loaded into IC RAM;
> + - maxim,soc_check_a		: ModelGauge SOCCheckA parameter, used for
> +				  verification of Custom Model calibration data
> +				  loaded into IC RAM;
> + - maxim,soc_check_b		: ModelGauge SOCCheckB parameter, used for
> +				  verification of Custom Model calibration data
> +				  loaded into IC RAM;
> + - maxim,bits			: ModelGauge Bits parameter, used as
> +				  scaling parameter in Custom Model algorithm;
> + - maxim,model_data		: ModelGauge ModelData data,
> +				  Custom Model calibration data.

I have no idea what these properties mean, so I can't comment on them as
they are other than to say this looks a bit low-level. Are there any
docs?

> +
> +Example:
> +
> +modelgauge@36 {
> +	compatible = "maxim,max17058";
> +	reg = <0x36>;
> +	interrupt-parent = <&msmgpio>;
> +	interrupts = <107 0x2>;

This portion of the example looks fine.

> +
> +	maxim,empty_alert_threshold = /bits/ 8 <15>;
> +	maxim,resetvoltage = /bits/ 16 <0>;
> +	maxim,empty_adjustment = /bits/ 8 <0>;
> +	maxim,full_adjustment = /bits/ 8 <100>;
> +	maxim,rcomp0 = /bits/ 8 <175>;

You did not describe that any of these were 8-bit values in the binding.

> +	maxim,temp_co_up = <(-1100)>;
> +	maxim,temp_co_down = <(-4000)>;

These weren't described as signed.

> +	maxim,ocvtest = /bits/ 16 <56144>;
> +	maxim,soc_check_a = /bits/ 8 <241>;
> +	maxim,soc_check_b = /bits/ 8 <243>;
> +	maxim,bits = /bits/ 8 <19>;

These weren't described as 8-bit either.

> +
> +	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>;
> +};

This looks scary.

Thanks,
Mark.

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

* Re: [PATCH 2/3] dt: Document ModelGauge gauge bindings
@ 2014-01-10 10:56     ` Mark Rutland
  0 siblings, 0 replies; 27+ messages in thread
From: Mark Rutland @ 2014-01-10 10:56 UTC (permalink / raw)
  To: Vladimir Barinov
  Cc: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	mk7.kang-Sze3O3UU22JBDgjK7y7TUQ

On Thu, Jan 09, 2014 at 04:49:04PM +0000, Vladimir Barinov wrote:
> 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 |   82 ++++++++++
>  1 file changed, 82 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-01-09 15:09:38.035138887 +0400
> @@ -0,0 +1,82 @@
> +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,empty_alert_threshold	: Capacity threshold where an interrupt is
> +				  generated on the ALRT pin;

s/_/-/ in proeprty names please.

Why is this property in the dt at all?

Surely the driver can choose the value it wants.

The driver can choose a sensible value, surely?

> +
> + - soc_change_alert		: /* alert for 1% soc change */

Likewise, surely the driver should decide if it wants this?

> + - hibernate_threshold		: Hibernate threshold (crate), where IC
> +				  enters hibernate mode
> + - active_threshold		: Active threshold (mV), where IC exits
> +				  hibernate mode
> + - undervoltage			: Voltage (mV), when IC alerts while battery
> +				  voltage less then undervoltage
> + - overvoltage			: Voltage (mV), when IC alerts while battery
> +				  voltage greater then overvoltage
> + - maxim,resetvoltage		: Voltage threshold (mV) below which the IC
> +				  resets itself. Used to detect battery removal
> +				  and reinsertion;

Could you elaborate on what these are for. How variable are these
between batteries?

> + - maxim,empty_adjustment	: Capacity charge empty design value;
> + - maxim,full_adjustment	: Capacity charge full design value;

These names are a bit odd.

How about maxim,charge-empty and maxim,charge-full (perhaps
maxim,charge-empty-design).

> + - maxim,rcomp0			: ModelGauge RCOMP parameter, used for
> +				  temperature compensation;
> + - maxim,temp_co_up		: ModelGauge TempCoUp parameter, used for
> +				  temperature compensation;
> + - maxim,temp_co_down		: ModelGauge TempCoDown parameter, used for
> +				  temperature compensation;
> + - maxim,ocvtest		: ModelGauge OCVTest parameter, used for
> +				  verification of Custom Model calibration data
> +				  loaded into IC RAM;
> + - maxim,soc_check_a		: ModelGauge SOCCheckA parameter, used for
> +				  verification of Custom Model calibration data
> +				  loaded into IC RAM;
> + - maxim,soc_check_b		: ModelGauge SOCCheckB parameter, used for
> +				  verification of Custom Model calibration data
> +				  loaded into IC RAM;
> + - maxim,bits			: ModelGauge Bits parameter, used as
> +				  scaling parameter in Custom Model algorithm;
> + - maxim,model_data		: ModelGauge ModelData data,
> +				  Custom Model calibration data.

I have no idea what these properties mean, so I can't comment on them as
they are other than to say this looks a bit low-level. Are there any
docs?

> +
> +Example:
> +
> +modelgauge@36 {
> +	compatible = "maxim,max17058";
> +	reg = <0x36>;
> +	interrupt-parent = <&msmgpio>;
> +	interrupts = <107 0x2>;

This portion of the example looks fine.

> +
> +	maxim,empty_alert_threshold = /bits/ 8 <15>;
> +	maxim,resetvoltage = /bits/ 16 <0>;
> +	maxim,empty_adjustment = /bits/ 8 <0>;
> +	maxim,full_adjustment = /bits/ 8 <100>;
> +	maxim,rcomp0 = /bits/ 8 <175>;

You did not describe that any of these were 8-bit values in the binding.

> +	maxim,temp_co_up = <(-1100)>;
> +	maxim,temp_co_down = <(-4000)>;

These weren't described as signed.

> +	maxim,ocvtest = /bits/ 16 <56144>;
> +	maxim,soc_check_a = /bits/ 8 <241>;
> +	maxim,soc_check_b = /bits/ 8 <243>;
> +	maxim,bits = /bits/ 8 <19>;

These weren't described as 8-bit either.

> +
> +	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>;
> +};

This looks scary.

Thanks,
Mark.
--
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] 27+ messages in thread

* Re: [PATCH 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
  2014-01-09 16:49   ` Vladimir Barinov
  (?)
@ 2014-01-10 11:11   ` Mark Rutland
  2014-01-10 14:29       ` Vladimir Barinov
  -1 siblings, 1 reply; 27+ messages in thread
From: Mark Rutland @ 2014-01-10 11:11 UTC (permalink / raw)
  To: Vladimir Barinov; +Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang

On Thu, Jan 09, 2014 at 04:49:03PM +0000, Vladimir Barinov wrote:
> 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                            |    8
>  drivers/power/Makefile                           |    1
>  drivers/power/modelgauge_battery.c               |  875 +++++++++++++++++++++++
>  include/linux/platform_data/battery-modelgauge.h |   44 +
>  4 files changed, 928 insertions(+)

[...]

> +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;
> +
> +       if (!of_get_property(np, "maxim,empty_alert_threshold", NULL) &&
> +           !of_get_property(np, "maxim,soc_change_alert", NULL) &&
> +           !of_get_property(np, "maxim,hibernate_threshold", NULL) &&
> +           !of_get_property(np, "maxim,active_threshold", NULL) &&
> +           !of_get_property(np, "maxim,undervoltage", NULL) &&
> +           !of_get_property(np, "maxim,overvoltage", NULL) &&
> +           !of_get_property(np, "maxim,resetvoltage", NULL))
> +               return NULL;

These were described as optional in the binding. It wasn't clear that to
have one you need the others. It would be nice for that to be clarified
in the binding.

> +
> +       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> +       if (!pdata)
> +               return NULL;
> +
> +       of_property_read_u8(np, "maxim,empty_alert_threshold",
> +                           &pdata->empty_alert_threshold);
> +       pdata->soc_change_alert =
> +                       of_property_read_bool(np, "maxim,soc_change_alert");

As mentioned in my comments on the binding document, I don't think this
property is necessary at all.

> +       of_property_read_u8(np, "maxim,hibernate_threshold",
> +                           &pdata->hibernate_threshold);
> +       of_property_read_u8(np, "maxim,active_threshold",
> +                           &pdata->active_threshold);
> +       of_property_read_u16(np, "maxim,undervoltage", &pdata->undervoltage);
> +       of_property_read_u16(np, "maxim,overvoltage", &pdata->overvoltage);
> +       of_property_read_u16(np, "maxim,resetvoltage", &pdata->resetvoltage);
> +
> +       prop = of_find_property(np, "maxim,ocvtest", NULL);

Here you seem to be using of_find_property to check if a property is
present, but earlier you used of_get_property for this purpose. It would
be nice if one or the other were used consistently.

> +       if (prop) {
> +               pdata->model = devm_kzalloc(dev, sizeof(*pdata->model),
> +                                           GFP_KERNEL);
> +               if (!pdata->model)
> +                       return NULL;
> +
> +               of_property_read_u8(np, "maxim,empty_adjustment",
> +                                   &pdata->model->empty_adjustment);
> +               of_property_read_u8(np, "maxim,full_adjustment",
> +                                   &pdata->model->full_adjustment);
> +               of_property_read_u8(np, "maxim,rcomp0",
> +                                   &pdata->model->rcomp0);
> +               prop = of_find_property(np, "maxim,temp_co_up", NULL);
> +               if (prop)
> +                       pdata->model->temp_co_up = be32_to_cpup(prop->value);

Use of_property_read_u32. If it can't read the property it won't
modify the pointer it's been handed, and it handles the endianness
conversion.

You seem to be happy to use of_property_read_u{8,16}, so I don't
understand why you are treating 32-bit differently.

> +               prop = of_find_property(np, "maxim,temp_co_down", NULL);
> +               if (prop)
> +                       pdata->model->temp_co_down = be32_to_cpup(prop->value);

Likewise.

> +               of_property_read_u16(np, "maxim,ocvtest",
> +                                    &pdata->model->ocvtest);

While you've checked that this property was present earlier, you don't
know it's size. You might want to check the return value of
of_property_read_u16 (and you might want to do so for other accessors
too).

> +               of_property_read_u8(np, "maxim,soc_check_a",
> +                                   &pdata->model->soc_check_a);
> +               of_property_read_u8(np, "maxim,soc_check_b",
> +                                   &pdata->model->soc_check_b);
> +               of_property_read_u8(np, "maxim,bits",
> +                                   &pdata->model->bits);
> +               of_property_read_u16(np, "maxim,rcomp_seg",
> +                                    &pdata->model->rcomp_seg);
> +       }
> +
> +       prop = of_find_property(np, "maxim,model_data", NULL);
> +       if (prop && prop->length == MODELGAUGE_TABLE_SIZE) {
> +               pdata->model->model_data = devm_kzalloc(dev,
> +                                                       MODELGAUGE_TABLE_SIZE,
> +                                                       GFP_KERNEL);
> +               if (!pdata->model->model_data)
> +                       return NULL;
> +
> +               of_property_read_u8_array(np, "maxim,model_data",
> +                                         pdata->model->model_data,
> +                                         MODELGAUGE_TABLE_SIZE);
> +       }

It's probably worth printing a warning or error if this isn't the size
you expect (perhaps failing to probe).

> +
> +       return pdata;
> +}

Thanks,
Mark.

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

* Re: [PATCH 2/3] dt: Document ModelGauge gauge bindings
  2014-01-10  1:00     ` Kyungmin Park
  (?)
@ 2014-01-10 12:59     ` Vladimir Barinov
  -1 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-10 12:59 UTC (permalink / raw)
  To: Kyungmin Park
  Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang, Krzysztof Kozlowski

Hello,

On 01/10/2014 05:00 AM, Kyungmin Park wrote:
> On Fri, Jan 10, 2014 at 1:49 AM, Vladimir Barinov
> <vladimir.barinov@cogentembedded.com>  wrote:
>> 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 |   82 ++++++++++
>>   1 file changed, 82 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-01-09 15:09:38.035138887 +0400
>> @@ -0,0 +1,82 @@
>> +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,empty_alert_threshold : Capacity threshold where an interrupt is
>> +                                 generated on the ALRT pin;
>> +
>> + - soc_change_alert            : /* alert for 1% soc change */
>> + - hibernate_threshold         : Hibernate threshold (crate), where IC
>> +                                 enters hibernate mode
>> + - active_threshold            : Active threshold (mV), where IC exits
>> +                                 hibernate mode
>> + - undervoltage                        : Voltage (mV), when IC alerts while battery
>> +                                 voltage less then undervoltage
>> + - overvoltage                 : Voltage (mV), when IC alerts while battery
>> +                                 voltage greater then overvoltage
>> + - maxim,resetvoltage          : Voltage threshold (mV) below which the IC
>> +                                 resets itself. Used to detect battery removal
>> +                                 and reinsertion;
>> + - maxim,empty_adjustment      : Capacity charge empty design value;
>> + - maxim,full_adjustment       : Capacity charge full design value;
>> + - maxim,rcomp0                        : ModelGauge RCOMP parameter, used for
>> +                                 temperature compensation;
>> + - maxim,temp_co_up            : ModelGauge TempCoUp parameter, used for
>> +                                 temperature compensation;
>> + - maxim,temp_co_down          : ModelGauge TempCoDown parameter, used for
>> +                                 temperature compensation;
>> + - maxim,ocvtest               : ModelGauge OCVTest parameter, used for
>> +                                 verification of Custom Model calibration data
>> +                                 loaded into IC RAM;
>> + - maxim,soc_check_a           : ModelGauge SOCCheckA parameter, used for
>> +                                 verification of Custom Model calibration data
>> +                                 loaded into IC RAM;
>> + - maxim,soc_check_b           : ModelGauge SOCCheckB parameter, used for
>> +                                 verification of Custom Model calibration data
>> +                                 loaded into IC RAM;
>> + - maxim,bits                  : ModelGauge Bits parameter, used as
>> +                                 scaling parameter in Custom Model algorithm;
>> + - maxim,model_data            : ModelGauge ModelData data,
>> +                                 Custom Model calibration data.
> Dose it open to vendor? we're using this chip. we don't need to setup
> it at all. most of property except "rcomp" doesn't used.
Some parameters are open to vendor in open documentation, except the 
following:

rcomp0, temp_co_up, temp_co_down, ocvtest, soc_check_a, soc_check_b, bits, model_data,

because these are the unique (vendor's) battery parameters to be used in 
MAXIM ModelGauge
Algorithm for accurate capacity calculation.

Actually, all above properties are optional, and can be skipped.

In accordance to MAXIM documentation the RCOMP can be adjusted using 
linear formula from
RCOMP0, TempCoUp and TempCoDown parameters, which are unique for every 
battery.
It is explicitly noted that you have to connect to MAXIM in order to get 
these parameters for your
specific battery.
I wonder how you able to adjust RCOMP without help of MAXIM vendor.

Regards,
Vladimir
>
> Thank you,
> Kyungmin Park
>> +
>> +Example:
>> +
>> +modelgauge@36 {
>> +       compatible = "maxim,max17058";
>> +       reg =<0x36>;
>> +       interrupt-parent =<&msmgpio>;
>> +       interrupts =<107 0x2>;
>> +
>> +       maxim,empty_alert_threshold = /bits/ 8<15>;
>> +       maxim,resetvoltage = /bits/ 16<0>;
>> +       maxim,empty_adjustment = /bits/ 8<0>;
>> +       maxim,full_adjustment = /bits/ 8<100>;
>> +       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 linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH 2/3] dt: Document ModelGauge gauge bindings
  2014-01-10 10:56     ` Mark Rutland
  (?)
@ 2014-01-10 14:08     ` Vladimir Barinov
  -1 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-10 14:08 UTC (permalink / raw)
  To: Mark Rutland; +Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang

Hello,

thank you for the review.

On 01/10/2014 02:56 PM, Mark Rutland wrote:
> On Thu, Jan 09, 2014 at 04:49:04PM +0000, Vladimir Barinov wrote:
>> 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 |   82 ++++++++++
>>   1 file changed, 82 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-01-09 15:09:38.035138887 +0400
>> @@ -0,0 +1,82 @@
>> +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,empty_alert_threshold	: Capacity threshold where an interrupt is
>> +				  generated on the ALRT pin;
> s/_/-/ in proeprty names please.
I'll make this parameter configurable via sysfs in the driver. Is it ok?
>
> Why is this property in the dt at all?
>
> Surely the driver can choose the value it wants.
>
> The driver can choose a sensible value, surely?
Ok. I'll exclude the platform data from DT and put into sysfs.
>> +
>> + - soc_change_alert		: /* alert for 1% soc change */
> Likewise, surely the driver should decide if it wants this?
Ditto.
>
>> + - hibernate_threshold		: Hibernate threshold (crate), where IC
>> +				  enters hibernate mode
>> + - active_threshold		: Active threshold (mV), where IC exits
>> +				  hibernate mode
>> + - undervoltage			: Voltage (mV), when IC alerts while battery
>> +				  voltage less then undervoltage
>> + - overvoltage			: Voltage (mV), when IC alerts while battery
>> +				  voltage greater then overvoltage
>> + - maxim,resetvoltage		: Voltage threshold (mV) below which the IC
>> +				  resets itself. Used to detect battery removal
>> +				  and reinsertion;
> Could you elaborate on what these are for. How variable are these
> between batteries?
Ditto.
>
>> + - maxim,empty_adjustment	: Capacity charge empty design value;
>> + - maxim,full_adjustment	: Capacity charge full design value;
> These names are a bit odd.
May be you are right. But I've got this from MAXIM documentation.
>
> How about maxim,charge-empty and maxim,charge-full (perhaps
> maxim,charge-empty-design).
I'll leave the original names to avoid misunderstanding between names in 
MAXIM docs
and driver's naming.
>
>> + - maxim,rcomp0			: ModelGauge RCOMP parameter, used for
>> +				  temperature compensation;
>> + - maxim,temp_co_up		: ModelGauge TempCoUp parameter, used for
>> +				  temperature compensation;
>> + - maxim,temp_co_down		: ModelGauge TempCoDown parameter, used for
>> +				  temperature compensation;
>> + - maxim,ocvtest		: ModelGauge OCVTest parameter, used for
>> +				  verification of Custom Model calibration data
>> +				  loaded into IC RAM;
>> + - maxim,soc_check_a		: ModelGauge SOCCheckA parameter, used for
>> +				  verification of Custom Model calibration data
>> +				  loaded into IC RAM;
>> + - maxim,soc_check_b		: ModelGauge SOCCheckB parameter, used for
>> +				  verification of Custom Model calibration data
>> +				  loaded into IC RAM;
>> + - maxim,bits			: ModelGauge Bits parameter, used as
>> +				  scaling parameter in Custom Model algorithm;
>> + - maxim,model_data		: ModelGauge ModelData data,
>> +				  Custom Model calibration data.
> I have no idea what these properties mean, so I can't comment on them as
> they are other than to say this looks a bit low-level. Are there any
> docs?
These are the calibration parameters for specific battery to be used in 
ModelGauge algorithm inside MAXIM ICs.
They are provided by MAXIM for unique battery once requested. So vendor 
needs to send the battery to MAXIM in order
to calibrate/adopt it for MAXIM's firmware algorithm that makes capacity 
calculation more accurate.
>
>> +
>> +Example:
>> +
>> +modelgauge@36 {
>> +	compatible = "maxim,max17058";
>> +	reg =<0x36>;
>> +	interrupt-parent =<&msmgpio>;
>> +	interrupts =<107 0x2>;
> This portion of the example looks fine.
>
>> +
>> +	maxim,empty_alert_threshold = /bits/ 8<15>;
>> +	maxim,resetvoltage = /bits/ 16<0>;
>> +	maxim,empty_adjustment = /bits/ 8<0>;
>> +	maxim,full_adjustment = /bits/ 8<100>;
>> +	maxim,rcomp0 = /bits/ 8<175>;
> You did not describe that any of these were 8-bit values in the binding.
As mentioned above, I'll move this portion out from DT, except rcomp0, 
since this is battery unique value.
>
>> +	maxim,temp_co_up =<(-1100)>;
>> +	maxim,temp_co_down =<(-4000)>;
> These weren't described as signed.
Will describe, thx.
>
>> +	maxim,ocvtest = /bits/ 16<56144>;
>> +	maxim,soc_check_a = /bits/ 8<241>;
>> +	maxim,soc_check_b = /bits/ 8<243>;
>> +	maxim,bits = /bits/ 8<19>;
> These weren't described as 8-bit either.
Will describe.
>
>> +
>> +	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>;
>> +};
> This looks scary.
This is a calibration data provided by MAXIM vendor for specific battery.
These are unique data for every battery and they are intended to be loaded
into IC's RAM for further use by MAXIM MadelGauge algorithm.

I do not know the internals for MAXIM's firmware, but I assume that 
these data are
reference offsets for Capacity on OCV dependency.

The vendor can calibrate the battery by itself in s/w (Capacity(OCV) 
dependency). The MAXIM
allows to do it in h/w.

Regards,
Vladimir

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

* Re: [PATCH 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
@ 2014-01-10 14:29       ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-10 14:29 UTC (permalink / raw)
  To: Mark Rutland; +Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang

Hello,

On 01/10/2014 03:11 PM, Mark Rutland wrote:
> On Thu, Jan 09, 2014 at 04:49:03PM +0000, Vladimir Barinov wrote:
>> 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                            |    8
>>   drivers/power/Makefile                           |    1
>>   drivers/power/modelgauge_battery.c               |  875 +++++++++++++++++++++++
>>   include/linux/platform_data/battery-modelgauge.h |   44 +
>>   4 files changed, 928 insertions(+)
> [...]
>
>> +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;
>> +
>> +       if (!of_get_property(np, "maxim,empty_alert_threshold", NULL)&&
>> +           !of_get_property(np, "maxim,soc_change_alert", NULL)&&
>> +           !of_get_property(np, "maxim,hibernate_threshold", NULL)&&
>> +           !of_get_property(np, "maxim,active_threshold", NULL)&&
>> +           !of_get_property(np, "maxim,undervoltage", NULL)&&
>> +           !of_get_property(np, "maxim,overvoltage", NULL)&&
>> +           !of_get_property(np, "maxim,resetvoltage", NULL))
>> +               return NULL;
> These were described as optional in the binding. It wasn't clear that to
> have one you need the others. It would be nice for that to be clarified
> in the binding.
Yes, since they are optional then we'll return NULL here, that means no 
platform data provided.
The "if" statement checked if nothing was provided in DT then there is 
not platform data.

Since, you requested to remove above binding from DT and make the driver 
to take care, then I'll move them to sysfs.
>
>> +
>> +       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
>> +       if (!pdata)
>> +               return NULL;
>> +
>> +       of_property_read_u8(np, "maxim,empty_alert_threshold",
>> +&pdata->empty_alert_threshold);
>> +       pdata->soc_change_alert =
>> +                       of_property_read_bool(np, "maxim,soc_change_alert");
> As mentioned in my comments on the binding document, I don't think this
> property is necessary at all.
Yes, I will move it into driver.
>
>> +       of_property_read_u8(np, "maxim,hibernate_threshold",
>> +&pdata->hibernate_threshold);
>> +       of_property_read_u8(np, "maxim,active_threshold",
>> +&pdata->active_threshold);
>> +       of_property_read_u16(np, "maxim,undervoltage",&pdata->undervoltage);
>> +       of_property_read_u16(np, "maxim,overvoltage",&pdata->overvoltage);
>> +       of_property_read_u16(np, "maxim,resetvoltage",&pdata->resetvoltage);
Ditto for above.
>> +
>> +       prop = of_find_property(np, "maxim,ocvtest", NULL);
> Here you seem to be using of_find_property to check if a property is
> present, but earlier you used of_get_property for this purpose. It would
> be nice if one or the other were used consistently.
Since above code will be removed then only this parameter will be used 
for battery specific data presence check.
>
>> +       if (prop) {
>> +               pdata->model = devm_kzalloc(dev, sizeof(*pdata->model),
>> +                                           GFP_KERNEL);
>> +               if (!pdata->model)
>> +                       return NULL;
>> +
>> +               of_property_read_u8(np, "maxim,empty_adjustment",
>> +&pdata->model->empty_adjustment);
>> +               of_property_read_u8(np, "maxim,full_adjustment",
>> +&pdata->model->full_adjustment);
>> +               of_property_read_u8(np, "maxim,rcomp0",
>> +&pdata->model->rcomp0);
>> +               prop = of_find_property(np, "maxim,temp_co_up", NULL);
>> +               if (prop)
>> +                       pdata->model->temp_co_up = be32_to_cpup(prop->value);
> Use of_property_read_u32. If it can't read the property it won't
> modify the pointer it's been handed, and it handles the endianness
> conversion.
>
> You seem to be happy to use of_property_read_u{8,16}, so I don't
> understand why you are treating 32-bit differently.
Because the this property is signed. So I can't use of_property_read_u32.
>
>> +               prop = of_find_property(np, "maxim,temp_co_down", NULL);
>> +               if (prop)
>> +                       pdata->model->temp_co_down = be32_to_cpup(prop->value);
> Likewise.
Ditto.
>
>> +               of_property_read_u16(np, "maxim,ocvtest",
>> +&pdata->model->ocvtest);
> While you've checked that this property was present earlier, you don't
> know it's size. You might want to check the return value of
> of_property_read_u16 (and you might want to do so for other accessors
> too).
Ok, I will add checking of of_property_read_XX() return values.
>
>> +               of_property_read_u8(np, "maxim,soc_check_a",
>> +&pdata->model->soc_check_a);
>> +               of_property_read_u8(np, "maxim,soc_check_b",
>> +&pdata->model->soc_check_b);
>> +               of_property_read_u8(np, "maxim,bits",
>> +&pdata->model->bits);
>> +               of_property_read_u16(np, "maxim,rcomp_seg",
>> +&pdata->model->rcomp_seg);
>> +       }
>> +
>> +       prop = of_find_property(np, "maxim,model_data", NULL);
>> +       if (prop&&  prop->length == MODELGAUGE_TABLE_SIZE) {
>> +               pdata->model->model_data = devm_kzalloc(dev,
>> +                                                       MODELGAUGE_TABLE_SIZE,
>> +                                                       GFP_KERNEL);
>> +               if (!pdata->model->model_data)
>> +                       return NULL;
>> +
>> +               of_property_read_u8_array(np, "maxim,model_data",
>> +                                         pdata->model->model_data,
>> +                                         MODELGAUGE_TABLE_SIZE);
>> +       }
> It's probably worth printing a warning or error if this isn't the size
> you expect (perhaps failing to probe).
okay.
>
>> +
>> +       return pdata;
>> +}
> Thanks,
> Mark.
Regards,
Vladimir


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

* Re: [PATCH 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
@ 2014-01-10 14:29       ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-10 14:29 UTC (permalink / raw)
  To: Mark Rutland
  Cc: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	mk7.kang-Sze3O3UU22JBDgjK7y7TUQ

Hello,

On 01/10/2014 03:11 PM, Mark Rutland wrote:
> On Thu, Jan 09, 2014 at 04:49:03PM +0000, Vladimir Barinov wrote:
>> 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                            |    8
>>   drivers/power/Makefile                           |    1
>>   drivers/power/modelgauge_battery.c               |  875 +++++++++++++++++++++++
>>   include/linux/platform_data/battery-modelgauge.h |   44 +
>>   4 files changed, 928 insertions(+)
> [...]
>
>> +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;
>> +
>> +       if (!of_get_property(np, "maxim,empty_alert_threshold", NULL)&&
>> +           !of_get_property(np, "maxim,soc_change_alert", NULL)&&
>> +           !of_get_property(np, "maxim,hibernate_threshold", NULL)&&
>> +           !of_get_property(np, "maxim,active_threshold", NULL)&&
>> +           !of_get_property(np, "maxim,undervoltage", NULL)&&
>> +           !of_get_property(np, "maxim,overvoltage", NULL)&&
>> +           !of_get_property(np, "maxim,resetvoltage", NULL))
>> +               return NULL;
> These were described as optional in the binding. It wasn't clear that to
> have one you need the others. It would be nice for that to be clarified
> in the binding.
Yes, since they are optional then we'll return NULL here, that means no 
platform data provided.
The "if" statement checked if nothing was provided in DT then there is 
not platform data.

Since, you requested to remove above binding from DT and make the driver 
to take care, then I'll move them to sysfs.
>
>> +
>> +       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
>> +       if (!pdata)
>> +               return NULL;
>> +
>> +       of_property_read_u8(np, "maxim,empty_alert_threshold",
>> +&pdata->empty_alert_threshold);
>> +       pdata->soc_change_alert =
>> +                       of_property_read_bool(np, "maxim,soc_change_alert");
> As mentioned in my comments on the binding document, I don't think this
> property is necessary at all.
Yes, I will move it into driver.
>
>> +       of_property_read_u8(np, "maxim,hibernate_threshold",
>> +&pdata->hibernate_threshold);
>> +       of_property_read_u8(np, "maxim,active_threshold",
>> +&pdata->active_threshold);
>> +       of_property_read_u16(np, "maxim,undervoltage",&pdata->undervoltage);
>> +       of_property_read_u16(np, "maxim,overvoltage",&pdata->overvoltage);
>> +       of_property_read_u16(np, "maxim,resetvoltage",&pdata->resetvoltage);
Ditto for above.
>> +
>> +       prop = of_find_property(np, "maxim,ocvtest", NULL);
> Here you seem to be using of_find_property to check if a property is
> present, but earlier you used of_get_property for this purpose. It would
> be nice if one or the other were used consistently.
Since above code will be removed then only this parameter will be used 
for battery specific data presence check.
>
>> +       if (prop) {
>> +               pdata->model = devm_kzalloc(dev, sizeof(*pdata->model),
>> +                                           GFP_KERNEL);
>> +               if (!pdata->model)
>> +                       return NULL;
>> +
>> +               of_property_read_u8(np, "maxim,empty_adjustment",
>> +&pdata->model->empty_adjustment);
>> +               of_property_read_u8(np, "maxim,full_adjustment",
>> +&pdata->model->full_adjustment);
>> +               of_property_read_u8(np, "maxim,rcomp0",
>> +&pdata->model->rcomp0);
>> +               prop = of_find_property(np, "maxim,temp_co_up", NULL);
>> +               if (prop)
>> +                       pdata->model->temp_co_up = be32_to_cpup(prop->value);
> Use of_property_read_u32. If it can't read the property it won't
> modify the pointer it's been handed, and it handles the endianness
> conversion.
>
> You seem to be happy to use of_property_read_u{8,16}, so I don't
> understand why you are treating 32-bit differently.
Because the this property is signed. So I can't use of_property_read_u32.
>
>> +               prop = of_find_property(np, "maxim,temp_co_down", NULL);
>> +               if (prop)
>> +                       pdata->model->temp_co_down = be32_to_cpup(prop->value);
> Likewise.
Ditto.
>
>> +               of_property_read_u16(np, "maxim,ocvtest",
>> +&pdata->model->ocvtest);
> While you've checked that this property was present earlier, you don't
> know it's size. You might want to check the return value of
> of_property_read_u16 (and you might want to do so for other accessors
> too).
Ok, I will add checking of of_property_read_XX() return values.
>
>> +               of_property_read_u8(np, "maxim,soc_check_a",
>> +&pdata->model->soc_check_a);
>> +               of_property_read_u8(np, "maxim,soc_check_b",
>> +&pdata->model->soc_check_b);
>> +               of_property_read_u8(np, "maxim,bits",
>> +&pdata->model->bits);
>> +               of_property_read_u16(np, "maxim,rcomp_seg",
>> +&pdata->model->rcomp_seg);
>> +       }
>> +
>> +       prop = of_find_property(np, "maxim,model_data", NULL);
>> +       if (prop&&  prop->length == MODELGAUGE_TABLE_SIZE) {
>> +               pdata->model->model_data = devm_kzalloc(dev,
>> +                                                       MODELGAUGE_TABLE_SIZE,
>> +                                                       GFP_KERNEL);
>> +               if (!pdata->model->model_data)
>> +                       return NULL;
>> +
>> +               of_property_read_u8_array(np, "maxim,model_data",
>> +                                         pdata->model->model_data,
>> +                                         MODELGAUGE_TABLE_SIZE);
>> +       }
> It's probably worth printing a warning or error if this isn't the size
> you expect (perhaps failing to probe).
okay.
>
>> +
>> +       return pdata;
>> +}
> Thanks,
> Mark.
Regards,
Vladimir

--
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] 27+ messages in thread

* Re: [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
  2014-01-09 16:49 ` Vladimir Barinov
@ 2014-01-14 15:59   ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2014-01-14 15:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: devicetree, linux-kernel

On 01/09/2014 05:49 PM, Vladimir Barinov wrote:
> 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

On which tree your patchset is based on? I had conflicts when trying to 
apply this on 3.12 and 3.13.

Best regards,
Krzysztof



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

* Re: [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
@ 2014-01-14 15:59   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2014-01-14 15:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: devicetree

On 01/09/2014 05:49 PM, Vladimir Barinov wrote:
> 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

On which tree your patchset is based on? I had conflicts when trying to 
apply this on 3.12 and 3.13.

Best regards,
Krzysztof

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

* Re: Please confirm your message
       [not found]   ` <1389715207.8892.TMDA@plane.gmane.org>
@ 2014-01-14 16:04     ` Krzysztof Kozlowski
       [not found]       ` <1389715485.4811.TMDA@plane.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2014-01-14 16:04 UTC (permalink / raw)
  To: Gmane Remailer






On Tue, 2014-01-14 at 17:00 +0100, Gmane Remailer wrote:
> This message was created automatically by mail delivery software (TMDA).
> 
> Your message attached below is being held because the address
> <k.kozlowski@samsung.com> has not been verified.
> 
> To release your message for delivery, please send an empty message
> to the following address, or use your mailer's "Reply" feature.
> 
>    public-linux-kernel-u79uwXL29TY76Z2rM5mHXA-confirm-1389715205.8892.b9b146@plane.gmane.org
> 
> This confirmation verifies that your message is legitimate and not
> junk-mail. You should only have to confirm your address once.
> 
> If you do not respond to this confirmation request within 14 days,
> your message will not be delivered.




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

* Re: Please confirm your message
       [not found]       ` <1389715485.4811.TMDA@plane.gmane.org>
@ 2014-01-14 16:05         ` Krzysztof Kozlowski
       [not found]           ` <1389715520.8422.TMDA@plane.gmane.org>
  0 siblings, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2014-01-14 16:05 UTC (permalink / raw)
  To: Gmane Remailer






On Tue, 2014-01-14 at 17:04 +0100, Gmane Remailer wrote:
> This message was created automatically by mail delivery software (TMDA).
> 
> Your message attached below is being held because the address
> <k.kozlowski@samsung.com> has not been verified.
> 
> To release your message for delivery, please send an empty message
> to the following address, or use your mailer's "Reply" feature.
> 
>    public-linux-kernel-u79uwXL29TY76Z2rM5mHXA-confirm-1389715484.4811.fc3a9b@plane.gmane.org
> 
> This confirmation verifies that your message is legitimate and not
> junk-mail. You should only have to confirm your address once.
> 
> If you do not respond to this confirmation request within 14 days,
> your message will not be delivered.




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

* Re: Please confirm your message
       [not found]           ` <1389715520.8422.TMDA@plane.gmane.org>
@ 2014-01-14 16:05             ` Krzysztof Kozlowski
  0 siblings, 0 replies; 27+ messages in thread
From: Krzysztof Kozlowski @ 2014-01-14 16:05 UTC (permalink / raw)
  To: Gmane Remailer






On Tue, 2014-01-14 at 17:05 +0100, Gmane Remailer wrote:
> This message was created automatically by mail delivery software (TMDA).
> 
> Your message attached below is being held because the address
> <k.kozlowski@samsung.com> has not been verified.
> 
> To release your message for delivery, please send an empty message
> to the following address, or use your mailer's "Reply" feature.
> 
>    public-linux-kernel-u79uwXL29TY76Z2rM5mHXA-confirm-1389715519.8422.1f4b95@plane.gmane.org
> 
> This confirmation verifies that your message is legitimate and not
> junk-mail. You should only have to confirm your address once.
> 
> If you do not respond to this confirmation request within 14 days,
> your message will not be delivered.




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

* Re: [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
  2014-01-09 16:49 ` Vladimir Barinov
                   ` (4 preceding siblings ...)
  (?)
@ 2014-01-14 16:29 ` Krzysztof Kozlowski
  2014-01-15 10:16     ` Vladimir Barinov
  -1 siblings, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2014-01-14 16:29 UTC (permalink / raw)
  To: Vladimir Barinov, linux-kernel, devicetree
  Cc: anton, dwmw2, mk7.kang, Kyungmin Park

On 01/09/2014 05:49 PM, 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

On which tree your patchset is based on? I had conflicts when trying to
apply this on 3.12 and 3.13.

Best regards,
Krzysztof


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

* Re: [PATCH 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
  2014-01-09 16:49   ` Vladimir Barinov
  (?)
  (?)
@ 2014-01-14 16:31   ` Krzysztof Kozlowski
  2014-01-15 10:20     ` Vladimir Barinov
  -1 siblings, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2014-01-14 16:31 UTC (permalink / raw)
  To: Vladimir Barinov, dwmw2, linux-kernel, devicetree; +Cc: anton, mk7.kang, kmpark

On 01/09/2014 05:49 PM, Vladimir Barinov wrote:
> 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                            |    8
>   drivers/power/Makefile                           |    1
>   drivers/power/modelgauge_battery.c               |  875 +++++++++++++++++++++++
>   include/linux/platform_data/battery-modelgauge.h |   44 +
>   4 files changed, 928 insertions(+)
>

[...]

> +static int modelgauge_read_reg(struct i2c_client *client, u8 reg, u16 *value)
> +{
> +	int ret = i2c_smbus_read_word_data(client, reg);
> +
> +	if (ret < 0) {
> +		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
> +		return ret;
> +	}
> +
> +	*value = be16_to_cpu(ret);
> +	return 0;
> +}

Have you considered using regmap for accessing registers? I know that 
other max17* drivers don't use it but it may be this could be the time 
to switch to regmap API?

[...]

> +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->client	= client;
> +	priv->chip	= id->driver_data;
> +
> +	i2c_set_clientdata(client, priv);
> +
> +	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(&client->dev, "failed: power supply register\n");
> +		goto err_supply;
> +	}
> +
> +	if (client->irq) {
> +		switch (priv->chip) {
> +		case ID_MAX17040:
> +		case ID_MAX17041:
> +			dev_err(&client->dev, "alert line is not supported\n");
> +			ret = -EINVAL;
> +			goto err_irq;
> +		default:
> +			ret = request_threaded_irq(client->irq, NULL,
> +						   modelgauge_irq_handler,
> +						   IRQF_TRIGGER_FALLING,
> +						   priv->battery.name, priv);

I think you may use devm_request_threaded_irq() here.

Best regards,
Krzysztof

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

* Re: [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
@ 2014-01-15 10:16     ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-15 10:16 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-kernel, devicetree, anton, dwmw2, mk7.kang, Kyungmin Park

Hello,

On 01/14/2014 08:29 PM, Krzysztof Kozlowski wrote:
> On 01/09/2014 05:49 PM, 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
>
> On which tree your patchset is based on? I had conflicts when trying to
> apply this on 3.12 and 3.13.
Initially I've prepared them against 
git://git.infradead.org/battery-2.6.git master branch.
I've verified that it also applies against 
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git.

For the next try I will refresh patches against the latest version of 
above trees.

> Best regards,
> Krzysztof
>
Regards,
Vladimir


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

* Re: [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge
@ 2014-01-15 10:16     ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-15 10:16 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, anton-9xeibp6oKSgdnm+yROfE0A,
	dwmw2-wEGCiKHe2LqWVfeAwA7xHQ, mk7.kang-Sze3O3UU22JBDgjK7y7TUQ,
	Kyungmin Park

Hello,

On 01/14/2014 08:29 PM, Krzysztof Kozlowski wrote:
> On 01/09/2014 05:49 PM, 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
>
> On which tree your patchset is based on? I had conflicts when trying to
> apply this on 3.12 and 3.13.
Initially I've prepared them against 
git://git.infradead.org/battery-2.6.git master branch.
I've verified that it also applies against 
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git.

For the next try I will refresh patches against the latest version of 
above trees.

> Best regards,
> Krzysztof
>
Regards,
Vladimir

--
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] 27+ messages in thread

* Re: [PATCH 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge
  2014-01-14 16:31   ` Krzysztof Kozlowski
@ 2014-01-15 10:20     ` Vladimir Barinov
  0 siblings, 0 replies; 27+ messages in thread
From: Vladimir Barinov @ 2014-01-15 10:20 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: dwmw2, linux-kernel, devicetree, anton, mk7.kang, kmpark

Hello, Krzysztof,

Thank you for the review.

On 01/14/2014 08:31 PM, Krzysztof Kozlowski wrote:
> On 01/09/2014 05:49 PM, Vladimir Barinov wrote:
>> 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                            |    8
>>   drivers/power/Makefile                           |    1
>>   drivers/power/modelgauge_battery.c               |  875 
>> +++++++++++++++++++++++
>>   include/linux/platform_data/battery-modelgauge.h |   44 +
>>   4 files changed, 928 insertions(+)
>>
>
> [...]
>
>> +static int modelgauge_read_reg(struct i2c_client *client, u8 reg, 
>> u16 *value)
>> +{
>> +    int ret = i2c_smbus_read_word_data(client, reg);
>> +
>> +    if (ret < 0) {
>> +        dev_err(&client->dev, "%s: err %d\n", __func__, ret);
>> +        return ret;
>> +    }
>> +
>> +    *value = be16_to_cpu(ret);
>> +    return 0;
>> +}
>
> Have you considered using regmap for accessing registers? I know that 
> other max17* drivers don't use it but it may be this could be the time 
> to switch to regmap API?
>
> [...]
Sure, I will rework for the next try. Thx for pointing to this.
>
>> +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->client    = client;
>> +    priv->chip    = id->driver_data;
>> +
>> +    i2c_set_clientdata(client, priv);
>> +
>> +    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(&client->dev, "failed: power supply register\n");
>> +        goto err_supply;
>> +    }
>> +
>> +    if (client->irq) {
>> +        switch (priv->chip) {
>> +        case ID_MAX17040:
>> +        case ID_MAX17041:
>> +            dev_err(&client->dev, "alert line is not supported\n");
>> +            ret = -EINVAL;
>> +            goto err_irq;
>> +        default:
>> +            ret = request_threaded_irq(client->irq, NULL,
>> +                           modelgauge_irq_handler,
>> +                           IRQF_TRIGGER_FALLING,
>> +                           priv->battery.name, priv);
>
> I think you may use devm_request_threaded_irq() here.
Ok, thx,
>
> Best regards,
> Krzysztof

Regards,
Vladimir

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

end of thread, other threads:[~2014-01-20  2:12 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-09 16:49 [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov
2014-01-09 16:49 ` Vladimir Barinov
2014-01-09 16:49 ` [PATCH 1/3] power_supply: modelgauge_battery: " Vladimir Barinov
2014-01-09 16:49   ` Vladimir Barinov
2014-01-10 11:11   ` Mark Rutland
2014-01-10 14:29     ` Vladimir Barinov
2014-01-10 14:29       ` Vladimir Barinov
2014-01-14 16:31   ` Krzysztof Kozlowski
2014-01-15 10:20     ` Vladimir Barinov
2014-01-09 16:49 ` [PATCH 2/3] dt: Document ModelGauge gauge bindings Vladimir Barinov
2014-01-09 16:49   ` Vladimir Barinov
2014-01-10  1:00   ` Kyungmin Park
2014-01-10  1:00     ` Kyungmin Park
2014-01-10 12:59     ` Vladimir Barinov
2014-01-10 10:56   ` Mark Rutland
2014-01-10 10:56     ` Mark Rutland
2014-01-10 14:08     ` Vladimir Barinov
2014-01-09 16:49 ` [PATCH 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge Vladimir Barinov
2014-01-09 16:49   ` Vladimir Barinov
2014-01-14 15:59 ` [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Krzysztof Kozlowski
2014-01-14 15:59   ` Krzysztof Kozlowski
     [not found]   ` <1389715207.8892.TMDA@plane.gmane.org>
2014-01-14 16:04     ` Please confirm your message Krzysztof Kozlowski
     [not found]       ` <1389715485.4811.TMDA@plane.gmane.org>
2014-01-14 16:05         ` Krzysztof Kozlowski
     [not found]           ` <1389715520.8422.TMDA@plane.gmane.org>
2014-01-14 16:05             ` Krzysztof Kozlowski
2014-01-14 16:29 ` [PATCH 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Krzysztof Kozlowski
2014-01-15 10:16   ` Vladimir Barinov
2014-01-15 10:16     ` 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.