* [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge @ 2014-02-01 22:23 Vladimir Barinov [not found] ` <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> ` (2 more replies) 0 siblings, 3 replies; 7+ messages in thread From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw) To: anton, dwmw2, linux-kernel, devicetree Cc: mk7.kang, k.kozlowski, mark.rutland Hello. This adds the folowing: - Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips - Document DT bindings - Remove superseded Maxim MAX17040 gauge driver Vladimir Barinov (3): [1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge [2/3] dt: Document ModelGauge gauge bindings [3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge --- This patchset is against the 'kernel/git/torvalds/linux.git' repo. Changes since v1: - switched to REGMAP API - replaced request_threaded_irq with devm_request_threaded_irq - replaced cancel_delayed_work with _sync version - moved "empty_alert_threshold, soc_change_alert, hibernate_threshold, active_threshold, undervoltage, overvoltage, resetvoltage" parameters out from platform_data and DT - removed unused parameters "empty_adjustment, empty_adjustment" - added return value checks for of_property_read_XX functions - removed irrelevant bindings - fixed dt properties naming in documentation - added binding size description in documentation - removed satelite include file include/linux/max17040_battery.h Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt | 61 drivers/power/Kconfig | 17 drivers/power/Makefile | 2 drivers/power/max17040_battery.c | 297 --- drivers/power/modelgauge_battery.c | 838 ++++++++++ include/linux/max17040_battery.h | 19 include/linux/platform_data/battery-modelgauge.h | 31 7 files changed, 940 insertions(+), 325 deletions(-) ^ permalink raw reply [flat|nested] 7+ messages in thread
[parent not found: <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>]
* [PATCH v2 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge [not found] ` <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> @ 2014-02-01 22:23 ` Vladimir Barinov 2014-03-04 10:48 ` Krzysztof Kozlowski 2014-03-04 12:05 ` Krzysztof Kozlowski 2014-02-01 22:23 ` [PATCH v2 2/3] dt: Document ModelGauge gauge bindings Vladimir Barinov 1 sibling, 2 replies; 7+ messages in thread From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw) To: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: mk7.kang-Sze3O3UU22JBDgjK7y7TUQ, k.kozlowski-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland-5wv7dgnIgG8 Add Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips Signed-off-by: Vladimir Barinov <vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> --- drivers/power/Kconfig | 9 drivers/power/Makefile | 1 drivers/power/modelgauge_battery.c | 838 +++++++++++++++++++++++ include/linux/platform_data/battery-modelgauge.h | 31 4 files changed, 879 insertions(+) Index: battery-2.6/drivers/power/Kconfig =================================================================== --- battery-2.6.orig/drivers/power/Kconfig 2014-02-02 01:29:07.434614235 +0400 +++ battery-2.6/drivers/power/Kconfig 2014-02-02 01:29:29.070614750 +0400 @@ -205,6 +205,15 @@ with MAX17042. This driver also supports max17047/50 chips which are improved version of max17042. +config BATTERY_MODELGAUGE + tristate "Maxim ModelGauge ICs fuel gauge" + depends on I2C + select REGMAP_I2C + help + ModelGauge(TM) is a Maxim algorithm incorporated in + MAX17040/41/43/44/48/49/58/59 fuel-gauges for lithium-ion (Li+) + batteries. + config BATTERY_Z2 tristate "Z2 battery driver" depends on I2C && MACH_ZIPIT2 Index: battery-2.6/drivers/power/Makefile =================================================================== --- battery-2.6.orig/drivers/power/Makefile 2014-02-02 01:29:07.462614237 +0400 +++ battery-2.6/drivers/power/Makefile 2014-02-02 01:29:12.978614368 +0400 @@ -32,6 +32,7 @@ obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o +obj-$(CONFIG_BATTERY_MODELGAUGE) += modelgauge_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o Index: battery-2.6/drivers/power/modelgauge_battery.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ battery-2.6/drivers/power/modelgauge_battery.c 2014-02-02 01:29:34.314614874 +0400 @@ -0,0 +1,838 @@ +/* + * Maxim ModelGauge ICs fuel gauge driver + * + * Author: Vladimir Barinov <source-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> + * Copyright (C) 2013 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/power_supply.h> +#include <linux/platform_device.h> +#include <linux/platform_data/battery-modelgauge.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#define DRV_NAME "modelgauge" + +/* Register offsets for ModelGauge ICs */ +#define MODELGAUGE_VCELL_REG 0x02 +#define MODELGAUGE_SOC_REG 0x04 +#define MODELGAUGE_MODE_REG 0x06 +#define MODELGAUGE_VERSION_REG 0x08 +#define MODELGAUGE_HIBRT_REG 0x0A +#define MODELGAUGE_CONFIG_REG 0x0C +#define MODELGAUGE_OCV_REG 0x0E +#define MODELGAUGE_VALRT_REG 0x14 +#define MODELGAUGE_CRATE_REG 0x16 +#define MODELGAUGE_VRESETID_REG 0x18 +#define MODELGAUGE_STATUS_REG 0x1A +#define MODELGAUGE_UNLOCK_REG 0x3E +#define MODELGAUGE_TABLE_REG 0x40 +#define MODELGAUGE_RCOMPSEG_REG 0x80 +#define MODELGAUGE_CMD_REG 0xFE + +/* MODE register bits */ +#define MODELGAUGE_MODE_QUICKSTART (1 << 14) +#define MODELGAUGE_MODE_ENSLEEP (1 << 13) +#define MODELGAUGE_MODE_HIBSTAT (1 << 12) + +/* CONFIG register bits */ +#define MODELGAUGE_CONFIG_SLEEP (1 << 7) +#define MODELGAUGE_CONFIG_ALSC (1 << 6) +#define MODELGAUGE_CONFIG_ALRT (1 << 5) +#define MODELGAUGE_CONFIG_ATHD_MASK 0x1f + +/* STATUS register bits */ +#define MODELGAUGE_STATUS_ENVR (1 << 14) +#define MODELGAUGE_STATUS_SC (1 << 13) +#define MODELGAUGE_STATUS_HD (1 << 12) +#define MODELGAUGE_STATUS_VR (1 << 11) +#define MODELGAUGE_STATUS_VL (1 << 10) +#define MODELGAUGE_STATUS_VH (1 << 9) +#define MODELGAUGE_STATUS_RI (1 << 8) + +/* VRESETID register bits */ +#define MODELGAUGE_VRESETID_DIS (1 << 8) + +#define MODELGAUGE_UNLOCK_VALUE 0x4a57 +#define MODELGAUGE_RESET_VALUE 0x5400 + +#define MODELGAUGE_RCOMP_UPDATE_DELAY 60000 + +/* Capacity threshold where an interrupt is generated on the ALRT pin */ +#define MODELGAUGE_EMPTY_ATHD 15 +/* Enable alert for 1% soc change */ +#define MODELGAUGE_SOC_CHANGE_ALERT 1 +/* Hibernate threshold (crate), where IC enters hibernate mode */ +#define MODELGAUGE_HIBRT_THD 20 +/* Active threshold (mV), where IC exits hibernate mode */ +#define MODELGAUGE_ACTIVE_THD 60 +/* Voltage (mV), when IC alerts if battery voltage less then undervoltage */ +#define MODELGAUGE_UV 0 +/* Voltage (mV), when IC alerts if battery voltage greater then overvoltage */ +#define MODELGAUGE_OV 5120 +/* + * Voltage threshold (mV) below which the IC resets itself. + * Used to detect battery removal and reinsertion + */ +#define MODELGAUGE_RV 0 + +enum chip_id { + ID_MAX17040, + ID_MAX17041, + ID_MAX17043, + ID_MAX17044, + ID_MAX17048, + ID_MAX17049, + ID_MAX17058, + ID_MAX17059, +}; + +struct modelgauge_priv { + struct device *dev; + struct regmap *regmap; + struct power_supply battery; + struct modelgauge_platform_data *pdata; + enum chip_id chip; + struct work_struct load_work; + struct delayed_work rcomp_work; + int soc_shift; +}; + +static void modelgauge_write_block(struct regmap *regmap, u8 adr, u8 size, + u16 *data) +{ + int k; + + /* RAM has different endianness then registers */ + for (k = 0; k < size; k += 2, adr += 2, data++) + regmap_write(regmap, adr, cpu_to_be16(*data)); +} + +static int modelgauge_lsb_to_uvolts(struct modelgauge_priv *priv, int lsb) +{ + switch (priv->chip) { + case ID_MAX17040: + case ID_MAX17043: + return (lsb >> 4) * 1250; /* 1.25mV per bit */ + case ID_MAX17041: + case ID_MAX17044: + return (lsb >> 4) * 2500; /* 2.5mV per bit */ + case ID_MAX17048: + case ID_MAX17058: + return lsb * 625 / 8; /* 78.125uV per bit */ + case ID_MAX17049: + case ID_MAX17059: + return lsb * 625 / 4; /* 156.25uV per bit */ + default: + return -EINVAL; + } +} + +static enum power_supply_property modelgauge_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_OCV, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_TEMP, +}; + +static int modelgauge_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct modelgauge_priv *priv = container_of(psy, + struct modelgauge_priv, + battery); + struct regmap *regmap = priv->regmap; + struct modelgauge_platform_data *pdata = priv->pdata; + int reg; + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (pdata && pdata->get_charging_status) + val->intval = pdata->get_charging_status(); + else + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = regmap_read(regmap, MODELGAUGE_VCELL_REG, ®); + if (ret < 0) + return ret; + + val->intval = modelgauge_lsb_to_uvolts(priv, reg); + break; + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + /* Unlock model access */ + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, + MODELGAUGE_UNLOCK_VALUE); + ret = regmap_read(regmap, MODELGAUGE_OCV_REG, ®); + /* Lock model access */ + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0); + if (ret < 0) + return ret; + + val->intval = modelgauge_lsb_to_uvolts(priv, reg); + break; + case POWER_SUPPLY_PROP_CAPACITY: + ret = regmap_read(regmap, MODELGAUGE_SOC_REG, ®); + if (ret < 0) + return ret; + + val->intval = reg / (1 << priv->soc_shift); + break; + case POWER_SUPPLY_PROP_TEMP: + if (pdata && pdata->get_temperature) + val->intval = pdata->get_temperature(); + else + val->intval = 25; + break; + default: + return -EINVAL; + } + return 0; +} + +static void modelgauge_update_rcomp(struct modelgauge_priv *priv) +{ + struct regmap *regmap = priv->regmap; + struct modelgauge_platform_data *pdata = priv->pdata; + u16 rcomp; + int temp; + + if (pdata->get_temperature) + temp = pdata->get_temperature(); + else + temp = 25; + + if (!pdata->temp_co_up) + pdata->temp_co_up = -500; + if (!pdata->temp_co_down) + pdata->temp_co_down = -5000; + + rcomp = pdata->rcomp0; + if (temp > 20) + rcomp += (temp - 20) * pdata->temp_co_up / 1000; + else + rcomp += (temp - 20) * pdata->temp_co_down / 1000; + + /* Update RCOMP */ + regmap_update_bits(regmap, MODELGAUGE_CONFIG_REG, 0xff, rcomp << 8); +} + +static void modelgauge_update_rcomp_work(struct work_struct *work) +{ + struct modelgauge_priv *priv = container_of(work, + struct modelgauge_priv, + rcomp_work.work); + + modelgauge_update_rcomp(priv); + schedule_delayed_work(&priv->rcomp_work, + msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY)); +} + +static int modelgauge_load_model(struct modelgauge_priv *priv) +{ + struct regmap *regmap = priv->regmap; + struct modelgauge_platform_data *pdata = priv->pdata; + int ret = -EINVAL; + int timeout, k; + int ocv, config, soc; + + /* Save CONFIG */ + regmap_read(regmap, MODELGAUGE_CONFIG_REG, &config); + + for (timeout = 0; timeout < 100; timeout++) { + /* Unlock model access */ + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, + MODELGAUGE_UNLOCK_VALUE); + + /* Read OCV */ + regmap_read(regmap, MODELGAUGE_OCV_REG, &ocv); + if (ocv != 0xffff) + break; + } + + if (timeout >= 100) { + dev_err(priv->dev, "timeout to unlock model access\n"); + ret = -EIO; + goto exit; + } + + switch (priv->chip) { + case ID_MAX17058: + case ID_MAX17059: + /* Reset chip transaction does not provide ACK */ + regmap_write(regmap, MODELGAUGE_CMD_REG, + MODELGAUGE_RESET_VALUE); + msleep(150); + + for (timeout = 0; timeout < 100; timeout++) { + int reg; + + /* Unlock Model Access */ + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, + MODELGAUGE_UNLOCK_VALUE); + + /* Read OCV */ + regmap_read(regmap, MODELGAUGE_OCV_REG, ®); + if (reg != 0xffff) + break; + } + + if (timeout >= 100) { + dev_err(priv->dev, "timeout to unlock model access\n"); + ret = -EIO; + goto exit; + } + break; + default: + break; + } + + switch (priv->chip) { + case ID_MAX17040: + case ID_MAX17041: + case ID_MAX17043: + case ID_MAX17044: + /* Write OCV */ + regmap_write(regmap, MODELGAUGE_OCV_REG, pdata->ocvtest); + /* Write RCOMP to its maximum value */ + regmap_write(regmap, MODELGAUGE_CONFIG_REG, 0xff00); + break; + default: + break; + } + + /* Write the model */ + modelgauge_write_block(regmap, MODELGAUGE_TABLE_REG, + MODELGAUGE_TABLE_SIZE, + (u16 *)pdata->model_data); + + switch (priv->chip) { + case ID_MAX17048: + case ID_MAX17049: { + u16 buf[16]; + + if (!pdata->rcomp_seg) + pdata->rcomp_seg = 0x80; + + for (k = 0; k < 16; k++) + *buf = pdata->rcomp_seg; + + /* Write RCOMPSeg */ + modelgauge_write_block(regmap, MODELGAUGE_RCOMPSEG_REG, + 32, buf); + } + break; + default: + break; + } + + switch (priv->chip) { + case ID_MAX17040: + case ID_MAX17041: + case ID_MAX17043: + case ID_MAX17044: + /* Delay at least 150ms */ + msleep(150); + break; + default: + break; + } + + /* Write OCV */ + regmap_write(regmap, MODELGAUGE_OCV_REG, pdata->ocvtest); + + switch (priv->chip) { + case ID_MAX17048: + case ID_MAX17049: + /* Disable Hibernate */ + regmap_write(regmap, MODELGAUGE_HIBRT_REG, 0); + /* fall-through */ + case ID_MAX17058: + case ID_MAX17059: + /* Lock Model Access */ + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0); + break; + default: + break; + } + + /* Delay between 150ms and 600ms */ + msleep(200); + + /* Read SOC Register and compare to expected result */ + regmap_read(regmap, MODELGAUGE_SOC_REG, &soc); + soc >>= 8; + if (soc >= pdata->soc_check_a && soc <= pdata->soc_check_b) + ret = 0; + + switch (priv->chip) { + case ID_MAX17048: + case ID_MAX17049: + case ID_MAX17058: + case ID_MAX17059: + /* Unlock model access */ + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, + MODELGAUGE_UNLOCK_VALUE); + break; + default: + break; + } + + /* Restore CONFIG and OCV */ + regmap_write(regmap, MODELGAUGE_CONFIG_REG, config); + regmap_write(regmap, MODELGAUGE_OCV_REG, ocv); + + switch (priv->chip) { + case ID_MAX17048: + case ID_MAX17049: + /* Restore Hibernate */ + regmap_write(regmap, MODELGAUGE_HIBRT_REG, + (MODELGAUGE_HIBRT_THD << 8) | + MODELGAUGE_ACTIVE_THD); + break; + default: + break; + } + +exit: + /* Lock model access */ + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0); + + /* Wait 150ms minimum */ + msleep(150); + + return ret; +} + +static void modelgauge_load_model_work(struct work_struct *work) +{ + struct modelgauge_priv *priv = container_of(work, + struct modelgauge_priv, + load_work); + struct regmap *regmap = priv->regmap; + int ret; + int timeout; + + for (timeout = 0; timeout < 10; timeout++) { + /* Load custom model data */ + ret = modelgauge_load_model(priv); + if (!ret) + break; + } + + if (timeout >= 10) { + dev_info(priv->dev, "failed to load custom model\n"); + return; + } + + switch (priv->chip) { + case ID_MAX17048: + case ID_MAX17049: + case ID_MAX17058: + case ID_MAX17059: + /* Clear reset indicator bit */ + regmap_update_bits(regmap, MODELGAUGE_STATUS_REG, + MODELGAUGE_STATUS_RI, 0); + break; + default: + break; + } +} + +static irqreturn_t modelgauge_irq_handler(int id, void *dev) +{ + struct modelgauge_priv *priv = dev; + + /* clear alert status bit */ + regmap_update_bits(priv->regmap, MODELGAUGE_CONFIG_REG, + MODELGAUGE_CONFIG_ALRT, 0); + + power_supply_changed(&priv->battery); + return IRQ_HANDLED; +} + +static int modelgauge_init(struct modelgauge_priv *priv) +{ + struct regmap *regmap = priv->regmap; + struct modelgauge_platform_data *pdata = priv->pdata; + int ret; + int reg; + + ret = regmap_read(regmap, MODELGAUGE_VERSION_REG, ®); + if (ret < 0) + return -ENODEV; + + dev_info(priv->dev, "IC production version 0x%04x\n", reg); + + /* SOC=0 means unrecoverable IC fault, reset is a workaround */ + regmap_read(regmap, MODELGAUGE_SOC_REG, ®); + if (!reg) { + dev_info(priv->dev, "Reset chip, SOC measurement stall\n"); + /* Reset chip transaction does not provide ACK */ + regmap_write(regmap, MODELGAUGE_CMD_REG, + MODELGAUGE_RESET_VALUE); + msleep(150); + } + + /* Default model uses 8 bits per percent */ + priv->soc_shift = 8; + + if (!priv->pdata) { + dev_info(priv->dev, "no platform data provided\n"); + return 0; + } + + switch (pdata->bits) { + case 19: + priv->soc_shift = 9; + break; + case 18: + default: + priv->soc_shift = 8; + break; + } + + /* Set RCOMP */ + modelgauge_update_rcomp(priv); + if (pdata->get_temperature) { + /* Schedule update RCOMP */ + schedule_delayed_work(&priv->rcomp_work, + msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY)); + } + + /* Clear alert status bit, wake-up, set alert threshold */ + reg = 0; + switch (priv->chip) { + case ID_MAX17048: + case ID_MAX17049: + reg |= MODELGAUGE_SOC_CHANGE_ALERT ? MODELGAUGE_CONFIG_ALSC : 0; + /* fall-through */ + case ID_MAX17043: + case ID_MAX17044: + case ID_MAX17058: + case ID_MAX17059: + reg |= 32 - (MODELGAUGE_EMPTY_ATHD << (priv->soc_shift - 8)); + break; + default: + break; + } + regmap_update_bits(regmap, MODELGAUGE_CONFIG_REG, + MODELGAUGE_CONFIG_ALRT | MODELGAUGE_CONFIG_SLEEP | + MODELGAUGE_CONFIG_ALSC | MODELGAUGE_CONFIG_ATHD_MASK, + reg); + + switch (priv->chip) { + case ID_MAX17048: + case ID_MAX17049: + /* Set Hibernate thresholds */ + reg = (MODELGAUGE_HIBRT_THD * 125 / 26) & 0xff; + reg <<= 8; + reg |= (MODELGAUGE_ACTIVE_THD * 4 / 5) & 0xff; + regmap_write(regmap, MODELGAUGE_HIBRT_REG, reg); + + /* Set undervoltage/overvoltage alerts */ + reg = (MODELGAUGE_UV / 20) & 0xff; + reg <<= 8; + reg |= (MODELGAUGE_OV / 20) & 0xff; + regmap_write(regmap, MODELGAUGE_VALRT_REG, reg); + /* fall-through */ + case ID_MAX17058: + case ID_MAX17059: + /* Disable sleep mode and quick start */ + regmap_write(regmap, MODELGAUGE_MODE_REG, 0); + + /* Setup reset voltage threshold */ + if (MODELGAUGE_RV) + reg = ((MODELGAUGE_RV / 40) & 0x7f) << 9; + else + reg = MODELGAUGE_VRESETID_DIS; + regmap_write(regmap, MODELGAUGE_VRESETID_REG, reg); + + /* Skip load model if reset indicator cleared */ + regmap_read(regmap, MODELGAUGE_STATUS_REG, ®); + /* Skip load custom model */ + if (!(reg & MODELGAUGE_STATUS_RI)) + return 0; + break; + default: + break; + } + + /* Schedule load custom model work */ + if (pdata->model_data) + schedule_work(&priv->load_work); + + return 0; +} + +static struct modelgauge_platform_data *modelgauge_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct modelgauge_platform_data *pdata; + struct property *prop; + int ret; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + ret = of_property_read_u8(np, "maxim,rcomp0", &pdata->rcomp0); + if (ret) + pdata->rcomp0 = 25; + + ret = of_property_read_u32(np, "maxim,temp-co-up", &pdata->temp_co_up); + if (ret) + pdata->temp_co_up = -500; + + ret = of_property_read_u32(np, "maxim,temp-co-down", + &pdata->temp_co_down); + if (ret) + pdata->temp_co_down = -5000; + + ret = of_property_read_u16(np, "maxim,ocvtest", &pdata->ocvtest); + if (ret) + pdata->ocvtest = 0; + + ret = of_property_read_u8(np, "maxim,soc-check-a", &pdata->soc_check_a); + if (ret) + pdata->soc_check_a = 0; + + ret = of_property_read_u8(np, "maxim,soc-check-b", &pdata->soc_check_b); + if (ret) + pdata->soc_check_b = 0; + + ret = of_property_read_u8(np, "maxim,bits", &pdata->bits); + if (ret) + pdata->bits = 18; + + ret = of_property_read_u16(np, "maxim,rcomp-seg", &pdata->rcomp_seg); + if (ret) + pdata->rcomp_seg = 0; + + prop = of_find_property(np, "maxim,model-data", NULL); + if (prop && prop->length == MODELGAUGE_TABLE_SIZE) { + pdata->model_data = devm_kzalloc(dev, MODELGAUGE_TABLE_SIZE, + GFP_KERNEL); + if (!pdata->model_data) + goto out; + + ret = of_property_read_u8_array(np, "maxim,model-data", + pdata->model_data, + MODELGAUGE_TABLE_SIZE); + if (ret) { + dev_warn(dev, "failed to get model_data %d\n", ret); + devm_kfree(dev, pdata->model_data); + pdata->model_data = NULL; + } + } + +out: + return pdata; +} + +static const struct regmap_config modelgauge_regmap = { + .reg_bits = 8, + .val_bits = 16, +}; + +static int modelgauge_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct modelgauge_priv *priv; + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (client->dev.of_node) + priv->pdata = modelgauge_parse_dt(&client->dev); + else + priv->pdata = client->dev.platform_data; + + priv->dev = &client->dev; + priv->chip = id->driver_data; + + i2c_set_clientdata(client, priv); + + priv->regmap = devm_regmap_init_i2c(client, &modelgauge_regmap); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + priv->battery.name = "modelgauge_battery"; + priv->battery.type = POWER_SUPPLY_TYPE_BATTERY; + priv->battery.get_property = modelgauge_get_property; + priv->battery.properties = modelgauge_battery_props; + priv->battery.num_properties = ARRAY_SIZE(modelgauge_battery_props); + + INIT_WORK(&priv->load_work, modelgauge_load_model_work); + INIT_DELAYED_WORK(&priv->rcomp_work, modelgauge_update_rcomp_work); + + ret = modelgauge_init(priv); + if (ret) + return ret; + + ret = power_supply_register(&client->dev, &priv->battery); + if (ret) { + dev_err(priv->dev, "failed: power supply register\n"); + goto err_supply; + } + + if (client->irq) { + switch (priv->chip) { + case ID_MAX17040: + case ID_MAX17041: + dev_err(priv->dev, "alert line is not supported\n"); + ret = -EINVAL; + goto err_irq; + default: + ret = devm_request_threaded_irq(priv->dev, client->irq, + NULL, + modelgauge_irq_handler, + IRQF_TRIGGER_FALLING, + priv->battery.name, + priv); + if (ret) { + dev_err(priv->dev, "failed to request irq %d\n", + client->irq); + goto err_irq; + } + } + } + + return 0; + +err_irq: + power_supply_unregister(&priv->battery); +err_supply: + cancel_work_sync(&priv->load_work); + cancel_delayed_work_sync(&priv->rcomp_work); + return ret; +} + +static int modelgauge_remove(struct i2c_client *client) +{ + struct modelgauge_priv *priv = i2c_get_clientdata(client); + + cancel_work_sync(&priv->load_work); + cancel_delayed_work_sync(&priv->rcomp_work); + + power_supply_unregister(&priv->battery); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int modelgauge_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct modelgauge_priv *priv = i2c_get_clientdata(client); + struct modelgauge_platform_data *pdata = priv->pdata; + + if (pdata && pdata->get_temperature) + cancel_delayed_work_sync(&priv->rcomp_work); + + switch (priv->chip) { + case ID_MAX17040: + case ID_MAX17041: + return 0; + default: + if (client->irq) { + disable_irq(client->irq); + enable_irq_wake(client->irq); + } + } + + return 0; +} + +static int modelgauge_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct modelgauge_priv *priv = i2c_get_clientdata(client); + struct modelgauge_platform_data *pdata = priv->pdata; + + if (pdata && pdata->get_temperature) + schedule_delayed_work(&priv->rcomp_work, + msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY)); + + switch (priv->chip) { + case ID_MAX17040: + case ID_MAX17041: + return 0; + default: + if (client->irq) { + disable_irq_wake(client->irq); + enable_irq(client->irq); + } + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(modelgauge_pm_ops, + modelgauge_suspend, modelgauge_resume); +#define MODELGAUGE_PM_OPS (&modelgauge_pm_ops) +#else +#define MODELGAUGE_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static const struct of_device_id modelgauge_match[] = { + { .compatible = "maxim,max17040" }, + { .compatible = "maxim,max17041" }, + { .compatible = "maxim,max17043" }, + { .compatible = "maxim,max17044" }, + { .compatible = "maxim,max17048" }, + { .compatible = "maxim,max17049" }, + { .compatible = "maxim,max17058" }, + { .compatible = "maxim,max17059" }, + { }, +}; +MODULE_DEVICE_TABLE(of, modelgauge_match); + +static const struct i2c_device_id modelgauge_id[] = { + { "max17040", ID_MAX17040 }, + { "max17041", ID_MAX17041 }, + { "max17043", ID_MAX17043 }, + { "max17044", ID_MAX17044 }, + { "max17048", ID_MAX17048 }, + { "max17049", ID_MAX17049 }, + { "max17058", ID_MAX17058 }, + { "max17059", ID_MAX17059 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, modelgauge_id); + +static struct i2c_driver modelgauge_i2c_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(modelgauge_match), + .pm = MODELGAUGE_PM_OPS, + }, + .probe = modelgauge_probe, + .remove = modelgauge_remove, + .id_table = modelgauge_id, +}; +module_i2c_driver(modelgauge_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_DESCRIPTION("Maxim ModelGauge fuel gauge"); Index: battery-2.6/include/linux/platform_data/battery-modelgauge.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ battery-2.6/include/linux/platform_data/battery-modelgauge.h 2014-02-02 01:29:34.314614874 +0400 @@ -0,0 +1,31 @@ +/* + * Maxim ModelGauge ICs fuel gauge driver header file + * + * Author: Vladimir Barinov <source-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> + * Copyright (C) 2013 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __BATTERY_MODELGAUGE_H_ +#define __BATTERY_MODELGAUGE_H_ + +#define MODELGAUGE_TABLE_SIZE 64 + +struct modelgauge_platform_data { + u8 rcomp0; + int temp_co_up; + int temp_co_down; + u16 ocvtest; + u8 soc_check_a; + u8 soc_check_b; + u8 bits; + u16 rcomp_seg; + u8 *model_data; + int (*get_temperature)(void); + int (*get_charging_status)(void); +}; +#endif -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge 2014-02-01 22:23 ` [PATCH v2 1/3] power_supply: modelgauge_battery: " Vladimir Barinov @ 2014-03-04 10:48 ` Krzysztof Kozlowski 2014-03-04 12:05 ` Krzysztof Kozlowski 1 sibling, 0 replies; 7+ messages in thread From: Krzysztof Kozlowski @ 2014-03-04 10:48 UTC (permalink / raw) To: Vladimir Barinov Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang, mark.rutland Hi, On Sun, 2014-02-02 at 02:23 +0400, Vladimir Barinov wrote: > Index: battery-2.6/drivers/power/modelgauge_battery.c > =================================================================== > --- /dev/null 1970-01-01 00:00:00.000000000 +0000 > +++ battery-2.6/drivers/power/modelgauge_battery.c 2014-02-02 01:29:34.314614874 +0400 > @@ -0,0 +1,838 @@ > +/* > + * Maxim ModelGauge ICs fuel gauge driver > + * > + * Author: Vladimir Barinov <source@cogentembedded.com> > + * Copyright (C) 2013 Cogent Embedded, Inc. > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + */ (...) > +static int modelgauge_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); > + struct modelgauge_priv *priv; > + int ret; > + > + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) > + return -EIO; > + > + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + if (client->dev.of_node) > + priv->pdata = modelgauge_parse_dt(&client->dev); > + else > + priv->pdata = client->dev.platform_data; > + > + priv->dev = &client->dev; > + priv->chip = id->driver_data; > + > + i2c_set_clientdata(client, priv); > + > + priv->regmap = devm_regmap_init_i2c(client, &modelgauge_regmap); > + if (IS_ERR(priv->regmap)) > + return PTR_ERR(priv->regmap); > + > + priv->battery.name = "modelgauge_battery"; > + priv->battery.type = POWER_SUPPLY_TYPE_BATTERY; > + priv->battery.get_property = modelgauge_get_property; > + priv->battery.properties = modelgauge_battery_props; > + priv->battery.num_properties = ARRAY_SIZE(modelgauge_battery_props); > + > + INIT_WORK(&priv->load_work, modelgauge_load_model_work); > + INIT_DELAYED_WORK(&priv->rcomp_work, modelgauge_update_rcomp_work); > + > + ret = modelgauge_init(priv); > + if (ret) > + return ret; > + > + ret = power_supply_register(&client->dev, &priv->battery); > + if (ret) { > + dev_err(priv->dev, "failed: power supply register\n"); > + goto err_supply; > + } > + > + if (client->irq) { > + switch (priv->chip) { > + case ID_MAX17040: > + case ID_MAX17041: > + dev_err(priv->dev, "alert line is not supported\n"); > + ret = -EINVAL; > + goto err_irq; > + default: > + ret = devm_request_threaded_irq(priv->dev, client->irq, > + NULL, > + modelgauge_irq_handler, > + IRQF_TRIGGER_FALLING, > + priv->battery.name, > + priv); Shouldn't it be also IRQF_ONESHOT? Without this you may get an error: genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq > + if (ret) { > + dev_err(priv->dev, "failed to request irq %d\n", > + client->irq); > + goto err_irq; > + } > + } > + } > + > + return 0; > + > +err_irq: > + power_supply_unregister(&priv->battery); > +err_supply: > + cancel_work_sync(&priv->load_work); > + cancel_delayed_work_sync(&priv->rcomp_work); > + return ret; > +} > + > +static int modelgauge_remove(struct i2c_client *client) > +{ > + struct modelgauge_priv *priv = i2c_get_clientdata(client); > + > + cancel_work_sync(&priv->load_work); > + cancel_delayed_work_sync(&priv->rcomp_work); > + > + power_supply_unregister(&priv->battery); > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int modelgauge_suspend(struct device *dev) > +{ > + struct i2c_client *client = to_i2c_client(dev); > + struct modelgauge_priv *priv = i2c_get_clientdata(client); > + struct modelgauge_platform_data *pdata = priv->pdata; > + > + if (pdata && pdata->get_temperature) > + cancel_delayed_work_sync(&priv->rcomp_work); > + > + switch (priv->chip) { > + case ID_MAX17040: > + case ID_MAX17041: > + return 0; > + default: > + if (client->irq) { > + disable_irq(client->irq); > + enable_irq_wake(client->irq); > + } > + } > + > + return 0; > +} > + > +static int modelgauge_resume(struct device *dev) > +{ > + struct i2c_client *client = to_i2c_client(dev); > + struct modelgauge_priv *priv = i2c_get_clientdata(client); > + struct modelgauge_platform_data *pdata = priv->pdata; > + > + if (pdata && pdata->get_temperature) > + schedule_delayed_work(&priv->rcomp_work, > + msecs_to_jiffies(MODELGAUGE_RCOMP_UPDATE_DELAY)); > + > + switch (priv->chip) { > + case ID_MAX17040: > + case ID_MAX17041: > + return 0; > + default: > + if (client->irq) { > + disable_irq_wake(client->irq); > + enable_irq(client->irq); > + } > + } > + > + return 0; > +} > + > +static SIMPLE_DEV_PM_OPS(modelgauge_pm_ops, > + modelgauge_suspend, modelgauge_resume); > +#define MODELGAUGE_PM_OPS (&modelgauge_pm_ops) > +#else > +#define MODELGAUGE_PM_OPS NULL > +#endif /* CONFIG_PM_SLEEP */ You can simplify this into: +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(modelgauge_pm_ops, + modelgauge_suspend, modelgauge_resume); And later: +static struct i2c_driver modelgauge_i2c_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(modelgauge_match), + .pm = &modelgauge_pm_ops, Anyway, I like the idea of merging these drivers so I'm happy to test it further. Best regards, Krzysztof ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge 2014-02-01 22:23 ` [PATCH v2 1/3] power_supply: modelgauge_battery: " Vladimir Barinov 2014-03-04 10:48 ` Krzysztof Kozlowski @ 2014-03-04 12:05 ` Krzysztof Kozlowski 1 sibling, 0 replies; 7+ messages in thread From: Krzysztof Kozlowski @ 2014-03-04 12:05 UTC (permalink / raw) To: Vladimir Barinov Cc: anton, dwmw2, linux-kernel, devicetree, mk7.kang, mark.rutland And one more comment: On Sun, 2014-02-02 at 02:23 +0400, Vladimir Barinov wrote: > +static int modelgauge_get_property(struct power_supply *psy, > + enum power_supply_property psp, > + union power_supply_propval *val) > +{ > + struct modelgauge_priv *priv = container_of(psy, > + struct modelgauge_priv, > + battery); > + struct regmap *regmap = priv->regmap; > + struct modelgauge_platform_data *pdata = priv->pdata; > + int reg; > + int ret; > + > + switch (psp) { > + case POWER_SUPPLY_PROP_STATUS: > + if (pdata && pdata->get_charging_status) > + val->intval = pdata->get_charging_status(); > + else > + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; > + break; > + case POWER_SUPPLY_PROP_VOLTAGE_NOW: > + ret = regmap_read(regmap, MODELGAUGE_VCELL_REG, ®); > + if (ret < 0) > + return ret; > + > + val->intval = modelgauge_lsb_to_uvolts(priv, reg); > + break; > + case POWER_SUPPLY_PROP_VOLTAGE_OCV: > + /* Unlock model access */ > + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, > + MODELGAUGE_UNLOCK_VALUE); > + ret = regmap_read(regmap, MODELGAUGE_OCV_REG, ®); > + /* Lock model access */ > + regmap_write(regmap, MODELGAUGE_UNLOCK_REG, 0); > + if (ret < 0) > + return ret; > + > + val->intval = modelgauge_lsb_to_uvolts(priv, reg); > + break; > + case POWER_SUPPLY_PROP_CAPACITY: > + ret = regmap_read(regmap, MODELGAUGE_SOC_REG, ®); > + if (ret < 0) > + return ret; > + > + val->intval = reg / (1 << priv->soc_shift); > + break; > + case POWER_SUPPLY_PROP_TEMP: > + if (pdata && pdata->get_temperature) > + val->intval = pdata->get_temperature(); > + else > + val->intval = 25; If pdata->get_temperature() is not supplied then probably the driver should not support POWER_SUPPLY_PROP_TEMP at all. I think it is better not to report any temperature than to report a wrong one. Best regards, Krzysztof ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] dt: Document ModelGauge gauge bindings [not found] ` <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 2014-02-01 22:23 ` [PATCH v2 1/3] power_supply: modelgauge_battery: " Vladimir Barinov @ 2014-02-01 22:23 ` Vladimir Barinov 1 sibling, 0 replies; 7+ messages in thread From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw) To: anton-9xeibp6oKSgdnm+yROfE0A, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: mk7.kang-Sze3O3UU22JBDgjK7y7TUQ, k.kozlowski-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland-5wv7dgnIgG8 These bindings can be used to register Maxim ModelGauge ICs fuel gauge (MAX17040/41/43/44/48/49/58/59) Signed-off-by: Vladimir Barinov <vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> --- Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt | 61 ++++++++++ 1 file changed, 61 insertions(+) Index: battery-2.6/Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ battery-2.6/Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt 2014-02-02 01:36:12.638624341 +0400 @@ -0,0 +1,61 @@ +modelgauge_battery +~~~~~~~~~~~~~~~~~~ + +Required properties: + - compatible : should contain one of the following: + - "maxim,max17040" for MAX17040 + - "maxim,max17041" for MAX17041 + - "maxim,max17043" for MAX17043 + - "maxim,max17044" for MAX17044 + - "maxim,max17048" for MAX17048 + - "maxim,max17049" for MAX17049 + - "maxim,max17058" for MAX17058 + - "maxim,max17059" for MAX17059 + +Optional properties: + - maxim,rcomp0 : ModelGauge RCOMP parameter, used for + temperature compensation (u8); + - maxim,temp-co-up : ModelGauge TempCoUp parameter, used for + temperature compensation (signed); + - maxim,temp-co-down : ModelGauge TempCoDown parameter, used for + temperature compensation (signed); + - maxim,ocvtest : ModelGauge OCVTest parameter, used for + verification of Custom Model calibration data + loaded into IC RAM (u16); + - maxim,soc-check-a : ModelGauge SOCCheckA parameter, used for + verification of Custom Model calibration data + loaded into IC RAM (u8); + - maxim,soc-check-b : ModelGauge SOCCheckB parameter, used for + verification of Custom Model calibration data + loaded into IC RAM (u8); + - maxim,bits : ModelGauge Bits parameter, used as + scaling parameter in Custom Model algorithm (u8); + - maxim,model-data : ModelGauge ModelData data, + Custom Model calibration data (array_u8[64]). + +Example: + +modelgauge@36 { + compatible = "maxim,max17058"; + reg = <0x36>; + interrupt-parent = <&msmgpio>; + interrupts = <107 0x2>; + + maxim,rcomp0 = /bits/ 8 <175>; + maxim,temp-co-up = <(-1100)>; + maxim,temp-co-down = <(-4000)>; + maxim,ocvtest = /bits/ 16 <56144>; + maxim,soc-check-a = /bits/ 8 <241>; + maxim,soc-check-b = /bits/ 8 <243>; + maxim,bits = /bits/ 8 <19>; + + maxim,model-data = /bits/ 8 < + 0x9B 0x70 0xAB 0x30 0xB5 0xA0 0xB9 0xD0 + 0xBB 0xA0 0xBC 0x00 0xBC 0xB0 0xBD 0x00 + 0xBD 0x60 0xBE 0x40 0xBF 0x40 0xC1 0xF0 + 0xC5 0x60 0xC8 0xA0 0xCD 0x00 0xD1 0x50 + 0x00 0xE0 0x01 0x80 0x18 0x60 0x1C 0x20 + 0x54 0x00 0x6A 0xC0 0x79 0x20 0x65 0xC0 + 0x0B 0xE0 0x2A 0xC0 0x1D 0x00 0x17 0xE0 + 0x15 0xE0 0x11 0xE0 0x11 0x00 0x11 0x00>; +}; -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge 2014-02-01 22:23 [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov [not found] ` <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> @ 2014-02-01 22:23 ` Vladimir Barinov 2014-02-26 10:21 ` [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov 2 siblings, 0 replies; 7+ messages in thread From: Vladimir Barinov @ 2014-02-01 22:23 UTC (permalink / raw) To: anton, dwmw2, linux-kernel, devicetree Cc: mk7.kang, k.kozlowski, mark.rutland Remove Maxim MAX17040 gauge driver since it is superseded by full-functional Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com> --- drivers/power/Kconfig | 8 - drivers/power/Makefile | 1 drivers/power/max17040_battery.c | 297 --------------------------------------- include/linux/max17040_battery.h | 19 -- 4 files changed, 325 deletions(-) Index: linux-2.6.torvalds/drivers/power/Kconfig =================================================================== --- linux-2.6.torvalds.orig/drivers/power/Kconfig 2014-02-02 01:37:35.374626307 +0400 +++ linux-2.6.torvalds/drivers/power/Kconfig 2014-02-02 01:38:21.966627415 +0400 @@ -185,14 +185,6 @@ Say Y here to enable support for batteries charger integrated into DA9052 PMIC. -config BATTERY_MAX17040 - tristate "Maxim MAX17040 Fuel Gauge" - depends on I2C - help - MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries - in handheld and portable equipment. The MAX17040 is configured - to operate with a single lithium cell - config BATTERY_MAX17042 tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge" depends on I2C Index: linux-2.6.torvalds/drivers/power/Makefile =================================================================== --- linux-2.6.torvalds.orig/drivers/power/Makefile 2014-02-02 01:37:35.000000000 +0400 +++ linux-2.6.torvalds/drivers/power/Makefile 2014-02-02 01:38:21.966627415 +0400 @@ -30,7 +30,6 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o -obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o obj-$(CONFIG_BATTERY_MODELGAUGE) += modelgauge_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o Index: linux-2.6.torvalds/drivers/power/max17040_battery.c =================================================================== --- linux-2.6.torvalds.orig/drivers/power/max17040_battery.c 2014-02-02 01:38:29.614627597 +0400 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,297 +0,0 @@ -/* - * max17040_battery.c - * fuel-gauge systems for lithium-ion (Li+) batteries - * - * Copyright (C) 2009 Samsung Electronics - * Minkyu Kang <mk7.kang@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/err.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/power_supply.h> -#include <linux/max17040_battery.h> -#include <linux/slab.h> - -#define MAX17040_VCELL_MSB 0x02 -#define MAX17040_VCELL_LSB 0x03 -#define MAX17040_SOC_MSB 0x04 -#define MAX17040_SOC_LSB 0x05 -#define MAX17040_MODE_MSB 0x06 -#define MAX17040_MODE_LSB 0x07 -#define MAX17040_VER_MSB 0x08 -#define MAX17040_VER_LSB 0x09 -#define MAX17040_RCOMP_MSB 0x0C -#define MAX17040_RCOMP_LSB 0x0D -#define MAX17040_CMD_MSB 0xFE -#define MAX17040_CMD_LSB 0xFF - -#define MAX17040_DELAY 1000 -#define MAX17040_BATTERY_FULL 95 - -struct max17040_chip { - struct i2c_client *client; - struct delayed_work work; - struct power_supply battery; - struct max17040_platform_data *pdata; - - /* State Of Connect */ - int online; - /* battery voltage */ - int vcell; - /* battery capacity */ - int soc; - /* State Of Charge */ - int status; -}; - -static int max17040_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct max17040_chip *chip = container_of(psy, - struct max17040_chip, battery); - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = chip->status; - break; - case POWER_SUPPLY_PROP_ONLINE: - val->intval = chip->online; - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = chip->vcell; - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = chip->soc; - break; - default: - return -EINVAL; - } - return 0; -} - -static int max17040_write_reg(struct i2c_client *client, int reg, u8 value) -{ - int ret; - - ret = i2c_smbus_write_byte_data(client, reg, value); - - if (ret < 0) - dev_err(&client->dev, "%s: err %d\n", __func__, ret); - - return ret; -} - -static int max17040_read_reg(struct i2c_client *client, int reg) -{ - int ret; - - ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) - dev_err(&client->dev, "%s: err %d\n", __func__, ret); - - return ret; -} - -static void max17040_reset(struct i2c_client *client) -{ - max17040_write_reg(client, MAX17040_CMD_MSB, 0x54); - max17040_write_reg(client, MAX17040_CMD_LSB, 0x00); -} - -static void max17040_get_vcell(struct i2c_client *client) -{ - struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; - - msb = max17040_read_reg(client, MAX17040_VCELL_MSB); - lsb = max17040_read_reg(client, MAX17040_VCELL_LSB); - - chip->vcell = (msb << 4) + (lsb >> 4); -} - -static void max17040_get_soc(struct i2c_client *client) -{ - struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; - - msb = max17040_read_reg(client, MAX17040_SOC_MSB); - lsb = max17040_read_reg(client, MAX17040_SOC_LSB); - - chip->soc = msb; -} - -static void max17040_get_version(struct i2c_client *client) -{ - u8 msb; - u8 lsb; - - msb = max17040_read_reg(client, MAX17040_VER_MSB); - lsb = max17040_read_reg(client, MAX17040_VER_LSB); - - dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb); -} - -static void max17040_get_online(struct i2c_client *client) -{ - struct max17040_chip *chip = i2c_get_clientdata(client); - - if (chip->pdata->battery_online) - chip->online = chip->pdata->battery_online(); - else - chip->online = 1; -} - -static void max17040_get_status(struct i2c_client *client) -{ - struct max17040_chip *chip = i2c_get_clientdata(client); - - if (!chip->pdata->charger_online || !chip->pdata->charger_enable) { - chip->status = POWER_SUPPLY_STATUS_UNKNOWN; - return; - } - - if (chip->pdata->charger_online()) { - if (chip->pdata->charger_enable()) - chip->status = POWER_SUPPLY_STATUS_CHARGING; - else - chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING; - } else { - chip->status = POWER_SUPPLY_STATUS_DISCHARGING; - } - - if (chip->soc > MAX17040_BATTERY_FULL) - chip->status = POWER_SUPPLY_STATUS_FULL; -} - -static void max17040_work(struct work_struct *work) -{ - struct max17040_chip *chip; - - chip = container_of(work, struct max17040_chip, work.work); - - max17040_get_vcell(chip->client); - max17040_get_soc(chip->client); - max17040_get_online(chip->client); - max17040_get_status(chip->client); - - schedule_delayed_work(&chip->work, MAX17040_DELAY); -} - -static enum power_supply_property max17040_battery_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CAPACITY, -}; - -static int max17040_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct max17040_chip *chip; - int ret; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - return -EIO; - - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->client = client; - chip->pdata = client->dev.platform_data; - - i2c_set_clientdata(client, chip); - - chip->battery.name = "battery"; - chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; - chip->battery.get_property = max17040_get_property; - chip->battery.properties = max17040_battery_props; - chip->battery.num_properties = ARRAY_SIZE(max17040_battery_props); - - ret = power_supply_register(&client->dev, &chip->battery); - if (ret) { - dev_err(&client->dev, "failed: power supply register\n"); - return ret; - } - - max17040_reset(client); - max17040_get_version(client); - - INIT_DEFERRABLE_WORK(&chip->work, max17040_work); - schedule_delayed_work(&chip->work, MAX17040_DELAY); - - return 0; -} - -static int max17040_remove(struct i2c_client *client) -{ - struct max17040_chip *chip = i2c_get_clientdata(client); - - power_supply_unregister(&chip->battery); - cancel_delayed_work(&chip->work); - return 0; -} - -#ifdef CONFIG_PM_SLEEP - -static int max17040_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct max17040_chip *chip = i2c_get_clientdata(client); - - cancel_delayed_work(&chip->work); - return 0; -} - -static int max17040_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct max17040_chip *chip = i2c_get_clientdata(client); - - schedule_delayed_work(&chip->work, MAX17040_DELAY); - return 0; -} - -static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume); -#define MAX17040_PM_OPS (&max17040_pm_ops) - -#else - -#define MAX17040_PM_OPS NULL - -#endif /* CONFIG_PM_SLEEP */ - -static const struct i2c_device_id max17040_id[] = { - { "max17040", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, max17040_id); - -static struct i2c_driver max17040_i2c_driver = { - .driver = { - .name = "max17040", - .pm = MAX17040_PM_OPS, - }, - .probe = max17040_probe, - .remove = max17040_remove, - .id_table = max17040_id, -}; -module_i2c_driver(max17040_i2c_driver); - -MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>"); -MODULE_DESCRIPTION("MAX17040 Fuel Gauge"); -MODULE_LICENSE("GPL"); Index: linux-2.6.torvalds/include/linux/max17040_battery.h =================================================================== --- linux-2.6.torvalds.orig/include/linux/max17040_battery.h 2014-01-15 14:11:22.000000000 +0400 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2009 Samsung Electronics - * Minkyu Kang <mk7.kang@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __MAX17040_BATTERY_H_ -#define __MAX17040_BATTERY_H_ - -struct max17040_platform_data { - int (*battery_online)(void); - int (*charger_online)(void); - int (*charger_enable)(void); -}; - -#endif ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge 2014-02-01 22:23 [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov [not found] ` <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 2014-02-01 22:23 ` [PATCH v2 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge Vladimir Barinov @ 2014-02-26 10:21 ` Vladimir Barinov 2 siblings, 0 replies; 7+ messages in thread From: Vladimir Barinov @ 2014-02-26 10:21 UTC (permalink / raw) To: dbaryshkov Cc: anton@enomsg.org, dwmw2, linux-kernel, devicetree, mk7.kang, k.kozlowski, mark.rutland Hello Dmitry, In accordance to this change you've taken the responsibility for power supply maintainership. https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/MAINTAINERS?id=573189354b7c97cd2256b87cf083ee435584594e It passed almost month and no answer from you. Does it make sense to apply this patch series? Regards, Vladimir On 02/02/2014 02:23 AM, Vladimir Barinov wrote: > Hello. > > This adds the folowing: > - Maxim ModelGauge ICs gauge driver for MAX17040/41/43/44/48/49/58/59 chips > - Document DT bindings > - Remove superseded Maxim MAX17040 gauge driver > > Vladimir Barinov (3): > [1/3] power_supply: modelgauge_battery: Maxim ModelGauge ICs gauge > [2/3] dt: Document ModelGauge gauge bindings > [3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge > > --- > This patchset is against the 'kernel/git/torvalds/linux.git' repo. > > Changes since v1: > - switched to REGMAP API > - replaced request_threaded_irq with devm_request_threaded_irq > - replaced cancel_delayed_work with _sync version > - moved "empty_alert_threshold, soc_change_alert, hibernate_threshold, > active_threshold, undervoltage, overvoltage, resetvoltage" parameters > out from platform_data and DT > - removed unused parameters "empty_adjustment, empty_adjustment" > - added return value checks for of_property_read_XX functions > - removed irrelevant bindings > - fixed dt properties naming in documentation > - added binding size description in documentation > - removed satelite include file include/linux/max17040_battery.h > > Documentation/devicetree/bindings/power_supply/modelgauge_battery.txt | 61 > drivers/power/Kconfig | 17 > drivers/power/Makefile | 2 > drivers/power/max17040_battery.c | 297 --- > drivers/power/modelgauge_battery.c | 838 ++++++++++ > include/linux/max17040_battery.h | 19 > include/linux/platform_data/battery-modelgauge.h | 31 > 7 files changed, 940 insertions(+), 325 deletions(-) ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2014-03-04 12:05 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-02-01 22:23 [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov [not found] ` <1391293385-27539-1-git-send-email-vladimir.barinov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org> 2014-02-01 22:23 ` [PATCH v2 1/3] power_supply: modelgauge_battery: " Vladimir Barinov 2014-03-04 10:48 ` Krzysztof Kozlowski 2014-03-04 12:05 ` Krzysztof Kozlowski 2014-02-01 22:23 ` [PATCH v2 2/3] dt: Document ModelGauge gauge bindings Vladimir Barinov 2014-02-01 22:23 ` [PATCH v2 3/3] power_supply: modelgauge_battery: Remove Maxim MAX17040 gauge Vladimir Barinov 2014-02-26 10:21 ` [PATCH v2 0/3] power_supply: modelgauge_battery: Add Maxim ModelGauge ICs gauge Vladimir Barinov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).