linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Maxim Semiconductor MAX1721x power_supply driver
@ 2017-05-25 17:46 Alex A. Mihaylov
  2017-05-25 17:46 ` [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus Alex A. Mihaylov
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Alex A. Mihaylov @ 2017-05-25 17:46 UTC (permalink / raw)
  To: Mark Brown, Greg Kroah-Hartman, Sebastian Reichel,
	Evgeniy Polyakov, linux-kernel, linux-pm
  Cc: Alex A. Mihaylov

Maxim Semiconductor MAX1721x series chip is standalone fuel gauge
for singlecell (MAX17211) or multicell (MAX17215) batteries.
This device use OneWire (W1) interface with W1-Family code 0x26

PATCHES:
  1. Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
  2. Introduce new OneWire (W1) family 0x26 with slave device Maxim
    Semconductor MAX17211/MAX17215 Fuel Gauge IC
  3.Introduce Maxim Semiconductor MAX17211/MAX17215 Standalone Fuel Gauge
    IC support for power_supply class driver
  4. Fix W1 slave exchange with second device on probe step

 drivers/base/regmap/Kconfig             |   6 +-
 drivers/base/regmap/Makefile            |   1 +
 drivers/base/regmap/regmap-w1.c         | 241 +++++++++++++++++++++
 drivers/power/supply/Kconfig            |  14 ++
 drivers/power/supply/Makefile           |   1 +
 drivers/power/supply/max1721x_battery.c | 357 ++++++++++++++++++++++++++++++++
 drivers/w1/slaves/Kconfig               |  12 ++
 drivers/w1/slaves/Makefile              |   1 +
 drivers/w1/slaves/w1_max1721x.c         |  73 +++++++
 drivers/w1/slaves/w1_max1721x.h         | 102 +++++++++
 drivers/w1/w1.c                         |   4 +-
 drivers/w1/w1_family.h                  |   1 +
 include/linux/regmap.h                  |  34 +++
 13 files changed, 844 insertions(+), 3 deletions(-)
 create mode 100644 drivers/base/regmap/regmap-w1.c
 create mode 100644 drivers/power/supply/max1721x_battery.c
 create mode 100644 drivers/w1/slaves/w1_max1721x.c
 create mode 100644 drivers/w1/slaves/w1_max1721x.h

-- 
2.8.4 (Apple Git-73)

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

* [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
  2017-05-25 17:46 [PATCH 0/4] Maxim Semiconductor MAX1721x power_supply driver Alex A. Mihaylov
@ 2017-05-25 17:46 ` Alex A. Mihaylov
  2017-05-25 18:51   ` Greg Kroah-Hartman
                     ` (2 more replies)
  2017-05-25 17:46 ` [PATCH 2/4] Introduce new OneWire (W1) family 0x26 with slave device Maxim Semconductor MAX17211/MAX17215 Fuel Gauge IC Alex A. Mihaylov
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 14+ messages in thread
From: Alex A. Mihaylov @ 2017-05-25 17:46 UTC (permalink / raw)
  To: Mark Brown, Greg Kroah-Hartman, Sebastian Reichel,
	Evgeniy Polyakov, linux-kernel, linux-pm
  Cc: Alex A. Mihaylov

Signed-off-by: Alex A. Mihaylov <minimumlaw@rambler.ru>
---
 drivers/base/regmap/Kconfig     |   6 +-
 drivers/base/regmap/Makefile    |   1 +
 drivers/base/regmap/regmap-w1.c | 241 ++++++++++++++++++++++++++++++++++++++++
 include/linux/regmap.h          |  34 ++++++
 4 files changed, 281 insertions(+), 1 deletion(-)
 create mode 100644 drivers/base/regmap/regmap-w1.c

diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index db9d00c..413af5f 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -3,7 +3,7 @@
 # subsystems should select the appropriate symbols.
 
 config REGMAP
-	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
+	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
 	select IRQ_DOMAIN if REGMAP_IRQ
@@ -24,6 +24,10 @@ config REGMAP_SPMI
 	tristate
 	depends on SPMI
 
+config REGMAP_W1
+	tristate
+	depends on W1
+
 config REGMAP_MMIO
 	tristate
 
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 609e4c8..17741ae 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
 obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
 obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
 obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
+obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
diff --git a/drivers/base/regmap/regmap-w1.c b/drivers/base/regmap/regmap-w1.c
new file mode 100644
index 0000000..6d042cb
--- /dev/null
+++ b/drivers/base/regmap/regmap-w1.c
@@ -0,0 +1,241 @@
+/*
+ * Register map access API - W1 (OneWire) support
+ *
+ * Copyright (C) 2017 OAO Radioavionica
+ * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
+ *
+ * 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/regmap.h>
+#include <linux/module.h>
+#include "../../w1/w1.h"
+
+#include "internal.h"
+
+#define W1_CMD_READ_DATA	0x69
+#define W1_CMD_WRITE_DATA	0x6C
+
+/*
+ * OneWire slaves registers with addess 8 bit and data 8 bit
+ */
+
+static int w1_reg_a8_v8_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct device *dev = context;
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret = -ENODEV;
+
+
+	if (reg > 255)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	if (!w1_reset_select_slave(sl)) {
+		w1_write_8(sl->master, W1_CMD_READ_DATA);
+		w1_write_8(sl->master, reg);
+		*val = w1_read_8(sl->master);
+		ret = 0;
+	}
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static int w1_reg_a8_v8_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct device *dev = context;
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret = -ENODEV;
+
+
+	if (reg > 255)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	if (!w1_reset_select_slave(sl)) {
+		w1_write_8(sl->master, W1_CMD_WRITE_DATA);
+		w1_write_8(sl->master, reg);
+		w1_write_8(sl->master, val);
+		ret = 0;
+	}
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static struct regmap_bus regmap_w1_bus_a8_v8 = {
+	.reg_read = w1_reg_a8_v8_read,
+	.reg_write = w1_reg_a8_v8_write,
+};
+
+/*
+ * OneWire slaves registers with addess 8 bit and data 16 bit
+ */
+
+static int w1_reg_a8_v16_read(void *context, unsigned int reg,
+				unsigned int *val)
+{
+	struct device *dev = context;
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret = -ENODEV;
+
+
+	if (reg > 255)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	if (!w1_reset_select_slave(sl)) {
+		w1_write_8(sl->master, W1_CMD_READ_DATA);
+		w1_write_8(sl->master, reg);
+		*val = w1_read_8(sl->master);
+		*val |= w1_read_8(sl->master)<<8;
+		ret = 0;
+	}
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static int w1_reg_a8_v16_write(void *context, unsigned int reg,
+				unsigned int val)
+{
+	struct device *dev = context;
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret = -ENODEV;
+
+
+	if (reg > 255)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	if (!w1_reset_select_slave(sl)) {
+		w1_write_8(sl->master, W1_CMD_WRITE_DATA);
+		w1_write_8(sl->master, reg);
+		w1_write_8(sl->master, val & 0x00FF);
+		w1_write_8(sl->master, val>>8 & 0x00FF);
+		ret = 0;
+	}
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static struct regmap_bus regmap_w1_bus_a8_v16 = {
+	.reg_read = w1_reg_a8_v16_read,
+	.reg_write = w1_reg_a8_v16_write,
+};
+
+/*
+ * OneWire slaves registers with addess 16 bit and data 16 bit
+ */
+
+static int w1_reg_a16_v16_read(void *context, unsigned int reg,
+				unsigned int *val)
+{
+	struct device *dev = context;
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret = -ENODEV;
+
+
+	if (reg > 65535)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	if (!w1_reset_select_slave(sl)) {
+		w1_write_8(sl->master, W1_CMD_READ_DATA);
+		w1_write_8(sl->master, reg & 0x00FF);
+		w1_write_8(sl->master, reg>>8 & 0x00FF);
+		*val = w1_read_8(sl->master);
+		*val |= w1_read_8(sl->master)<<8;
+		ret = 0;
+	}
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static int w1_reg_a16_v16_write(void *context, unsigned int reg,
+				unsigned int val)
+{
+	struct device *dev = context;
+	struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+	int ret = -ENODEV;
+
+
+	if (reg > 65535)
+		return -EINVAL;
+
+	mutex_lock(&sl->master->bus_mutex);
+	if (!w1_reset_select_slave(sl)) {
+		w1_write_8(sl->master, W1_CMD_WRITE_DATA);
+		w1_write_8(sl->master, reg & 0x00FF);
+		w1_write_8(sl->master, reg>>8 & 0x00FF);
+		w1_write_8(sl->master, val & 0x00FF);
+		w1_write_8(sl->master, val>>8 & 0x00FF);
+		ret = 0;
+	}
+	mutex_unlock(&sl->master->bus_mutex);
+
+	return ret;
+}
+
+static struct regmap_bus regmap_w1_bus_a16_v16 = {
+	.reg_read = w1_reg_a16_v16_read,
+	.reg_write = w1_reg_a16_v16_write,
+};
+
+static const struct regmap_bus *regmap_get_w1_bus(struct device *w1_dev,
+					const struct regmap_config *config)
+{
+	if (config->reg_bits == 8 && config->val_bits == 8)
+		return &regmap_w1_bus_a8_v8;
+
+	if (config->reg_bits == 8 && config->val_bits == 16)
+		return &regmap_w1_bus_a8_v16;
+
+	if (config->reg_bits == 16 && config->val_bits == 16)
+		return &regmap_w1_bus_a16_v16;
+
+	return ERR_PTR(-ENOTSUPP);
+}
+
+struct regmap *__regmap_init_w1(struct device *w1_dev,
+				 const struct regmap_config *config,
+				 struct lock_class_key *lock_key,
+				 const char *lock_name)
+{
+
+	const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config);
+
+	if (IS_ERR(bus))
+		return ERR_CAST(bus);
+
+	return __regmap_init(w1_dev, bus, w1_dev, config,
+			 lock_key, lock_name);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(__regmap_init_w1);
+
+struct regmap *__devm_regmap_init_w1(struct device *w1_dev,
+				 const struct regmap_config *config,
+				 struct lock_class_key *lock_key,
+				 const char *lock_name)
+{
+
+	const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config);
+
+	if (IS_ERR(bus))
+		return ERR_CAST(bus);
+
+	return __devm_regmap_init(w1_dev, bus, w1_dev, config,
+				 lock_key, lock_name);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_w1);
+
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index e886492..86eeacc 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -461,6 +461,10 @@ struct regmap *__regmap_init_spmi_ext(struct spmi_device *dev,
 				      const struct regmap_config *config,
 				      struct lock_class_key *lock_key,
 				      const char *lock_name);
+struct regmap *__regmap_init_w1(struct device *w1_dev,
+				 const struct regmap_config *config,
+				 struct lock_class_key *lock_key,
+				 const char *lock_name);
 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
 				      void __iomem *regs,
 				      const struct regmap_config *config,
@@ -493,6 +497,10 @@ struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *dev,
 					   const struct regmap_config *config,
 					   struct lock_class_key *lock_key,
 					   const char *lock_name);
+struct regmap *__devm_regmap_init_w1(struct device *w1_dev,
+				      const struct regmap_config *config,
+				      struct lock_class_key *lock_key,
+				      const char *lock_name);
 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
 					   const char *clk_id,
 					   void __iomem *regs,
@@ -597,6 +605,19 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
 				dev, config)
 
 /**
+ * regmap_init_w1() - Initialise register map
+ *
+ * @w1_dev: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+#define regmap_init_w1(w1_dev, config)					\
+	__regmap_lockdep_wrapper(__regmap_init_w1, #config,		\
+				w1_dev, config)
+
+/**
  * regmap_init_mmio_clk() - Initialise register map with register clock
  *
  * @dev: Device that will be interacted with
@@ -712,6 +733,19 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
 				dev, config)
 
 /**
+ * devm_regmap_init_w1() - Initialise managed register map
+ *
+ * @w1_dev: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+#define devm_regmap_init_w1(w1_dev, config)				\
+	__regmap_lockdep_wrapper(__devm_regmap_init_w1, #config,	\
+				w1_dev, config)
+/**
  * devm_regmap_init_mmio_clk() - Initialise managed register map with clock
  *
  * @dev: Device that will be interacted with
-- 
2.8.4 (Apple Git-73)

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

* [PATCH 2/4] Introduce new OneWire (W1) family 0x26 with slave device Maxim Semconductor MAX17211/MAX17215 Fuel Gauge IC
  2017-05-25 17:46 [PATCH 0/4] Maxim Semiconductor MAX1721x power_supply driver Alex A. Mihaylov
  2017-05-25 17:46 ` [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus Alex A. Mihaylov
@ 2017-05-25 17:46 ` Alex A. Mihaylov
  2017-05-25 17:46 ` [PATCH 3/4] Introduce Maxim Semiconductor MAX17211/MAX17215 Standalone Fuel Gauge IC support for power_supply class driver Alex A. Mihaylov
  2017-05-25 17:47 ` [PATCH 4/4] Fix W1 slave exchange with second device on probe step Alex A. Mihaylov
  3 siblings, 0 replies; 14+ messages in thread
From: Alex A. Mihaylov @ 2017-05-25 17:46 UTC (permalink / raw)
  To: Mark Brown, Greg Kroah-Hartman, Sebastian Reichel,
	Evgeniy Polyakov, linux-kernel, linux-pm
  Cc: Alex A. Mihaylov

Signed-off-by: Alex A. Mihaylov <minimumlaw@rambler.ru>
---
 drivers/w1/slaves/Kconfig       |  12 +++++
 drivers/w1/slaves/Makefile      |   1 +
 drivers/w1/slaves/w1_max1721x.c |  73 ++++++++++++++++++++++++++++
 drivers/w1/slaves/w1_max1721x.h | 102 ++++++++++++++++++++++++++++++++++++++++
 drivers/w1/w1_family.h          |   1 +
 5 files changed, 189 insertions(+)
 create mode 100644 drivers/w1/slaves/w1_max1721x.c
 create mode 100644 drivers/w1/slaves/w1_max1721x.h

diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index 0ef9f26..06a63a1 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -86,6 +86,18 @@ config W1_SLAVE_DS2433_CRC
 	  Each block has 30 bytes of data and a two byte CRC16.
 	  Full block writes are only allowed if the CRC is valid.
 
+config W1_SLAVE_MAX1721X
+	tristate "Maxim MAX17211/MAX17215 battery monitor chip"
+	help
+	  If you enable this you will have the MAX17211/MAX17215 battery
+	  monitor chip support.
+
+	  The battery monitor chip is used in many batteries/devices
+	  as the one who is responsible for charging/discharging/monitoring
+	  Li+ batteries.
+
+	  If you are unsure, say N.
+
 config W1_SLAVE_DS2760
 	tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)"
 	help
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index b4a3589..967329a 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_W1_SLAVE_DS2406)	+= w1_ds2406.o
 obj-$(CONFIG_W1_SLAVE_DS2423)	+= w1_ds2423.o
 obj-$(CONFIG_W1_SLAVE_DS2431)	+= w1_ds2431.o
 obj-$(CONFIG_W1_SLAVE_DS2433)	+= w1_ds2433.o
+obj-$(CONFIG_W1_SLAVE_MAX1721X)	+= w1_max1721x.o
 obj-$(CONFIG_W1_SLAVE_DS2760)	+= w1_ds2760.o
 obj-$(CONFIG_W1_SLAVE_DS2780)	+= w1_ds2780.o
 obj-$(CONFIG_W1_SLAVE_DS2781)	+= w1_ds2781.o
diff --git a/drivers/w1/slaves/w1_max1721x.c b/drivers/w1/slaves/w1_max1721x.c
new file mode 100644
index 0000000..017ec3e
--- /dev/null
+++ b/drivers/w1/slaves/w1_max1721x.c
@@ -0,0 +1,73 @@
+/*
+ * 1-Wire implementation for Maxim Semiconductor
+ * MAX17211/MAX17215 standalone fuel gauge chip
+ *
+ * Copyright (C) 2017 OAO Radioavionica
+ * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/idr.h>
+#include <linux/gfp.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+#include "w1_max1721x.h"
+
+static int w1_max17211_add_device(struct w1_slave *sl)
+{
+	int ret;
+	struct platform_device *pdev;
+
+	pdev = platform_device_alloc("max1721x-battery", PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return -ENOMEM;
+	pdev->dev.parent = &sl->dev;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto pdev_add_failed;
+
+	dev_set_drvdata(&sl->dev, pdev);
+
+	return 0;
+
+pdev_add_failed:
+	platform_device_put(pdev);
+
+	return ret;
+}
+
+static void w1_max17211_remove_device(struct w1_slave *sl)
+{
+	struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+
+	platform_device_unregister(pdev);
+}
+
+static struct w1_family_ops w1_max17211_fops = {
+	.add_slave    = w1_max17211_add_device,
+	.remove_slave = w1_max17211_remove_device,
+};
+
+static struct w1_family w1_max17211_family = {
+	.fid = W1_FAMILY_MAX17211,
+	.fops = &w1_max17211_fops,
+};
+module_w1_family(w1_max17211_family);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex A. Mihaylov <minimumlaw@rambler.ru>");
+MODULE_DESCRIPTION("1-wire Driver for MAX17211/MAX17215 battery monitor");
+MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_MAX17211));
diff --git a/drivers/w1/slaves/w1_max1721x.h b/drivers/w1/slaves/w1_max1721x.h
new file mode 100644
index 0000000..47694d9
--- /dev/null
+++ b/drivers/w1/slaves/w1_max1721x.h
@@ -0,0 +1,102 @@
+/*
+ * 1-Wire implementation for Maxim Semiconductor
+ * MAX7211/MAX17215 stanalone fuel gauge chip
+ *
+ * Copyright (C) 2017 OAO Radioavionica
+ * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ */
+
+#ifndef __w1_max17211_h__
+#define __w1_max17211_h__
+
+/* Known commands to the MAX1721X chip */
+#define W1_MAX1721X_READ_DATA		0x69
+#define W1_MAX1721X_WRITE_DATA		0x6C
+
+/* Factory settings (nonvilatile registers) (W1 specific) */
+
+#define MAX1721X_REG_NRSENSE	0x1CF	/* RSense in 10^-5 Ohm */
+/* Strings */
+#define MAX1721X_REG_MFG_STR	0x1CC
+#define MAX1721X_REG_MFG_NUMB	3
+#define MAX1721X_REG_DEV_STR	0x1DB
+#define MAX1721X_REG_DEV_NUMB	5
+/* HEX Strings */
+#define MAX1721X_REG_SER_HEX	0x1D8
+
+/* MAX1721X/MAX17215 Output Registers for I2C and W1 chips */
+
+#define MAX172XX_REG_STATUS	0x000	/* status reg */
+#define MAX172XX_BAT_PRESENT	(1<<4)	/* battery connected bit */
+#define MAX172XX_REG_DEVNAME	0x021	/* chip config */
+#define MAX172XX_DEV_MASK	0x000F	/* chip type mask */
+#define MAX172X1_DEV		0x0001
+#define MAX172X5_DEV		0x0005
+#define MAX172XX_REG_TEMP	0x008	/* Temperature */
+#define MAX172XX_REG_BATT	0x0DA	/* Battery voltage */
+#define MAX172XX_REG_CURRENT	0x00A	/* Actual current */
+#define MAX172XX_REG_AVGCURRENT	0x00B	/* Average current */
+#define MAX172XX_REG_REPSOC	0x006	/* Percentage of charge */
+#define MAX172XX_REG_DESIGNCAP	0x018	/* Design capacity */
+#define MAX172XX_REG_REPCAP	0x005	/* Average capacity */
+#define MAX172XX_REG_TTE	0x011	/* Time to empty */
+#define MAX172XX_REG_TTF	0x020	/* Time to full */
+
+/* Number of valid register addresses */
+#define MAX1721X_MAX_REG_NR	0x1EF
+
+/* Convert regs value to power_supply units */
+
+static inline int max172xx_time_to_ps(unsigned int reg)
+{
+	return reg * 5625 / 1000;	/* in sec. */
+}
+
+static inline int max172xx_percent_to_ps(unsigned int reg)
+{
+	return reg / 256;	/* in percent from 0 to 100 */
+}
+
+static inline int max172xx_voltage_to_ps(unsigned int reg)
+{
+	return reg * 1250;	/* in uV */
+}
+
+static inline int max172xx_capacity_to_ps(unsigned int reg)
+{
+	return reg * 500;	/* in uAh */
+}
+
+/*
+ * Current and temperature is signed values, so unsigned regs
+ * value must be converted to signed type
+ */
+
+static inline int max172xx_temperature_to_ps(unsigned int reg)
+{
+	int val = (int16_t)(reg);
+
+	return val * 10 / 256; /* in tenths of deg. C */
+}
+
+/*
+ * Calculating current registers resolution:
+ *
+ * RSense stored in 10^-5 Ohm, so mesaurment voltage must be
+ * in 10^-11 Volts for get current in uA.
+ * 16 bit current reg fullscale +/-51.2mV is 102400 uV.
+ * So: 102400 / 65535 * 10^5 = 156252
+ */
+static inline int max172xx_current_to_voltage(unsigned int reg)
+{
+	int val = (int16_t)(reg);
+
+	return val * 156252;
+}
+
+#endif /* !__w1_max17211_h__ */
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index c4a6b25..398adc9 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -29,6 +29,7 @@
 #define W1_COUNTER_DS2423	0x1D
 #define W1_THERM_DS1822  	0x22
 #define W1_EEPROM_DS2433  	0x23
+#define W1_FAMILY_MAX17211	0x26
 #define W1_THERM_DS18B20 	0x28
 #define W1_FAMILY_DS2408	0x29
 #define W1_EEPROM_DS2431	0x2D
-- 
2.8.4 (Apple Git-73)

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

* [PATCH 3/4] Introduce Maxim Semiconductor MAX17211/MAX17215 Standalone Fuel Gauge IC support for power_supply class driver
  2017-05-25 17:46 [PATCH 0/4] Maxim Semiconductor MAX1721x power_supply driver Alex A. Mihaylov
  2017-05-25 17:46 ` [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus Alex A. Mihaylov
  2017-05-25 17:46 ` [PATCH 2/4] Introduce new OneWire (W1) family 0x26 with slave device Maxim Semconductor MAX17211/MAX17215 Fuel Gauge IC Alex A. Mihaylov
@ 2017-05-25 17:46 ` Alex A. Mihaylov
  2017-05-25 17:47 ` [PATCH 4/4] Fix W1 slave exchange with second device on probe step Alex A. Mihaylov
  3 siblings, 0 replies; 14+ messages in thread
From: Alex A. Mihaylov @ 2017-05-25 17:46 UTC (permalink / raw)
  To: Mark Brown, Greg Kroah-Hartman, Sebastian Reichel,
	Evgeniy Polyakov, linux-kernel, linux-pm
  Cc: Alex A. Mihaylov

Signed-off-by: Alex A. Mihaylov <minimumlaw@rambler.ru>
---
 drivers/power/supply/Kconfig            |  14 ++
 drivers/power/supply/Makefile           |   1 +
 drivers/power/supply/max1721x_battery.c | 357 ++++++++++++++++++++++++++++++++
 3 files changed, 372 insertions(+)
 create mode 100644 drivers/power/supply/max1721x_battery.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index da54ac8..0df90ac 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -268,6 +268,20 @@ config BATTERY_MAX17042
 	  with MAX17042. This driver also supports max17047/50 chips which are
 	  improved version of max17042.
 
+config BATTERY_MAX1721X
+	tristate "MAX17211/MAX17215 standalone gas-gauge"
+	depends on W1
+	select W1_SLAVE_MAX1721X
+	select REGMAP_W1
+	help
+	  MAX1721x is fuel-gauge systems for lithium-ion (Li+) batteries
+	  in handheld and portable equipment. MAX17211 used with single cell
+	  battery. MAX17215 designed for muticell battery. Both them have
+	  OneWire (W1) host interface.
+
+	  Say Y here to enable support for the MAX17211/MAX17215 standalone
+	  battery gas-gauge.
+
 config BATTERY_Z2
 	tristate "Z2 battery driver"
 	depends on I2C && MACH_ZIPIT2
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 3789a2c..c785d05 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_CHARGER_DA9150)	+= da9150-charger.o
 obj-$(CONFIG_BATTERY_DA9150)	+= da9150-fg.o
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
+obj-$(CONFIG_BATTERY_MAX1721X)	+= max1721x_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
 obj-$(CONFIG_BATTERY_RT5033)	+= rt5033_battery.o
 obj-$(CONFIG_CHARGER_RT9455)	+= rt9455_charger.o
diff --git a/drivers/power/supply/max1721x_battery.c b/drivers/power/supply/max1721x_battery.c
new file mode 100644
index 0000000..aa0effe
--- /dev/null
+++ b/drivers/power/supply/max1721x_battery.c
@@ -0,0 +1,357 @@
+/*
+ * 1-wire client/driver for the Maxim Semicondactor
+ * MAX17211/MAX17215 Standalone Fuel Gauge IC
+ *
+ * Copyright (C) 2017 OAO Radioavionica
+ * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
+ *
+ * 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/slab.h>
+#include <linux/param.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/idr.h>
+
+#include "../../w1/w1.h"
+#include "../../w1/slaves/w1_max1721x.h"
+
+#define DEF_DEV_NAME_MAX17211	"MAX17211"
+#define DEF_DEV_NAME_MAX17215	"MAX17215"
+#define DEF_DEV_NAME_UNKNOWN	"UNKNOWN"
+#define DEF_MFG_NAME		"MAXIM"
+
+struct max17211_device_info {
+	struct device *dev;
+	struct power_supply *bat;
+	struct power_supply_desc bat_desc;
+	struct device *w1_dev;
+	struct regmap *regmap;
+	/* battery design format */
+	unsigned int rsense; /* in tenths uOhm */
+	char DeviceName[2 * MAX1721X_REG_DEV_NUMB + 1];
+	char ManufacturerName[2 * MAX1721X_REG_MFG_NUMB + 1];
+	char SerialNumber[13]; /* see get_sn_str() later for comment */
+};
+
+static inline struct max17211_device_info *
+to_device_info(struct power_supply *psy)
+{
+	return power_supply_get_drvdata(psy);
+}
+
+static int max1721x_battery_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	struct max17211_device_info *info = to_device_info(psy);
+	unsigned int reg = 0;
+	int ret = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		/*
+		 * POWER_SUPPLY_PROP_PRESENT will always readable via
+		 * sysfs interface. Value return 0 if battery not
+		 * present or unaccesable via W1.
+		 */
+		val->intval =
+			regmap_read(info->regmap, MAX172XX_REG_STATUS,
+			&reg) ? 0 : !(reg & MAX172XX_BAT_PRESENT);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = regmap_read(info->regmap, MAX172XX_REG_REPSOC, &reg);
+		val->intval = max172xx_percent_to_ps(reg);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = regmap_read(info->regmap, MAX172XX_REG_BATT, &reg);
+		val->intval = max172xx_voltage_to_ps(reg);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		ret = regmap_read(info->regmap, MAX172XX_REG_DESIGNCAP, &reg);
+		val->intval = max172xx_capacity_to_ps(reg);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_AVG:
+		ret = regmap_read(info->regmap, MAX172XX_REG_REPCAP, &reg);
+		val->intval = max172xx_capacity_to_ps(reg);
+		break;
+	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+		ret = regmap_read(info->regmap, MAX172XX_REG_TTE, &reg);
+		val->intval = max172xx_time_to_ps(reg);
+		break;
+	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+		ret = regmap_read(info->regmap, MAX172XX_REG_TTF, &reg);
+		val->intval = max172xx_time_to_ps(reg);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		ret = regmap_read(info->regmap, MAX172XX_REG_TEMP, &reg);
+		val->intval = max172xx_temperature_to_ps(reg);
+		break;
+	/* We need signed current, so must cast info->rsense to signed type */
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		ret = regmap_read(info->regmap, MAX172XX_REG_CURRENT, &reg);
+		val->intval =
+			max172xx_current_to_voltage(reg) / (int)info->rsense;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		ret = regmap_read(info->regmap, MAX172XX_REG_AVGCURRENT, &reg);
+		val->intval =
+			max172xx_current_to_voltage(reg) / (int)info->rsense;
+		break;
+	/*
+	 * Strings already received and inited by probe.
+	 * We do dummy read for check battery still available.
+	 */
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		ret = regmap_read(info->regmap, MAX1721X_REG_DEV_STR, &reg);
+		val->strval = info->DeviceName;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		ret = regmap_read(info->regmap, MAX1721X_REG_MFG_STR, &reg);
+		val->strval = info->ManufacturerName;
+		break;
+	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+		ret = regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &reg);
+		val->strval = info->SerialNumber;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static enum power_supply_property max1721x_battery_props[] = {
+	/* int */
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_AVG,
+	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	/* strings */
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static int get_string(struct max17211_device_info *info,
+			uint16_t reg, uint8_t nr, char *str)
+{
+	unsigned int val;
+
+	if (!str || !(reg == MAX1721X_REG_MFG_STR ||
+			reg == MAX1721X_REG_DEV_STR))
+		return -EFAULT;
+
+	while (nr--) {
+		if (regmap_read(info->regmap, reg++, &val))
+			return -EFAULT;
+		*str++ = val>>8 & 0x00FF;
+		*str++ = val & 0x00FF;
+	}
+	return 0;
+}
+
+/* Maxim say: Serial number is a hex string up to 12 hex characters */
+static int get_sn_string(struct max17211_device_info *info, char *str)
+{
+	unsigned int val[3];
+
+	if (!str)
+		return -EFAULT;
+
+	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &val[0]))
+		return -EFAULT;
+	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 1, &val[1]))
+		return -EFAULT;
+	if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 2, &val[2]))
+		return -EFAULT;
+
+	snprintf(str, 13, "%04X%04X%04X", val[0], val[1], val[2]);
+	return 0;
+}
+
+/* Model Gauge M5 Register Memory Map access */
+static const struct regmap_range max1721x_regs_allow[] = {
+	/* M5 Model Gauge Algorithm area */
+	regmap_reg_range(0x00, 0x23),
+	regmap_reg_range(0x27, 0x2F),
+	regmap_reg_range(0x32, 0x32),
+	regmap_reg_range(0x35, 0x36),
+	regmap_reg_range(0x38, 0x3A),
+	regmap_reg_range(0x3D, 0x3F),
+	regmap_reg_range(0x42, 0x42),
+	regmap_reg_range(0x45, 0x46),
+	regmap_reg_range(0x4A, 0x4A),
+	regmap_reg_range(0x4D, 0x4D),
+	regmap_reg_range(0xB0, 0xB0),
+	regmap_reg_range(0xB4, 0xB4),
+	regmap_reg_range(0xB8, 0xBE),
+	regmap_reg_range(0xD1, 0xDA),
+	regmap_reg_range(0xDC, 0xDF),
+	/* Factory settins area */
+	regmap_reg_range(0x180, 0x1DF),
+	{ }
+};
+
+static const struct regmap_range max1721x_regs_deny[] = {
+	regmap_reg_range(0x24, 0x26),
+	regmap_reg_range(0x30, 0x31),
+	regmap_reg_range(0x33, 0x34),
+	regmap_reg_range(0x37, 0x37),
+	regmap_reg_range(0x3B, 0x3C),
+	regmap_reg_range(0x40, 0x41),
+	regmap_reg_range(0x43, 0x44),
+	regmap_reg_range(0x47, 0x49),
+	regmap_reg_range(0x4B, 0x4C),
+	regmap_reg_range(0x4E, 0xAF),
+	regmap_reg_range(0xB1, 0xB3),
+	regmap_reg_range(0xB5, 0xB7),
+	regmap_reg_range(0xBF, 0xD0),
+	regmap_reg_range(0xDB, 0xDB),
+	regmap_reg_range(0xE0, 0x17F),
+	{ }
+};
+
+static const struct regmap_access_table max1721x_regs = {
+	.yes_ranges	= max1721x_regs_allow,
+	.n_yes_ranges	= ARRAY_SIZE(max1721x_regs_allow),
+	.no_ranges	= max1721x_regs_deny,
+	.n_no_ranges	= ARRAY_SIZE(max1721x_regs_deny),
+};
+
+/* W1 regmap config */
+static const struct regmap_config max1721x_regmap_w1_config = {
+	.reg_bits = 16,
+	.val_bits = 16,
+	.volatile_table = &max1721x_regs,
+	.max_register = MAX1721X_MAX_REG_NR,
+};
+
+static int max1721x_battery_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct max17211_device_info *info;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, info);
+
+	info->dev = &pdev->dev;
+	info->w1_dev = pdev->dev.parent;
+	info->bat_desc.name = dev_name(&pdev->dev);
+	info->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	info->bat_desc.properties = max1721x_battery_props;
+	info->bat_desc.num_properties = ARRAY_SIZE(max1721x_battery_props);
+	info->bat_desc.get_property = max1721x_battery_get_property;
+	/*
+	 * FixMe:
+	 * Device without no_thermal = true not register (err -22)
+	 * Len of platform device name "max17211-battery.X.auto"
+	 * more than 20 chars limit in THERMAL_NAME_LENGTH from
+	 * include/uapi/linux/thermal.h
+	 */
+	info->bat_desc.no_thermal = true;
+	psy_cfg.drv_data = info;
+
+	/* regmap init */
+	info->regmap = devm_regmap_init_w1(info->w1_dev,
+					&max1721x_regmap_w1_config);
+	if (IS_ERR(info->regmap)) {
+		int err = PTR_ERR(info->regmap);
+
+		dev_err(info->dev, "Failed to allocate register map: %d\n",
+			err);
+		return err;
+	}
+
+	/* rsense init */
+	info->rsense = 0;
+	if (regmap_read(info->regmap, MAX1721X_REG_NRSENSE, &info->rsense))
+
+	if (!info->rsense) {
+		dev_warn(info->dev, "RSenese not calibrated, set 10 mOhms!\n");
+		info->rsense = 1000; /* in regs in 10^-5 */
+	}
+	dev_info(info->dev, "RSense: %d mOhms.\n", info->rsense / 100);
+
+	if (get_string(info, MAX1721X_REG_MFG_STR,
+			MAX1721X_REG_MFG_NUMB, info->ManufacturerName)) {
+		dev_err(info->dev, "Can't read manufacturer. Hardware error.\n");
+		return -ENODEV;
+	}
+
+	if (!info->ManufacturerName[0])
+		strncpy(info->ManufacturerName, DEF_MFG_NAME,
+			2 * MAX1721X_REG_MFG_NUMB);
+
+	if (get_string(info, MAX1721X_REG_DEV_STR,
+			MAX1721X_REG_DEV_NUMB, info->DeviceName)) {
+		dev_err(info->dev, "Can't read device. Hardware error.\n");
+		return -ENODEV;
+	}
+	if (!info->DeviceName[0]) {
+		unsigned int dev_name;
+
+		if (regmap_read(info->regmap,
+				MAX172XX_REG_DEVNAME, &dev_name)) {
+			dev_err(info->w1_dev, "Can't read device name reg.\n");
+			return -ENODEV;
+		}
+
+		switch (dev_name & MAX172XX_DEV_MASK) {
+		case MAX172X1_DEV:
+			strncpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
+				2 * MAX1721X_REG_DEV_NUMB);
+			break;
+		case MAX172X5_DEV:
+			strncpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
+				2 * MAX1721X_REG_DEV_NUMB);
+			break;
+		default:
+			strncpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
+				2 * MAX1721X_REG_DEV_NUMB);
+		}
+	}
+
+	if (get_sn_string(info, info->SerialNumber)) {
+		dev_err(info->dev, "Can't read serial. Hardware error.\n");
+		return -ENODEV;
+	}
+
+	info->bat = devm_power_supply_register(&pdev->dev, &info->bat_desc,
+						&psy_cfg);
+	if (IS_ERR(info->bat)) {
+		dev_err(info->dev, "failed to register battery\n");
+		return PTR_ERR(info->bat);
+	}
+
+	return 0;
+}
+
+static struct platform_driver max1721x_battery_driver = {
+	.driver = {
+		.name = "max1721x-battery",
+	},
+	.probe	  = max1721x_battery_probe,
+};
+module_platform_driver(max1721x_battery_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex A. Mihaylov <minimumlaw@rambler.ru>");
+MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauage IC driver");
+MODULE_ALIAS("platform:max1721x-battery");
-- 
2.8.4 (Apple Git-73)

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

* [PATCH 4/4] Fix W1 slave exchange with second device on probe step
  2017-05-25 17:46 [PATCH 0/4] Maxim Semiconductor MAX1721x power_supply driver Alex A. Mihaylov
                   ` (2 preceding siblings ...)
  2017-05-25 17:46 ` [PATCH 3/4] Introduce Maxim Semiconductor MAX17211/MAX17215 Standalone Fuel Gauge IC support for power_supply class driver Alex A. Mihaylov
@ 2017-05-25 17:47 ` Alex A. Mihaylov
  3 siblings, 0 replies; 14+ messages in thread
From: Alex A. Mihaylov @ 2017-05-25 17:47 UTC (permalink / raw)
  To: Mark Brown, Greg Kroah-Hartman, Sebastian Reichel,
	Evgeniy Polyakov, linux-kernel, linux-pm
  Cc: Alex A. Mihaylov

Signed-off-by: Alex A. Mihaylov <minimumlaw@rambler.ru>
---
 drivers/w1/w1.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 90a3d93..5b8b976 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -731,6 +731,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
 	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
 	atomic_set(&sl->refcnt, 1);
 	atomic_inc(&sl->master->refcnt);
+	dev->slave_count++;
 
 	/* slave modules need to be loaded in a context with unlocked mutex */
 	mutex_unlock(&dev->mutex);
@@ -750,11 +751,11 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
 
 	sl->family = f;
 
-
 	err = __w1_attach_slave_device(sl);
 	if (err < 0) {
 		dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
 			 sl->name);
+		dev->slave_count--;
 		w1_family_put(sl->family);
 		atomic_dec(&sl->master->refcnt);
 		kfree(sl);
@@ -762,7 +763,6 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
 	}
 
 	sl->ttl = dev->slave_ttl;
-	dev->slave_count++;
 
 	memcpy(msg.id.id, rn, sizeof(msg.id));
 	msg.type = W1_SLAVE_ADD;
-- 
2.8.4 (Apple Git-73)

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
  2017-05-25 17:46 ` [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus Alex A. Mihaylov
@ 2017-05-25 18:51   ` Greg Kroah-Hartman
  2017-05-26  9:56     ` Mark Brown
  2017-05-26 10:21   ` Mark Brown
       [not found]   ` <404871495743279@web24o.yandex.ru>
  2 siblings, 1 reply; 14+ messages in thread
From: Greg Kroah-Hartman @ 2017-05-25 18:51 UTC (permalink / raw)
  To: Alex A. Mihaylov
  Cc: Mark Brown, Sebastian Reichel, Evgeniy Polyakov, linux-kernel, linux-pm

On Thu, May 25, 2017 at 08:46:36PM +0300, Alex A. Mihaylov wrote:
> Signed-off-by: Alex A. Mihaylov <minimumlaw@rambler.ru>

I just said I can ont take patches without any changelog text.  Why did
you resend these without fixing that up?

greg k-h

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
  2017-05-25 18:51   ` Greg Kroah-Hartman
@ 2017-05-26  9:56     ` Mark Brown
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2017-05-26  9:56 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Alex A. Mihaylov, Sebastian Reichel, Evgeniy Polyakov,
	linux-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 467 bytes --]

On Thu, May 25, 2017 at 08:51:36PM +0200, Greg Kroah-Hartman wrote:
> On Thu, May 25, 2017 at 08:46:36PM +0300, Alex A. Mihaylov wrote:

> > Signed-off-by: Alex A. Mihaylov <minimumlaw@rambler.ru>

> I just said I can ont take patches without any changelog text.  Why did
> you resend these without fixing that up?

Please don't take regmap patches without my review!  Though that's going
to be a lot faster if the subject line matches the style for the
subsystem...

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
  2017-05-25 17:46 ` [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus Alex A. Mihaylov
  2017-05-25 18:51   ` Greg Kroah-Hartman
@ 2017-05-26 10:21   ` Mark Brown
  2017-05-26 15:50     ` Alex A. Mihaylov
       [not found]   ` <404871495743279@web24o.yandex.ru>
  2 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2017-05-26 10:21 UTC (permalink / raw)
  To: Alex A. Mihaylov
  Cc: Greg Kroah-Hartman, Sebastian Reichel, Evgeniy Polyakov,
	linux-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 1075 bytes --]

On Thu, May 25, 2017 at 08:46:36PM +0300, Alex A. Mihaylov wrote:

This looks mostly fine, a couple of small things and like I said in
reply to Greg please use subject lines matching the style for the
subsystem - this makes it a lot easier for people to identify relevant
patches.

> +	int ret = -ENODEV;
> +
> +
> +	if (reg > 255)
> +		return -EINVAL;
> +
> +	mutex_lock(&sl->master->bus_mutex);
> +	if (!w1_reset_select_slave(sl)) {
> +		w1_write_8(sl->master, W1_CMD_READ_DATA);
> +		w1_write_8(sl->master, reg);
> +		*val = w1_read_8(sl->master);
> +		ret = 0;
> +	}
> +	mutex_unlock(&sl->master->bus_mutex);

This is a bit confusing with how -ENODEV is generated - move the
assignment into the if statement so it doesn't look like we're silently
ignoring errors unless you look back to the top of the function.

> +static struct regmap_bus regmap_w1_bus_a8_v16 = {
> +	.reg_read = w1_reg_a8_v16_read,
> +	.reg_write = w1_reg_a8_v16_write,
> +};

It'd be clearer to just have all all these structs at the end of the set
of functions rather than scattered about randomly.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
       [not found]   ` <404871495743279@web24o.yandex.ru>
@ 2017-05-26 11:06     ` Mark Brown
       [not found]       ` <3411811495806312@web49j.yandex.ru>
  0 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2017-05-26 11:06 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: Alex A. Mihaylov, Greg Kroah-Hartman, Sebastian Reichel,
	linux-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 1230 bytes --]

On Thu, May 25, 2017 at 11:14:39PM +0300, Evgeniy Polyakov wrote:

> Frankly saying, your non-regmap version was so much simpler, smaller and cleaner.
> I wonder why did people force you to use regmap.

> Guys, please speak up, if you want driver authors to use THIS, it is really flawed.

> Sebastien, iirc it was your idea to use regmaps, what was the reason for this?

So, this is the first I've seen of this series but in general the main
reason for using regmap is that it allows best practice to be factored
out into common code both in terms of the I/O itself and also in terms
of framework code being able to provide regmap based helpers for common
operations so drivers need less code.  The cache code is also really
useful for a lot of devices, it's a performance boost for reads and is
well optimized for restoring device state if you don't care about
sequencing (this is where some of the MMIO users come from).  You also
get a bunch of debug support for free, things like the tracepoints and
debugfs files (those do work better if you describe the register map).

Looking at the code in the regmap patch I have to say I'm very surprised
if this is adding much complexity, usually moving to regmap is basically
a sed.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
  2017-05-26 10:21   ` Mark Brown
@ 2017-05-26 15:50     ` Alex A. Mihaylov
  0 siblings, 0 replies; 14+ messages in thread
From: Alex A. Mihaylov @ 2017-05-26 15:50 UTC (permalink / raw)
  To: Mark Brown
  Cc: Greg Kroah-Hartman, Sebastian Reichel, Evgeniy Polyakov,
	linux-kernel, linux-pm


> This looks mostly fine, a couple of small things and like I said in
> reply to Greg please use subject lines matching the style for the
> subsystem - this makes it a lot easier for people to identify relevant
> patches.
>
>> +	int ret = -ENODEV;
>> +
>> +
>> +	if (reg > 255)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&sl->master->bus_mutex);
>> +	if (!w1_reset_select_slave(sl)) {
>> +		w1_write_8(sl->master, W1_CMD_READ_DATA);
>> +		w1_write_8(sl->master, reg);
>> +		*val = w1_read_8(sl->master);
>> +		ret = 0;
>> +	}
>> +	mutex_unlock(&sl->master->bus_mutex);
> This is a bit confusing with how -ENODEV is generated - move the
> assignment into the if statement so it doesn't look like we're silently
> ignoring errors unless you look back to the top of the function.
Ok. I set default return value to -ENODEV. W1 (OneWire) Bus periodically 
scan for connected devices. Typical time between scans about 60 sec. 
This period W1 slave device can present in kernel device list, but will 
physically disconnected.

Only w1_reset_select_slave(sl) can say me about device still physically 
accessible. Only on success w1_reset_select_slave return zero. I think 
code, like

if (!w1_reset_select_slave(sl)) {
   [...]
   ret =0;
} else
   ret = -ENODEV;

not good.

>> +static struct regmap_bus regmap_w1_bus_a8_v16 = {
>> +	.reg_read = w1_reg_a8_v16_read,
>> +	.reg_write = w1_reg_a8_v16_write,
>> +};
> It'd be clearer to just have all all these structs at the end of the set
> of functions rather than scattered about randomly.
Ok. I move this structs down in next version of patches.

I hope that the next edition will not contain such a large number of 
registration errors. Sorry for all.

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
       [not found]       ` <3411811495806312@web49j.yandex.ru>
@ 2017-05-26 16:17         ` Alex A. Mihaylov
  2017-05-26 17:18         ` Mark Brown
  1 sibling, 0 replies; 14+ messages in thread
From: Alex A. Mihaylov @ 2017-05-26 16:17 UTC (permalink / raw)
  To: Evgeniy Polyakov, Mark Brown
  Cc: Greg Kroah-Hartman, Sebastian Reichel, linux-kernel, linux-pm


> Alex, it is up to you to decide whether you want to push your regmap version or not,
> I will not object against, but in my personal opinion your first version version was much cleaner.

I don't know. First edition (without regmap) was very simple. I think 
anyone could understand how this code works.

On the other hand, there is already a lot of duplicate code in the 
kernel, which is responsible for accessing device registers on the bus. 
In this sense, using the regmap infrastructure should help. As for the 
complex description of registers of a simple device, I consciously went 
into this complication by describing all the holes in the register map. 
Since this driver is a pioneer, he must use the maximum of 
infrastructure capabilities.

But I somehow do not really believe in the correctness of the 
realisation of regmap for W1. I have too few devices working with this 
bus. Theory, they all can work with my implementation of regmap. But not 
the fact that there will not be those who can not.

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
       [not found]       ` <3411811495806312@web49j.yandex.ru>
  2017-05-26 16:17         ` Alex A. Mihaylov
@ 2017-05-26 17:18         ` Mark Brown
       [not found]           ` <4265821495830391@web12o.yandex.ru>
  1 sibling, 1 reply; 14+ messages in thread
From: Mark Brown @ 2017-05-26 17:18 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: Alex A. Mihaylov, Greg Kroah-Hartman, Sebastian Reichel,
	linux-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 982 bytes --]

