regmap: Generic I2C and SPI register map library
cover regmap: Generic I2C and SPI register map library
This is a version of a series I've been posting for most of this release cycle which abstracts out a bunch of widely duplicated code for doing register I/O on devices with control slow buses like I2C and SPI. As well as saving us code for the register I/O itself this should also make it easier to factor out further higher level code for this class of devices.
The only update in this version is that I've moved the bus-specific code back into the regmap directory.
I realise it's a bit late in the cycle but it'd be really good if we could get this merged in the next merge window, or accepted for about then so we can create a stable branch we can merge into subsystem trees in order to get drivers using this merged for 3.2. As there's only one user included the series it should be pretty low risk.
The code is in a subdirectory because I'm anticipating it'll grow quite a bit as we add facilities like fancy cache mechanisms on top of it.
A more verbose cover letter:
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, along with logging and diagnostic infrastructure for register maps. 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 bunch more drivers have been converted to use this framework, including the existing ASoC register I/O code, but due to various -next dependencies these don't apply easily so I've omitted them from this posting of the series - you can see them in the mailing list archives, they've not been updated during the review.
There's a git branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git for-next
I've also created a regmap-asoc branch there which merges current ASoC code with the regmap code.
The following changes since commit 620917de59eeb934b9f8cf35cc2d95c1ac8ed0fc:
Linux 3.0-rc7 (2011-07-11 16:51:52 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git for-next
Mark Brown (4):
regmap: Add generic non-memory mapped register access API
regmap: Add I2C bus support
regmap: Add SPI bus support
regulator: Convert tps65023 to use regmap API
MAINTAINERS | 9 + drivers/base/Kconfig | 2 + drivers/base/Makefile | 1 + drivers/base/regmap/Kconfig | 14 + drivers/base/regmap/Makefile | 3 + drivers/base/regmap/regmap-i2c.c | 115 ++++++++ drivers/base/regmap/regmap-spi.c | 73 +++++ drivers/base/regmap/regmap.c | 455 ++++++++++++++++++++++++++++++++ drivers/regulator/Kconfig | 1 + drivers/regulator/tps65023-regulator.c | 97 ++----- include/linux/regmap.h | 79 ++++++ 11 files changed, 779 insertions(+), 70 deletions(-) create mode 100644 drivers/base/regmap/Kconfig create mode 100644 drivers/base/regmap/Makefile create mode 100644 drivers/base/regmap/regmap-i2c.c create mode 100644 drivers/base/regmap/regmap-spi.c create mode 100644 drivers/base/regmap/regmap.c create mode 100644 include/linux/regmap.h
PATCH 1/4 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.
--- MAINTAINERS | 7 + drivers/base/Kconfig | 2 + drivers/base/Makefile | 1 + drivers/base/regmap/Kconfig | 6 + drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap.c | 455 ++++++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 74 +++++++ 7 files changed, 546 insertions(+), 0 deletions(-) create mode 100644 drivers/base/regmap/Kconfig create mode 100644 drivers/base/regmap/Makefile create mode 100644 drivers/base/regmap/regmap.c create mode 100644 include/linux/regmap.h
MAINTAINERS +7 -0
@@ -5313,6 +5313,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/base/regmap/ +F: include/linux/regmap.h + RFKILL M: Johannes Berg <[email protected]> L: [email protected]
drivers/base/Kconfig +2 -0
@@ -168,4 +168,6 @@ config SYS_HYPERVISOR bool default n +source "drivers/base/regmap/Kconfig" + endmenu
drivers/base/Makefile +1 -0
@@ -18,6 +18,7 @@ ifeq ($(CONFIG_SYSFS),y) obj-$(CONFIG_MODULES) += module.o endif obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o +obj-$(CONFIG_REGMAP) += regmap/ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
drivers/base/regmap/Kconfig new file +6 -0
@@ -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/base/regmap/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-$(CONFIG_REGMAP) += regmap.o
drivers/base/regmap/regmap.c new file +455 -0
455 lines not on this page · raw message
include/linux/regmap.h new file +74 -0
74 lines not on this page · raw message
Signature · 1 line
1.7.5.4
PATCH 2/4 regmap: Add I2C bus support
--- drivers/base/regmap/Kconfig | 4 + drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-i2c.c | 115 ++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 2 + 5 files changed, 123 insertions(+), 0 deletions(-) create mode 100644 drivers/base/regmap/regmap-i2c.c
drivers/base/regmap/Kconfig +4 -0
@@ -4,3 +4,7 @@ config REGMAP bool + +config REGMAP_I2C + tristate + default I2C
drivers/base/regmap/Makefile +1 -0
@@ -1 +1,2 @@ obj-$(CONFIG_REGMAP) += regmap.o +obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
drivers/base/regmap/regmap-i2c.c new file +115 -0
115 lines not on this page · raw message
include/linux/regmap.h +2 -0
@@ -59,6 +59,8 @@ struct regmap_bus {struct regmap *regmap_init (struct device *dev,const struct regmap_bus *bus,const struct regmap_config *config); +struct regmap *regmap_init_i2c (struct device *dev, +const struct regmap_config *config);void regmap_exit (struct regmap *map);int regmap_write (struct regmap *map,unsigned int reg,unsigned int val); int regmap_raw_write(struct regmap *map, unsigned int reg,
Signature · 1 line
1.7.5.4
PATCH 3/4 regmap: Add SPI bus support
In reply to Mark Brown--- drivers/base/regmap/Kconfig | 4 ++ drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-spi.c | 73 ++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 3 ++ 5 files changed, 82 insertions(+), 0 deletions(-) create mode 100644 drivers/base/regmap/regmap-spi.c
drivers/base/regmap/Kconfig +4 -0
@@ -8,3 +8,7 @@ config REGMAP config REGMAP_I2C tristate default I2C + +config REGMAP_SPI + tristate + default SPI_MASTER
drivers/base/regmap/Makefile +1 -0
@@ -1,2 +1,3 @@ obj-$(CONFIG_REGMAP) += regmap.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o +obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
drivers/base/regmap/regmap-spi.c new file +73 -0
73 lines not on this page · raw message
include/linux/regmap.h +3 -0
@@ -61,6 +61,9 @@ struct regmap *regmap_init(struct device *dev, const struct regmap_config *config);struct regmap *regmap_init_i2c (struct device *dev,const struct regmap_config *config); +struct regmap *regmap_init_spi (struct device *dev, +const struct regmap_config *config); +void regmap_exit (struct regmap *map);int regmap_write (struct regmap *map,unsigned int reg,unsigned int val); int regmap_raw_write(struct regmap *map, unsigned int reg,
Signature · 1 line
1.7.5.4
Re: [PATCH 3/4] regmap: Add SPI bus support
Quoted 3 lines · Mark Brown
Signed-off-by Mark Brown <[email protected]>Acked-by Liam Girdwood <[email protected]>Acked-by Wolfram Sang <[email protected]>
One comment below, but otherwise:
on the whole series.
include/linux/regmap.h struct regmap *regmap_init(struct device *dev, · line 66
Quoted 11 lines
include/linux/regmap.h +3
-0@@ -61,6 +61,9 @@ struct regmap *regmap_init(struct device *dev, const struct regmap_config *config);struct regmap *regmap_init_i2c (struct device *dev,const struct regmap_config *config); +struct regmap *regmap_init_spi (struct device *dev, +const struct regmap_config *config); +
regmap_init_i2c/spi should take an i2c_client and spi_device pointer respectively so it can be type checked.
Quoted 6 lines
include/linux/regmap.h +0
-0void regmap_exit (struct regmap *map);int regmap_write (struct regmap *map,unsigned int reg,unsigned int val); int regmap_raw_write(struct regmap *map, unsigned int reg,Signature · 1 line
1.7.5.4
Re: [PATCH 3/4] regmap: Add SPI bus support
Quoted 2 lines · Grant Likely
regmap_init_i2c/spi should take an
i2c_clientandspi_devicepointer respectively so it can be type checked.
Bah, you're right. That was me trying to do the update far too quickly. Fixed now, thanks for spotting. Though I still don't find this interface so pleasant to use with the multi-bus devices.
PATCH 4/4 regulator: Convert tps65023 to use regmap API
In reply to Mark Brown--- drivers/regulator/Kconfig | 1 + drivers/regulator/tps65023-regulator.c | 97 +++++++++----------------------- 2 files changed, 28 insertions(+), 70 deletions(-)
drivers/regulator/Kconfig +1 -0
@@ -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 -70
151 lines not on this page · raw message
Signature · 1 line
1.7.5.4
Re: [PATCH 1/4] regmap: Add generic non-memory mapped register access API
In reply to Mark BrownAt Mon, 18 Jul 2011 19:07:40 +0900,
Quoted 18 lines · Mark Brown
drivers/base/regmap/regmap.c new file +17
-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, + val, val_len); + +/* Otherwise fall back on linearising by hand. */ +if (ret == -ENOTSUPP ) {
drivers/base/regmap/regmap.c line 222
Quoted 10 lines
drivers/base/regmap/regmap.c new file +10
-0+ 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); + ret = map->bus->write (map->dev, buf, len); + +kfree (buf);
In most cases, val = map->work_buf + map->format.reg_bytes. How about a bit optimization?
if (ret == -ENOTSUPP) {
len = map->format.reg_bytes + val_len;
if (val == map->work_buf + map->format.reg_bytes)
ret = map->bus->write(map->dev, map->work_buf, len);
else {
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);
ret = map->bus->write(map->dev, buf, len);
kfree(buf);
}
}thanks,
Takashi
Re: [PATCH 1/4] regmap: Add generic non-memory mapped register access API
Quoted 4 lines · Takashi Iwai
In most cases, val =
map->work_buf+map->format.reg_bytes. How about a bit optimization?if (ret == -ENOTSUPP) {
Indeed, I'd had an additional optimization there in mind but it was to do the checking before we try the gather write rather than after since generally it'll be cheaper to do the pre-gathered write than the gathered write (sometimes noticably cheaper as some controllers have an appreciable overhead for starting transfers, especially at high data rates).
I mostly didn't implement it yet because I was trying to minimize the code complexity of the initial submission in order to aid review so was avoiding non-essential features.