Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1652049 > unrolled thread
| Started by | "Alex A. Mihaylov" <minimumlaw@rambler.ru> |
|---|---|
| First post | 2017-05-28 09:20 +0200 |
| Last post | 2017-05-29 17:10 +0200 |
| Articles | 5 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH 1/3] regmap: Add OneWire (W1) bus support "Alex A. Mihaylov" <minimumlaw@rambler.ru> - 2017-05-28 09:20 +0200
Re: [PATCH 1/3] regmap: Add OneWire (W1) bus support Mark Brown <broonie@kernel.org> - 2017-05-29 15:20 +0200
Re: [PATCH 1/3] regmap: Add OneWire (W1) bus support "Alex A. Mihaylov" <minimumlaw@rambler.ru> - 2017-05-29 18:40 +0200
Re: [PATCH 1/3] regmap: Add OneWire (W1) bus support Mark Brown <broonie@kernel.org> - 2017-05-30 14:00 +0200
Re: [PATCH 1/3] regmap: Add OneWire (W1) bus support Geert Uytterhoeven <geert@linux-m68k.org> - 2017-05-29 17:10 +0200
| From | "Alex A. Mihaylov" <minimumlaw@rambler.ru> |
|---|---|
| Date | 2017-05-28 09:20 +0200 |
| Subject | [PATCH 1/3] regmap: Add OneWire (W1) bus support |
| Message-ID | <tM0Ey-7eT-9@gated-at.bofh.it> |
Add basic support regmap (register map access) API for OneWire (W1) bus
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..6852889
--- /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;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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_a8_v8 = {
+ .reg_read = w1_reg_a8_v8_read,
+ .reg_write = w1_reg_a8_v8_write,
+};
+
+static struct regmap_bus regmap_w1_bus_a8_v16 = {
+ .reg_read = w1_reg_a8_v16_read,
+ .reg_write = w1_reg_a8_v16_write,
+};
+
+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] | [next] | [standalone]
| From | Mark Brown <broonie@kernel.org> |
|---|---|
| Date | 2017-05-29 15:20 +0200 |
| Message-ID | <tMsKu-oh-19@gated-at.bofh.it> |
| In reply to | #1652049 |
[Multipart message — attachments visible in raw view] — view raw
On Sun, May 28, 2017 at 10:11:18AM +0300, Alex A. Mihaylov wrote:
> + int ret = -ENODEV;
> +
> + 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;
> + }
I asked you to move the error handling into the else case in these :(
[toc] | [prev] | [next] | [standalone]
| From | "Alex A. Mihaylov" <minimumlaw@rambler.ru> |
|---|---|
| Date | 2017-05-29 18:40 +0200 |
| Message-ID | <tMvS2-2uZ-15@gated-at.bofh.it> |
| In reply to | #1652523 |
29.05.17 16:13, Mark Brown пишет:
>> + int ret = -ENODEV;
>> +
>> + 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;
>> + }
> I asked you to move the error handling into the else case in these :(
Why do you want to see exactly the construction of if/else?
I already wrote that for me this will worsen the quality and
understanding of the code. And another point - in fact it is not an
error handler. This is a completely normal and permissible situation.
There is no "disconnect" event for this bus, and consequently at any
arbitrary time the kernel can not be sure that the device is still
available.
My ret = -ENODEV is exactly about this.
I can see this pattern in other kernel place, like:
drivers/usb/musb/da8xx.c line 374
drivers/usb/musb/davinci.c line 381
drivers/usb/host/xhci-mtk.c line 531
and many other palces.
[toc] | [prev] | [next] | [standalone]
| From | Mark Brown <broonie@kernel.org> |
|---|---|
| Date | 2017-05-30 14:00 +0200 |
| Message-ID | <tMNYC-6Sw-13@gated-at.bofh.it> |
| In reply to | #1652646 |
[Multipart message — attachments visible in raw view] — view raw
On Mon, May 29, 2017 at 07:37:58PM +0300, Alex A. Mihaylov wrote: > 29.05.17 16:13, Mark Brown пишет: > > I asked you to move the error handling into the else case in these :( > Why do you want to see exactly the construction of if/else? I want to see some error handling in the lock so it doesn't look like it's missing, especially since this is the unusual pattern of "mark it as OK in an if statement then carry on running". The code pattern is too unusual and there's too much code and blank space between the ret = 0 meaning it takes too much effort to slow down and check that there's not a bug. > I already wrote that for me this will worsen the quality and understanding > of the code. And another point - in fact it is not an error handler. This is > a completely normal and permissible situation. There is no "disconnect" It's an error. It may be an expected and recoverable error but as far as this write is concerned it's an error. > I can see this pattern in other kernel place, like: > drivers/usb/musb/da8xx.c line 374 This one for example looks like normal code - it's jumping to error in the error handling cases, the success case is a normal direct return with the error cases in the if checks and there's multiple conditions that could trigger an error. You need to get out of the locked region so you have limited options but only have one conditional, moving the assignment inside the else seems like the clearest.
[toc] | [prev] | [next] | [standalone]
| From | Geert Uytterhoeven <geert@linux-m68k.org> |
|---|---|
| Date | 2017-05-29 17:10 +0200 |
| Message-ID | <tMusV-1Cu-9@gated-at.bofh.it> |
| In reply to | #1652049 |
On Sun, May 28, 2017 at 9:11 AM, Alex A. Mihaylov <minimumlaw@rambler.ru> wrote:
> Add basic support regmap (register map access) API for OneWire (W1) bus
It's called "1-wire" or "1-Wire" almost everywhere else in the kernel,
and on the Maxim
website (except in the URL
https://www.maximintegrated.com/en/products/digital/one-wire.html ;-)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web