Skip to contentSkip to conversation

Generic I2C and SPI register map library

PATCH In review Mark Brown 5 participants 19 messages Jun 22, 2011 – Jul 1, 2011

Subsystems (6)
lore
Share & tools
lore

Mark Brown

author
#0 lore raw

cover Generic I2C and SPI register map library

[This reposting of the series should address all the review comments on the series so far.]

Many I2C and SPI based devices implement register maps on top of the raw wire interface. This is generally done in a very standard fashion by devices, resulting in a lot of very similar code in drivers. For some time now ASoC has factored this code out into the subsystem but that's only useful for audio devices. The intention with this series is to generalise the concept so that it can be used throughout the kernel.

It's not intended that this be suitable for all devices - some devices have things that are hard to generalise like registers with variable size and paging which are hard to support genericly. At the minute the code is focused on the common cases. It is likely that the same code could be used with other buses with similar properties to I2C and SPI.

Currently only physical I/O is handled, the intention is that once this support has been reviewed and merged the generic register cache code that ASoC includes will also be factored out too. For devices with read heavy workloads (especially those that need a lot of read/modify/write cycles) or which don't support read at all this can provide a useful performance improvement and for sparse register maps there's a lot of benefit in relatively complex cache code.

I'm not entirely happy with the implementation currently but am fairly happy with the external interfaces.

A semi-random set of driver conversions have been included in the series with various degrees of testing including the subsystem wide ASoC code. Far more drivers could use the code, these have mostly just been done as samples in a minimally invasive fashion.

There's a git branch at:

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git for-next

but due to various -next dependencies this does not currently include all of the patches posted here. I've also created a regmap-asoc branch there which merges current ASoC code with the regmap code.

Mark Brown (8):
regmap: Add generic non-memory mapped register access API
regmap: Add I2C bus support
regmap: Add SPI bus support
ASoC: Use new register map API for ASoC generic physical I/O
mfd: Convert WM831x to use regmap API
mfd: Convert WM8994 to use new register map API
mfd: Convert pcf50633 to use new register map API
regulator: Convert tps65023 to use regmap API

 MAINTAINERS                            |    7 +
 drivers/Kconfig                        |    1 +
 drivers/Makefile                       |    1 +
 drivers/mfd/Kconfig                    |    4 +
 drivers/mfd/pcf50633-core.c            |  114 ++------
 drivers/mfd/wm831x-core.c              |   97 +++----
 drivers/mfd/wm831x-i2c.c               |   56 ----
 drivers/mfd/wm831x-spi.c               |   48 ----
 drivers/mfd/wm8994-core.c              |  175 ++----------
 drivers/regmap/Kconfig                 |    6 +
 drivers/regmap/Makefile                |    3 +
 drivers/regmap/regmap-i2c.c            |  113 ++++++++
 drivers/regmap/regmap-spi.c            |   75 +++++
 drivers/regmap/regmap.c                |  484 ++++++++++++++++++++++++++++++++
 drivers/regulator/Kconfig              |    1 +
 drivers/regulator/tps65023-regulator.c |   98 ++-----
 include/linux/mfd/pcf50633/core.h      |    3 +-
 include/linux/mfd/wm831x/core.h        |    7 +-
 include/linux/mfd/wm8994/core.h        |    9 +-
 include/linux/regmap.h                 |   77 +++++
 include/sound/soc.h                    |    2 +
 sound/soc/Kconfig                      |    1 +
 sound/soc/soc-io.c                     |  316 ++-------------------
 23 files changed, 929 insertions(+), 769 deletions(-)
author
#1 lore raw

PATCH 1/8 regmap: Add generic non-memory mapped register access API

There are many places in the tree where we implement register access for devices on non-memory mapped buses, especially I2C and SPI. Since hardware designers seem to have settled on a relatively consistent set of register interfaces this can be effectively factored out into shared code. There are a standard set of formats for marshalling data for exchange with the device, with the actual I/O mechanisms generally being simple byte streams.

