diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-08 16:35:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-08 16:35:24 -0500 |
commit | b7d845f8825b058b80e76320f573505afbf4a1fc (patch) | |
tree | dc66dec44b489723427c9c4a9a92ef6e9f17c55b /drivers | |
parent | 2943c833222ef87c111ee0c6b7b8519ad2983e99 (diff) | |
parent | 0a92815db789bd5a922d882826cf710f9b0b9d85 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (36 commits)
mfd: Clearing events requires event registers to be writable for da9052-core
mfd: Fix annotations in da9052-core
gpiolib: Mark da9052 driver broken
mfd: Declare da9052_regmap_config for the bus drivers
MFD: DA9052/53 MFD core module add SPI support v2
MFD: DA9052/53 MFD core module
regmap: Add irq_base accessor to regmap_irq
regmap: Allow drivers to reinitialise the register cache at runtime
regmap: Add trace event for successful cache reads
regmap: Allow regmap_update_bits() users to detect changes
regmap: Report if we actually handled an interrupt in regmap-irq
regmap: Fix rbtreee build when not using debugfs
regmap: Provide debugfs dump of the rbtree cache data
regmap: Do debugfs init before cache init
regmap: Suppress noop writes in regmap_update_bits()
regmap: Remove indexed cache type
regmap: Drop check whether a register is readable in regcache_read
regmap: Properly round cache_word_size
regmap: Add support for 10/14 register formating
regmap: Try cached read before checking if a hardware read is possible
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/regmap/Kconfig | 3 | ||||
-rw-r--r-- | drivers/base/regmap/Makefile | 4 | ||||
-rw-r--r-- | drivers/base/regmap/internal.h | 6 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-indexed.c | 64 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-lzo.c | 21 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-rbtree.c | 61 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 87 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 302 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 179 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 28 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 5 | ||||
-rw-r--r-- | drivers/mfd/da9052-core.c | 694 | ||||
-rw-r--r-- | drivers/mfd/da9052-i2c.c | 140 | ||||
-rw-r--r-- | drivers/mfd/da9052-spi.c | 115 |
15 files changed, 1557 insertions, 154 deletions
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 2fc6a66f39a4..0f6c7fb418e8 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig | |||
@@ -13,3 +13,6 @@ config REGMAP_I2C | |||
13 | 13 | ||
14 | config REGMAP_SPI | 14 | config REGMAP_SPI |
15 | tristate | 15 | tristate |
16 | |||
17 | config REGMAP_IRQ | ||
18 | bool | ||
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 0573c8a9dacb..defd57963c84 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile | |||
@@ -1,4 +1,6 @@ | |||
1 | obj-$(CONFIG_REGMAP) += regmap.o regcache.o regcache-indexed.o regcache-rbtree.o regcache-lzo.o | 1 | obj-$(CONFIG_REGMAP) += regmap.o regcache.o |
2 | obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o | ||
2 | obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o | 3 | obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o |
3 | obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o | 4 | obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o |
4 | obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o | 5 | obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o |
6 | obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o | ||
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 348ff02eb93e..1a02b7537c8b 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -74,6 +74,7 @@ struct regmap { | |||
74 | struct reg_default *reg_defaults; | 74 | struct reg_default *reg_defaults; |
75 | const void *reg_defaults_raw; | 75 | const void *reg_defaults_raw; |
76 | void *cache; | 76 | void *cache; |
77 | bool cache_dirty; | ||
77 | }; | 78 | }; |
78 | 79 | ||
79 | struct regcache_ops { | 80 | struct regcache_ops { |
@@ -105,7 +106,7 @@ static inline void regmap_debugfs_exit(struct regmap *map) { } | |||
105 | #endif | 106 | #endif |
106 | 107 | ||
107 | /* regcache core declarations */ | 108 | /* regcache core declarations */ |
108 | int regcache_init(struct regmap *map); | 109 | int regcache_init(struct regmap *map, const struct regmap_config *config); |
109 | void regcache_exit(struct regmap *map); | 110 | void regcache_exit(struct regmap *map); |
110 | int regcache_read(struct regmap *map, | 111 | int regcache_read(struct regmap *map, |
111 | unsigned int reg, unsigned int *value); | 112 | unsigned int reg, unsigned int *value); |
@@ -118,10 +119,7 @@ unsigned int regcache_get_val(const void *base, unsigned int idx, | |||
118 | bool regcache_set_val(void *base, unsigned int idx, | 119 | bool regcache_set_val(void *base, unsigned int idx, |
119 | unsigned int val, unsigned int word_size); | 120 | unsigned int val, unsigned int word_size); |
120 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); | 121 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); |
121 | int regcache_insert_reg(struct regmap *map, unsigned int reg, | ||
122 | unsigned int val); | ||
123 | 122 | ||
124 | extern struct regcache_ops regcache_indexed_ops; | ||
125 | extern struct regcache_ops regcache_rbtree_ops; | 123 | extern struct regcache_ops regcache_rbtree_ops; |
126 | extern struct regcache_ops regcache_lzo_ops; | 124 | extern struct regcache_ops regcache_lzo_ops; |
127 | 125 | ||
diff --git a/drivers/base/regmap/regcache-indexed.c b/drivers/base/regmap/regcache-indexed.c deleted file mode 100644 index 507731ad8ec1..000000000000 --- a/drivers/base/regmap/regcache-indexed.c +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | /* | ||
2 | * Register cache access API - indexed caching support | ||
3 | * | ||
4 | * Copyright 2011 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Dimitris Papastamos <dp@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 | |||
15 | #include "internal.h" | ||
16 | |||
17 | static int regcache_indexed_read(struct regmap *map, unsigned int reg, | ||
18 | unsigned int *value) | ||
19 | { | ||
20 | int ret; | ||
21 | |||
22 | ret = regcache_lookup_reg(map, reg); | ||
23 | if (ret >= 0) | ||
24 | *value = map->reg_defaults[ret].def; | ||
25 | |||
26 | return ret; | ||
27 | } | ||
28 | |||
29 | static int regcache_indexed_write(struct regmap *map, unsigned int reg, | ||
30 | unsigned int value) | ||
31 | { | ||
32 | int ret; | ||
33 | |||
34 | ret = regcache_lookup_reg(map, reg); | ||
35 | if (ret < 0) | ||
36 | return regcache_insert_reg(map, reg, value); | ||
37 | map->reg_defaults[ret].def = value; | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int regcache_indexed_sync(struct regmap *map) | ||
42 | { | ||
43 | unsigned int i; | ||
44 | int ret; | ||
45 | |||
46 | for (i = 0; i < map->num_reg_defaults; i++) { | ||
47 | ret = _regmap_write(map, map->reg_defaults[i].reg, | ||
48 | map->reg_defaults[i].def); | ||
49 | if (ret < 0) | ||
50 | return ret; | ||
51 | dev_dbg(map->dev, "Synced register %#x, value %#x\n", | ||
52 | map->reg_defaults[i].reg, | ||
53 | map->reg_defaults[i].def); | ||
54 | } | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | struct regcache_ops regcache_indexed_ops = { | ||
59 | .type = REGCACHE_INDEXED, | ||
60 | .name = "indexed", | ||
61 | .read = regcache_indexed_read, | ||
62 | .write = regcache_indexed_write, | ||
63 | .sync = regcache_indexed_sync | ||
64 | }; | ||
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c index 066aeece3626..b7d16143edeb 100644 --- a/drivers/base/regmap/regcache-lzo.c +++ b/drivers/base/regmap/regcache-lzo.c | |||
@@ -15,6 +15,8 @@ | |||
15 | 15 | ||
16 | #include "internal.h" | 16 | #include "internal.h" |
17 | 17 | ||
18 | static int regcache_lzo_exit(struct regmap *map); | ||
19 | |||
18 | struct regcache_lzo_ctx { | 20 | struct regcache_lzo_ctx { |
19 | void *wmem; | 21 | void *wmem; |
20 | void *dst; | 22 | void *dst; |
@@ -27,7 +29,7 @@ struct regcache_lzo_ctx { | |||
27 | }; | 29 | }; |
28 | 30 | ||
29 | #define LZO_BLOCK_NUM 8 | 31 | #define LZO_BLOCK_NUM 8 |
30 | static int regcache_lzo_block_count(void) | 32 | static int regcache_lzo_block_count(struct regmap *map) |
31 | { | 33 | { |
32 | return LZO_BLOCK_NUM; | 34 | return LZO_BLOCK_NUM; |
33 | } | 35 | } |
@@ -106,19 +108,22 @@ static inline int regcache_lzo_get_blkindex(struct regmap *map, | |||
106 | unsigned int reg) | 108 | unsigned int reg) |
107 | { | 109 | { |
108 | return (reg * map->cache_word_size) / | 110 | return (reg * map->cache_word_size) / |
109 | DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()); | 111 | DIV_ROUND_UP(map->cache_size_raw, |
112 | regcache_lzo_block_count(map)); | ||
110 | } | 113 | } |
111 | 114 | ||
112 | static inline int regcache_lzo_get_blkpos(struct regmap *map, | 115 | static inline int regcache_lzo_get_blkpos(struct regmap *map, |
113 | unsigned int reg) | 116 | unsigned int reg) |
114 | { | 117 | { |
115 | return reg % (DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()) / | 118 | return reg % (DIV_ROUND_UP(map->cache_size_raw, |
119 | regcache_lzo_block_count(map)) / | ||
116 | map->cache_word_size); | 120 | map->cache_word_size); |
117 | } | 121 | } |
118 | 122 | ||
119 | static inline int regcache_lzo_get_blksize(struct regmap *map) | 123 | static inline int regcache_lzo_get_blksize(struct regmap *map) |
120 | { | 124 | { |
121 | return DIV_ROUND_UP(map->cache_size_raw, regcache_lzo_block_count()); | 125 | return DIV_ROUND_UP(map->cache_size_raw, |
126 | regcache_lzo_block_count(map)); | ||
122 | } | 127 | } |
123 | 128 | ||
124 | static int regcache_lzo_init(struct regmap *map) | 129 | static int regcache_lzo_init(struct regmap *map) |
@@ -131,7 +136,7 @@ static int regcache_lzo_init(struct regmap *map) | |||
131 | 136 | ||
132 | ret = 0; | 137 | ret = 0; |
133 | 138 | ||
134 | blkcount = regcache_lzo_block_count(); | 139 | blkcount = regcache_lzo_block_count(map); |
135 | map->cache = kzalloc(blkcount * sizeof *lzo_blocks, | 140 | map->cache = kzalloc(blkcount * sizeof *lzo_blocks, |
136 | GFP_KERNEL); | 141 | GFP_KERNEL); |
137 | if (!map->cache) | 142 | if (!map->cache) |
@@ -190,7 +195,7 @@ static int regcache_lzo_init(struct regmap *map) | |||
190 | 195 | ||
191 | return 0; | 196 | return 0; |
192 | err: | 197 | err: |
193 | regcache_exit(map); | 198 | regcache_lzo_exit(map); |
194 | return ret; | 199 | return ret; |
195 | } | 200 | } |
196 | 201 | ||
@@ -203,7 +208,7 @@ static int regcache_lzo_exit(struct regmap *map) | |||
203 | if (!lzo_blocks) | 208 | if (!lzo_blocks) |
204 | return 0; | 209 | return 0; |
205 | 210 | ||
206 | blkcount = regcache_lzo_block_count(); | 211 | blkcount = regcache_lzo_block_count(map); |
207 | /* | 212 | /* |
208 | * the pointer to the bitmap used for syncing the cache | 213 | * the pointer to the bitmap used for syncing the cache |
209 | * is shared amongst all lzo_blocks. Ensure it is freed | 214 | * is shared amongst all lzo_blocks. Ensure it is freed |
@@ -351,7 +356,7 @@ static int regcache_lzo_sync(struct regmap *map) | |||
351 | } | 356 | } |
352 | 357 | ||
353 | struct regcache_ops regcache_lzo_ops = { | 358 | struct regcache_ops regcache_lzo_ops = { |
354 | .type = REGCACHE_LZO, | 359 | .type = REGCACHE_COMPRESSED, |
355 | .name = "lzo", | 360 | .name = "lzo", |
356 | .init = regcache_lzo_init, | 361 | .init = regcache_lzo_init, |
357 | .exit = regcache_lzo_exit, | 362 | .exit = regcache_lzo_exit, |
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index e31498499b0f..32620c4f1683 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c | |||
@@ -11,12 +11,15 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/debugfs.h> | ||
14 | #include <linux/rbtree.h> | 15 | #include <linux/rbtree.h> |
16 | #include <linux/seq_file.h> | ||
15 | 17 | ||
16 | #include "internal.h" | 18 | #include "internal.h" |
17 | 19 | ||
18 | static int regcache_rbtree_write(struct regmap *map, unsigned int reg, | 20 | static int regcache_rbtree_write(struct regmap *map, unsigned int reg, |
19 | unsigned int value); | 21 | unsigned int value); |
22 | static int regcache_rbtree_exit(struct regmap *map); | ||
20 | 23 | ||
21 | struct regcache_rbtree_node { | 24 | struct regcache_rbtree_node { |
22 | /* the actual rbtree node holding this block */ | 25 | /* the actual rbtree node holding this block */ |
@@ -124,6 +127,60 @@ static int regcache_rbtree_insert(struct rb_root *root, | |||
124 | return 1; | 127 | return 1; |
125 | } | 128 | } |
126 | 129 | ||
130 | #ifdef CONFIG_DEBUG_FS | ||
131 | static int rbtree_show(struct seq_file *s, void *ignored) | ||
132 | { | ||
133 | struct regmap *map = s->private; | ||
134 | struct regcache_rbtree_ctx *rbtree_ctx = map->cache; | ||
135 | struct regcache_rbtree_node *n; | ||
136 | struct rb_node *node; | ||
137 | unsigned int base, top; | ||
138 | int nodes = 0; | ||
139 | int registers = 0; | ||
140 | |||
141 | mutex_lock(&map->lock); | ||
142 | |||
143 | for (node = rb_first(&rbtree_ctx->root); node != NULL; | ||
144 | node = rb_next(node)) { | ||
145 | n = container_of(node, struct regcache_rbtree_node, node); | ||
146 | |||
147 | regcache_rbtree_get_base_top_reg(n, &base, &top); | ||
148 | seq_printf(s, "%x-%x (%d)\n", base, top, top - base + 1); | ||
149 | |||
150 | nodes++; | ||
151 | registers += top - base + 1; | ||
152 | } | ||
153 | |||
154 | seq_printf(s, "%d nodes, %d registers, average %d registers\n", | ||
155 | nodes, registers, registers / nodes); | ||
156 | |||
157 | mutex_unlock(&map->lock); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int rbtree_open(struct inode *inode, struct file *file) | ||
163 | { | ||
164 | return single_open(file, rbtree_show, inode->i_private); | ||
165 | } | ||
166 | |||
167 | static const struct file_operations rbtree_fops = { | ||
168 | .open = rbtree_open, | ||
169 | .read = seq_read, | ||
170 | .llseek = seq_lseek, | ||
171 | .release = single_release, | ||
172 | }; | ||
173 | |||
174 | static void rbtree_debugfs_init(struct regmap *map) | ||
175 | { | ||
176 | debugfs_create_file("rbtree", 0400, map->debugfs, map, &rbtree_fops); | ||
177 | } | ||
178 | #else | ||
179 | static void rbtree_debugfs_init(struct regmap *map) | ||
180 | { | ||
181 | } | ||
182 | #endif | ||
183 | |||
127 | static int regcache_rbtree_init(struct regmap *map) | 184 | static int regcache_rbtree_init(struct regmap *map) |
128 | { | 185 | { |
129 | struct regcache_rbtree_ctx *rbtree_ctx; | 186 | struct regcache_rbtree_ctx *rbtree_ctx; |
@@ -146,10 +203,12 @@ static int regcache_rbtree_init(struct regmap *map) | |||
146 | goto err; | 203 | goto err; |
147 | } | 204 | } |
148 | 205 | ||
206 | rbtree_debugfs_init(map); | ||
207 | |||
149 | return 0; | 208 | return 0; |
150 | 209 | ||
151 | err: | 210 | err: |
152 | regcache_exit(map); | 211 | regcache_rbtree_exit(map); |
153 | return ret; | 212 | return ret; |
154 | } | 213 | } |
155 | 214 | ||
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 666f6f5011dc..1ead66186b7c 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include "internal.h" | 19 | #include "internal.h" |
20 | 20 | ||
21 | static const struct regcache_ops *cache_types[] = { | 21 | static const struct regcache_ops *cache_types[] = { |
22 | ®cache_indexed_ops, | ||
23 | ®cache_rbtree_ops, | 22 | ®cache_rbtree_ops, |
24 | ®cache_lzo_ops, | 23 | ®cache_lzo_ops, |
25 | }; | 24 | }; |
@@ -61,8 +60,10 @@ static int regcache_hw_init(struct regmap *map) | |||
61 | 60 | ||
62 | map->reg_defaults = kmalloc(count * sizeof(struct reg_default), | 61 | map->reg_defaults = kmalloc(count * sizeof(struct reg_default), |
63 | GFP_KERNEL); | 62 | GFP_KERNEL); |
64 | if (!map->reg_defaults) | 63 | if (!map->reg_defaults) { |
65 | return -ENOMEM; | 64 | ret = -ENOMEM; |
65 | goto err_free; | ||
66 | } | ||
66 | 67 | ||
67 | /* fill the reg_defaults */ | 68 | /* fill the reg_defaults */ |
68 | map->num_reg_defaults = count; | 69 | map->num_reg_defaults = count; |
@@ -77,9 +78,15 @@ static int regcache_hw_init(struct regmap *map) | |||
77 | } | 78 | } |
78 | 79 | ||
79 | return 0; | 80 | return 0; |
81 | |||
82 | err_free: | ||
83 | if (map->cache_free) | ||
84 | kfree(map->reg_defaults_raw); | ||
85 | |||
86 | return ret; | ||
80 | } | 87 | } |
81 | 88 | ||
82 | int regcache_init(struct regmap *map) | 89 | int regcache_init(struct regmap *map, const struct regmap_config *config) |
83 | { | 90 | { |
84 | int ret; | 91 | int ret; |
85 | int i; | 92 | int i; |
@@ -100,6 +107,12 @@ int regcache_init(struct regmap *map) | |||
100 | return -EINVAL; | 107 | return -EINVAL; |
101 | } | 108 | } |
102 | 109 | ||
110 | map->num_reg_defaults = config->num_reg_defaults; | ||
111 | map->num_reg_defaults_raw = config->num_reg_defaults_raw; | ||
112 | map->reg_defaults_raw = config->reg_defaults_raw; | ||
113 | map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); | ||
114 | map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; | ||
115 | |||
103 | map->cache = NULL; | 116 | map->cache = NULL; |
104 | map->cache_ops = cache_types[i]; | 117 | map->cache_ops = cache_types[i]; |
105 | 118 | ||
@@ -112,10 +125,10 @@ int regcache_init(struct regmap *map) | |||
112 | * won't vanish from under us. We'll need to make | 125 | * won't vanish from under us. We'll need to make |
113 | * a copy of it. | 126 | * a copy of it. |
114 | */ | 127 | */ |
115 | if (map->reg_defaults) { | 128 | if (config->reg_defaults) { |
116 | if (!map->num_reg_defaults) | 129 | if (!map->num_reg_defaults) |
117 | return -EINVAL; | 130 | return -EINVAL; |
118 | tmp_buf = kmemdup(map->reg_defaults, map->num_reg_defaults * | 131 | tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults * |
119 | sizeof(struct reg_default), GFP_KERNEL); | 132 | sizeof(struct reg_default), GFP_KERNEL); |
120 | if (!tmp_buf) | 133 | if (!tmp_buf) |
121 | return -ENOMEM; | 134 | return -ENOMEM; |
@@ -136,9 +149,18 @@ int regcache_init(struct regmap *map) | |||
136 | if (map->cache_ops->init) { | 149 | if (map->cache_ops->init) { |
137 | dev_dbg(map->dev, "Initializing %s cache\n", | 150 | dev_dbg(map->dev, "Initializing %s cache\n", |
138 | map->cache_ops->name); | 151 | map->cache_ops->name); |
139 | return map->cache_ops->init(map); | 152 | ret = map->cache_ops->init(map); |
153 | if (ret) | ||
154 | goto err_free; | ||
140 | } | 155 | } |
141 | return 0; | 156 | return 0; |
157 | |||
158 | err_free: | ||
159 | kfree(map->reg_defaults); | ||
160 | if (map->cache_free) | ||
161 | kfree(map->reg_defaults_raw); | ||
162 | |||
163 | return ret; | ||
142 | } | 164 | } |
143 | 165 | ||
144 | void regcache_exit(struct regmap *map) | 166 | void regcache_exit(struct regmap *map) |
@@ -171,16 +193,21 @@ void regcache_exit(struct regmap *map) | |||
171 | int regcache_read(struct regmap *map, | 193 | int regcache_read(struct regmap *map, |
172 | unsigned int reg, unsigned int *value) | 194 | unsigned int reg, unsigned int *value) |
173 | { | 195 | { |
196 | int ret; | ||
197 | |||
174 | if (map->cache_type == REGCACHE_NONE) | 198 | if (map->cache_type == REGCACHE_NONE) |
175 | return -ENOSYS; | 199 | return -ENOSYS; |
176 | 200 | ||
177 | BUG_ON(!map->cache_ops); | 201 | BUG_ON(!map->cache_ops); |
178 | 202 | ||
179 | if (!regmap_readable(map, reg)) | 203 | if (!regmap_volatile(map, reg)) { |
180 | return -EIO; | 204 | ret = map->cache_ops->read(map, reg, value); |
181 | 205 | ||
182 | if (!regmap_volatile(map, reg)) | 206 | if (ret == 0) |
183 | return map->cache_ops->read(map, reg, value); | 207 | trace_regmap_reg_read_cache(map->dev, reg, *value); |
208 | |||
209 | return ret; | ||
210 | } | ||
184 | 211 | ||
185 | return -EINVAL; | 212 | return -EINVAL; |
186 | } | 213 | } |
@@ -241,6 +268,8 @@ int regcache_sync(struct regmap *map) | |||
241 | map->cache_ops->name); | 268 | map->cache_ops->name); |
242 | name = map->cache_ops->name; | 269 | name = map->cache_ops->name; |
243 | trace_regcache_sync(map->dev, name, "start"); | 270 | trace_regcache_sync(map->dev, name, "start"); |
271 | if (!map->cache_dirty) | ||
272 | goto out; | ||
244 | if (map->cache_ops->sync) { | 273 | if (map->cache_ops->sync) { |
245 | ret = map->cache_ops->sync(map); | 274 | ret = map->cache_ops->sync(map); |
246 | } else { | 275 | } else { |
@@ -291,6 +320,23 @@ void regcache_cache_only(struct regmap *map, bool enable) | |||
291 | EXPORT_SYMBOL_GPL(regcache_cache_only); | 320 | EXPORT_SYMBOL_GPL(regcache_cache_only); |
292 | 321 | ||
293 | /** | 322 | /** |
323 | * regcache_mark_dirty: Mark the register cache as dirty | ||
324 | * | ||
325 | * @map: map to mark | ||
326 | * | ||
327 | * Mark the register cache as dirty, for example due to the device | ||
328 | * having been powered down for suspend. If the cache is not marked | ||
329 | * as dirty then the cache sync will be suppressed. | ||
330 | */ | ||
331 | void regcache_mark_dirty(struct regmap *map) | ||
332 | { | ||
333 | mutex_lock(&map->lock); | ||
334 | map->cache_dirty = true; | ||
335 | mutex_unlock(&map->lock); | ||
336 | } | ||
337 | EXPORT_SYMBOL_GPL(regcache_mark_dirty); | ||
338 | |||
339 | /** | ||
294 | * regcache_cache_bypass: Put a register map into cache bypass mode | 340 | * regcache_cache_bypass: Put a register map into cache bypass mode |
295 | * | 341 | * |
296 | * @map: map to configure | 342 | * @map: map to configure |
@@ -381,22 +427,3 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg) | |||
381 | else | 427 | else |
382 | return -ENOENT; | 428 | return -ENOENT; |
383 | } | 429 | } |
384 | |||
385 | int regcache_insert_reg(struct regmap *map, unsigned int reg, | ||
386 | unsigned int val) | ||
387 | { | ||
388 | void *tmp; | ||
389 | |||
390 | tmp = krealloc(map->reg_defaults, | ||
391 | (map->num_reg_defaults + 1) * sizeof(struct reg_default), | ||
392 | GFP_KERNEL); | ||
393 | if (!tmp) | ||
394 | return -ENOMEM; | ||
395 | map->reg_defaults = tmp; | ||
396 | map->num_reg_defaults++; | ||
397 | map->reg_defaults[map->num_reg_defaults - 1].reg = reg; | ||
398 | map->reg_defaults[map->num_reg_defaults - 1].def = val; | ||
399 | sort(map->reg_defaults, map->num_reg_defaults, | ||
400 | sizeof(struct reg_default), regcache_default_cmp, NULL); | ||
401 | return 0; | ||
402 | } | ||
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c new file mode 100644 index 000000000000..428836fc5835 --- /dev/null +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * regmap based irq_chip | ||
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/export.h> | ||
14 | #include <linux/regmap.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include "internal.h" | ||
20 | |||
21 | struct regmap_irq_chip_data { | ||
22 | struct mutex lock; | ||
23 | |||
24 | struct regmap *map; | ||
25 | struct regmap_irq_chip *chip; | ||
26 | |||
27 | int irq_base; | ||
28 | |||
29 | void *status_reg_buf; | ||
30 | unsigned int *status_buf; | ||
31 | unsigned int *mask_buf; | ||
32 | unsigned int *mask_buf_def; | ||
33 | }; | ||
34 | |||
35 | static inline const | ||
36 | struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data, | ||
37 | int irq) | ||
38 | { | ||
39 | return &data->chip->irqs[irq - data->irq_base]; | ||
40 | } | ||
41 | |||
42 | static void regmap_irq_lock(struct irq_data *data) | ||
43 | { | ||
44 | struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); | ||
45 | |||
46 | mutex_lock(&d->lock); | ||
47 | } | ||
48 | |||
49 | static void regmap_irq_sync_unlock(struct irq_data *data) | ||
50 | { | ||
51 | struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); | ||
52 | int i, ret; | ||
53 | |||
54 | /* | ||
55 | * If there's been a change in the mask write it back to the | ||
56 | * hardware. We rely on the use of the regmap core cache to | ||
57 | * suppress pointless writes. | ||
58 | */ | ||
59 | for (i = 0; i < d->chip->num_regs; i++) { | ||
60 | ret = regmap_update_bits(d->map, d->chip->mask_base + i, | ||
61 | d->mask_buf_def[i], d->mask_buf[i]); | ||
62 | if (ret != 0) | ||
63 | dev_err(d->map->dev, "Failed to sync masks in %x\n", | ||
64 | d->chip->mask_base + i); | ||
65 | } | ||
66 | |||
67 | mutex_unlock(&d->lock); | ||
68 | } | ||
69 | |||
70 | static void regmap_irq_enable(struct irq_data *data) | ||
71 | { | ||
72 | struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); | ||
73 | const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq); | ||
74 | |||
75 | d->mask_buf[irq_data->reg_offset] &= ~irq_data->mask; | ||
76 | } | ||
77 | |||
78 | static void regmap_irq_disable(struct irq_data *data) | ||
79 | { | ||
80 | struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); | ||
81 | const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq); | ||
82 | |||
83 | d->mask_buf[irq_data->reg_offset] |= irq_data->mask; | ||
84 | } | ||
85 | |||
86 | static struct irq_chip regmap_irq_chip = { | ||
87 | .name = "regmap", | ||
88 | .irq_bus_lock = regmap_irq_lock, | ||
89 | .irq_bus_sync_unlock = regmap_irq_sync_unlock, | ||
90 | .irq_disable = regmap_irq_disable, | ||
91 | .irq_enable = regmap_irq_enable, | ||
92 | }; | ||
93 | |||
94 | static irqreturn_t regmap_irq_thread(int irq, void *d) | ||
95 | { | ||
96 | struct regmap_irq_chip_data *data = d; | ||
97 | struct regmap_irq_chip *chip = data->chip; | ||
98 | struct regmap *map = data->map; | ||
99 | int ret, i; | ||
100 | u8 *buf8 = data->status_reg_buf; | ||
101 | u16 *buf16 = data->status_reg_buf; | ||
102 | u32 *buf32 = data->status_reg_buf; | ||
103 | bool handled = false; | ||
104 | |||
105 | ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf, | ||
106 | chip->num_regs); | ||
107 | if (ret != 0) { | ||
108 | dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); | ||
109 | return IRQ_NONE; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Ignore masked IRQs and ack if we need to; we ack early so | ||
114 | * there is no race between handling and acknowleding the | ||
115 | * interrupt. We assume that typically few of the interrupts | ||
116 | * will fire simultaneously so don't worry about overhead from | ||
117 | * doing a write per register. | ||
118 | */ | ||
119 | for (i = 0; i < data->chip->num_regs; i++) { | ||
120 | switch (map->format.val_bytes) { | ||
121 | case 1: | ||
122 | data->status_buf[i] = buf8[i]; | ||
123 | break; | ||
124 | case 2: | ||
125 | data->status_buf[i] = buf16[i]; | ||
126 | break; | ||
127 | case 4: | ||
128 | data->status_buf[i] = buf32[i]; | ||
129 | break; | ||
130 | default: | ||
131 | BUG(); | ||
132 | return IRQ_NONE; | ||
133 | } | ||
134 | |||
135 | data->status_buf[i] &= ~data->mask_buf[i]; | ||
136 | |||
137 | if (data->status_buf[i] && chip->ack_base) { | ||
138 | ret = regmap_write(map, chip->ack_base + i, | ||
139 | data->status_buf[i]); | ||
140 | if (ret != 0) | ||
141 | dev_err(map->dev, "Failed to ack 0x%x: %d\n", | ||
142 | chip->ack_base + i, ret); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | for (i = 0; i < chip->num_irqs; i++) { | ||
147 | if (data->status_buf[chip->irqs[i].reg_offset] & | ||
148 | chip->irqs[i].mask) { | ||
149 | handle_nested_irq(data->irq_base + i); | ||
150 | handled = true; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | if (handled) | ||
155 | return IRQ_HANDLED; | ||
156 | else | ||
157 | return IRQ_NONE; | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * regmap_add_irq_chip(): Use standard regmap IRQ controller handling | ||
162 | * | ||
163 | * map: The regmap for the device. | ||
164 | * irq: The IRQ the device uses to signal interrupts | ||
165 | * irq_flags: The IRQF_ flags to use for the primary interrupt. | ||
166 | * chip: Configuration for the interrupt controller. | ||
167 | * data: Runtime data structure for the controller, allocated on success | ||
168 | * | ||
169 | * Returns 0 on success or an errno on failure. | ||
170 | * | ||
171 | * In order for this to be efficient the chip really should use a | ||
172 | * register cache. The chip driver is responsible for restoring the | ||
173 | * register values used by the IRQ controller over suspend and resume. | ||
174 | */ | ||
175 | int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | ||
176 | int irq_base, struct regmap_irq_chip *chip, | ||
177 | struct regmap_irq_chip_data **data) | ||
178 | { | ||
179 | struct regmap_irq_chip_data *d; | ||
180 | int cur_irq, i; | ||
181 | int ret = -ENOMEM; | ||
182 | |||
183 | irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0); | ||
184 | if (irq_base < 0) { | ||
185 | dev_warn(map->dev, "Failed to allocate IRQs: %d\n", | ||
186 | irq_base); | ||
187 | return irq_base; | ||
188 | } | ||
189 | |||
190 | d = kzalloc(sizeof(*d), GFP_KERNEL); | ||
191 | if (!d) | ||
192 | return -ENOMEM; | ||
193 | |||
194 | d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, | ||
195 | GFP_KERNEL); | ||
196 | if (!d->status_buf) | ||
197 | goto err_alloc; | ||
198 | |||
199 | d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs, | ||
200 | GFP_KERNEL); | ||
201 | if (!d->status_reg_buf) | ||
202 | goto err_alloc; | ||
203 | |||
204 | d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, | ||
205 | GFP_KERNEL); | ||
206 | if (!d->mask_buf) | ||
207 | goto err_alloc; | ||
208 | |||
209 | d->mask_buf_def = kzalloc(sizeof(unsigned int) * chip->num_regs, | ||
210 | GFP_KERNEL); | ||
211 | if (!d->mask_buf_def) | ||
212 | goto err_alloc; | ||
213 | |||
214 | d->map = map; | ||
215 | d->chip = chip; | ||
216 | d->irq_base = irq_base; | ||
217 | mutex_init(&d->lock); | ||
218 | |||
219 | for (i = 0; i < chip->num_irqs; i++) | ||
220 | d->mask_buf_def[chip->irqs[i].reg_offset] | ||
221 | |= chip->irqs[i].mask; | ||
222 | |||
223 | /* Mask all the interrupts by default */ | ||
224 | for (i = 0; i < chip->num_regs; i++) { | ||
225 | d->mask_buf[i] = d->mask_buf_def[i]; | ||
226 | ret = regmap_write(map, chip->mask_base + i, d->mask_buf[i]); | ||
227 | if (ret != 0) { | ||
228 | dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", | ||
229 | chip->mask_base + i, ret); | ||
230 | goto err_alloc; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /* Register them with genirq */ | ||
235 | for (cur_irq = irq_base; | ||
236 | cur_irq < chip->num_irqs + irq_base; | ||
237 | cur_irq++) { | ||
238 | irq_set_chip_data(cur_irq, d); | ||
239 | irq_set_chip_and_handler(cur_irq, ®map_irq_chip, | ||
240 | handle_edge_irq); | ||
241 | irq_set_nested_thread(cur_irq, 1); | ||
242 | |||
243 | /* ARM needs us to explicitly flag the IRQ as valid | ||
244 | * and will set them noprobe when we do so. */ | ||
245 | #ifdef CONFIG_ARM | ||
246 | set_irq_flags(cur_irq, IRQF_VALID); | ||
247 | #else | ||
248 | irq_set_noprobe(cur_irq); | ||
249 | #endif | ||
250 | } | ||
251 | |||
252 | ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags, | ||
253 | chip->name, d); | ||
254 | if (ret != 0) { | ||
255 | dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret); | ||
256 | goto err_alloc; | ||
257 | } | ||
258 | |||
259 | return 0; | ||
260 | |||
261 | err_alloc: | ||
262 | kfree(d->mask_buf_def); | ||
263 | kfree(d->mask_buf); | ||
264 | kfree(d->status_reg_buf); | ||
265 | kfree(d->status_buf); | ||
266 | kfree(d); | ||
267 | return ret; | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(regmap_add_irq_chip); | ||
270 | |||
271 | /** | ||
272 | * regmap_del_irq_chip(): Stop interrupt handling for a regmap IRQ chip | ||
273 | * | ||
274 | * @irq: Primary IRQ for the device | ||
275 | * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() | ||
276 | */ | ||
277 | void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) | ||
278 | { | ||
279 | if (!d) | ||
280 | return; | ||
281 | |||
282 | free_irq(irq, d); | ||
283 | kfree(d->mask_buf_def); | ||
284 | kfree(d->mask_buf); | ||
285 | kfree(d->status_reg_buf); | ||
286 | kfree(d->status_buf); | ||
287 | kfree(d); | ||
288 | } | ||
289 | EXPORT_SYMBOL_GPL(regmap_del_irq_chip); | ||
290 | |||
291 | /** | ||
292 | * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip | ||
293 | * | ||
294 | * Useful for drivers to request their own IRQs. | ||
295 | * | ||
296 | * @data: regmap_irq controller to operate on. | ||
297 | */ | ||
298 | int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data) | ||
299 | { | ||
300 | return data->irq_base; | ||
301 | } | ||
302 | EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index bf441db1ee90..be10a4ff6609 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -64,6 +64,18 @@ bool regmap_precious(struct regmap *map, unsigned int reg) | |||
64 | return false; | 64 | return false; |
65 | } | 65 | } |
66 | 66 | ||
67 | static bool regmap_volatile_range(struct regmap *map, unsigned int reg, | ||
68 | unsigned int num) | ||
69 | { | ||
70 | unsigned int i; | ||
71 | |||
72 | for (i = 0; i < num; i++) | ||
73 | if (!regmap_volatile(map, reg + i)) | ||
74 | return false; | ||
75 | |||
76 | return true; | ||
77 | } | ||
78 | |||
67 | static void regmap_format_4_12_write(struct regmap *map, | 79 | static void regmap_format_4_12_write(struct regmap *map, |
68 | unsigned int reg, unsigned int val) | 80 | unsigned int reg, unsigned int val) |
69 | { | 81 | { |
@@ -78,6 +90,16 @@ static void regmap_format_7_9_write(struct regmap *map, | |||
78 | *out = cpu_to_be16((reg << 9) | val); | 90 | *out = cpu_to_be16((reg << 9) | val); |
79 | } | 91 | } |
80 | 92 | ||
93 | static void regmap_format_10_14_write(struct regmap *map, | ||
94 | unsigned int reg, unsigned int val) | ||
95 | { | ||
96 | u8 *out = map->work_buf; | ||
97 | |||
98 | out[2] = val; | ||
99 | out[1] = (val >> 8) | (reg << 6); | ||
100 | out[0] = reg >> 2; | ||
101 | } | ||
102 | |||
81 | static void regmap_format_8(void *buf, unsigned int val) | 103 | static void regmap_format_8(void *buf, unsigned int val) |
82 | { | 104 | { |
83 | u8 *b = buf; | 105 | u8 *b = buf; |
@@ -127,7 +149,7 @@ struct regmap *regmap_init(struct device *dev, | |||
127 | int ret = -EINVAL; | 149 | int ret = -EINVAL; |
128 | 150 | ||
129 | if (!bus || !config) | 151 | if (!bus || !config) |
130 | return NULL; | 152 | goto err; |
131 | 153 | ||
132 | map = kzalloc(sizeof(*map), GFP_KERNEL); | 154 | map = kzalloc(sizeof(*map), GFP_KERNEL); |
133 | if (map == NULL) { | 155 | if (map == NULL) { |
@@ -147,12 +169,6 @@ struct regmap *regmap_init(struct device *dev, | |||
147 | map->volatile_reg = config->volatile_reg; | 169 | map->volatile_reg = config->volatile_reg; |
148 | map->precious_reg = config->precious_reg; | 170 | map->precious_reg = config->precious_reg; |
149 | map->cache_type = config->cache_type; | 171 | map->cache_type = config->cache_type; |
150 | map->reg_defaults = config->reg_defaults; | ||
151 | map->num_reg_defaults = config->num_reg_defaults; | ||
152 | map->num_reg_defaults_raw = config->num_reg_defaults_raw; | ||
153 | map->reg_defaults_raw = config->reg_defaults_raw; | ||
154 | map->cache_size_raw = (config->val_bits / 8) * config->num_reg_defaults_raw; | ||
155 | map->cache_word_size = config->val_bits / 8; | ||
156 | 172 | ||
157 | if (config->read_flag_mask || config->write_flag_mask) { | 173 | if (config->read_flag_mask || config->write_flag_mask) { |
158 | map->read_flag_mask = config->read_flag_mask; | 174 | map->read_flag_mask = config->read_flag_mask; |
@@ -182,6 +198,16 @@ struct regmap *regmap_init(struct device *dev, | |||
182 | } | 198 | } |
183 | break; | 199 | break; |
184 | 200 | ||
201 | case 10: | ||
202 | switch (config->val_bits) { | ||
203 | case 14: | ||
204 | map->format.format_write = regmap_format_10_14_write; | ||
205 | break; | ||
206 | default: | ||
207 | goto err_map; | ||
208 | } | ||
209 | break; | ||
210 | |||
185 | case 8: | 211 | case 8: |
186 | map->format.format_reg = regmap_format_8; | 212 | map->format.format_reg = regmap_format_8; |
187 | break; | 213 | break; |
@@ -215,14 +241,16 @@ struct regmap *regmap_init(struct device *dev, | |||
215 | goto err_map; | 241 | goto err_map; |
216 | } | 242 | } |
217 | 243 | ||
218 | ret = regcache_init(map); | ||
219 | if (ret < 0) | ||
220 | goto err_map; | ||
221 | |||
222 | regmap_debugfs_init(map); | 244 | regmap_debugfs_init(map); |
223 | 245 | ||
246 | ret = regcache_init(map, config); | ||
247 | if (ret < 0) | ||
248 | goto err_free_workbuf; | ||
249 | |||
224 | return map; | 250 | return map; |
225 | 251 | ||
252 | err_free_workbuf: | ||
253 | kfree(map->work_buf); | ||
226 | err_map: | 254 | err_map: |
227 | kfree(map); | 255 | kfree(map); |
228 | err: | 256 | err: |
@@ -231,6 +259,39 @@ err: | |||
231 | EXPORT_SYMBOL_GPL(regmap_init); | 259 | EXPORT_SYMBOL_GPL(regmap_init); |
232 | 260 | ||
233 | /** | 261 | /** |
262 | * regmap_reinit_cache(): Reinitialise the current register cache | ||
263 | * | ||
264 | * @map: Register map to operate on. | ||
265 | * @config: New configuration. Only the cache data will be used. | ||
266 | * | ||
267 | * Discard any existing register cache for the map and initialize a | ||
268 | * new cache. This can be used to restore the cache to defaults or to | ||
269 | * update the cache configuration to reflect runtime discovery of the | ||
270 | * hardware. | ||
271 | */ | ||
272 | int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) | ||
273 | { | ||
274 | int ret; | ||
275 | |||
276 | mutex_lock(&map->lock); | ||
277 | |||
278 | regcache_exit(map); | ||
279 | |||
280 | map->max_register = config->max_register; | ||
281 | map->writeable_reg = config->writeable_reg; | ||
282 | map->readable_reg = config->readable_reg; | ||
283 | map->volatile_reg = config->volatile_reg; | ||
284 | map->precious_reg = config->precious_reg; | ||
285 | map->cache_type = config->cache_type; | ||
286 | |||
287 | ret = regcache_init(map, config); | ||
288 | |||
289 | mutex_unlock(&map->lock); | ||
290 | |||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | /** | ||
234 | * regmap_exit(): Free a previously allocated register map | 295 | * regmap_exit(): Free a previously allocated register map |
235 | */ | 296 | */ |
236 | void regmap_exit(struct regmap *map) | 297 | void regmap_exit(struct regmap *map) |
@@ -306,8 +367,10 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
306 | ret = regcache_write(map, reg, val); | 367 | ret = regcache_write(map, reg, val); |
307 | if (ret != 0) | 368 | if (ret != 0) |
308 | return ret; | 369 | return ret; |
309 | if (map->cache_only) | 370 | if (map->cache_only) { |
371 | map->cache_dirty = true; | ||
310 | return 0; | 372 | return 0; |
373 | } | ||
311 | } | 374 | } |
312 | 375 | ||
313 | trace_regmap_reg_write(map->dev, reg, val); | 376 | trace_regmap_reg_write(map->dev, reg, val); |
@@ -375,9 +438,11 @@ EXPORT_SYMBOL_GPL(regmap_write); | |||
375 | int regmap_raw_write(struct regmap *map, unsigned int reg, | 438 | int regmap_raw_write(struct regmap *map, unsigned int reg, |
376 | const void *val, size_t val_len) | 439 | const void *val, size_t val_len) |
377 | { | 440 | { |
441 | size_t val_count = val_len / map->format.val_bytes; | ||
378 | int ret; | 442 | int ret; |
379 | 443 | ||
380 | WARN_ON(map->cache_type != REGCACHE_NONE); | 444 | WARN_ON(!regmap_volatile_range(map, reg, val_count) && |
445 | map->cache_type != REGCACHE_NONE); | ||
381 | 446 | ||
382 | mutex_lock(&map->lock); | 447 | mutex_lock(&map->lock); |
383 | 448 | ||
@@ -422,15 +487,15 @@ static int _regmap_read(struct regmap *map, unsigned int reg, | |||
422 | { | 487 | { |
423 | int ret; | 488 | int ret; |
424 | 489 | ||
425 | if (!map->format.parse_val) | ||
426 | return -EINVAL; | ||
427 | |||
428 | if (!map->cache_bypass) { | 490 | if (!map->cache_bypass) { |
429 | ret = regcache_read(map, reg, val); | 491 | ret = regcache_read(map, reg, val); |
430 | if (ret == 0) | 492 | if (ret == 0) |
431 | return 0; | 493 | return 0; |
432 | } | 494 | } |
433 | 495 | ||
496 | if (!map->format.parse_val) | ||
497 | return -EINVAL; | ||
498 | |||
434 | if (map->cache_only) | 499 | if (map->cache_only) |
435 | return -EBUSY; | 500 | return -EBUSY; |
436 | 501 | ||
@@ -481,15 +546,11 @@ EXPORT_SYMBOL_GPL(regmap_read); | |||
481 | int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | 546 | int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, |
482 | size_t val_len) | 547 | size_t val_len) |
483 | { | 548 | { |
549 | size_t val_count = val_len / map->format.val_bytes; | ||
484 | int ret; | 550 | int ret; |
485 | int i; | ||
486 | bool vol = true; | ||
487 | 551 | ||
488 | for (i = 0; i < val_len / map->format.val_bytes; i++) | 552 | WARN_ON(!regmap_volatile_range(map, reg, val_count) && |
489 | if (!regmap_volatile(map, reg + i)) | 553 | map->cache_type != REGCACHE_NONE); |
490 | vol = false; | ||
491 | |||
492 | WARN_ON(!vol && map->cache_type != REGCACHE_NONE); | ||
493 | 554 | ||
494 | mutex_lock(&map->lock); | 555 | mutex_lock(&map->lock); |
495 | 556 | ||
@@ -517,16 +578,11 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, | |||
517 | { | 578 | { |
518 | int ret, i; | 579 | int ret, i; |
519 | size_t val_bytes = map->format.val_bytes; | 580 | size_t val_bytes = map->format.val_bytes; |
520 | bool vol = true; | 581 | bool vol = regmap_volatile_range(map, reg, val_count); |
521 | 582 | ||
522 | if (!map->format.parse_val) | 583 | if (!map->format.parse_val) |
523 | return -EINVAL; | 584 | return -EINVAL; |
524 | 585 | ||
525 | /* Is this a block of volatile registers? */ | ||
526 | for (i = 0; i < val_count; i++) | ||
527 | if (!regmap_volatile(map, reg + i)) | ||
528 | vol = false; | ||
529 | |||
530 | if (vol || map->cache_type == REGCACHE_NONE) { | 586 | if (vol || map->cache_type == REGCACHE_NONE) { |
531 | ret = regmap_raw_read(map, reg, val, val_bytes * val_count); | 587 | ret = regmap_raw_read(map, reg, val, val_bytes * val_count); |
532 | if (ret != 0) | 588 | if (ret != 0) |
@@ -546,40 +602,73 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, | |||
546 | } | 602 | } |
547 | EXPORT_SYMBOL_GPL(regmap_bulk_read); | 603 | EXPORT_SYMBOL_GPL(regmap_bulk_read); |
548 | 604 | ||
549 | /** | 605 | static int _regmap_update_bits(struct regmap *map, unsigned int reg, |
550 | * remap_update_bits: Perform a read/modify/write cycle on the register map | 606 | unsigned int mask, unsigned int val, |
551 | * | 607 | bool *change) |
552 | * @map: Register map to update | ||
553 | * @reg: Register to update | ||
554 | * @mask: Bitmask to change | ||
555 | * @val: New value for bitmask | ||
556 | * | ||
557 | * Returns zero for success, a negative number on error. | ||
558 | */ | ||
559 | int regmap_update_bits(struct regmap *map, unsigned int reg, | ||
560 | unsigned int mask, unsigned int val) | ||
561 | { | 608 | { |
562 | int ret; | 609 | int ret; |
563 | unsigned int tmp; | 610 | unsigned int tmp, orig; |
564 | 611 | ||
565 | mutex_lock(&map->lock); | 612 | mutex_lock(&map->lock); |
566 | 613 | ||
567 | ret = _regmap_read(map, reg, &tmp); | 614 | ret = _regmap_read(map, reg, &orig); |
568 | if (ret != 0) | 615 | if (ret != 0) |
569 | goto out; | 616 | goto out; |
570 | 617 | ||
571 | tmp &= ~mask; | 618 | tmp = orig & ~mask; |
572 | tmp |= val & mask; | 619 | tmp |= val & mask; |
573 | 620 | ||
574 | ret = _regmap_write(map, reg, tmp); | 621 | if (tmp != orig) { |
622 | ret = _regmap_write(map, reg, tmp); | ||
623 | *change = true; | ||
624 | } else { | ||
625 | *change = false; | ||
626 | } | ||
575 | 627 | ||
576 | out: | 628 | out: |
577 | mutex_unlock(&map->lock); | 629 | mutex_unlock(&map->lock); |
578 | 630 | ||
579 | return ret; | 631 | return ret; |
580 | } | 632 | } |
633 | |||
634 | /** | ||
635 | * regmap_update_bits: Perform a read/modify/write cycle on the register map | ||
636 | * | ||
637 | * @map: Register map to update | ||
638 | * @reg: Register to update | ||
639 | * @mask: Bitmask to change | ||
640 | * @val: New value for bitmask | ||
641 | * | ||
642 | * Returns zero for success, a negative number on error. | ||
643 | */ | ||
644 | int regmap_update_bits(struct regmap *map, unsigned int reg, | ||
645 | unsigned int mask, unsigned int val) | ||
646 | { | ||
647 | bool change; | ||
648 | return _regmap_update_bits(map, reg, mask, val, &change); | ||
649 | } | ||
581 | EXPORT_SYMBOL_GPL(regmap_update_bits); | 650 | EXPORT_SYMBOL_GPL(regmap_update_bits); |
582 | 651 | ||
652 | /** | ||
653 | * regmap_update_bits_check: Perform a read/modify/write cycle on the | ||
654 | * register map and report if updated | ||
655 | * | ||
656 | * @map: Register map to update | ||
657 | * @reg: Register to update | ||
658 | * @mask: Bitmask to change | ||
659 | * @val: New value for bitmask | ||
660 | * @change: Boolean indicating if a write was done | ||
661 | * | ||
662 | * Returns zero for success, a negative number on error. | ||
663 | */ | ||
664 | int regmap_update_bits_check(struct regmap *map, unsigned int reg, | ||
665 | unsigned int mask, unsigned int val, | ||
666 | bool *change) | ||
667 | { | ||
668 | return _regmap_update_bits(map, reg, mask, val, change); | ||
669 | } | ||
670 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); | ||
671 | |||
583 | static int __init regmap_initcall(void) | 672 | static int __init regmap_initcall(void) |
584 | { | 673 | { |
585 | regmap_debugfs_initcall(); | 674 | regmap_debugfs_initcall(); |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d476880c6fff..5099681cf503 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -70,7 +70,7 @@ config GPIO_GENERIC | |||
70 | 70 | ||
71 | config GPIO_DA9052 | 71 | config GPIO_DA9052 |
72 | tristate "Dialog DA9052 GPIO" | 72 | tristate "Dialog DA9052 GPIO" |
73 | depends on PMIC_DA9052 | 73 | depends on PMIC_DA9052 && BROKEN |
74 | help | 74 | help |
75 | Say yes here to enable the GPIO driver for the DA9052 chip. | 75 | Say yes here to enable the GPIO driver for the DA9052 chip. |
76 | 76 | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f1391c21ef26..c8322eefc865 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -328,6 +328,34 @@ config PMIC_DA903X | |||
328 | individual components like LCD backlight, voltage regulators, | 328 | individual components like LCD backlight, voltage regulators, |
329 | LEDs and battery-charger under the corresponding menus. | 329 | LEDs and battery-charger under the corresponding menus. |
330 | 330 | ||
331 | config PMIC_DA9052 | ||
332 | bool | ||
333 | select MFD_CORE | ||
334 | |||
335 | config MFD_DA9052_SPI | ||
336 | bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI" | ||
337 | select REGMAP_SPI | ||
338 | select REGMAP_IRQ | ||
339 | select PMIC_DA9052 | ||
340 | depends on SPI_MASTER=y | ||
341 | help | ||
342 | Support for the Dialog Semiconductor DA9052 PMIC | ||
343 | when controlled using SPI. This driver provides common support | ||
344 | for accessing the device, additional drivers must be enabled in | ||
345 | order to use the functionality of the device. | ||
346 | |||
347 | config MFD_DA9052_I2C | ||
348 | bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C" | ||
349 | select REGMAP_I2C | ||
350 | select REGMAP_IRQ | ||
351 | select PMIC_DA9052 | ||
352 | depends on I2C=y | ||
353 | help | ||
354 | Support for the Dialog Semiconductor DA9052 PMIC | ||
355 | when controlled using I2C. This driver provides common support | ||
356 | for accessing the device, additional drivers must be enabled in | ||
357 | order to use the functionality of the device. | ||
358 | |||
331 | config PMIC_ADP5520 | 359 | config PMIC_ADP5520 |
332 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | 360 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" |
333 | depends on I2C=y | 361 | depends on I2C=y |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b2292eb75242..d5f574306c7f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -67,6 +67,11 @@ endif | |||
67 | obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | 67 | obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o |
68 | 68 | ||
69 | obj-$(CONFIG_PMIC_DA903X) += da903x.o | 69 | obj-$(CONFIG_PMIC_DA903X) += da903x.o |
70 | |||
71 | obj-$(CONFIG_PMIC_DA9052) += da9052-core.o | ||
72 | obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o | ||
73 | obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o | ||
74 | |||
70 | max8925-objs := max8925-core.o max8925-i2c.o | 75 | max8925-objs := max8925-core.o max8925-i2c.o |
71 | obj-$(CONFIG_MFD_MAX8925) += max8925.o | 76 | obj-$(CONFIG_MFD_MAX8925) += max8925.o |
72 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o | 77 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o |
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c new file mode 100644 index 000000000000..5ddde2a9176a --- /dev/null +++ b/drivers/mfd/da9052-core.c | |||
@@ -0,0 +1,694 @@ | |||
1 | /* | ||
2 | * Device access for Dialog DA9052 PMICs. | ||
3 | * | ||
4 | * Copyright(c) 2011 Dialog Semiconductor Ltd. | ||
5 | * | ||
6 | * Author: David Dajun Chen <dchen@diasemi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/input.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/mfd/core.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include <linux/mfd/da9052/da9052.h> | ||
25 | #include <linux/mfd/da9052/pdata.h> | ||
26 | #include <linux/mfd/da9052/reg.h> | ||
27 | |||
28 | #define DA9052_NUM_IRQ_REGS 4 | ||
29 | #define DA9052_IRQ_MASK_POS_1 0x01 | ||
30 | #define DA9052_IRQ_MASK_POS_2 0x02 | ||
31 | #define DA9052_IRQ_MASK_POS_3 0x04 | ||
32 | #define DA9052_IRQ_MASK_POS_4 0x08 | ||
33 | #define DA9052_IRQ_MASK_POS_5 0x10 | ||
34 | #define DA9052_IRQ_MASK_POS_6 0x20 | ||
35 | #define DA9052_IRQ_MASK_POS_7 0x40 | ||
36 | #define DA9052_IRQ_MASK_POS_8 0x80 | ||
37 | |||
38 | static bool da9052_reg_readable(struct device *dev, unsigned int reg) | ||
39 | { | ||
40 | switch (reg) { | ||
41 | case DA9052_PAGE0_CON_REG: | ||
42 | case DA9052_STATUS_A_REG: | ||
43 | case DA9052_STATUS_B_REG: | ||
44 | case DA9052_STATUS_C_REG: | ||
45 | case DA9052_STATUS_D_REG: | ||
46 | case DA9052_EVENT_A_REG: | ||
47 | case DA9052_EVENT_B_REG: | ||
48 | case DA9052_EVENT_C_REG: | ||
49 | case DA9052_EVENT_D_REG: | ||
50 | case DA9052_FAULTLOG_REG: | ||
51 | case DA9052_IRQ_MASK_A_REG: | ||
52 | case DA9052_IRQ_MASK_B_REG: | ||
53 | case DA9052_IRQ_MASK_C_REG: | ||
54 | case DA9052_IRQ_MASK_D_REG: | ||
55 | case DA9052_CONTROL_A_REG: | ||
56 | case DA9052_CONTROL_B_REG: | ||
57 | case DA9052_CONTROL_C_REG: | ||
58 | case DA9052_CONTROL_D_REG: | ||
59 | case DA9052_PDDIS_REG: | ||
60 | case DA9052_INTERFACE_REG: | ||
61 | case DA9052_RESET_REG: | ||
62 | case DA9052_GPIO_0_1_REG: | ||
63 | case DA9052_GPIO_2_3_REG: | ||
64 | case DA9052_GPIO_4_5_REG: | ||
65 | case DA9052_GPIO_6_7_REG: | ||
66 | case DA9052_GPIO_14_15_REG: | ||
67 | case DA9052_ID_0_1_REG: | ||
68 | case DA9052_ID_2_3_REG: | ||
69 | case DA9052_ID_4_5_REG: | ||
70 | case DA9052_ID_6_7_REG: | ||
71 | case DA9052_ID_8_9_REG: | ||
72 | case DA9052_ID_10_11_REG: | ||
73 | case DA9052_ID_12_13_REG: | ||
74 | case DA9052_ID_14_15_REG: | ||
75 | case DA9052_ID_16_17_REG: | ||
76 | case DA9052_ID_18_19_REG: | ||
77 | case DA9052_ID_20_21_REG: | ||
78 | case DA9052_SEQ_STATUS_REG: | ||
79 | case DA9052_SEQ_A_REG: | ||
80 | case DA9052_SEQ_B_REG: | ||
81 | case DA9052_SEQ_TIMER_REG: | ||
82 | case DA9052_BUCKA_REG: | ||
83 | case DA9052_BUCKB_REG: | ||
84 | case DA9052_BUCKCORE_REG: | ||
85 | case DA9052_BUCKPRO_REG: | ||
86 | case DA9052_BUCKMEM_REG: | ||
87 | case DA9052_BUCKPERI_REG: | ||
88 | case DA9052_LDO1_REG: | ||
89 | case DA9052_LDO2_REG: | ||
90 | case DA9052_LDO3_REG: | ||
91 | case DA9052_LDO4_REG: | ||
92 | case DA9052_LDO5_REG: | ||
93 | case DA9052_LDO6_REG: | ||
94 | case DA9052_LDO7_REG: | ||
95 | case DA9052_LDO8_REG: | ||
96 | case DA9052_LDO9_REG: | ||
97 | case DA9052_LDO10_REG: | ||
98 | case DA9052_SUPPLY_REG: | ||
99 | case DA9052_PULLDOWN_REG: | ||
100 | case DA9052_CHGBUCK_REG: | ||
101 | case DA9052_WAITCONT_REG: | ||
102 | case DA9052_ISET_REG: | ||
103 | case DA9052_BATCHG_REG: | ||
104 | case DA9052_CHG_CONT_REG: | ||
105 | case DA9052_INPUT_CONT_REG: | ||
106 | case DA9052_CHG_TIME_REG: | ||
107 | case DA9052_BBAT_CONT_REG: | ||
108 | case DA9052_BOOST_REG: | ||
109 | case DA9052_LED_CONT_REG: | ||
110 | case DA9052_LEDMIN123_REG: | ||
111 | case DA9052_LED1_CONF_REG: | ||
112 | case DA9052_LED2_CONF_REG: | ||
113 | case DA9052_LED3_CONF_REG: | ||
114 | case DA9052_LED1CONT_REG: | ||
115 | case DA9052_LED2CONT_REG: | ||
116 | case DA9052_LED3CONT_REG: | ||
117 | case DA9052_LED_CONT_4_REG: | ||
118 | case DA9052_LED_CONT_5_REG: | ||
119 | case DA9052_ADC_MAN_REG: | ||
120 | case DA9052_ADC_CONT_REG: | ||
121 | case DA9052_ADC_RES_L_REG: | ||
122 | case DA9052_ADC_RES_H_REG: | ||
123 | case DA9052_VDD_RES_REG: | ||
124 | case DA9052_VDD_MON_REG: | ||
125 | case DA9052_ICHG_AV_REG: | ||
126 | case DA9052_ICHG_THD_REG: | ||
127 | case DA9052_ICHG_END_REG: | ||
128 | case DA9052_TBAT_RES_REG: | ||
129 | case DA9052_TBAT_HIGHP_REG: | ||
130 | case DA9052_TBAT_HIGHN_REG: | ||
131 | case DA9052_TBAT_LOW_REG: | ||
132 | case DA9052_T_OFFSET_REG: | ||
133 | case DA9052_ADCIN4_RES_REG: | ||
134 | case DA9052_AUTO4_HIGH_REG: | ||
135 | case DA9052_AUTO4_LOW_REG: | ||
136 | case DA9052_ADCIN5_RES_REG: | ||
137 | case DA9052_AUTO5_HIGH_REG: | ||
138 | case DA9052_AUTO5_LOW_REG: | ||
139 | case DA9052_ADCIN6_RES_REG: | ||
140 | case DA9052_AUTO6_HIGH_REG: | ||
141 | case DA9052_AUTO6_LOW_REG: | ||
142 | case DA9052_TJUNC_RES_REG: | ||
143 | case DA9052_TSI_CONT_A_REG: | ||
144 | case DA9052_TSI_CONT_B_REG: | ||
145 | case DA9052_TSI_X_MSB_REG: | ||
146 | case DA9052_TSI_Y_MSB_REG: | ||
147 | case DA9052_TSI_LSB_REG: | ||
148 | case DA9052_TSI_Z_MSB_REG: | ||
149 | case DA9052_COUNT_S_REG: | ||
150 | case DA9052_COUNT_MI_REG: | ||
151 | case DA9052_COUNT_H_REG: | ||
152 | case DA9052_COUNT_D_REG: | ||
153 | case DA9052_COUNT_MO_REG: | ||
154 | case DA9052_COUNT_Y_REG: | ||
155 | case DA9052_ALARM_MI_REG: | ||
156 | case DA9052_ALARM_H_REG: | ||
157 | case DA9052_ALARM_D_REG: | ||
158 | case DA9052_ALARM_MO_REG: | ||
159 | case DA9052_ALARM_Y_REG: | ||
160 | case DA9052_SECOND_A_REG: | ||
161 | case DA9052_SECOND_B_REG: | ||
162 | case DA9052_SECOND_C_REG: | ||
163 | case DA9052_SECOND_D_REG: | ||
164 | case DA9052_PAGE1_CON_REG: | ||
165 | return true; | ||
166 | default: | ||
167 | return false; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | static bool da9052_reg_writeable(struct device *dev, unsigned int reg) | ||
172 | { | ||
173 | switch (reg) { | ||
174 | case DA9052_PAGE0_CON_REG: | ||
175 | case DA9052_EVENT_A_REG: | ||
176 | case DA9052_EVENT_B_REG: | ||
177 | case DA9052_EVENT_C_REG: | ||
178 | case DA9052_EVENT_D_REG: | ||
179 | case DA9052_IRQ_MASK_A_REG: | ||
180 | case DA9052_IRQ_MASK_B_REG: | ||
181 | case DA9052_IRQ_MASK_C_REG: | ||
182 | case DA9052_IRQ_MASK_D_REG: | ||
183 | case DA9052_CONTROL_A_REG: | ||
184 | case DA9052_CONTROL_B_REG: | ||
185 | case DA9052_CONTROL_C_REG: | ||
186 | case DA9052_CONTROL_D_REG: | ||
187 | case DA9052_PDDIS_REG: | ||
188 | case DA9052_RESET_REG: | ||
189 | case DA9052_GPIO_0_1_REG: | ||
190 | case DA9052_GPIO_2_3_REG: | ||
191 | case DA9052_GPIO_4_5_REG: | ||
192 | case DA9052_GPIO_6_7_REG: | ||
193 | case DA9052_GPIO_14_15_REG: | ||
194 | case DA9052_ID_0_1_REG: | ||
195 | case DA9052_ID_2_3_REG: | ||
196 | case DA9052_ID_4_5_REG: | ||
197 | case DA9052_ID_6_7_REG: | ||
198 | case DA9052_ID_8_9_REG: | ||
199 | case DA9052_ID_10_11_REG: | ||
200 | case DA9052_ID_12_13_REG: | ||
201 | case DA9052_ID_14_15_REG: | ||
202 | case DA9052_ID_16_17_REG: | ||
203 | case DA9052_ID_18_19_REG: | ||
204 | case DA9052_ID_20_21_REG: | ||
205 | case DA9052_SEQ_STATUS_REG: | ||
206 | case DA9052_SEQ_A_REG: | ||
207 | case DA9052_SEQ_B_REG: | ||
208 | case DA9052_SEQ_TIMER_REG: | ||
209 | case DA9052_BUCKA_REG: | ||
210 | case DA9052_BUCKB_REG: | ||
211 | case DA9052_BUCKCORE_REG: | ||
212 | case DA9052_BUCKPRO_REG: | ||
213 | case DA9052_BUCKMEM_REG: | ||
214 | case DA9052_BUCKPERI_REG: | ||
215 | case DA9052_LDO1_REG: | ||
216 | case DA9052_LDO2_REG: | ||
217 | case DA9052_LDO3_REG: | ||
218 | case DA9052_LDO4_REG: | ||
219 | case DA9052_LDO5_REG: | ||
220 | case DA9052_LDO6_REG: | ||
221 | case DA9052_LDO7_REG: | ||
222 | case DA9052_LDO8_REG: | ||
223 | case DA9052_LDO9_REG: | ||
224 | case DA9052_LDO10_REG: | ||
225 | case DA9052_SUPPLY_REG: | ||
226 | case DA9052_PULLDOWN_REG: | ||
227 | case DA9052_CHGBUCK_REG: | ||
228 | case DA9052_WAITCONT_REG: | ||
229 | case DA9052_ISET_REG: | ||
230 | case DA9052_BATCHG_REG: | ||
231 | case DA9052_CHG_CONT_REG: | ||
232 | case DA9052_INPUT_CONT_REG: | ||
233 | case DA9052_BBAT_CONT_REG: | ||
234 | case DA9052_BOOST_REG: | ||
235 | case DA9052_LED_CONT_REG: | ||
236 | case DA9052_LEDMIN123_REG: | ||
237 | case DA9052_LED1_CONF_REG: | ||
238 | case DA9052_LED2_CONF_REG: | ||
239 | case DA9052_LED3_CONF_REG: | ||
240 | case DA9052_LED1CONT_REG: | ||
241 | case DA9052_LED2CONT_REG: | ||
242 | case DA9052_LED3CONT_REG: | ||
243 | case DA9052_LED_CONT_4_REG: | ||
244 | case DA9052_LED_CONT_5_REG: | ||
245 | case DA9052_ADC_MAN_REG: | ||
246 | case DA9052_ADC_CONT_REG: | ||
247 | case DA9052_ADC_RES_L_REG: | ||
248 | case DA9052_ADC_RES_H_REG: | ||
249 | case DA9052_VDD_RES_REG: | ||
250 | case DA9052_VDD_MON_REG: | ||
251 | case DA9052_ICHG_THD_REG: | ||
252 | case DA9052_ICHG_END_REG: | ||
253 | case DA9052_TBAT_HIGHP_REG: | ||
254 | case DA9052_TBAT_HIGHN_REG: | ||
255 | case DA9052_TBAT_LOW_REG: | ||
256 | case DA9052_T_OFFSET_REG: | ||
257 | case DA9052_AUTO4_HIGH_REG: | ||
258 | case DA9052_AUTO4_LOW_REG: | ||
259 | case DA9052_AUTO5_HIGH_REG: | ||
260 | case DA9052_AUTO5_LOW_REG: | ||
261 | case DA9052_AUTO6_HIGH_REG: | ||
262 | case DA9052_AUTO6_LOW_REG: | ||
263 | case DA9052_TSI_CONT_A_REG: | ||
264 | case DA9052_TSI_CONT_B_REG: | ||
265 | case DA9052_COUNT_S_REG: | ||
266 | case DA9052_COUNT_MI_REG: | ||
267 | case DA9052_COUNT_H_REG: | ||
268 | case DA9052_COUNT_D_REG: | ||
269 | case DA9052_COUNT_MO_REG: | ||
270 | case DA9052_COUNT_Y_REG: | ||
271 | case DA9052_ALARM_MI_REG: | ||
272 | case DA9052_ALARM_H_REG: | ||
273 | case DA9052_ALARM_D_REG: | ||
274 | case DA9052_ALARM_MO_REG: | ||
275 | case DA9052_ALARM_Y_REG: | ||
276 | case DA9052_PAGE1_CON_REG: | ||
277 | return true; | ||
278 | default: | ||
279 | return false; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | static bool da9052_reg_volatile(struct device *dev, unsigned int reg) | ||
284 | { | ||
285 | switch (reg) { | ||
286 | case DA9052_STATUS_A_REG: | ||
287 | case DA9052_STATUS_B_REG: | ||
288 | case DA9052_STATUS_C_REG: | ||
289 | case DA9052_STATUS_D_REG: | ||
290 | case DA9052_EVENT_A_REG: | ||
291 | case DA9052_EVENT_B_REG: | ||
292 | case DA9052_EVENT_C_REG: | ||
293 | case DA9052_EVENT_D_REG: | ||
294 | case DA9052_FAULTLOG_REG: | ||
295 | case DA9052_CHG_TIME_REG: | ||
296 | case DA9052_ADC_RES_L_REG: | ||
297 | case DA9052_ADC_RES_H_REG: | ||
298 | case DA9052_VDD_RES_REG: | ||
299 | case DA9052_ICHG_AV_REG: | ||
300 | case DA9052_TBAT_RES_REG: | ||
301 | case DA9052_ADCIN4_RES_REG: | ||
302 | case DA9052_ADCIN5_RES_REG: | ||
303 | case DA9052_ADCIN6_RES_REG: | ||
304 | case DA9052_TJUNC_RES_REG: | ||
305 | case DA9052_TSI_X_MSB_REG: | ||
306 | case DA9052_TSI_Y_MSB_REG: | ||
307 | case DA9052_TSI_LSB_REG: | ||
308 | case DA9052_TSI_Z_MSB_REG: | ||
309 | case DA9052_COUNT_S_REG: | ||
310 | case DA9052_COUNT_MI_REG: | ||
311 | case DA9052_COUNT_H_REG: | ||
312 | case DA9052_COUNT_D_REG: | ||
313 | case DA9052_COUNT_MO_REG: | ||
314 | case DA9052_COUNT_Y_REG: | ||
315 | case DA9052_ALARM_MI_REG: | ||
316 | return true; | ||
317 | default: | ||
318 | return false; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | static struct resource da9052_rtc_resource = { | ||
323 | .name = "ALM", | ||
324 | .start = DA9052_IRQ_ALARM, | ||
325 | .end = DA9052_IRQ_ALARM, | ||
326 | .flags = IORESOURCE_IRQ, | ||
327 | }; | ||
328 | |||
329 | static struct resource da9052_onkey_resource = { | ||
330 | .name = "ONKEY", | ||
331 | .start = DA9052_IRQ_NONKEY, | ||
332 | .end = DA9052_IRQ_NONKEY, | ||
333 | .flags = IORESOURCE_IRQ, | ||
334 | }; | ||
335 | |||
336 | static struct resource da9052_bat_resources[] = { | ||
337 | { | ||
338 | .name = "BATT TEMP", | ||
339 | .start = DA9052_IRQ_TBAT, | ||
340 | .end = DA9052_IRQ_TBAT, | ||
341 | .flags = IORESOURCE_IRQ, | ||
342 | }, | ||
343 | { | ||
344 | .name = "DCIN DET", | ||
345 | .start = DA9052_IRQ_DCIN, | ||
346 | .end = DA9052_IRQ_DCIN, | ||
347 | .flags = IORESOURCE_IRQ, | ||
348 | }, | ||
349 | { | ||
350 | .name = "DCIN REM", | ||
351 | .start = DA9052_IRQ_DCINREM, | ||
352 | .end = DA9052_IRQ_DCINREM, | ||
353 | .flags = IORESOURCE_IRQ, | ||
354 | }, | ||
355 | { | ||
356 | .name = "VBUS DET", | ||
357 | .start = DA9052_IRQ_VBUS, | ||
358 | .end = DA9052_IRQ_VBUS, | ||
359 | .flags = IORESOURCE_IRQ, | ||
360 | }, | ||
361 | { | ||
362 | .name = "VBUS REM", | ||
363 | .start = DA9052_IRQ_VBUSREM, | ||
364 | .end = DA9052_IRQ_VBUSREM, | ||
365 | .flags = IORESOURCE_IRQ, | ||
366 | }, | ||
367 | { | ||
368 | .name = "CHG END", | ||
369 | .start = DA9052_IRQ_CHGEND, | ||
370 | .end = DA9052_IRQ_CHGEND, | ||
371 | .flags = IORESOURCE_IRQ, | ||
372 | }, | ||
373 | }; | ||
374 | |||
375 | static struct resource da9052_tsi_resources[] = { | ||
376 | { | ||
377 | .name = "PENDWN", | ||
378 | .start = DA9052_IRQ_PENDOWN, | ||
379 | .end = DA9052_IRQ_PENDOWN, | ||
380 | .flags = IORESOURCE_IRQ, | ||
381 | }, | ||
382 | { | ||
383 | .name = "TSIRDY", | ||
384 | .start = DA9052_IRQ_TSIREADY, | ||
385 | .end = DA9052_IRQ_TSIREADY, | ||
386 | .flags = IORESOURCE_IRQ, | ||
387 | }, | ||
388 | }; | ||
389 | |||
390 | static struct mfd_cell __devinitdata da9052_subdev_info[] = { | ||
391 | { | ||
392 | .name = "da9052-regulator", | ||
393 | .id = 1, | ||
394 | }, | ||
395 | { | ||
396 | .name = "da9052-regulator", | ||
397 | .id = 2, | ||
398 | }, | ||
399 | { | ||
400 | .name = "da9052-regulator", | ||
401 | .id = 3, | ||
402 | }, | ||
403 | { | ||
404 | .name = "da9052-regulator", | ||
405 | .id = 4, | ||
406 | }, | ||
407 | { | ||
408 | .name = "da9052-regulator", | ||
409 | .id = 5, | ||
410 | }, | ||
411 | { | ||
412 | .name = "da9052-regulator", | ||
413 | .id = 6, | ||
414 | }, | ||
415 | { | ||
416 | .name = "da9052-regulator", | ||
417 | .id = 7, | ||
418 | }, | ||
419 | { | ||
420 | .name = "da9052-regulator", | ||
421 | .id = 8, | ||
422 | }, | ||
423 | { | ||
424 | .name = "da9052-regulator", | ||
425 | .id = 9, | ||
426 | }, | ||
427 | { | ||
428 | .name = "da9052-regulator", | ||
429 | .id = 10, | ||
430 | }, | ||
431 | { | ||
432 | .name = "da9052-regulator", | ||
433 | .id = 11, | ||
434 | }, | ||
435 | { | ||
436 | .name = "da9052-regulator", | ||
437 | .id = 12, | ||
438 | }, | ||
439 | { | ||
440 | .name = "da9052-regulator", | ||
441 | .id = 13, | ||
442 | }, | ||
443 | { | ||
444 | .name = "da9052-regulator", | ||
445 | .id = 14, | ||
446 | }, | ||
447 | { | ||
448 | .name = "da9052-onkey", | ||
449 | .resources = &da9052_onkey_resource, | ||
450 | .num_resources = 1, | ||
451 | }, | ||
452 | { | ||
453 | .name = "da9052-rtc", | ||
454 | .resources = &da9052_rtc_resource, | ||
455 | .num_resources = 1, | ||
456 | }, | ||
457 | { | ||
458 | .name = "da9052-gpio", | ||
459 | }, | ||
460 | { | ||
461 | .name = "da9052-hwmon", | ||
462 | }, | ||
463 | { | ||
464 | .name = "da9052-leds", | ||
465 | }, | ||
466 | { | ||
467 | .name = "da9052-wled1", | ||
468 | }, | ||
469 | { | ||
470 | .name = "da9052-wled2", | ||
471 | }, | ||
472 | { | ||
473 | .name = "da9052-wled3", | ||
474 | }, | ||
475 | { | ||
476 | .name = "da9052-tsi", | ||
477 | .resources = da9052_tsi_resources, | ||
478 | .num_resources = ARRAY_SIZE(da9052_tsi_resources), | ||
479 | }, | ||
480 | { | ||
481 | .name = "da9052-bat", | ||
482 | .resources = da9052_bat_resources, | ||
483 | .num_resources = ARRAY_SIZE(da9052_bat_resources), | ||
484 | }, | ||
485 | { | ||
486 | .name = "da9052-watchdog", | ||
487 | }, | ||
488 | }; | ||
489 | |||
490 | static struct regmap_irq da9052_irqs[] = { | ||
491 | [DA9052_IRQ_DCIN] = { | ||
492 | .reg_offset = 0, | ||
493 | .mask = DA9052_IRQ_MASK_POS_1, | ||
494 | }, | ||
495 | [DA9052_IRQ_VBUS] = { | ||
496 | .reg_offset = 0, | ||
497 | .mask = DA9052_IRQ_MASK_POS_2, | ||
498 | }, | ||
499 | [DA9052_IRQ_DCINREM] = { | ||
500 | .reg_offset = 0, | ||
501 | .mask = DA9052_IRQ_MASK_POS_3, | ||
502 | }, | ||
503 | [DA9052_IRQ_VBUSREM] = { | ||
504 | .reg_offset = 0, | ||
505 | .mask = DA9052_IRQ_MASK_POS_4, | ||
506 | }, | ||
507 | [DA9052_IRQ_VDDLOW] = { | ||
508 | .reg_offset = 0, | ||
509 | .mask = DA9052_IRQ_MASK_POS_5, | ||
510 | }, | ||
511 | [DA9052_IRQ_ALARM] = { | ||
512 | .reg_offset = 0, | ||
513 | .mask = DA9052_IRQ_MASK_POS_6, | ||
514 | }, | ||
515 | [DA9052_IRQ_SEQRDY] = { | ||
516 | .reg_offset = 0, | ||
517 | .mask = DA9052_IRQ_MASK_POS_7, | ||
518 | }, | ||
519 | [DA9052_IRQ_COMP1V2] = { | ||
520 | .reg_offset = 0, | ||
521 | .mask = DA9052_IRQ_MASK_POS_8, | ||
522 | }, | ||
523 | [DA9052_IRQ_NONKEY] = { | ||
524 | .reg_offset = 1, | ||
525 | .mask = DA9052_IRQ_MASK_POS_1, | ||
526 | }, | ||
527 | [DA9052_IRQ_IDFLOAT] = { | ||
528 | .reg_offset = 1, | ||
529 | .mask = DA9052_IRQ_MASK_POS_2, | ||
530 | }, | ||
531 | [DA9052_IRQ_IDGND] = { | ||
532 | .reg_offset = 1, | ||
533 | .mask = DA9052_IRQ_MASK_POS_3, | ||
534 | }, | ||
535 | [DA9052_IRQ_CHGEND] = { | ||
536 | .reg_offset = 1, | ||
537 | .mask = DA9052_IRQ_MASK_POS_4, | ||
538 | }, | ||
539 | [DA9052_IRQ_TBAT] = { | ||
540 | .reg_offset = 1, | ||
541 | .mask = DA9052_IRQ_MASK_POS_5, | ||
542 | }, | ||
543 | [DA9052_IRQ_ADC_EOM] = { | ||
544 | .reg_offset = 1, | ||
545 | .mask = DA9052_IRQ_MASK_POS_6, | ||
546 | }, | ||
547 | [DA9052_IRQ_PENDOWN] = { | ||
548 | .reg_offset = 1, | ||
549 | .mask = DA9052_IRQ_MASK_POS_7, | ||
550 | }, | ||
551 | [DA9052_IRQ_TSIREADY] = { | ||
552 | .reg_offset = 1, | ||
553 | .mask = DA9052_IRQ_MASK_POS_8, | ||
554 | }, | ||
555 | [DA9052_IRQ_GPI0] = { | ||
556 | .reg_offset = 2, | ||
557 | .mask = DA9052_IRQ_MASK_POS_1, | ||
558 | }, | ||
559 | [DA9052_IRQ_GPI1] = { | ||
560 | .reg_offset = 2, | ||
561 | .mask = DA9052_IRQ_MASK_POS_2, | ||
562 | }, | ||
563 | [DA9052_IRQ_GPI2] = { | ||
564 | .reg_offset = 2, | ||
565 | .mask = DA9052_IRQ_MASK_POS_3, | ||
566 | }, | ||
567 | [DA9052_IRQ_GPI3] = { | ||
568 | .reg_offset = 2, | ||
569 | .mask = DA9052_IRQ_MASK_POS_4, | ||
570 | }, | ||
571 | [DA9052_IRQ_GPI4] = { | ||
572 | .reg_offset = 2, | ||
573 | .mask = DA9052_IRQ_MASK_POS_5, | ||
574 | }, | ||
575 | [DA9052_IRQ_GPI5] = { | ||
576 | .reg_offset = 2, | ||
577 | .mask = DA9052_IRQ_MASK_POS_6, | ||
578 | }, | ||
579 | [DA9052_IRQ_GPI6] = { | ||
580 | .reg_offset = 2, | ||
581 | .mask = DA9052_IRQ_MASK_POS_7, | ||
582 | }, | ||
583 | [DA9052_IRQ_GPI7] = { | ||
584 | .reg_offset = 2, | ||
585 | .mask = DA9052_IRQ_MASK_POS_8, | ||
586 | }, | ||
587 | [DA9052_IRQ_GPI8] = { | ||
588 | .reg_offset = 3, | ||
589 | .mask = DA9052_IRQ_MASK_POS_1, | ||
590 | }, | ||
591 | [DA9052_IRQ_GPI9] = { | ||
592 | .reg_offset = 3, | ||
593 | .mask = DA9052_IRQ_MASK_POS_2, | ||
594 | }, | ||
595 | [DA9052_IRQ_GPI10] = { | ||
596 | .reg_offset = 3, | ||
597 | .mask = DA9052_IRQ_MASK_POS_3, | ||
598 | }, | ||
599 | [DA9052_IRQ_GPI11] = { | ||
600 | .reg_offset = 3, | ||
601 | .mask = DA9052_IRQ_MASK_POS_4, | ||
602 | }, | ||
603 | [DA9052_IRQ_GPI12] = { | ||
604 | .reg_offset = 3, | ||
605 | .mask = DA9052_IRQ_MASK_POS_5, | ||
606 | }, | ||
607 | [DA9052_IRQ_GPI13] = { | ||
608 | .reg_offset = 3, | ||
609 | .mask = DA9052_IRQ_MASK_POS_6, | ||
610 | }, | ||
611 | [DA9052_IRQ_GPI14] = { | ||
612 | .reg_offset = 3, | ||
613 | .mask = DA9052_IRQ_MASK_POS_7, | ||
614 | }, | ||
615 | [DA9052_IRQ_GPI15] = { | ||
616 | .reg_offset = 3, | ||
617 | .mask = DA9052_IRQ_MASK_POS_8, | ||
618 | }, | ||
619 | }; | ||
620 | |||
621 | static struct regmap_irq_chip da9052_regmap_irq_chip = { | ||
622 | .name = "da9052_irq", | ||
623 | .status_base = DA9052_EVENT_A_REG, | ||
624 | .mask_base = DA9052_IRQ_MASK_A_REG, | ||
625 | .ack_base = DA9052_EVENT_A_REG, | ||
626 | .num_regs = DA9052_NUM_IRQ_REGS, | ||
627 | .irqs = da9052_irqs, | ||
628 | .num_irqs = ARRAY_SIZE(da9052_irqs), | ||
629 | }; | ||
630 | |||
631 | struct regmap_config da9052_regmap_config = { | ||
632 | .reg_bits = 8, | ||
633 | .val_bits = 8, | ||
634 | |||
635 | .cache_type = REGCACHE_RBTREE, | ||
636 | |||
637 | .max_register = DA9052_PAGE1_CON_REG, | ||
638 | .readable_reg = da9052_reg_readable, | ||
639 | .writeable_reg = da9052_reg_writeable, | ||
640 | .volatile_reg = da9052_reg_volatile, | ||
641 | }; | ||
642 | EXPORT_SYMBOL_GPL(da9052_regmap_config); | ||
643 | |||
644 | int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) | ||
645 | { | ||
646 | struct da9052_pdata *pdata = da9052->dev->platform_data; | ||
647 | struct irq_desc *desc; | ||
648 | int ret; | ||
649 | |||
650 | mutex_init(&da9052->io_lock); | ||
651 | |||
652 | if (pdata && pdata->init != NULL) | ||
653 | pdata->init(da9052); | ||
654 | |||
655 | da9052->chip_id = chip_id; | ||
656 | |||
657 | if (!pdata || !pdata->irq_base) | ||
658 | da9052->irq_base = -1; | ||
659 | else | ||
660 | da9052->irq_base = pdata->irq_base; | ||
661 | |||
662 | ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq, | ||
663 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
664 | da9052->irq_base, &da9052_regmap_irq_chip, | ||
665 | NULL); | ||
666 | if (ret < 0) | ||
667 | goto regmap_err; | ||
668 | |||
669 | desc = irq_to_desc(da9052->chip_irq); | ||
670 | da9052->irq_base = regmap_irq_chip_get_base(desc->action->dev_id); | ||
671 | |||
672 | ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, | ||
673 | ARRAY_SIZE(da9052_subdev_info), NULL, 0); | ||
674 | if (ret) | ||
675 | goto err; | ||
676 | |||
677 | return 0; | ||
678 | |||
679 | err: | ||
680 | mfd_remove_devices(da9052->dev); | ||
681 | regmap_err: | ||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | void da9052_device_exit(struct da9052 *da9052) | ||
686 | { | ||
687 | regmap_del_irq_chip(da9052->chip_irq, | ||
688 | irq_get_irq_data(da9052->irq_base)->chip_data); | ||
689 | mfd_remove_devices(da9052->dev); | ||
690 | } | ||
691 | |||
692 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | ||
693 | MODULE_DESCRIPTION("DA9052 MFD Core"); | ||
694 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c new file mode 100644 index 000000000000..44b97c70a61f --- /dev/null +++ b/drivers/mfd/da9052-i2c.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * I2C access for DA9052 PMICs. | ||
3 | * | ||
4 | * Copyright(c) 2011 Dialog Semiconductor Ltd. | ||
5 | * | ||
6 | * Author: David Dajun Chen <dchen@diasemi.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 as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/input.h> | ||
18 | #include <linux/mfd/core.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | #include <linux/mfd/da9052/da9052.h> | ||
23 | #include <linux/mfd/da9052/reg.h> | ||
24 | |||
25 | static int da9052_i2c_enable_multiwrite(struct da9052 *da9052) | ||
26 | { | ||
27 | int reg_val, ret; | ||
28 | |||
29 | ret = regmap_read(da9052->regmap, DA9052_CONTROL_B_REG, ®_val); | ||
30 | if (ret < 0) | ||
31 | return ret; | ||
32 | |||
33 | if (reg_val & DA9052_CONTROL_B_WRITEMODE) { | ||
34 | reg_val &= ~DA9052_CONTROL_B_WRITEMODE; | ||
35 | ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG, | ||
36 | reg_val); | ||
37 | if (ret < 0) | ||
38 | return ret; | ||
39 | } | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int __devinit da9052_i2c_probe(struct i2c_client *client, | ||
45 | const struct i2c_device_id *id) | ||
46 | { | ||
47 | struct da9052 *da9052; | ||
48 | int ret; | ||
49 | |||
50 | da9052 = kzalloc(sizeof(struct da9052), GFP_KERNEL); | ||
51 | if (!da9052) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | if (!i2c_check_functionality(client->adapter, | ||
55 | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
56 | dev_info(&client->dev, "Error in %s:i2c_check_functionality\n", | ||
57 | __func__); | ||
58 | ret = -ENODEV; | ||
59 | goto err; | ||
60 | } | ||
61 | |||
62 | da9052->dev = &client->dev; | ||
63 | da9052->chip_irq = client->irq; | ||
64 | |||
65 | i2c_set_clientdata(client, da9052); | ||
66 | |||
67 | da9052->regmap = regmap_init_i2c(client, &da9052_regmap_config); | ||
68 | if (IS_ERR(da9052->regmap)) { | ||
69 | ret = PTR_ERR(da9052->regmap); | ||
70 | dev_err(&client->dev, "Failed to allocate register map: %d\n", | ||
71 | ret); | ||
72 | goto err; | ||
73 | } | ||
74 | |||
75 | ret = da9052_i2c_enable_multiwrite(da9052); | ||
76 | if (ret < 0) | ||
77 | goto err; | ||
78 | |||
79 | ret = da9052_device_init(da9052, id->driver_data); | ||
80 | if (ret != 0) | ||
81 | goto err; | ||
82 | |||
83 | return 0; | ||
84 | |||
85 | err: | ||
86 | kfree(da9052); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | static int da9052_i2c_remove(struct i2c_client *client) | ||
91 | { | ||
92 | struct da9052 *da9052 = i2c_get_clientdata(client); | ||
93 | |||
94 | da9052_device_exit(da9052); | ||
95 | kfree(da9052); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static struct i2c_device_id da9052_i2c_id[] = { | ||
101 | {"da9052", DA9052}, | ||
102 | {"da9053-aa", DA9053_AA}, | ||
103 | {"da9053-ba", DA9053_BA}, | ||
104 | {"da9053-bb", DA9053_BB}, | ||
105 | {} | ||
106 | }; | ||
107 | |||
108 | static struct i2c_driver da9052_i2c_driver = { | ||
109 | .probe = da9052_i2c_probe, | ||
110 | .remove = da9052_i2c_remove, | ||
111 | .id_table = da9052_i2c_id, | ||
112 | .driver = { | ||
113 | .name = "da9052", | ||
114 | .owner = THIS_MODULE, | ||
115 | }, | ||
116 | }; | ||
117 | |||
118 | static int __init da9052_i2c_init(void) | ||
119 | { | ||
120 | int ret; | ||
121 | |||
122 | ret = i2c_add_driver(&da9052_i2c_driver); | ||
123 | if (ret != 0) { | ||
124 | pr_err("DA9052 I2C registration failed %d\n", ret); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | subsys_initcall(da9052_i2c_init); | ||
131 | |||
132 | static void __exit da9052_i2c_exit(void) | ||
133 | { | ||
134 | i2c_del_driver(&da9052_i2c_driver); | ||
135 | } | ||
136 | module_exit(da9052_i2c_exit); | ||
137 | |||
138 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | ||
139 | MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC"); | ||
140 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c new file mode 100644 index 000000000000..cdbc7cad326f --- /dev/null +++ b/drivers/mfd/da9052-spi.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * SPI access for Dialog DA9052 PMICs. | ||
3 | * | ||
4 | * Copyright(c) 2011 Dialog Semiconductor Ltd. | ||
5 | * | ||
6 | * Author: David Dajun Chen <dchen@diasemi.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 as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/input.h> | ||
18 | #include <linux/mfd/core.h> | ||
19 | #include <linux/spi/spi.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | #include <linux/mfd/da9052/da9052.h> | ||
23 | |||
24 | static int da9052_spi_probe(struct spi_device *spi) | ||
25 | { | ||
26 | int ret; | ||
27 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
28 | struct da9052 *da9052 = kzalloc(sizeof(struct da9052), GFP_KERNEL); | ||
29 | |||
30 | if (!da9052) | ||
31 | return -ENOMEM; | ||
32 | |||
33 | spi->mode = SPI_MODE_0 | SPI_CPOL; | ||
34 | spi->bits_per_word = 8; | ||
35 | spi_setup(spi); | ||
36 | |||
37 | da9052->dev = &spi->dev; | ||
38 | da9052->chip_irq = spi->irq; | ||
39 | |||
40 | dev_set_drvdata(&spi->dev, da9052); | ||
41 | |||
42 | da9052_regmap_config.read_flag_mask = 1; | ||
43 | da9052_regmap_config.write_flag_mask = 0; | ||
44 | |||
45 | da9052->regmap = regmap_init_spi(spi, &da9052_regmap_config); | ||
46 | if (IS_ERR(da9052->regmap)) { | ||
47 | ret = PTR_ERR(da9052->regmap); | ||
48 | dev_err(&spi->dev, "Failed to allocate register map: %d\n", | ||
49 | ret); | ||
50 | goto err; | ||
51 | } | ||
52 | |||
53 | ret = da9052_device_init(da9052, id->driver_data); | ||
54 | if (ret != 0) | ||
55 | goto err; | ||
56 | |||
57 | return 0; | ||
58 | |||
59 | err: | ||
60 | kfree(da9052); | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | static int da9052_spi_remove(struct spi_device *spi) | ||
65 | { | ||
66 | struct da9052 *da9052 = dev_get_drvdata(&spi->dev); | ||
67 | |||
68 | da9052_device_exit(da9052); | ||
69 | kfree(da9052); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static struct spi_device_id da9052_spi_id[] = { | ||
75 | {"da9052", DA9052}, | ||
76 | {"da9053-aa", DA9053_AA}, | ||
77 | {"da9053-ba", DA9053_BA}, | ||
78 | {"da9053-bb", DA9053_BB}, | ||
79 | {} | ||
80 | }; | ||
81 | |||
82 | static struct spi_driver da9052_spi_driver = { | ||
83 | .probe = da9052_spi_probe, | ||
84 | .remove = __devexit_p(da9052_spi_remove), | ||
85 | .id_table = da9052_spi_id, | ||
86 | .driver = { | ||
87 | .name = "da9052", | ||
88 | .bus = &spi_bus_type, | ||
89 | .owner = THIS_MODULE, | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | static int __init da9052_spi_init(void) | ||
94 | { | ||
95 | int ret; | ||
96 | |||
97 | ret = spi_register_driver(&da9052_spi_driver); | ||
98 | if (ret != 0) { | ||
99 | pr_err("Failed to register DA9052 SPI driver, %d\n", ret); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | subsys_initcall(da9052_spi_init); | ||
106 | |||
107 | static void __exit da9052_spi_exit(void) | ||
108 | { | ||
109 | spi_unregister_driver(&da9052_spi_driver); | ||
110 | } | ||
111 | module_exit(da9052_spi_exit); | ||
112 | |||
113 | MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); | ||
114 | MODULE_DESCRIPTION("SPI driver for Dialog DA9052 PMIC"); | ||
115 | MODULE_LICENSE("GPL"); | ||