aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-04-04 17:48:31 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-06 05:47:35 -0400
commit45f5ff8107a845854b1d1812ab1d9c5541f08b4d (patch)
treed0d532ba060e3f3db9c7e376d90d1fcb34035c04 /drivers/base/regmap
parentbacdbe077342ecc9e7b3e374cc5a41995116706a (diff)
regmap: add MMIO bus support
This is a basic memory-mapped-IO bus for regmap. It has the following features and limitations: * Registers themselves may be 8, 16, 32, or 64-bit. 64-bit is only supported on 64-bit platforms. * Register offsets are limited to precisely 32-bit. * IO is performed using readl/writel, with no provision for using the __raw_readl or readl_relaxed variants. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r--drivers/base/regmap/Kconfig3
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/regmap-mmio.c217
3 files changed, 221 insertions, 0 deletions
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 0f6c7fb418e..9ef0a5326f1 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -14,5 +14,8 @@ config REGMAP_I2C
14config REGMAP_SPI 14config REGMAP_SPI
15 tristate 15 tristate
16 16
17config REGMAP_MMIO
18 tristate
19
17config REGMAP_IRQ 20config REGMAP_IRQ
18 bool 21 bool
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index defd57963c8..5e75d1b683e 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -3,4 +3,5 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
3obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o 3obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
4obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o 4obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
5obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o 5obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
6obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
6obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o 7obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
new file mode 100644
index 00000000000..1a7b5ee11ab
--- /dev/null
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -0,0 +1,217 @@
1/*
2 * Register map access API - MMIO support
3 *
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/err.h>
20#include <linux/init.h>
21#include <linux/io.h>
22#include <linux/module.h>
23#include <linux/regmap.h>
24#include <linux/slab.h>
25
26struct regmap_mmio_context {
27 void __iomem *regs;
28 unsigned val_bytes;
29};
30
31static int regmap_mmio_gather_write(void *context,
32 const void *reg, size_t reg_size,
33 const void *val, size_t val_size)
34{
35 struct regmap_mmio_context *ctx = context;
36 u32 offset;
37
38 if (reg_size != 4)
39 return -EIO;
40 if (val_size % ctx->val_bytes)
41 return -EIO;
42
43 offset = be32_to_cpup(reg);
44
45 while (val_size) {
46 switch (ctx->val_bytes) {
47 case 1:
48 writeb(*(u8 *)val, ctx->regs + offset);
49 break;
50 case 2:
51 writew(be16_to_cpup(val), ctx->regs + offset);
52 break;
53 case 4:
54 writel(be32_to_cpup(val), ctx->regs + offset);
55 break;
56#ifdef CONFIG_64BIT
57 case 8:
58 writeq(be64_to_cpup(val), ctx->regs + offset);
59 break;
60#endif
61 default:
62 /* Should be caught by regmap_mmio_check_config */
63 return -EIO;
64 }
65 val_size -= ctx->val_bytes;
66 val += ctx->val_bytes;
67 offset += ctx->val_bytes;
68 }
69
70 return 0;
71}
72
73static int regmap_mmio_write(void *context, const void *data, size_t count)
74{
75 if (count < 4)
76 return -EIO;
77 return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
78}
79
80static int regmap_mmio_read(void *context,
81 const void *reg, size_t reg_size,
82 void *val, size_t val_size)
83{
84 struct regmap_mmio_context *ctx = context;
85 u32 offset;
86
87 if (reg_size != 4)
88 return -EIO;
89 if (val_size % ctx->val_bytes)
90 return -EIO;
91
92 offset = be32_to_cpup(reg);
93
94 while (val_size) {
95 switch (ctx->val_bytes) {
96 case 1:
97 *(u8 *)val = readb(ctx->regs + offset);
98 break;
99 case 2:
100 *(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
101 break;
102 case 4:
103 *(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
104 break;
105#ifdef CONFIG_64BIT
106 case 8:
107 *(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
108 break;
109#endif
110 default:
111 /* Should be caught by regmap_mmio_check_config */
112 return -EIO;
113 }
114 val_size -= ctx->val_bytes;
115 val += ctx->val_bytes;
116 offset += ctx->val_bytes;
117 }
118
119 return 0;
120}
121
122static void regmap_mmio_free_context(void *context)
123{
124 kfree(context);
125}
126
127static struct regmap_bus regmap_mmio = {
128 .fast_io = true,
129 .write = regmap_mmio_write,
130 .gather_write = regmap_mmio_gather_write,
131 .read = regmap_mmio_read,
132 .free_context = regmap_mmio_free_context,
133};
134
135struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
136 const struct regmap_config *config)
137{
138 struct regmap_mmio_context *ctx;
139
140 if (config->reg_bits != 32)
141 return ERR_PTR(-EINVAL);
142
143 if (config->pad_bits)
144 return ERR_PTR(-EINVAL);
145
146 switch (config->val_bits) {
147 case 8:
148 case 16:
149 case 32:
150#ifdef CONFIG_64BIT
151 case 64:
152#endif
153 break;
154 default:
155 return ERR_PTR(-EINVAL);
156 }
157
158 ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
159 if (!ctx)
160 return ERR_PTR(-ENOMEM);
161
162 ctx->regs = regs;
163 ctx->val_bytes = config->val_bits / 8;
164
165 return ctx;
166}
167
168/**
169 * regmap_init_mmio(): Initialise register map
170 *
171 * @dev: Device that will be interacted with
172 * @regs: Pointer to memory-mapped IO region
173 * @config: Configuration for register map
174 *
175 * The return value will be an ERR_PTR() on error or a valid pointer to
176 * a struct regmap.
177 */
178struct regmap *regmap_init_mmio(struct device *dev,
179 void __iomem *regs,
180 const struct regmap_config *config)
181{
182 struct regmap_mmio_context *ctx;
183
184 ctx = regmap_mmio_gen_context(regs, config);
185 if (IS_ERR(ctx))
186 return ERR_CAST(ctx);
187
188 return regmap_init(dev, &regmap_mmio, ctx, config);
189}
190EXPORT_SYMBOL_GPL(regmap_init_mmio);
191
192/**
193 * devm_regmap_init_mmio(): Initialise managed register map
194 *
195 * @dev: Device that will be interacted with
196 * @regs: Pointer to memory-mapped IO region
197 * @config: Configuration for register map
198 *
199 * The return value will be an ERR_PTR() on error or a valid pointer
200 * to a struct regmap. The regmap will be automatically freed by the
201 * device management code.
202 */
203struct regmap *devm_regmap_init_mmio(struct device *dev,
204 void __iomem *regs,
205 const struct regmap_config *config)
206{
207 struct regmap_mmio_context *ctx;
208
209 ctx = regmap_mmio_gen_context(regs, config);
210 if (IS_ERR(ctx))
211 return ERR_CAST(ctx);
212
213 return devm_regmap_init(dev, &regmap_mmio, ctx, config);
214}
215EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
216
217MODULE_LICENSE("GPL v2");