We create an abstraction for marshaling data into formats which can be sent on the control interfaces, and create a standard method for plugging in actual transport underneath that.

This is mostly a refactoring and renaming of the bottom level of the existing code for sharing register I/O which we have in ASoC. A subsequent patch in this series converts ASoC to use this. The main difference in interface is that reads return values by writing to a location provided by a pointer rather than in the return value, ensuring we can use the full range of the type for register data. We also use unsigned types rather than ints for the same reason.

As some of the devices can have very large register maps the existing ASoC code also contains infrastructure for managing register caches. This cache work will be moved over in a future stage to allow for separate review, the current patch only deals with the physical I/O. We also only deal with access to a single register at a time initially as this is the most common case.

---
 MAINTAINERS             |    7 +
 drivers/Kconfig         |    1 +
 drivers/Makefile        |    1 +
 drivers/regmap/Kconfig  |    6 +
 drivers/regmap/Makefile |    2 +
 drivers/regmap/regmap.c |  484 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/regmap.h  |   77 ++++++++
 7 files changed, 578 insertions(+), 0 deletions(-)
 create mode 100644 drivers/regmap/Kconfig
 create mode 100644 drivers/regmap/Makefile
 create mode 100644 drivers/regmap/regmap.c
 create mode 100644 include/linux/regmap.h
MAINTAINERS +7 -0
index a26e9ec..bd2ec03 100644
@@ -5318,6 +5318,13 @@ L:	[email protected]
 S:	Supported
 F:	fs/reiserfs/
 
+REGISTER MAP ABSTRACTION
+M:	Mark Brown <[email protected]>
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
+S:	Supported
+F:	drivers/regmap/
+F:	include/linux/regmap.h
+
 RFKILL
 M:	Johannes Berg <[email protected]>
 L:	[email protected]
drivers/Kconfig +1 -0
index 3bb154d..8c55790 100644
@@ -126,4 +126,5 @@ source "drivers/hwspinlock/Kconfig"
 
 source "drivers/clocksource/Kconfig"
 
+source "drivers/regmap/Kconfig"
 endmenu
drivers/Makefile +1 -0
index 09f3232..78ab0d6 100644
@@ -116,6 +116,7 @@ obj-$(CONFIG_BCMA)		+= bcma/
 obj-$(CONFIG_VHOST_NET)		+= vhost/
 obj-$(CONFIG_VLYNQ)		+= vlynq/
 obj-$(CONFIG_STAGING)		+= staging/
+obj-$(CONFIG_REGMAP)		+= regmap/
 obj-y				+= platform/
 obj-y				+= ieee802154/
 #common clk code
drivers/regmap/Kconfig new file +6 -0
new file mode 100644
index 0000000..fc0eb1d
@@ -0,0 +1,6 @@
+# Generic register map support.  There are no user servicable options here,
+# this is an API intended to be used by other kernel subsystems.  These
+# subsystems should select the appropriate symbols.
+
+config REGMAP
+	bool
drivers/regmap/Makefile new file +2 -0
new file mode 100644
index 0000000..1e5037e
@@ -0,0 +1,2 @@
+obj-$(CONFIG_REGMAP) += regmap.o
+
drivers/regmap/regmap.c new file +484 -0

484 lines not on this page · raw message

include/linux/regmap.h new file +77 -0

77 lines not on this page · raw message

Signature · 1 line
1.7.5.4
author
#2 lore raw

PATCH 2/8 regmap: Add I2C bus support

We initialise at postcore_initcall() so that we are available before users
- some users such as PMICs initialise very early. We won't actually try to use any of the bus until a device initialises a register map.

---
 drivers/regmap/Makefile     |    2 +-
 drivers/regmap/regmap-i2c.c |  113 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 114 insertions(+), 1 deletions(-)
 create mode 100644 drivers/regmap/regmap-i2c.c