On Fri, May 26, 2017 at 04:45:12PM +0300, Evgeniy Polyakov wrote:

Please fix your mail client to word wrap within paragraphs at something
substantially less than 80 columns.  Doing this makes your messages much
easier to read and reply to.

> I wonder what is 'cache' argument about? If I know that some read can be cached,
> since underlying hardware never changes these values, I can store it into local variable
> and use it. If I do not know in advance whether given register can be cached,
> how can regmap determine it for me? How to debug cases when register
> was erroneously considered to be cached?

regmap will only cache registers if it was explicitly told to cache, if
the driver gets that wrong it's just your bog standard bug that can be
debugged in the usual ways one might debug things.  By default nothing
will be cached.

> What is the reason to use regmap besides caching?

There's the other reasons I mentioned in the message you're replying
to for a start...

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
       [not found]           ` <4265821495830391@web12o.yandex.ru>
@ 2017-06-28 19:37             ` Mark Brown
       [not found]               ` <939401499441188@web18j.yandex.ru>
  0 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2017-06-28 19:37 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: Alex A. Mihaylov, Greg Kroah-Hartman, Sebastian Reichel,
	linux-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 1049 bytes --]

On Fri, May 26, 2017 at 11:26:31PM +0300, Evgeniy Polyakov wrote:

> 26.05.2017, 20:18, "Mark Brown" <broonie@kernel.org>:
> > On Fri, May 26, 2017 at 04:45:12PM +0300, Evgeniy Polyakov wrote:

> > Please fix your mail client to word wrap within paragraphs at something
> > substantially less than 80 columns. Doing this makes your messages much
> > easier to read and reply to.

> What part of the message spans behind this limit? Did you handwrap paragraph below
> or it looked like a single line?

Essentially every line of your mail is overly long, including the first
line of the above paragraph.  I've not reflowed anything.  I'd guess
your client is doing the wrapping (this is fairly standard for GUI
clients).

> >>  What is the reason to use regmap besides caching?

> > There's the other reasons I mentioned in the message you're replying
> > to for a start...

> That didn't show how it helps w1, so was the question.

I'm not clear why any of these benefits would be less applicable to w1
than to other buses.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus
       [not found]               ` <939401499441188@web18j.yandex.ru>
