aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-05-11 13:59:58 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-07-23 02:56:03 -0400
commitb83a313bf2520183641cf485d68cc273323597d2 (patch)
treee478834902bba3d4c774804d55a88c9b50bca2c0
parent620917de59eeb934b9f8cf35cc2d95c1ac8ed0fc (diff)
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. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@ti.com> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Acked-by: Wolfram Sang <w.sang@pengutronix.de> Acked-by: Grant Likely <grant.likely@secretlab.ca>
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/regmap/Kconfig6
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/regmap.c455
-rw-r--r--include/linux/regmap.h74
7 files changed, 546 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 187282da9213..b7eaf6393d36 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5313,6 +5313,13 @@ L: reiserfs-devel@vger.kernel.org
5313S: Supported 5313S: Supported
5314F: fs/reiserfs/ 5314F: fs/reiserfs/
5315 5315
5316REGISTER MAP ABSTRACTION
5317M: Mark Brown <broonie@opensource.wolfsonmicro.com>
5318T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
5319S: Supported
5320F: drivers/base/regmap/
5321F: include/linux/regmap.h
5322
5316RFKILL 5323RFKILL
5317M: Johannes Berg <johannes@sipsolutions.net> 5324M: Johannes Berg <johannes@sipsolutions.net>
5318L: linux-wireless@vger.kernel.org 5325L: linux-wireless@vger.kernel.org
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d57e8d0fb823..b605d01f5d45 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -168,4 +168,6 @@ config SYS_HYPERVISOR
168 bool 168 bool
169 default n 169 default n
170 170
171source "drivers/base/regmap/Kconfig"
172
171endmenu 173endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 4c5701c15f53..dd4f9b245fc1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -18,6 +18,7 @@ ifeq ($(CONFIG_SYSFS),y)
18obj-$(CONFIG_MODULES) += module.o 18obj-$(CONFIG_MODULES) += module.o
19endif 19endif
20obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o 20obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
21obj-$(CONFIG_REGMAP) += regmap/
21 22
22ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG 23ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
23 24
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
new file mode 100644
index 000000000000..fc0eb1d484dd
--- /dev/null
+++ b/drivers/base/regmap/Kconfig
@@ -0,0 +1,6 @@
1# Generic register map support. There are no user servicable options here,
2# this is an API intended to be used by other kernel subsystems. These
3# subsystems should select the appropriate symbols.
4
5config REGMAP
6 bool
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
new file mode 100644
index 000000000000..7532e13e0f00
--- /dev/null
+++ b/drivers/base/regmap/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_REGMAP) += regmap.o
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
new file mode 100644
index 000000000000..cf3565cae93d
--- /dev/null
+++ b/drivers/base/regmap/regmap.c
@@ -0,0 +1,455 @@
1/*
2 * Register map access API
3 *
4 * Copyright 2011 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/slab.h>
14#include <linux/module.h>
15#include <linux/mutex.h>
16#include <linux/err.h>
17
18#include <linux/regmap.h>
19
20struct regmap;
21
22struct regmap_format {
23 size_t buf_size;
24 size_t reg_bytes;
25 size_t val_bytes;
26 void (*format_write)(struct regmap *map,
27 unsigned int reg, unsigned int val);
28 void (*format_reg)(void *buf, unsigned int reg);
29 void (*format_val)(void *buf, unsigned int val);
30 unsigned int (*parse_val)(void *buf);
31};
32
33struct regmap {
34 struct mutex lock;
35
36 struct device *dev; /* Device we do I/O on */
37 void *work_buf; /* Scratch buffer used to format I/O */
38 struct regmap_format format; /* Buffer format */
39 const struct regmap_bus *bus;
40};
41
42static void regmap_format_4_12_write(struct regmap *map,
43 unsigned int reg, unsigned int val)
44{
45 __be16 *out = map->work_buf;
46 *out = cpu_to_be16((reg << 12) | val);
47}
48
49static void regmap_format_7_9_write(struct regmap *map,
50 unsigned int reg, unsigned int val)
51{
52 __be16 *out = map->work_buf;
53 *out = cpu_to_be16((reg << 9) | val);
54}
55
56static void regmap_format_8(void *buf, unsigned int val)
57{
58 u8 *b = buf;
59
60 b[0] = val;
61}
62
63static void regmap_format_16(void *buf, unsigned int val)
64{
65 __be16 *b = buf;
66
67 b[0] = cpu_to_be16(val);
68}
69
70static unsigned int regmap_parse_8(void *buf)
71{
72 u8 *b = buf;
73
74 return b[0];
75}
76
77static unsigned int regmap_parse_16(void *buf)
78{
79 __be16 *b = buf;
80
81 b[0] = be16_to_cpu(b[0]);
82
83 return b[0];
84}
85
86/**
87 * regmap_init(): Initialise register map
88 *
89 * @dev: Device that will be interacted with
90 * @bus: Bus-specific callbacks to use with device
91 * @config: Configuration for register map
92 *
93 * The return value will be an ERR_PTR() on error or a valid pointer to
94 * a struct regmap. This function should generally not be called
95 * directly, it should be called by bus-specific init functions.
96 */
97struct regmap *regmap_init(struct device *dev,
98 const struct regmap_bus *bus,
99 const struct regmap_config *config)
100{
101 struct regmap *map;
102 int ret = -EINVAL;
103
104 if (!bus || !config)
105 return NULL;
106
107 map = kzalloc(sizeof(*map), GFP_KERNEL);
108 if (map == NULL) {
109 ret = -ENOMEM;
110 goto err;
111 }
112
113 mutex_init(&map->lock);
114 map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
115 map->format.reg_bytes = config->reg_bits / 8;
116 map->format.val_bytes = config->val_bits / 8;
117 map->dev = dev;
118 map->bus = bus;
119
120 switch (config->reg_bits) {
121 case 4:
122 switch (config->val_bits) {
123 case 12:
124 map->format.format_write = regmap_format_4_12_write;
125 break;
126 default:
127 goto err_map;
128 }
129 break;
130
131 case 7:
132 switch (config->val_bits) {
133 case 9:
134 map->format.format_write = regmap_format_7_9_write;
135 break;
136 default:
<