drivers/regmap/Makefile +1 -1
index 1e5037e..641c20a 100644
@@ -1,2 +1,2 @@
 obj-$(CONFIG_REGMAP) += regmap.o
-
+obj-$(CONFIG_I2C) += regmap-i2c.o
drivers/regmap/regmap-i2c.c new file +113 -0

113 lines not on this page · raw message

Signature · 1 line
1.7.5.4
author
#3 lore raw

PATCH 3/8 regmap: Add SPI bus support

In reply to Mark Brown

We initialise at postcore_initcall() so that we are available before users
- some users such as PMICs initialise very early. We won't actually try to use any of the bus until a device initialises a register map.

---
 drivers/regmap/Makefile     |    1 +
 drivers/regmap/regmap-spi.c |   75 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 drivers/regmap/regmap-spi.c
drivers/regmap/Makefile +1 -0
index 641c20a..74c6680 100644
@@ -1,2 +1,3 @@
 obj-$(CONFIG_REGMAP) += regmap.o
 obj-$(CONFIG_I2C) += regmap-i2c.o
+obj-$(CONFIG_SPI) += regmap-spi.o
drivers/regmap/regmap-spi.c new file +75 -0

75 lines not on this page · raw message

Signature · 1 line
1.7.5.4
author
#4 lore raw

PATCH 4/8 ASoC: Use new register map API for ASoC generic physical I/O

In reply to Mark Brown

Remove all the ASoC specific physical I/O code and replace it with calls into the regmap API. The bulk write code can only be used safely if all regmap calls are locked with the CODEC lock, we need to add bulk support to the regmap API or replace the code with an open coded loop (though currently it has no users...).

---
 include/sound/soc.h |    2 +
 sound/soc/Kconfig   |    1 +
 sound/soc/soc-io.c  |  316 ++++-----------------------------------------------
 3 files changed, 28 insertions(+), 291 deletions(-)