@ 2017-07-07 17:11                 ` Mark Brown
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2017-07-07 17:11 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: Alex A. Mihaylov, Greg Kroah-Hartman, Sebastian Reichel,
	linux-kernel, linux-pm

[-- Attachment #1: Type: text/plain, Size: 561 bytes --]

On Fri, Jul 07, 2017 at 06:26:28PM +0300, Evgeniy Polyakov wrote:

> In fact, regmap-w1 brings virtually nothing to w1 from regmap point fo view -
> code is more complex and even a bit more error prone, but we found a nice feature,
> that we do not have to export IO functions anymore, they will be hidden behind
> regmap wrappers.

It's not for the benefit of the bus, it's for the benefit of the devices
on the bus and their subsystems.  From the point of view of the
subsystem it shouldn't have any impact at all, it's a helper library for
the layers above.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

end of thread, other threads:[~2017-07-07 17:11 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-25 17:46 [PATCH 0/4] Maxim Semiconductor MAX1721x power_supply driver Alex A. Mihaylov
2017-05-25 17:46 ` [PATCH 1/4] Introduce regmap infrastructure over Maxim/Dalas OneWire (W1) bus Alex A. Mihaylov
2017-05-25 18:51   ` Greg Kroah-Hartman
2017-05-26  9:56     ` Mark Brown
2017-05-26 10:21   ` Mark Brown
2017-05-26 15:50     ` Alex A. Mihaylov
     [not found]   ` <404871495743279@web24o.yandex.ru>
2017-05-26 11:06     ` Mark Brown
     [not found]       ` <3411811495806312@web49j.yandex.ru>
2017-05-26 16:17         ` Alex A. Mihaylov
2017-05-26 17:18         ` Mark Brown
     [not found]           ` <4265821495830391@web12o.yandex.ru>
2017-06-28 19:37             ` Mark Brown
     [not found]               ` <939401499441188@web18j.yandex.ru>
2017-07-07 17:11                 ` Mark Brown
2017-05-25 17:46 ` [PATCH 2/4] Introduce new OneWire (W1) family 0x26 with slave device Maxim Semconductor MAX17211/MAX17215 Fuel Gauge IC Alex A. Mihaylov
2017-05-25 17:46 ` [PATCH 3/4] Introduce Maxim Semiconductor MAX17211/MAX17215 Standalone Fuel Gauge IC support for power_supply class driver Alex A. Mihaylov
2017-05-25 17:47 ` [PATCH 4/4] Fix W1 slave exchange with second device on probe step Alex A. Mihaylov

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).