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:
137 goto err_map;
138 }
139 break;
140
141 case 8:
142 map->format.format_reg = regmap_format_8;
143 break;
144
145 case 16:
146 map->format.format_reg = regmap_format_16;
147 break;
148
149 default:
150 goto err_map;
151 }
152
153 switch (config->val_bits) {
154 case 8:
155 map->format.format_val = regmap_format_8;
156 map->format.parse_val = regmap_parse_8;
157 break;
158 case 16:
159 map->format.format_val = regmap_format_16;
160 map->format.parse_val = regmap_parse_16;
161 break;
162 }
163
164 if (!map->format.format_write &&
165 !(map->format.format_reg && map->format.format_val))
166 goto err_map;
167
168 map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
169 if (map->work_buf == NULL) {
170 ret = -ENOMEM;
171 goto err_bus;
172 }
173
174 return map;
175
176err_bus:
177 module_put(map->bus->owner);
178err_map:
179 kfree(map);
180err:
181 return ERR_PTR(ret);
182}
183EXPORT_SYMBOL_GPL(regmap_init);
184
185/**
186 * regmap_exit(): Free a previously allocated register map
187 */
188void regmap_exit(struct regmap *map)
189{
190 kfree(map->work_buf);
191 module_put(map->bus->owner);
192 kfree(map);
193}
194EXPORT_SYMBOL_GPL(regmap_exit);
195
196static int _regmap_raw_write(struct regmap *map, unsigned int reg,
197 const void *val, size_t val_len)
198{
199 void *buf;
200 int ret = -ENOTSUPP;
201 size_t len;
202
203 map->format.format_reg(map->work_buf, reg);
204
205 /* Try to do a gather write if we can */
206 if (map->bus->gather_write)
207 ret = map->bus->gather_write(map->dev, map->work_buf,
208 map->format.reg_bytes,
209 val, val_len);
210
211 /* Otherwise fall back on linearising by hand. */
212 if (ret == -ENOTSUPP) {
213 len = map->format.reg_bytes + val_len;
214 buf = kmalloc(len, GFP_KERNEL);
215 if (!buf)
216 return -ENOMEM;
217
218 memcpy(buf, map->work_buf, map->format.reg_bytes);
219 memcpy(buf + map->format.reg_bytes, val, val_len);
220 ret = map->bus->write(map->dev, buf, len);
221
222 kfree(buf);
223 }
224
225 return ret;
226}
227
228static int _regmap_write(struct regmap *map, unsigned int reg,
229 unsigned int val)
230{
231 BUG_ON(!map->format.format_write && !map->format.format_val);
232
233 if (map->format.format_write) {
234 map->format.format_write(map, reg, val);
235
236 return map->bus->write(map->dev, map->work_buf,
237 map->format.buf_size);
238 } else {
239 map->format.format_val(map->work_buf + map->format.reg_bytes,
240 val);
241 return _regmap_raw_write(map, reg,
242 map->work_buf + map->format.reg_bytes,
243 map->format.val_bytes);
244 }
245}
246
247/**
248 * regmap_write(): Write a value to a single register
249 *
250 * @map: Register map to write to
251 * @reg: Register to write to
252 * @val: Value to be written
253 *
254 * A value of zero will be returned on success, a negative errno will
255 * be returned in error cases.
256 */
257int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
258{
259 int ret;
260
261 mutex_lock(&map->lock);
262
263 ret = _regmap_write(map, reg, val);
264
265 mutex_unlock(&map->lock);
266
267 return ret;
268}
269EXPORT_SYMBOL_GPL(regmap_write);
270
271/**
272 * regmap_raw_write(): Write raw values to one or more registers
273 *
274 * @map: Register map to write to
275 * @reg: Initial register to write to
276 * @val: Block of data to be written, laid out for direct transmission to the
277 * device
278 * @val_len: Length of data pointed to by val.
279 *
280 * This function is intended to be used for things like firmware
281 * download where a large block of data needs to be transferred to the
282 * device. No formatting will be done on the data provided.
283 *
284 * A value of zero will be returned on success, a negative errno will
285 * be returned in error cases.
286 */
287int regmap_raw_write(struct regmap *map, unsigned int reg,
288 const void *val, size_t val_len)
289{
290 int ret;
291
292 mutex_lock(&map->lock);
293
294 ret = _regmap_raw_write(map, reg, val, val_len);
295
296 mutex_unlock(&map->lock);
297
298 return ret;
299}
300EXPORT_SYMBOL_GPL(regmap_raw_write);
301
302static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
303 unsigned int val_len)
304{
305 u8 *u8 = map->work_buf;
306 int ret;
307
308 map->format.format_reg(map->work_buf, reg);
309
310 /*
311 * Some buses flag reads by setting the high bits in the
312 * register addresss; since it's always the high bits for all
313 * current formats we can do this here rather than in
314 * formatting. This may break if we get interesting formats.
315 */
316 if (map->bus->read_flag_mask)
317 u8[0] |= map->bus->read_flag_mask;
318
319 ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
320 val, map->format.val_bytes);
321 if (ret != 0)
322 return ret;
323
324 return 0;
325}
326
327static int _regmap_read(struct regmap *map, unsigned int reg,
328 unsigned int *val)
329{
330 int ret;
331
332 if (!map->format.parse_val)
333 return -EINVAL;
334
335 ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
336 if (ret == 0)
337 *val = map->format.parse_val(map->work_buf);
338
339 return ret;
340}
341
342/**
343 * regmap_read(): Read a value from a single register
344 *
345 * @map: Register map to write to
346 * @reg: Register to be read from
347 * @val: Pointer to store read value
348 *
349 * A value of zero will be returned on success, a negative errno will
350 * be returned in error cases.
351 */
352int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
353{
354 int ret;
355
356 mutex_lock(&map->lock);
357
358 ret = _regmap_read(map, reg, val);
359
360 mutex_unlock(&map->lock);
361
362 return ret;
363}
364EXPORT_SYMBOL_GPL(regmap_read);
365
366/**
367 * regmap_raw_read(): Read raw data from the device
368 *
369 * @map: Register map to write to
370 * @reg: First register to be read from
371 * @val: Pointer to store read value
372 * @val_len: Size of data to read
373 *
374 * A value of zero will be returned on success, a negative errno will
375 * be returned in error cases.
376 */
377int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
378 size_t val_len)
379{
380 int ret;
381
382 mutex_lock(&map->lock);
383
384 ret = _regmap_raw_read(map, reg, val, val_len);
385
386 mutex_unlock(&map->lock);
387
388 return ret;
389}
390EXPORT_SYMBOL_GPL(regmap_raw_read);
391
392/**
393 * regmap_bulk_read(): Read multiple registers from the device
394 *
395 * @map: Register map to write to
396 * @reg: First register to be read from
397 * @val: Pointer to store read value, in native register size for device
398 * @val_count: Number of registers to read
399 *
400 * A value of zero will be returned on success, a negative errno will
401 * be returned in error cases.
402 */
403int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
404 size_t val_count)
405{
406 int ret, i;
407 size_t val_bytes = map->format.val_bytes;
408
409 if (!map->format.parse_val)
410 return -EINVAL;
411
412 ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
413 if (ret != 0)
414 return ret;
415
416 for (i = 0; i < val_count * val_bytes; i += val_bytes)
417 map->format.parse_val(val + i);
418
419 return 0;
420}
421EXPORT_SYMBOL_GPL(regmap_bulk_read);
422
423/**
424 * remap_update_bits: Perform a read/modify/write cycle on the register map
425 *
426 * @map: Register map to update
427 * @reg: Register to update
428 * @mask: Bitmask to change
429 * @val: New value for bitmask
430 *
431 * Returns zero for success, a negative number on error.
432 */
433int regmap_update_bits(struct regmap *map, unsigned int reg,
434 unsigned int mask, unsigned int val)
435{
436 int ret;
437 unsigned int tmp;
438
439 mutex_lock(&map->lock);
440
441 ret = _regmap_read(map, reg, &tmp);
442 if (ret != 0)
443 goto out;
444
445 tmp &= ~mask;
446 tmp |= val & mask;
447
448 ret = _regmap_write(map, reg, tmp);
449
450out:
451 mutex_unlock(&map->lock);
452
453 return ret;
454}
455EXPORT_SYMBOL_GPL(regmap_update_bits);
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
new file mode 100644
index 000000000000..a26c1d001401
--- /dev/null
+++ b/include/linux/regmap.h
@@ -0,0 +1,74 @@
1#ifndef __LINUX_REGMAP_H
2#define __LINUX_REGMAP_H
3
4/*
5 * Register map access API
6 *
7 * Copyright 2011 Wolfson Microelectronics plc
8 *
9 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#include <linux/device.h>
17#include <linux/list.h>
18#include <linux/module.h>
19
20struct regmap_config {
21 int reg_bits;
22 int val_bits;
23};
24
25typedef int (*regmap_hw_write)(struct device *dev, const void *data,
26 size_t count);
27typedef int (*regmap_hw_gather_write)(struct device *dev,
28 const void *reg, size_t reg_len,
29 const void *val, size_t val_len);
30typedef int (*regmap_hw_read)(struct device *dev,
31 const void *reg_buf, size_t reg_size,
32 void *val_buf, size_t val_size);
33
34/**
35 * Description of a hardware bus for the register map infrastructure.
36 *
37 * @list: Internal use.
38 * @type: Bus type, used to identify bus to be used for a device.
39 * @write: Write operation.
40 * @gather_write: Write operation with split register/value, return -ENOTSUPP
41 * if not implemented on a given device.
42 * @read: Read operation. Data is returned in the buffer used to transmit
43 * data.
44 * @owner: Module with the bus implementation, used to pin the implementation
45 * in memory.
46 * @read_flag_mask: Mask to be set in the top byte of the register when doing
47 * a read.
48 */
49struct regmap_bus {
50 struct list_head list;
51 struct bus_type *type;
52 regmap_hw_write write;
53 regmap_hw_gather_write gather_write;
54 regmap_hw_read read;
55 struct module *owner;
56 u8 read_flag_mask;
57};
58
59struct regmap *regmap_init(struct device *dev,
60 const struct regmap_bus *bus,
61 const struct regmap_config *config);
62void regmap_exit(struct regmap *map);
63int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
64int regmap_raw_write(struct regmap *map, unsigned int reg,
65 const void *val, size_t val_len);
66int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
67int regmap_raw_read(struct regmap *map, unsigned int reg,
68 void *val, size_t val_len);
69int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
70 size_t val_count);
71int regmap_update_bits(struct regmap *map, unsigned int reg,
72 unsigned int mask, unsigned int val);
73
74#endif