include/sound/soc.h +2 -0
index 6424b10..40436b8 100644
@@ -19,6 +19,7 @@
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
@@ -570,6 +571,7 @@ struct snd_soc_codec {
 	const void *reg_def_copy;
 	const struct snd_soc_cache_ops *cache_ops;
 	struct mutex cache_rw_mutex;
+	int val_bytes;
 
 	/* dapm */
 	struct snd_soc_dapm_context dapm;
sound/soc/Kconfig +1 -0
index 8224db5..32e5fd4 100644
@@ -7,6 +7,7 @@ menuconfig SND_SOC
 	select SND_PCM
 	select AC97_BUS if SND_SOC_AC97_BUS
 	select SND_JACK if INPUT=y || INPUT=SND
+	select REGMAP
 	---help---
 
 	  If you want ASoC support, you should say Y here and also to the
sound/soc/soc-io.c +25 -291

367 lines not on this page · raw message

Signature · 1 line
1.7.5.4
author
#5 lore raw

PATCH 5/8 mfd: Convert WM831x to use regmap API

In reply to Mark Brown

Factor out the register read/write code to use the register map API. We still need some wm831x specific code and locking in place to check that the user key is handled correctly but only on the write side, reads are not affected by the key.

---
 drivers/mfd/Kconfig             |    2 +
 drivers/mfd/wm831x-core.c       |   97 ++++++++++++++------------------------
 drivers/mfd/wm831x-i2c.c        |   56 ----------------------
 drivers/mfd/wm831x-spi.c        |   48 -------------------
 include/linux/mfd/wm831x/core.h |    7 +--
 5 files changed, 40 insertions(+), 170 deletions(-)
drivers/mfd/Kconfig +2 -0
index 6b0babc..9782296 100644
@@ -389,6 +389,7 @@ config MFD_WM831X_I2C
 	bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C"
 	select MFD_CORE
 	select MFD_WM831X
+	select REGMAP
 	depends on I2C=y && GENERIC_HARDIRQS
 	help
 	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
@@ -400,6 +401,7 @@ config MFD_WM831X_SPI
 	bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI"
 	select MFD_CORE
 	select MFD_WM831X
+	select REGMAP
 	depends on SPI_MASTER && GENERIC_HARDIRQS
 	help
 	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
drivers/mfd/wm831x-core.c +36 -61

216 lines not on this page · raw message

drivers/mfd/wm831x-i2c.c +0 -56

68 lines not on this page · raw message

drivers/mfd/wm831x-spi.c +0 -48

60 lines not on this page · raw message

include/linux/mfd/wm831x/core.h +2 -5
index 8dda8de..bd0615b 100644
@@ -18,6 +18,7 @@
 #include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
+#include <linux/regmap.h>
 
 /*
  * Register values.
@@ -361,12 +362,8 @@ struct wm831x {
 	struct mutex io_lock;
 
 	struct device *dev;
-	int (*read_dev)(struct wm831x *wm831x, unsigned short reg,
-			int bytes, void *dest);
-	int (*write_dev)(struct wm831x *wm831x, unsigned short reg,
-			 int bytes, void *src);
 
-	void *control_data;
+	struct regmap *regmap;
 
 	int irq;  /* Our chip IRQ */
 	struct mutex irq_lock;
Signature · 1 line
1.7.5.4
author
#6 lore raw

PATCH 6/8 mfd: Convert WM8994 to use new register map API

In reply to Mark Brown
---
 drivers/mfd/Kconfig             |    1 +
 drivers/mfd/wm8994-core.c       |  175 +++++++--------------------------------
 include/linux/mfd/wm8994/core.h |    9 +--
 3 files changed, 34 insertions(+), 151 deletions(-)
drivers/mfd/Kconfig +1 -0
index 9782296..97e01b4 100644
@@ -475,6 +475,7 @@ config MFD_WM8350_I2C
 config MFD_WM8994
 	bool "Support Wolfson Microelectronics WM8994"
 	select MFD_CORE
+	select REGMAP
 	depends on I2C=y && GENERIC_HARDIRQS
 	help
 	  The WM8994 is a highly integrated hi-fi CODEC designed for
drivers/mfd/wm8994-core.c +31 -144

288 lines not on this page · raw message

include/linux/mfd/wm8994/core.h +2 -7
index bfb221b..6268091 100644
@@ -25,6 +25,7 @@ enum wm8994_type {
 
 struct regulator_dev;
 struct regulator_bulk_data;
+struct regmap;
 
 #define WM8994_NUM_GPIO_REGS 11
 #define WM8994_NUM_LDO_REGS   2
@@ -51,18 +52,12 @@ struct regulator_bulk_data;
 #define WM8994_IRQ_GPIO(x) (x + WM8994_IRQ_TEMP_WARN)
 
 struct wm8994 {
-	struct mutex io_lock;
 	struct mutex irq_lock;
 
 	enum wm8994_type type;
 
 	struct device *dev;
-	int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
-			int bytes, void *dest);
-	int (*write_dev)(struct wm8994 *wm8994, unsigned short reg,
-			 int bytes, const void *src);
-
-	void *control_data;
+	struct regmap *regmap;
 
 	int gpio_base;
 	int irq_base;
Signature · 1 line
1.7.5.4
author
#7 lore raw

PATCH 7/8 mfd: Convert pcf50633 to use new register map API

In reply to Mark Brown
---
 drivers/mfd/Kconfig               |    1 +
 drivers/mfd/pcf50633-core.c       |  114 +++++++++---------------------------
 include/linux/mfd/pcf50633/core.h |    3 +-
 3 files changed, 32 insertions(+), 86 deletions(-)
drivers/mfd/Kconfig +1 -0
index 97e01b4..c5edb8b 100644
@@ -488,6 +488,7 @@ config MFD_WM8994
 config MFD_PCF50633
 	tristate "Support for NXP PCF50633"
 	depends on I2C
+	select REGMAP
 	help
 	  Say yes here if you have NXP PCF50633 chip on your board.
 	  This core driver provides register access and IRQ handling
drivers/mfd/pcf50633-core.c +29 -85

187 lines not on this page · raw message

include/linux/mfd/pcf50633/core.h +2 -1
index 50d4a04..a808407 100644
@@ -21,6 +21,7 @@
 #include <linux/mfd/pcf50633/backlight.h>
 
 struct pcf50633;
+struct regmap;
 
 #define PCF50633_NUM_REGULATORS	11
 
@@ -134,7 +135,7 @@ enum {
 
 struct pcf50633 {
 	struct device *dev;
-	struct i2c_client *i2c_client;
+	struct regmap *regmap;
 
 	struct pcf50633_platform_data *pdata;
 	int irq;
Signature · 1 line
1.7.5.4
author
#8 lore raw

PATCH 8/8 regulator: Convert tps65023 to use regmap API

In reply to Mark Brown
---
 drivers/regulator/Kconfig              |    1 +
 drivers/regulator/tps65023-regulator.c |   98 +++++++++-----------------------
 2 files changed, 28 insertions(+), 71 deletions(-)
drivers/regulator/Kconfig +1 -0
index a1dffd9..5e8707a 100644
@@ -235,6 +235,7 @@ config REGULATOR_TPS6105X
 config REGULATOR_TPS65023
 	tristate "TI TPS65023 Power regulators"
 	depends on I2C
+	select REGMAP
 	help
 	  This driver supports TPS65023 voltage regulator chips. TPS65023 provides
 	  three step-down converters and two general-purpose LDO voltage regulators.
drivers/regulator/tps65023-regulator.c +27 -71

155 lines not on this page · raw message

Signature · 1 line
1.7.5.4
#9 lore raw

Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API

In reply to Mark Brown
Quoted 8 lines · Mark Brown

[...]

drivers/regmap/regmap.c new file +7 -0
+
+static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
+			    unsigned int val_len)
+{
+	u8 *u8 = map->work_buf;
+	int ret;
+

drivers/regmap/regmap.c line 327

Quoted 10 lines
drivers/regmap/regmap.c new file +10 -0
+	map->format.format_reg(map->work_buf, reg);
+
+	/*
+	 * Some buses flag reads by setting the high bits in the
+	 * register addresss; since it's always the high bits for all
+	 * current formats we can do this here rather than in
+	 * formatting.  This may break if we get interesting formats.
+	 */
+	if (map->bus->read_flag_bit)
+		u8[0] |= 1 << map->bus->read_flag_bit;

Should be 1 << (map->bus->read_flag_bit - 1)

author
#10 lore raw

Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API

Quoted 6 lines · Lars-Peter Clausen

drivers/regmap/regmap.c line 327

Quoted 2 lines · Mark Brown
drivers/regmap/regmap.c new file +2 -0
+	if (map->bus->read_flag_bit)
+		u8[0] |= 1 << map->bus->read_flag_bit;

Should be 1 << (map->bus->read_flag_bit - 1)

The code has the sematic I intended; you can debate if it's the best semantic and looking at the documentation again it's not entirely clear so at least that should be updated.

#11 lore raw

Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API

Quoted 11 lines · Mark Brown
Quoted 6 lines · Lars-Peter Clausen

drivers/regmap/regmap.c line 327

Quoted 2 lines · Mark Brown
drivers/regmap/regmap.c new file +2 -0
+	if (map->bus->read_flag_bit)
+		u8[0] |= 1 << map->bus->read_flag_bit;

Should be 1 << (map->bus->read_flag_bit - 1)

The code has the sematic I intended; you can debate if it's the best semantic and looking at the documentation again it's not entirely clear so at least that should be updated.

Well, then the spi regmap driver needs to use read_flag_bit = 7 instead of read_flag_bit = 8 and the BUG_ON should also be updated to read_flag_bit >= 8.

And the current code also disallows to use the first bit as the read_flag. So in my opinion using a one-based index here is a good idea.

Quoted 4 lines

BTW, the reason I put you on the CCs was the hope that you could test on OpenMoko (I have one but I've not got any kind of working environment set up for it). You're the nearest thing to a mainline maintainer for stuff like the pcf driver.

It's already on my todo list.

author
#12 lore raw

Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API

Quoted 2 lines · Lars-Peter Clausen

Well, then the spi regmap driver needs to use read_flag_bit = 7 instead of read_flag_bit = 8 and the BUG_ON should also be updated to read_flag_bit >= 8.

Bah, so it should.

Quoted 2 lines

And the current code also disallows to use the first bit as the read_flag. So in my opinion using a one-based index here is a good idea.

Disallowing that case was half the intention, the main issue being that if you're flagging in the bottom bit of the top byte on the bus then you'll be in the middle of the bitfield used by the register which is going to confuse things.

If something really needs to use the bottom bit we probably need to add a second form of mangling which uses the bottom of the register rather than the top, or allow buses to have bus specific register formatting.

Although come to think of it this doesn't actually help your cases at all as those are per-device settings and this is a per bus setting so I'm inclined to just revert back to the original code and say that for a first pass those devices are being sufficiently odd that we don't support them, we can add support as an extension later.

#13 lore raw

Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API

In reply to Mark Brown

On Wed, 2011-06-22 at 19:45 +0100, Mark Brown wrote:
[...]

Quoted 2 lines
drivers/regmap/regmap.c new file +0 -0

[...]

drivers/regmap/regmap.c line 48

Quoted 4 lines
drivers/regmap/regmap.c new file +4 -0
+static void regmap_format_4_12_write(struct regmap *map,
+				     unsigned int reg, unsigned int val)
+{
+	u16 *out = map->work_buf;

__be16 *out

drivers/regmap/regmap.c line 55

Quoted 7 lines
drivers/regmap/regmap.c new file +7 -0
+	*out = cpu_to_be16((reg << 12) | val);
+}
+
+static void regmap_format_7_9_write(struct regmap *map,
+				    unsigned int reg, unsigned int val)
+{
+	u16 *out = map->work_buf;

__be16 *out

drivers/regmap/regmap.c line 68

Quoted 13 lines
drivers/regmap/regmap.c new file +13 -0
+	*out = cpu_to_be16((reg << 9) | val);
+}
+
+static void regmap_format_8(void *buf, unsigned int val)
+{
+	u8 *b = buf;
+
+	b[0] = val;
+}
+
+static void regmap_format_16(void *buf, unsigned int val)
+{
+	u16 *b = buf;

__be16 *b

drivers/regmap/regmap.c line 82

Quoted 13 lines
drivers/regmap/regmap.c new file +13 -0
+	b[0] = cpu_to_be16(val);
+}
+
+static unsigned int regmap_parse_8(void *buf)
+{
+	u8 *b = buf;
+
+	return b[0];
+}
+
+static unsigned int regmap_parse_16(void *buf)
+{
+	u16 *b = buf;

__be16 *b

drivers/regmap/regmap.c line 86

Quoted 3 lines
drivers/regmap/regmap.c new file +3 -0
+	b[0] = be16_to_cpu(b[0]);
+
+	return b[0];

The assignment doesn't seem to be necessary and will irritate sparse, so:

	return be16_to_cpu(b[0]);

drivers/regmap/regmap.c line 90

Quoted 4 lines
drivers/regmap/regmap.c new file +4 -0
+}
+
+/**
+ * remap_init: Initialise register map

Missing 'g' in 'regmap_init'. And the first line's format must be:

regmap_init() - Initialise register map

(The other functions all have this problem as well.)

Quoted 2 lines

+ * dev: Device that will be interacted with
+ * config: Configuration for register map

Missing '@' before the parameter names.

[...]

Quoted 13 lines
drivers/regmap/regmap.c new file +13 -0
+static int _regmap_raw_write(struct regmap *map, unsigned int reg,
+			     const void *val, size_t val_len)
+{
+	void *buf;
+	int ret = -ENOTSUPP;
+	size_t len;
+
+	map->format.format_reg(map->work_buf, reg);
+
+	/* Try to do a gather write if we can */
+	if (map->bus->gather_write)
+		ret = map->bus->gather_write(map->dev, map->work_buf,
+					     map->format.reg_bytes,

drivers/regmap/regmap.c line 229

Quoted 10 lines
drivers/regmap/regmap.c new file +10 -0
+					     val, val_len);
+
+	/* Otherwise fall back on linearising by hand. */
+	if (ret == -ENOTSUPP) {
+		len = map->format.reg_bytes + val_len;
+		buf = kmalloc(len, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+		memcpy(buf, map->work_buf, map->format.reg_bytes);
+		memcpy(buf + map->format.reg_bytes, val, val_len);

[...]

If I understand correctly, this is usually called by _regmap_write() and val is already at the appropriate offset in work_buf. Is it not worth avoiding the allocation in that case?

General comments:

- All the functions must be called in process context, but this isn't documented.
- I think this could go in lib or drivers/base rather than in a new directory. The specific support for I2C and SPI would go in their existing directories.

Ben.

Signature · 2 lines
Ben Hutchings
If the facts do not conform to your theory, they must be disposed of.
author
#14 lore raw

Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API

Quoted 10 lines · Ben Hutchings

drivers/regmap/regmap.c line 86

Quoted 3 lines · Mark Brown
drivers/regmap/regmap.c new file +3 -0
+	b[0] = be16_to_cpu(b[0]);
+
+	return b[0];

The assignment doesn't seem to be necessary and will irritate sparse, so:

	return be16_to_cpu(b[0]);

sparse is silent on whatever the issue is here and the assignment is used (we both modify the buffer in place and return the result of the conversion to make life more convenient for users). Which isn't urgently tasteful but felt less tasteless than anything else I thought of. Data manging doesn't lend itself to elegance.

Quoted 4 lines
Quoted 2 lines

+ * dev: Device that will be interacted with
+ * config: Configuration for register map

Missing '@' before the parameter names.

You're looking at an old version of the code.

Quoted 4 lines
Quoted 4 lines
drivers/regmap/regmap.c new file +4 -0
+	/* Otherwise fall back on linearising by hand. */
+	if (ret == -ENOTSUPP) {
+		len = map->format.reg_bytes + val_len;
+		buf = kmalloc(len, GFP_KERNEL);
Quoted 8 lines

drivers/regmap/regmap.c line 229

Quoted 4 lines
drivers/regmap/regmap.c new file +4 -0
+		if (!buf)
+			return -ENOMEM;
+		memcpy(buf, map->work_buf, map->format.reg_bytes);
+		memcpy(buf + map->format.reg_bytes, val, val_len);

If I understand correctly, this is usually called by _regmap_write() and val is already at the appropriate offset in work_buf. Is it not worth avoiding the allocation in that case?

It's marginal, and given that it's vanishingly rare to hit this case (essentially all the interesting controllers for this API can do the gather write) I didn't feel it was worth it for a first pass. We can always do the optimization later if someone finds it important. I suspect any controller that hits the issue is going to be slow enough to dwarf the cost of the allocation with the I/O cost.

Quoted 4 lines

General comments:

- All the functions must be called in process context, but this isn't documented.

This should be obvious, none of the relevant buses can be interacted with in anything other than process context anyway as they need to sleep.

Quoted 3 lines

- I think this could go in lib or drivers/base rather than in a new directory. The specific support for I2C and SPI would go in their existing directories.

lib feels wrong, it's going to be peering into the drivers directory too much.

drivers/base is a good point, but then the code will grow quite a bit once we start layering cache support on top of it and until the code settles down I don't really want to have to deal with cross tree issues if we decide we need to update the interface to the bus code, that's definitely a first pass thing right now. The latter is the main thing that made me do things this way rather than pushing things into the buses, it's definitely not the finished product right now internally - the client API should be reasonably stable so not have these issues.

My inclination is to start off isolating the code until we've reached the point where things are more static. I suppose we could put it in a subdirectory of drivers/base in the meantime, though. Will have a think for the next repost.

Fixed everything else, thanks.

#15 lore raw
In reply to Mark Brown
Quoted 10 lines · Mark Brown

[This reposting of the series should address all the review comments on the series so far.]

Many I2C and SPI based devices implement register maps on top of the raw wire interface. This is generally done in a very standard fashion by devices, resulting in a lot of very similar code in drivers. For some time now ASoC has factored this code out into the subsystem but that's only useful for audio devices. The intention with this series is to generalise the concept so that it can be used throughout the kernel.

Quoted 5 lines

It's not intended that this be suitable for all devices - some devices have things that are hard to generalise like registers with variable size and paging which are hard to support genericly. At the minute the code is focused on the common cases. It is likely that the same code could be used with other buses with similar properties to I2C and SPI.

you should look at SMBus
there seems to be quite some code to share.
in particular i2c rtc devices seem to be using SMBus functions to get the exact same semantics you are providing here.

I just added support for such a device today, and it struck me, that this API was necessary.

i did not look into it very deeply. and still dont really understand the diff between SMBus and i2c...

Quoted 8 lines

Currently only physical I/O is handled, the intention is that once this support has been reviewed and merged the generic register cache code that ASoC includes will also be factored out too. For devices with read heavy workloads (especially those that need a lot of read/modify/write cycles) or which don't support read at all this can provide a useful performance improvement and for sparse register maps there's a lot of benefit in relatively complex cache code.

hopefully, the caching can be selective.
keep rtcs in mind. huge potential for throwing code away there ;)

Signature · 1 line
torben Hohn
author
#16 lore raw
Quoted 4 lines · torbenh

you should look at SMBus
there seems to be quite some code to share.
in particular i2c rtc devices seem to be using SMBus functions to get the exact same semantics you are providing here.

SMBus is an I2C subset with a definition for 8 bit registers layered onto it, pretty much.

Quoted 2 lines

I just added support for such a device today, and it struck me, that this API was necessary.

If you're only using SMBus then the I2C interface includes SMBus based register support which should do what you want. With the regmap API it ought to work as a device with 8 bit registers and 8 bit values.

#17 lore raw
Quoted 10 lines · Mark Brown
Quoted 4 lines · torbenh

you should look at SMBus
there seems to be quite some code to share.
in particular i2c rtc devices seem to be using SMBus functions to get the exact same semantics you are providing here.

SMBus is an I2C subset with a definition for 8 bit registers layered onto it, pretty much.

Quoted 6 lines
Quoted 2 lines

I just added support for such a device today, and it struck me, that this API was necessary.

If you're only using SMBus then the I2C interface includes SMBus based register support which should do what you want. With the regmap API it ought to work as a device with 8 bit registers and 8 bit values.

The kicker here is that quite a few hosts only support the smbus subset. How should that be handled here?

author
#18 lore raw
Quoted 8 lines · Jonathan Cameron
Quoted 3 lines · Mark Brown

If you're only using SMBus then the I2C interface includes SMBus based register support which should do what you want. With the regmap API it ought to work as a device with 8 bit registers and 8 bit values.

The kicker here is that quite a few hosts only support the smbus subset. How should that be handled here?

For 8x8 registers we *should* end up only using the SMBus subset so it should just work.