Generic I2C and SPI register map library
Subsystems (6)
cover Generic I2C and SPI register map library
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.
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 | 112 ++++++++ drivers/regmap/regmap-spi.c | 75 +++++ drivers/regmap/regmap.c | 478 ++++++++++++++++++++++++++++++++ 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 | 75 +++++ include/sound/soc.h | 2 + sound/soc/Kconfig | 1 + sound/soc/soc-io.c | 316 ++------------------- 23 files changed, 920 insertions(+), 769 deletions(-)
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 | 478 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 75 ++++++++ 7 files changed, 570 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
@@ -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
@@ -126,4 +126,5 @@ source "drivers/hwspinlock/Kconfig" source "drivers/clocksource/Kconfig" +source "drivers/regmap/Kconfig" endmenu
drivers/Makefile +1 -0
@@ -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
@@ -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
@@ -0,0 +1,2 @@ +obj-$(CONFIG_REGMAP) += regmap.o +
drivers/regmap/regmap.c new file +478 -0
478 lines not on this page · raw message
include/linux/regmap.h new file +75 -0
75 lines not on this page · raw message
Signature · 1 line
1.7.5.4
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 | 112 +++++++++++++++++++++++++++++++++++++++++++ drivers/regmap/regmap.c | 4 +- 3 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 drivers/regmap/regmap-i2c.c
drivers/regmap/Makefile +1 -1
@@ -1,2 +1,2 @@ obj-$(CONFIG_REGMAP) += regmap.o - +obj-$(CONFIG_I2C) += regmap-i2c.o
drivers/regmap/regmap-i2c.c new file +112 -0
112 lines not on this page · raw message
drivers/regmap/regmap.c +2 -2
@@ -461,7 +461,7 @@ out: }EXPORT_SYMBOL_GPL (regmap_update_bits); -int regmap_add_bus (struct regmap_bus *bus) +void regmap_add_bus (struct regmap_bus *bus) {mutex_lock (®map_bus_lock);list_add (&bus->list, ®map_bus_list);
@@ -469,7 +469,7 @@ int regmap_add_bus(struct regmap_bus *bus) }EXPORT_SYMBOL_GPL (regmap_add_bus); -int regmap_del_bus (struct regmap_bus *bus) +void regmap_del_bus (struct regmap_bus *bus) {mutex_lock (®map_bus_lock);list_del (&bus->list);
Signature · 1 line
1.7.5.4
Re: [PATCH 2/8] regmap: Add I2C bus support
drivers/regmap/regmap-i2c.c line 14
Quoted 4 lines · Mark Brown
[...]
drivers/regmap/regmap-i2c.c new file +3
-0+ +#include <linux/regmap.h> +#include <linux/i2c.h>
#include <linux/init.h>
drivers/regmap/regmap-i2c.c line 72
Quoted 12 lines
[...]
drivers/regmap/regmap-i2c.c new file +11
-0+ +static int regmap_i2c_read (struct device *dev, +const void *reg,size_t reg_size, +void *val,size_t val_size) +{ +struct i2c_client *i2c =to_i2c_client (dev); +struct i2c_msg xfer[2 ]; +int ret; + +if (!i2c_check_functionality (i2c->adapter,I2C_FUNC_PROTOCOL_MANGLING )) +return -ENOTSUPP ;
You shouldn't need I2C_FUNC_PROTOCOL_MANGLING for reading.
drivers/regmap/regmap.c out:
Quoted 7 lines
[...]
drivers/regmap/regmap.c +0
-0@@ -461,7 +461,7 @@ out:
I guess this should be part of the first patch.
Re: [PATCH 2/8] regmap: Add I2C bus support
Quoted 7 lines · Lars-Peter Clausen
drivers/regmap/regmap-i2c.c line 14
Quoted 4 lines · Mark Brown
[...]
drivers/regmap/regmap-i2c.c new file +3
-0+ +#include <linux/regmap.h> +#include <linux/i2c.h> #include <
linux/init.h>
For...?
Quoted 8 lines
Quoted 7 lines
drivers/regmap/regmap-i2c.c new file +7
-0+static int regmap_i2c_read (struct device *dev, +const void *reg,size_t reg_size, +void *val,size_t val_size) +{ +struct i2c_client *i2c =to_i2c_client (dev); +struct i2c_msg xfer[2 ]; +int ret;
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_PROTOCOL_MANGLING)) + return -ENOTSUPP;You shouldn't need
I2C_FUNC_PROTOCOL_MANGLINGfor reading.
Hrm, yeah, probably not.
Re: [PATCH 2/8] regmap: Add I2C bus support
Quoted 11 lines · Mark Brown
Quoted 7 lines · Lars-Peter Clausen
drivers/regmap/regmap-i2c.c line 14
Quoted 4 lines · Mark Brown
[...]
drivers/regmap/regmap-i2c.c new file +3
-0+ +#include <linux/regmap.h> +#include <linux/i2c.h> #include <
linux/init.h>For...?
postcore_initcall and module_exit
PATCH 3/8 regmap: Add SPI bus support
In reply to Mark BrownWe 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
@@ -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
Re: [PATCH 3/8] regmap: Add SPI bus support
drivers/regmap/regmap-spi.c line 52
Quoted 9 lines · Mark Brown
[...]
drivers/regmap/regmap-spi.c new file +8
-0+ +static int regmap_spi_read (struct device *dev, +const void *reg,size_t reg_size, +void *val,size_t val_size) +{ +struct spi_device *spi =to_spi_device (dev); + +return spi_write_then_read (spi, reg, reg_size, val, val_size);
spi_write_then_read will use a bounce buffer internally, since we already have our own bounce buffer it is probably better to use the low-level spi interface directly in this case.
Re: [PATCH 3/8] regmap: Add SPI bus support
Quoted 8 lines · Lars-Peter Clausen
Quoted 5 lines · Mark Brown
drivers/regmap/regmap-spi.c new file +5
-0+static int regmap_spi_read (struct device *dev, +const void *reg,size_t reg_size, +void *val,size_t val_size) +{ +struct spi_device *spi =to_spi_device (dev);
Quoted 5 lines
drivers/regmap/regmap-spi.c line 52
Quoted 1 line
drivers/regmap/regmap-spi.c new file +1
-0+return spi_write_then_read (spi, reg, reg_size, val, val_size);
spi_write_then_readwill use a bounce buffer internally, since we already have our own bounce buffer it is probably better to use the low-level spi interface directly in this case.
I've got this horrible feeling that if we try that we'll discover that the reason the SPI API does this internally is just as valid here - if I remember correctly it's doing this due to restrictions on DMA from the stack and I'd strongly expect val to end up on the stack for registers. Or to look at it from the other point of view if we don't need the bounce buffers then why does spi_write_then_read() need them?
Re: [PATCH 3/8] regmap: Add SPI bus support
Quoted 15 lines · Mark Brown
Quoted 8 lines · Lars-Peter Clausen
Quoted 5 lines · Mark Brown
drivers/regmap/regmap-spi.c new file +5
-0+static int regmap_spi_read (struct device *dev, +const void *reg,size_t reg_size, +void *val,size_t val_size) +{ +struct spi_device *spi =to_spi_device (dev);Quoted 5 lines
drivers/regmap/regmap-spi.c line 52
Quoted 1 line
drivers/regmap/regmap-spi.c new file +1
-0+return spi_write_then_read (spi, reg, reg_size, val, val_size);
spi_write_then_readwill use a bounce buffer internally, since we already have our own bounce buffer it is probably better to use the low-level spi interface directly in this case.
Quoted 6 lines
I've got this horrible feeling that if we try that we'll discover that the reason the SPI API does this internally is just as valid here - if I remember correctly it's doing this due to restrictions on DMA from the stack and I'd strongly expect val to end up on the stack for registers. Or to look at it from the other point of view if we don't need the bounce buffers then why does
spi_write_then_read()need them?
hm, right, I overlooked that val could be on the stack. I though we were always using some kind of bounce buffer internally.
PATCH 4/8 ASoC: Use new register map API for ASoC generic physical I/O
In reply to Mark BrownRemove 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
@@ -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
@@ -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
PATCH 5/8 mfd: Convert WM831x to use regmap API
In reply to Mark BrownFactor 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
@@ -367,6 +367,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
@@ -378,6 +379,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
@@ -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
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
@@ -453,6 +453,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
@@ -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
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
@@ -466,6 +466,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
@@ -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
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
@@ -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
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
In reply to Mark BrownVery nice!
Quoted 30 lines
[...]
drivers/regmap/regmap.c new file +23
-0@@ -0,0 +1,478 @@ +/* +* Register map access API +* +* Copyright 2011 Wolfson Microelectronics plc +* +* Author: Mark Brown <[email protected]> +* +* 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/slab.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/err.h> + +#include <linux/regmap.h> + +struct regmap ; + +static DEFINE_MUTEX (regmap_bus_lock); +static LIST_HEAD (regmap_bus_list);
drivers/regmap/regmap.c line 33
Quoted 10 lines
drivers/regmap/regmap.c new file +10
-0+ +struct regmap_format { +size_t buf_size; +size_t reg_bytes; +size_t val_bytes; +void (*format_write)(struct regmap *map, +unsigned int reg,unsigned int val); +void (*format_reg)(void *buf,unsigned int reg); +void (*format_val)(void *buf,unsigned int val); +unsigned int (*parse_val)(void *buf);
const void *buf. It probably also makes sense to pass the regmap to all callbacks, so we can write generic format/parser functions which use information for example from the regmap_format.
drivers/regmap/regmap.c line 42
Quoted 9 lines
drivers/regmap/regmap.c new file +9
-0+}; + +struct regmap { +struct mutex lock; + +struct device *dev;/* Device we do I/O on */ +void *work_buf;/* Scratch buffer used to format I/O */ +struct regmap_format format;/* Buffer format */ +struct regmap_bus *bus;
const struct regmap_bus
Quoted 5 lines
drivers/regmap/regmap.c new file +5
-0+}; + +static void regmap_format_4_12_write (struct regmap *map, +unsigned int reg,unsigned int val) +{
drivers/regmap/regmap.c line 57
Quoted 10 lines
drivers/regmap/regmap.c new file +10
-0+u16 *out = map->work_buf; + *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; + *out =cpu_to_be16 ((reg <<9 ) | val); +}
It would make sense to keep val_bits around and implement these two generically:
*out = cpu_to_be16((reg << map->format.val_bits) | val);
drivers/regmap/regmap.c line 96
Quoted 11 lines
[...]
drivers/regmap/regmap.c new file +10
-0+/** +* remap_init: Initialise register map +* +* 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. +*/ +struct regmap *regmap_init (struct device *dev,struct regmap_config *config)
regmap_alloc would in my opinion be a better name.
Quoted 7 lines
[...]
drivers/regmap/regmap.c new file +6
-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 324
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 bit in the +* register addresss; since it's always the high bit 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_in_reg) + u8[0 ] |=0x80 ;
This is rather specific. Making this a per device mask or bit offset, would make more sense in my opinion. I have for example one SPI codec device which uses the 7th bit to indicate a read. And I also have devices on a custom bus, which needs to set the upper bit to indicate a write, so a mask for both write and read would be good.
Quoted 21 lines
drivers/regmap/regmap.c new file +20
-0+ + ret = map->bus->read (map->dev, map->work_buf, map->format.reg_bytes, + val, map->format.val_bytes); +if (ret !=0 ) +return ret; + +return 0 ; +} + +/** +* regmap_bulk_read: Read multiple registers from the device +* +* @map: Register map to write to +* @reg: First register to be read from +* @val: Pointer to store read value, in native register size for device +* @val_count: Number of registers to read +* +* A value of zero will be returned on success, a negative errno will +* be returned in error cases. +*/
drivers/regmap/regmap.c line 419
Quoted 10 lines
drivers/regmap/regmap.c new file +10
-0+int regmap_bulk_read (struct regmap *map,unsigned int reg,void *val, +size_t val_count) +{ +int ret, i; +size_t val_bytes = map->format.val_bytes; + +if (!map->format.parse_val) +return -EINVAL ; + + ret =regmap_raw_read (map, reg, val, val_bytes);
val_bytes * val_count
drivers/regmap/regmap.c line 424
Quoted 5 lines
drivers/regmap/regmap.c new file +5
-0+if (ret !=0 ) +return ret; + +for (i =0 ; i < val_count * val_bytes; i += val_bytes) + map->format.parse_val (val + i);
This doesn't make sense. parse_val returns the parsed value, but doesn't modify the parsed data. It would make sense to make the interface similar to regmap_read and make the returned values a unsigned integer array and use a bounce buffer for reading them from the device.
Quoted 19 lines
drivers/regmap/regmap.c new file +5
-0+ +return 0 ; +} +EXPORT_SYMBOL_GPL (regmap_bulk_read); +include/linux/regmap.h new file +7
-0@@ -0,0 +1,75 @@ +#ifndef __LINUX_REGMAP_H +#define __LINUX_REGMAP_H + +/* +* Register map access API +* +* Copyright 2011 Wolfson Microelectronics plc
include/linux/regmap.h line 17
Quoted 10 lines
include/linux/regmap.h new file +10
-0+* +* Author: Mark Brown <[email protected]> +* +* 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/device.h> +#include <linux/list.h>
#include <linux/module.h>
include/linux/regmap.h line 21
Quoted 4 lines
include/linux/regmap.h new file +4
-0+ +struct regmap_config { +int reg_bits; +int val_bits;
size_t for both?
include/linux/regmap.h line 59
Quoted 5 lines
include/linux/regmap.h new file +4
-0+}; + + +struct regmap *regmap_init (struct device *dev,struct regmap_config *config);
const struct regmap_config
include/linux/regmap.h line 68
Quoted 9 lines
include/linux/regmap.h new file +9
-0+void regmap_free (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, +const void *val,size_t val_len); +int regmap_read (struct regmap *map,unsigned int reg,unsigned int *val); +int regmap_raw_read (struct regmap *map,unsigned int reg, +void *val,size_t val_len); +int regmap_bulk_read (struct regmap *map,unsigned int reg,void *val, +size_t val_count);
What about bulk_write?
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
Quoted 5 lines · Lars-Peter Clausen
drivers/regmap/regmap.c line 33
Quoted 3 lines
drivers/regmap/regmap.c new file +3
-0+void (*format_reg)(void *buf,unsigned int reg); +void (*format_val)(void *buf,unsigned int val); +unsigned int (*parse_val)(void *buf);const void *buf. It probably also makes sense to pass the regmap to all
Hrm, yeah.
Quoted 2 lines
callbacks, so we can write generic format/parser functions which use information for example from the
regmap_format.
I'd rather add it when we need it, it's not much work to refactor and it's entirely in this file. Right now I like being sure I know what knows about what bit of data mangling.
Quoted 15 lines
drivers/regmap/regmap.c line 57
Quoted 13 lines
drivers/regmap/regmap.c new file +12
-0+static void regmap_format_4_12_write (struct regmap *map, +unsigned int reg,unsigned int val) +{ +u16 *out = map->work_buf; + *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; + *out =cpu_to_be16 ((reg <<9 ) | val); +}It would make sense to keep
val_bitsaround and implement these two generically:
Quoted 1 line
*out = cpu_to_be16((reg << map->format.val_bits) | val);
I'm not sure it's worth it for the two cases we know about, and as with passing the map into these I like keeping the byte oriented assumption in the interfaces as much as possible as it makes things easier to think about.
Quoted 3 lines
Quoted 1 line
+struct regmap *regmap_init(struct device *dev, struct
regmap_config*config)
regmap_allocwould in my opinion be a better name.
I like init, especially considering the plan to add cache support as there's more work in setting that up once you start doing the advanced caches.
Quoted 4 lines
Quoted 4 lines
drivers/regmap/regmap.c new file +4
-0+/* +* Some buses flag reads by setting the high bit in the +* register addresss; since it's always the high bit for all +* current formats we can do this here rather than in
Quoted 8 lines
drivers/regmap/regmap.c line 324
Quoted 4 lines
drivers/regmap/regmap.c new file +4
-0+* formatting. This may break if we get interesting formats. +*/ +if (map->bus->read_flag_in_reg) + u8[0 ] |=0x80 ;This is rather specific. Making this a per device mask or bit offset, would make more sense in my opinion. I have for example one SPI codec device which uses the 7th bit to indicate a read. And I also have devices on a custom bus,
Can you say what device this is? I'm just going on the devices we've seen in the kernel so far here... Still easy enough to do.
Quoted 2 lines
which needs to set the upper bit to indicate a write, so a mask for both write and read would be good.
Sure, though for stuff like this I'd say just implement them when we need them.
Quoted 4 lines
drivers/regmap/regmap.c line 424
Quoted 2 lines
drivers/regmap/regmap.c new file +2
-0+for (i =0 ; i < val_count * val_bytes; i += val_bytes) + map->format.parse_val (val + i);This doesn't make sense.
parse_valreturns the parsed value, but doesn't modify
Oh, meh. It used to.
Quoted 3 lines
the parsed data. It would make sense to make the interface similar to
regmap_readand make the returned values a unsigned integer array and use a bounce buffer for reading them from the device.
I thought about that but what it actually ends up meaning for most of the current users is that they then need to either implement their own bounce buffer or do some cross tree updates to switch from using the native type to ints. Neither seemed terribly appealing and it did seem reasonable to expect devices to know how big their own registers are.
Quoted 5 lines
include/linux/regmap.h line 21
Quoted 3 lines
include/linux/regmap.h new file +3
-0+struct regmap_config { +int reg_bits; +int val_bits;
size_tfor both?
It doesn't seem particularly appropriate as we're working with a bit count not the usual byte count where size_t gets used and I can't see it ever making any difference.
Quoted 4 lines
include/linux/regmap.h line 68
Quoted 2 lines
include/linux/regmap.h new file +2
-0+int regmap_bulk_read (struct regmap *map,unsigned int reg,void *val, +size_t val_count);What about
bulk_write?
It's painful to implement efficiently due to the need to mangle the data on the way down, and most of the time if you're doing a bulk operation it's because you want it to be efficient. I'm punting it until someone really wants it so we can have a separate think about what makes sense.
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
Quoted 18 lines · Mark Brown
Quoted 16 lines
Quoted 4 lines
drivers/regmap/regmap.c new file +3
-0+static void regmap_format_4_12_write (struct regmap *map, +unsigned int reg,unsigned int val) +{drivers/regmap/regmap.c line 57
Quoted 10 lines
drivers/regmap/regmap.c new file +9
-0+u16 *out = map->work_buf; + *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; + *out =cpu_to_be16 ((reg <<9 ) | val); +}It would make sense to keep
val_bitsaround and implement these two generically:Quoted 1 line
*out = cpu_to_be16((reg << map->format.val_bits) | val);
Quoted 4 lines
I'm not sure it's worth it for the two cases we know about, and as with passing the map into these I like keeping the byte oriented assumption in the interfaces as much as possible as it makes things easier to think about.
Hm, ok I guess we can wait with this until there are actually other similar formats which follow this scheme.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
+struct regmap *regmap_init(struct device *dev, struct
regmap_config*config)
regmap_allocwould in my opinion be a better name.I like init, especially considering the plan to add cache support as there's more work in setting that up once you start doing the advanced caches.
If you take a look at other kernel apis _alloc is usually used if the structure is allocated (and initialized) inside the function and _init is used when the function initializes an already existing structure. And it also matches better with regmap_free.
Quoted 14 lines
Quoted 13 lines
drivers/regmap/regmap.c line 324
Quoted 9 lines
drivers/regmap/regmap.c new file +8
-0+/* +* Some buses flag reads by setting the high bit in the +* register addresss; since it's always the high bit 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_in_reg) + u8[0 ] |=0x80 ;This is rather specific. Making this a per device mask or bit offset, would make more sense in my opinion. I have for example one SPI codec device which uses the 7th bit to indicate a read. And I also have devices on a custom bus,
Quoted 3 lines
Can you say what device this is? I'm just going on the devices we've seen in the kernel so far here... Still easy enough to do.
The ad1836 for example really only uses 10 bits for data instead of 12. The 11th bit is reserved and the 12th bit is used to indicate whether it is an read or write. Though since gaps between register and data are not supported data was made 12 bits wide and the upper 2 bits are always set to 0.
The adav801, which is going to be submitted upstream soon, uses a similar scheme. First seven bits are register address, then 1 bit which indicates read/write and then 8 bits data. We are currently using the same trick here and made data 9 bits wide.
Quoted 9 lines
Quoted 5 lines
include/linux/regmap.h line 21
Quoted 3 lines
include/linux/regmap.h new file +3
-0+struct regmap_config { +int reg_bits; +int val_bits;
size_tfor both?It doesn't seem particularly appropriate as we're working with a bit count not the usual byte count where
size_tgets used and I can't see it ever making any difference.
I suggested it because the byte count in the regmap_format struct is size_t and it calculated from the bit count.
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
Quoted 9 lines · Lars-Peter Clausen
Quoted 3 lines · Mark Brown
I like init, especially considering the plan to add cache support as there's more work in setting that up once you start doing the advanced caches.
If you take a look at other kernel apis
_allocis usually used if the structure is allocated (and initialized) inside the function and_initis used when the function initializes an already existing structure. And it also matches better
That more applies to split alloc/init models - here there's a single operation that does both. To me alloc() generally means that it just allocates a structure and leaves initialization still to be done while.
Quoted 1 line
with
regmap_free.
That's true.
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
Quoted 11 lines · Mark Brown
Quoted 9 lines · Lars-Peter Clausen
Quoted 3 lines · Mark Brown
I like init, especially considering the plan to add cache support as there's more work in setting that up once you start doing the advanced caches.
If you take a look at other kernel apis
_allocis usually used if the structure is allocated (and initialized) inside the function and_initis used when the function initializes an already existing structure. And it also matches better
Quoted 7 lines
That more applies to split alloc/init models - here there's a single operation that does both. To me
alloc()generally means that it just allocates a structure and leaves initialization still to be done while.Quoted 1 line
with
regmap_free.That's true.
In the soc-cache code we use _init and _exit respectively. Might be worth considering instead of _free?
Thanks,
Dimitris
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
Quoted 9 lines · Dimitris Papastamos
Quoted 5 lines · Mark Brown
Quoted 1 line · Lars-Peter Clausen
with
regmap_free.That's true.
In the soc-cache code we use
_initand_exitrespectively. Might be worth considering instead of_free?
Err, yes - that's what I said :)
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
In reply to Mark Browndrivers/regmap/regmap.c line 208
Quoted 6 lines · Mark Brown
drivers/regmap/regmap.c new file +6
-0+static int _regmap_raw_write (struct regmap *map,unsigned int reg, +const void *val,size_t val_len) +{ +void *buf; +int ret = -ENOTSUPP ; +int len;
size_t for len?
Thanks,
Dimitris
Re: [PATCH 1/8] regmap: Add generic non-memory mapped register access API
Quoted 10 lines · Dimitris Papastamos
drivers/regmap/regmap.c line 208
Quoted 6 lines · Mark Brown
drivers/regmap/regmap.c new file +6
-0+static int _regmap_raw_write (struct regmap *map,unsigned int reg, +const void *val,size_t val_len) +{ +void *buf; +int ret = -ENOTSUPP ; +int len;
size_tfor len?
Yes.