Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1637228 > unrolled thread
| Started by | "Alex A. Mihaylov" <minimumlaw@rambler.ru> |
|---|---|
| First post | 2017-05-08 08:20 +0200 |
| Last post | 2017-05-08 08:20 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
[RFC 0/2] Again w1-regman and power_supply MAX1721x "Alex A. Mihaylov" <minimumlaw@rambler.ru> - 2017-05-08 08:20 +0200
[RFC 1/2] Basic support for regmap ifrastucture over Maxim/Dalas OneWire Bus "Alex A. Mihaylov" <minimumlaw@rambler.ru> - 2017-05-08 08:20 +0200
| From | "Alex A. Mihaylov" <minimumlaw@rambler.ru> |
|---|---|
| Date | 2017-05-08 08:20 +0200 |
| Subject | [RFC 0/2] Again w1-regman and power_supply MAX1721x |
| Message-ID | <tEKbv-85-3@gated-at.bofh.it> |
Hi! I wrote driver for Maxim MAX17211/MAX17215 standalone fuel gauge IC. Earlier I post preliminary versions of this driver and got recommendations to translate it into the infrastructure of regmap. Accordingly, it was necessary to implement at least basic support of regmap for the OneWire bus. Which was done. There was a criticism about the use of an intermediate platform_device. In this edition, this is also fixed. I would like to hear not only criticism, but also constructive proposals for the implementation or correction of this code. Known issuie/troubles: ~~~~~~~~~~~~~~~~~~~~~~ 1. Endian for W1-regmap Code writen for use nativ endian for host (master) device. But waiting for little-endian slave divice. I don't know W1 slave device with big-endian addrees or data format. May be regmap_bus or regmap_config will be checked for host/device endian requirements? 2. W1 Family/device infrastructure All present power_supply class drivers in vanilla kernel use w1-slave devices. All of them create platform_device with name "chip-battery.X.auto", and power_supply class driver use this platform device. Why used this way? I write code, allocated power_supply at W1 slave (family) device register. This work as expected. 3. Device names All W1 device have unical 64 bit ID (8-bit family, 48-bit serial number, 8 bit CRC). W1 infrastructure show 56 bits (family-serial_nimber) as w1 slave device name. I use this (unical) device name as power_supply battery name. This work. But in /sys/class/power_supply is placed machine readabe subdir "26-HexDigString", instead of human-readable "chip-battery.X.auto". But in /sys/class/power_supply/26-HexDigString/type file still content human-readable type "Battery". Thermal zone working, but in /sys/class/thermal/thermal_zoneX/type also placed "26-HexDigString", instead of "chip-battery.X.auto". I can rename "26-HexDigString" to "battery-26-HexDigString" or "26-HexDigString-battery", but this exceeded 20 chars thermal zone device name. So, thermal zone will have to be disabled. Alex A. Mihaylov (2): Basic support for regmap ifrastucture over Maxim/Dalas OneWire Bus MAX1721x Standalone Fuel Gauge IC power_supply class driver 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 | 361 ++++++++++++++++++++++++++++++++ include/linux/power/max172xx-battery.h | 100 +++++++++ include/linux/regmap.h | 34 +++ 8 files changed, 757 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-w1.c create mode 100644 drivers/power/supply/max1721x_battery.c create mode 100644 include/linux/power/max172xx-battery.h -- 2.8.4 (Apple Git-73)
[toc] | [next] | [standalone]
| From | "Alex A. Mihaylov" <minimumlaw@rambler.ru> |
|---|---|
| Date | 2017-05-08 08:20 +0200 |
| Subject | [RFC 1/2] Basic support for regmap ifrastucture over Maxim/Dalas OneWire Bus |
| Message-ID | <tEKbv-85-19@gated-at.bofh.it> |
| In reply to | #1637228 |
---
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 ®map_w1_bus_a8_v8;
+
+ if (config->reg_bits == 8 && config->val_bits == 16)
+ return ®map_w1_bus_a8_v16;
+
+ if (config->reg_bits == 16 && config->val_bits == 16)
+ return ®map_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)
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web