diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/regmap/internal.h | 24 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 148 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 19 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 269 |
4 files changed, 365 insertions, 95 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 80f9ab9c3aa4..401d1919635a 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -15,10 +15,18 @@ | |||
15 | 15 | ||
16 | #include <linux/regmap.h> | 16 | #include <linux/regmap.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/list.h> | ||
18 | 19 | ||
19 | struct regmap; | 20 | struct regmap; |
20 | struct regcache_ops; | 21 | struct regcache_ops; |
21 | 22 | ||
23 | struct regmap_debugfs_off_cache { | ||
24 | struct list_head list; | ||
25 | off_t min; | ||
26 | off_t max; | ||
27 | unsigned int base_reg; | ||
28 | }; | ||
29 | |||
22 | struct regmap_format { | 30 | struct regmap_format { |
23 | size_t buf_size; | 31 | size_t buf_size; |
24 | size_t reg_bytes; | 32 | size_t reg_bytes; |
@@ -31,14 +39,12 @@ struct regmap_format { | |||
31 | unsigned int (*parse_val)(void *buf); | 39 | unsigned int (*parse_val)(void *buf); |
32 | }; | 40 | }; |
33 | 41 | ||
34 | typedef void (*regmap_lock)(struct regmap *map); | ||
35 | typedef void (*regmap_unlock)(struct regmap *map); | ||
36 | |||
37 | struct regmap { | 42 | struct regmap { |
38 | struct mutex mutex; | 43 | struct mutex mutex; |
39 | spinlock_t spinlock; | 44 | spinlock_t spinlock; |
40 | regmap_lock lock; | 45 | regmap_lock lock; |
41 | regmap_unlock unlock; | 46 | regmap_unlock unlock; |
47 | void *lock_arg; /* This is passed to lock/unlock functions */ | ||
42 | 48 | ||
43 | struct device *dev; /* Device we do I/O on */ | 49 | struct device *dev; /* Device we do I/O on */ |
44 | void *work_buf; /* Scratch buffer used to format I/O */ | 50 | void *work_buf; /* Scratch buffer used to format I/O */ |
@@ -50,6 +56,12 @@ struct regmap { | |||
50 | #ifdef CONFIG_DEBUG_FS | 56 | #ifdef CONFIG_DEBUG_FS |
51 | struct dentry *debugfs; | 57 | struct dentry *debugfs; |
52 | const char *debugfs_name; | 58 | const char *debugfs_name; |
59 | |||
60 | unsigned int debugfs_reg_len; | ||
61 | unsigned int debugfs_val_len; | ||
62 | unsigned int debugfs_tot_len; | ||
63 | |||
64 | struct list_head debugfs_off_cache; | ||
53 | #endif | 65 | #endif |
54 | 66 | ||
55 | unsigned int max_register; | 67 | unsigned int max_register; |
@@ -57,6 +69,10 @@ struct regmap { | |||
57 | bool (*readable_reg)(struct device *dev, unsigned int reg); | 69 | bool (*readable_reg)(struct device *dev, unsigned int reg); |
58 | bool (*volatile_reg)(struct device *dev, unsigned int reg); | 70 | bool (*volatile_reg)(struct device *dev, unsigned int reg); |
59 | bool (*precious_reg)(struct device *dev, unsigned int reg); | 71 | bool (*precious_reg)(struct device *dev, unsigned int reg); |
72 | const struct regmap_access_table *wr_table; | ||
73 | const struct regmap_access_table *rd_table; | ||
74 | const struct regmap_access_table *volatile_table; | ||
75 | const struct regmap_access_table *precious_table; | ||
60 | 76 | ||
61 | u8 read_flag_mask; | 77 | u8 read_flag_mask; |
62 | u8 write_flag_mask; | 78 | u8 write_flag_mask; |
@@ -120,6 +136,8 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
120 | 136 | ||
121 | struct regmap_range_node { | 137 | struct regmap_range_node { |
122 | struct rb_node node; | 138 | struct rb_node node; |
139 | const char *name; | ||
140 | struct regmap *map; | ||
123 | 141 | ||
124 | unsigned int range_min; | 142 | unsigned int range_min; |
125 | unsigned int range_max; | 143 | unsigned int range_max; |
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index bb1ff175b962..07aad786f817 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -56,17 +56,74 @@ static const struct file_operations regmap_name_fops = { | |||
56 | .llseek = default_llseek, | 56 | .llseek = default_llseek, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | 59 | /* |
60 | size_t count, loff_t *ppos) | 60 | * Work out where the start offset maps into register numbers, bearing |
61 | * in mind that we suppress hidden registers. | ||
62 | */ | ||
63 | static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | ||
64 | unsigned int base, | ||
65 | loff_t from, | ||
66 | loff_t *pos) | ||
61 | { | 67 | { |
62 | int reg_len, val_len, tot_len; | 68 | struct regmap_debugfs_off_cache *c = NULL; |
63 | size_t buf_pos = 0; | ||
64 | loff_t p = 0; | 69 | loff_t p = 0; |
70 | unsigned int i, ret; | ||
71 | |||
72 | /* | ||
73 | * If we don't have a cache build one so we don't have to do a | ||
74 | * linear scan each time. | ||
75 | */ | ||
76 | if (list_empty(&map->debugfs_off_cache)) { | ||
77 | for (i = base; i <= map->max_register; i += map->reg_stride) { | ||
78 | /* Skip unprinted registers, closing off cache entry */ | ||
79 | if (!regmap_readable(map, i) || | ||
80 | regmap_precious(map, i)) { | ||
81 | if (c) { | ||
82 | c->max = p - 1; | ||
83 | list_add_tail(&c->list, | ||
84 | &map->debugfs_off_cache); | ||
85 | c = NULL; | ||
86 | } | ||
87 | |||
88 | continue; | ||
89 | } | ||
90 | |||
91 | /* No cache entry? Start a new one */ | ||
92 | if (!c) { | ||
93 | c = kzalloc(sizeof(*c), GFP_KERNEL); | ||
94 | if (!c) | ||
95 | break; | ||
96 | c->min = p; | ||
97 | c->base_reg = i; | ||
98 | } | ||
99 | |||
100 | p += map->debugfs_tot_len; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* Find the relevant block */ | ||
105 | list_for_each_entry(c, &map->debugfs_off_cache, list) { | ||
106 | if (*pos >= c->min && *pos <= c->max) { | ||
107 | *pos = c->min; | ||
108 | return c->base_reg; | ||
109 | } | ||
110 | |||
111 | ret = c->max; | ||
112 | } | ||
113 | |||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, | ||
118 | unsigned int to, char __user *user_buf, | ||
119 | size_t count, loff_t *ppos) | ||
120 | { | ||
121 | size_t buf_pos = 0; | ||
122 | loff_t p = *ppos; | ||
65 | ssize_t ret; | 123 | ssize_t ret; |
66 | int i; | 124 | int i; |
67 | struct regmap *map = file->private_data; | ||
68 | char *buf; | 125 | char *buf; |
69 | unsigned int val; | 126 | unsigned int val, start_reg; |
70 | 127 | ||
71 | if (*ppos < 0 || !count) | 128 | if (*ppos < 0 || !count) |
72 | return -EINVAL; | 129 | return -EINVAL; |
@@ -76,11 +133,18 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | |||
76 | return -ENOMEM; | 133 | return -ENOMEM; |
77 | 134 | ||
78 | /* Calculate the length of a fixed format */ | 135 | /* Calculate the length of a fixed format */ |
79 | reg_len = regmap_calc_reg_len(map->max_register, buf, count); | 136 | if (!map->debugfs_tot_len) { |
80 | val_len = 2 * map->format.val_bytes; | 137 | map->debugfs_reg_len = regmap_calc_reg_len(map->max_register, |
81 | tot_len = reg_len + val_len + 3; /* : \n */ | 138 | buf, count); |
139 | map->debugfs_val_len = 2 * map->format.val_bytes; | ||
140 | map->debugfs_tot_len = map->debugfs_reg_len + | ||
141 | map->debugfs_val_len + 3; /* : \n */ | ||
142 | } | ||
82 | 143 | ||
83 | for (i = 0; i <= map->max_register; i += map->reg_stride) { | 144 | /* Work out which register we're starting at */ |
145 | start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p); | ||
146 | |||
147 | for (i = start_reg; i <= to; i += map->reg_stride) { | ||
84 | if (!regmap_readable(map, i)) | 148 | if (!regmap_readable(map, i)) |
85 | continue; | 149 | continue; |
86 | 150 | ||
@@ -90,26 +154,27 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | |||
90 | /* If we're in the region the user is trying to read */ | 154 | /* If we're in the region the user is trying to read */ |
91 | if (p >= *ppos) { | 155 | if (p >= *ppos) { |
92 | /* ...but not beyond it */ | 156 | /* ...but not beyond it */ |
93 | if (buf_pos >= count - 1 - tot_len) | 157 | if (buf_pos + 1 + map->debugfs_tot_len >= count) |
94 | break; | 158 | break; |
95 | 159 | ||
96 | /* Format the register */ | 160 | /* Format the register */ |
97 | snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", | 161 | snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", |
98 | reg_len, i); | 162 | map->debugfs_reg_len, i - from); |
99 | buf_pos += reg_len + 2; | 163 | buf_pos += map->debugfs_reg_len + 2; |
100 | 164 | ||
101 | /* Format the value, write all X if we can't read */ | 165 | /* Format the value, write all X if we can't read */ |
102 | ret = regmap_read(map, i, &val); | 166 | ret = regmap_read(map, i, &val); |
103 | if (ret == 0) | 167 | if (ret == 0) |
104 | snprintf(buf + buf_pos, count - buf_pos, | 168 | snprintf(buf + buf_pos, count - buf_pos, |
105 | "%.*x", val_len, val); | 169 | "%.*x", map->debugfs_val_len, val); |
106 | else | 170 | else |
107 | memset(buf + buf_pos, 'X', val_len); | 171 | memset(buf + buf_pos, 'X', |
172 | map->debugfs_val_len); | ||
108 | buf_pos += 2 * map->format.val_bytes; | 173 | buf_pos += 2 * map->format.val_bytes; |
109 | 174 | ||
110 | buf[buf_pos++] = '\n'; | 175 | buf[buf_pos++] = '\n'; |
111 | } | 176 | } |
112 | p += tot_len; | 177 | p += map->debugfs_tot_len; |
113 | } | 178 | } |
114 | 179 | ||
115 | ret = buf_pos; | 180 | ret = buf_pos; |
@@ -126,6 +191,15 @@ out: | |||
126 | return ret; | 191 | return ret; |
127 | } | 192 | } |
128 | 193 | ||
194 | static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, | ||
195 | size_t count, loff_t *ppos) | ||
196 | { | ||
197 | struct regmap *map = file->private_data; | ||
198 | |||
199 | return regmap_read_debugfs(map, 0, map->max_register, user_buf, | ||
200 | count, ppos); | ||
201 | } | ||
202 | |||
129 | #undef REGMAP_ALLOW_WRITE_DEBUGFS | 203 | #undef REGMAP_ALLOW_WRITE_DEBUGFS |
130 | #ifdef REGMAP_ALLOW_WRITE_DEBUGFS | 204 | #ifdef REGMAP_ALLOW_WRITE_DEBUGFS |
131 | /* | 205 | /* |
@@ -174,6 +248,22 @@ static const struct file_operations regmap_map_fops = { | |||
174 | .llseek = default_llseek, | 248 | .llseek = default_llseek, |
175 | }; | 249 | }; |
176 | 250 | ||
251 | static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf, | ||
252 | size_t count, loff_t *ppos) | ||
253 | { | ||
254 | struct regmap_range_node *range = file->private_data; | ||
255 | struct regmap *map = range->map; | ||
256 | |||
257 | return regmap_read_debugfs(map, range->range_min, range->range_max, | ||
258 | user_buf, count, ppos); | ||
259 | } | ||
260 | |||
261 | static const struct file_operations regmap_range_fops = { | ||
262 | .open = simple_open, | ||
263 | .read = regmap_range_read_file, | ||
264 | .llseek = default_llseek, | ||
265 | }; | ||
266 | |||
177 | static ssize_t regmap_access_read_file(struct file *file, | 267 | static ssize_t regmap_access_read_file(struct file *file, |
178 | char __user *user_buf, size_t count, | 268 | char __user *user_buf, size_t count, |
179 | loff_t *ppos) | 269 | loff_t *ppos) |
@@ -244,6 +334,11 @@ static const struct file_operations regmap_access_fops = { | |||
244 | 334 | ||
245 | void regmap_debugfs_init(struct regmap *map, const char *name) | 335 | void regmap_debugfs_init(struct regmap *map, const char *name) |
246 | { | 336 | { |
337 | struct rb_node *next; | ||
338 | struct regmap_range_node *range_node; | ||
339 | |||
340 | INIT_LIST_HEAD(&map->debugfs_off_cache); | ||
341 | |||
247 | if (name) { | 342 | if (name) { |
248 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", | 343 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", |
249 | dev_name(map->dev), name); | 344 | dev_name(map->dev), name); |
@@ -276,11 +371,32 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
276 | debugfs_create_bool("cache_bypass", 0400, map->debugfs, | 371 | debugfs_create_bool("cache_bypass", 0400, map->debugfs, |
277 | &map->cache_bypass); | 372 | &map->cache_bypass); |
278 | } | 373 | } |
374 | |||
375 | next = rb_first(&map->range_tree); | ||
376 | while (next) { | ||
377 | range_node = rb_entry(next, struct regmap_range_node, node); | ||
378 | |||
379 | if (range_node->name) | ||
380 | debugfs_create_file(range_node->name, 0400, | ||
381 | map->debugfs, range_node, | ||
382 | ®map_range_fops); | ||
383 | |||
384 | next = rb_next(&range_node->node); | ||
385 | } | ||
279 | } | 386 | } |
280 | 387 | ||
281 | void regmap_debugfs_exit(struct regmap *map) | 388 | void regmap_debugfs_exit(struct regmap *map) |
282 | { | 389 | { |
390 | struct regmap_debugfs_off_cache *c; | ||
391 | |||
283 | debugfs_remove_recursive(map->debugfs); | 392 | debugfs_remove_recursive(map->debugfs); |
393 | while (!list_empty(&map->debugfs_off_cache)) { | ||
394 | c = list_first_entry(&map->debugfs_off_cache, | ||
395 | struct regmap_debugfs_off_cache, | ||
396 | list); | ||
397 | list_del(&c->list); | ||
398 | kfree(c); | ||
399 | } | ||
284 | kfree(map->debugfs_name); | 400 | kfree(map->debugfs_name); |
285 | } | 401 | } |
286 | 402 | ||
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 5b6b1d8e6cc0..5972ad958544 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -458,3 +458,22 @@ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) | |||
458 | return irq_create_mapping(data->domain, irq); | 458 | return irq_create_mapping(data->domain, irq); |
459 | } | 459 | } |
460 | EXPORT_SYMBOL_GPL(regmap_irq_get_virq); | 460 | EXPORT_SYMBOL_GPL(regmap_irq_get_virq); |
461 | |||
462 | /** | ||
463 | * regmap_irq_get_domain(): Retrieve the irq_domain for the chip | ||
464 | * | ||
465 | * Useful for drivers to request their own IRQs and for integration | ||
466 | * with subsystems. For ease of integration NULL is accepted as a | ||
467 | * domain, allowing devices to just call this even if no domain is | ||
468 | * allocated. | ||
469 | * | ||
470 | * @data: regmap_irq controller to operate on. | ||
471 | */ | ||
472 | struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data) | ||
473 | { | ||
474 | if (data) | ||
475 | return data->domain; | ||
476 | else | ||
477 | return NULL; | ||
478 | } | ||
479 | EXPORT_SYMBOL_GPL(regmap_irq_get_domain); | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 52069d29ff12..42d5cb0f503f 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -34,6 +34,36 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
34 | unsigned int mask, unsigned int val, | 34 | unsigned int mask, unsigned int val, |
35 | bool *change); | 35 | bool *change); |
36 | 36 | ||
37 | bool regmap_reg_in_ranges(unsigned int reg, | ||
38 | const struct regmap_range *ranges, | ||
39 | unsigned int nranges) | ||
40 | { | ||
41 | const struct regmap_range *r; | ||
42 | int i; | ||
43 | |||
44 | for (i = 0, r = ranges; i < nranges; i++, r++) | ||
45 | if (regmap_reg_in_range(reg, r)) | ||
46 | return true; | ||
47 | return false; | ||
48 | } | ||
49 | EXPORT_SYMBOL_GPL(regmap_reg_in_ranges); | ||
50 | |||
51 | static bool _regmap_check_range_table(struct regmap *map, | ||
52 | unsigned int reg, | ||
53 | const struct regmap_access_table *table) | ||
54 | { | ||
55 | /* Check "no ranges" first */ | ||
56 | if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) | ||
57 | return false; | ||
58 | |||
59 | /* In case zero "yes ranges" are supplied, any reg is OK */ | ||
60 | if (!table->n_yes_ranges) | ||
61 | return true; | ||
62 | |||
63 | return regmap_reg_in_ranges(reg, table->yes_ranges, | ||
64 | table->n_yes_ranges); | ||
65 | } | ||
66 | |||
37 | bool regmap_writeable(struct regmap *map, unsigned int reg) | 67 | bool regmap_writeable(struct regmap *map, unsigned int reg) |
38 | { | 68 | { |
39 | if (map->max_register && reg > map->max_register) | 69 | if (map->max_register && reg > map->max_register) |
@@ -42,6 +72,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg) | |||
42 | if (map->writeable_reg) | 72 | if (map->writeable_reg) |
43 | return map->writeable_reg(map->dev, reg); | 73 | return map->writeable_reg(map->dev, reg); |
44 | 74 | ||
75 | if (map->wr_table) | ||
76 | return _regmap_check_range_table(map, reg, map->wr_table); | ||
77 | |||
45 | return true; | 78 | return true; |
46 | } | 79 | } |
47 | 80 | ||
@@ -56,6 +89,9 @@ bool regmap_readable(struct regmap *map, unsigned int reg) | |||
56 | if (map->readable_reg) | 89 | if (map->readable_reg) |
57 | return map->readable_reg(map->dev, reg); | 90 | return map->readable_reg(map->dev, reg); |
58 | 91 | ||
92 | if (map->rd_table) | ||
93 | return _regmap_check_range_table(map, reg, map->rd_table); | ||
94 | |||
59 | return true; | 95 | return true; |
60 | } | 96 | } |
61 | 97 | ||
@@ -67,6 +103,9 @@ bool regmap_volatile(struct regmap *map, unsigned int reg) | |||
67 | if (map->volatile_reg) | 103 | if (map->volatile_reg) |
68 | return map->volatile_reg(map->dev, reg); | 104 | return map->volatile_reg(map->dev, reg); |
69 | 105 | ||
106 | if (map->volatile_table) | ||
107 | return _regmap_check_range_table(map, reg, map->volatile_table); | ||
108 | |||
70 | return true; | 109 | return true; |
71 | } | 110 | } |
72 | 111 | ||
@@ -78,11 +117,14 @@ bool regmap_precious(struct regmap *map, unsigned int reg) | |||
78 | if (map->precious_reg) | 117 | if (map->precious_reg) |
79 | return map->precious_reg(map->dev, reg); | 118 | return map->precious_reg(map->dev, reg); |
80 | 119 | ||
120 | if (map->precious_table) | ||
121 | return _regmap_check_range_table(map, reg, map->precious_table); | ||
122 | |||
81 | return false; | 123 | return false; |
82 | } | 124 | } |
83 | 125 | ||
84 | static bool regmap_volatile_range(struct regmap *map, unsigned int reg, | 126 | static bool regmap_volatile_range(struct regmap *map, unsigned int reg, |
85 | unsigned int num) | 127 | size_t num) |
86 | { | 128 | { |
87 | unsigned int i; | 129 | unsigned int i; |
88 | 130 | ||
@@ -214,23 +256,27 @@ static unsigned int regmap_parse_32_native(void *buf) | |||
214 | return *(u32 *)buf; | 256 | return *(u32 *)buf; |
215 | } | 257 | } |
216 | 258 | ||
217 | static void regmap_lock_mutex(struct regmap *map) | 259 | static void regmap_lock_mutex(void *__map) |
218 | { | 260 | { |
261 | struct regmap *map = __map; | ||
219 | mutex_lock(&map->mutex); | 262 | mutex_lock(&map->mutex); |
220 | } | 263 | } |
221 | 264 | ||
222 | static void regmap_unlock_mutex(struct regmap *map) | 265 | static void regmap_unlock_mutex(void *__map) |
223 | { | 266 | { |
267 | struct regmap *map = __map; | ||
224 | mutex_unlock(&map->mutex); | 268 | mutex_unlock(&map->mutex); |
225 | } | 269 | } |
226 | 270 | ||
227 | static void regmap_lock_spinlock(struct regmap *map) | 271 | static void regmap_lock_spinlock(void *__map) |
228 | { | 272 | { |
273 | struct regmap *map = __map; | ||
229 | spin_lock(&map->spinlock); | 274 | spin_lock(&map->spinlock); |
230 | } | 275 | } |
231 | 276 | ||
232 | static void regmap_unlock_spinlock(struct regmap *map) | 277 | static void regmap_unlock_spinlock(void *__map) |
233 | { | 278 | { |
279 | struct regmap *map = __map; | ||
234 | spin_unlock(&map->spinlock); | 280 | spin_unlock(&map->spinlock); |
235 | } | 281 | } |
236 | 282 | ||
@@ -335,14 +381,21 @@ struct regmap *regmap_init(struct device *dev, | |||
335 | goto err; | 381 | goto err; |
336 | } | 382 | } |
337 | 383 | ||
338 | if (bus->fast_io) { | 384 | if (config->lock && config->unlock) { |
339 | spin_lock_init(&map->spinlock); | 385 | map->lock = config->lock; |
340 | map->lock = regmap_lock_spinlock; | 386 | map->unlock = config->unlock; |
341 | map->unlock = regmap_unlock_spinlock; | 387 | map->lock_arg = config->lock_arg; |
342 | } else { | 388 | } else { |
343 | mutex_init(&map->mutex); | 389 | if (bus->fast_io) { |
344 | map->lock = regmap_lock_mutex; | 390 | spin_lock_init(&map->spinlock); |
345 | map->unlock = regmap_unlock_mutex; | 391 | map->lock = regmap_lock_spinlock; |
392 | map->unlock = regmap_unlock_spinlock; | ||
393 | } else { | ||
394 | mutex_init(&map->mutex); | ||
395 | map->lock = regmap_lock_mutex; | ||
396 | map->unlock = regmap_unlock_mutex; | ||
397 | } | ||
398 | map->lock_arg = map; | ||
346 | } | 399 | } |
347 | map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); | 400 | map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); |
348 | map->format.pad_bytes = config->pad_bits / 8; | 401 | map->format.pad_bytes = config->pad_bits / 8; |
@@ -359,6 +412,10 @@ struct regmap *regmap_init(struct device *dev, | |||
359 | map->bus = bus; | 412 | map->bus = bus; |
360 | map->bus_context = bus_context; | 413 | map->bus_context = bus_context; |
361 | map->max_register = config->max_register; | 414 | map->max_register = config->max_register; |
415 | map->wr_table = config->wr_table; | ||
416 | map->rd_table = config->rd_table; | ||
417 | map->volatile_table = config->volatile_table; | ||
418 | map->precious_table = config->precious_table; | ||
362 | map->writeable_reg = config->writeable_reg; | 419 | map->writeable_reg = config->writeable_reg; |
363 | map->readable_reg = config->readable_reg; | 420 | map->readable_reg = config->readable_reg; |
364 | map->volatile_reg = config->volatile_reg; | 421 | map->volatile_reg = config->volatile_reg; |
@@ -519,20 +576,38 @@ struct regmap *regmap_init(struct device *dev, | |||
519 | } | 576 | } |
520 | 577 | ||
521 | map->range_tree = RB_ROOT; | 578 | map->range_tree = RB_ROOT; |
522 | for (i = 0; i < config->n_ranges; i++) { | 579 | for (i = 0; i < config->num_ranges; i++) { |
523 | const struct regmap_range_cfg *range_cfg = &config->ranges[i]; | 580 | const struct regmap_range_cfg *range_cfg = &config->ranges[i]; |
524 | struct regmap_range_node *new; | 581 | struct regmap_range_node *new; |
525 | 582 | ||
526 | /* Sanity check */ | 583 | /* Sanity check */ |
527 | if (range_cfg->range_max < range_cfg->range_min || | 584 | if (range_cfg->range_max < range_cfg->range_min) { |
528 | range_cfg->range_max > map->max_register || | 585 | dev_err(map->dev, "Invalid range %d: %d < %d\n", i, |
529 | range_cfg->selector_reg > map->max_register || | 586 | range_cfg->range_max, range_cfg->range_min); |
530 | range_cfg->window_len == 0) | 587 | goto err_range; |
588 | } | ||
589 | |||
590 | if (range_cfg->range_max > map->max_register) { | ||
591 | dev_err(map->dev, "Invalid range %d: %d > %d\n", i, | ||
592 | range_cfg->range_max, map->max_register); | ||
593 | goto err_range; | ||
594 | } | ||
595 | |||
596 | if (range_cfg->selector_reg > map->max_register) { | ||
597 | dev_err(map->dev, | ||
598 | "Invalid range %d: selector out of map\n", i); | ||
599 | goto err_range; | ||
600 | } | ||
601 | |||
602 | if (range_cfg->window_len == 0) { | ||
603 | dev_err(map->dev, "Invalid range %d: window_len 0\n", | ||
604 | i); | ||
531 | goto err_range; | 605 | goto err_range; |
606 | } | ||
532 | 607 | ||
533 | /* Make sure, that this register range has no selector | 608 | /* Make sure, that this register range has no selector |
534 | or data window within its boundary */ | 609 | or data window within its boundary */ |
535 | for (j = 0; j < config->n_ranges; j++) { | 610 | for (j = 0; j < config->num_ranges; j++) { |
536 | unsigned sel_reg = config->ranges[j].selector_reg; | 611 | unsigned sel_reg = config->ranges[j].selector_reg; |
537 | unsigned win_min = config->ranges[j].window_start; | 612 | unsigned win_min = config->ranges[j].window_start; |
538 | unsigned win_max = win_min + | 613 | unsigned win_max = win_min + |
@@ -540,11 +615,17 @@ struct regmap *regmap_init(struct device *dev, | |||
540 | 615 | ||
541 | if (range_cfg->range_min <= sel_reg && | 616 | if (range_cfg->range_min <= sel_reg && |
542 | sel_reg <= range_cfg->range_max) { | 617 | sel_reg <= range_cfg->range_max) { |
618 | dev_err(map->dev, | ||
619 | "Range %d: selector for %d in window\n", | ||
620 | i, j); | ||
543 | goto err_range; | 621 | goto err_range; |
544 | } | 622 | } |
545 | 623 | ||
546 | if (!(win_max < range_cfg->range_min || | 624 | if (!(win_max < range_cfg->range_min || |
547 | win_min > range_cfg->range_max)) { | 625 | win_min > range_cfg->range_max)) { |
626 | dev_err(map->dev, | ||
627 | "Range %d: window for %d in window\n", | ||
628 | i, j); | ||
548 | goto err_range; | 629 | goto err_range; |
549 | } | 630 | } |
550 | } | 631 | } |
@@ -555,6 +636,8 @@ struct regmap *regmap_init(struct device *dev, | |||
555 | goto err_range; | 636 | goto err_range; |
556 | } | 637 | } |
557 | 638 | ||
639 | new->map = map; | ||
640 | new->name = range_cfg->name; | ||
558 | new->range_min = range_cfg->range_min; | 641 | new->range_min = range_cfg->range_min; |
559 | new->range_max = range_cfg->range_max; | 642 | new->range_max = range_cfg->range_max; |
560 | new->selector_reg = range_cfg->selector_reg; | 643 | new->selector_reg = range_cfg->selector_reg; |
@@ -564,6 +647,7 @@ struct regmap *regmap_init(struct device *dev, | |||
564 | new->window_len = range_cfg->window_len; | 647 | new->window_len = range_cfg->window_len; |
565 | 648 | ||
566 | if (_regmap_range_add(map, new) == false) { | 649 | if (_regmap_range_add(map, new) == false) { |
650 | dev_err(map->dev, "Failed to add range %d\n", i); | ||
567 | kfree(new); | 651 | kfree(new); |
568 | goto err_range; | 652 | goto err_range; |
569 | } | 653 | } |
@@ -579,7 +663,7 @@ struct regmap *regmap_init(struct device *dev, | |||
579 | } | 663 | } |
580 | 664 | ||
581 | ret = regcache_init(map, config); | 665 | ret = regcache_init(map, config); |
582 | if (ret < 0) | 666 | if (ret != 0) |
583 | goto err_range; | 667 | goto err_range; |
584 | 668 | ||
585 | regmap_debugfs_init(map, config->name); | 669 | regmap_debugfs_init(map, config->name); |
@@ -738,59 +822,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) | |||
738 | EXPORT_SYMBOL_GPL(dev_get_regmap); | 822 | EXPORT_SYMBOL_GPL(dev_get_regmap); |
739 | 823 | ||
740 | static int _regmap_select_page(struct regmap *map, unsigned int *reg, | 824 | static int _regmap_select_page(struct regmap *map, unsigned int *reg, |
825 | struct regmap_range_node *range, | ||
741 | unsigned int val_num) | 826 | unsigned int val_num) |
742 | { | 827 | { |
743 | struct regmap_range_node *range; | ||
744 | void *orig_work_buf; | 828 | void *orig_work_buf; |
745 | unsigned int win_offset; | 829 | unsigned int win_offset; |
746 | unsigned int win_page; | 830 | unsigned int win_page; |
747 | bool page_chg; | 831 | bool page_chg; |
748 | int ret; | 832 | int ret; |
749 | 833 | ||
750 | range = _regmap_range_lookup(map, *reg); | 834 | win_offset = (*reg - range->range_min) % range->window_len; |
751 | if (range) { | 835 | win_page = (*reg - range->range_min) / range->window_len; |
752 | win_offset = (*reg - range->range_min) % range->window_len; | ||
753 | win_page = (*reg - range->range_min) / range->window_len; | ||
754 | |||
755 | if (val_num > 1) { | ||
756 | /* Bulk write shouldn't cross range boundary */ | ||
757 | if (*reg + val_num - 1 > range->range_max) | ||
758 | return -EINVAL; | ||
759 | 836 | ||
760 | /* ... or single page boundary */ | 837 | if (val_num > 1) { |
761 | if (val_num > range->window_len - win_offset) | 838 | /* Bulk write shouldn't cross range boundary */ |
762 | return -EINVAL; | 839 | if (*reg + val_num - 1 > range->range_max) |
763 | } | 840 | return -EINVAL; |
764 | 841 | ||
765 | /* It is possible to have selector register inside data window. | 842 | /* ... or single page boundary */ |
766 | In that case, selector register is located on every page and | 843 | if (val_num > range->window_len - win_offset) |
767 | it needs no page switching, when accessed alone. */ | 844 | return -EINVAL; |
768 | if (val_num > 1 || | 845 | } |
769 | range->window_start + win_offset != range->selector_reg) { | ||
770 | /* Use separate work_buf during page switching */ | ||
771 | orig_work_buf = map->work_buf; | ||
772 | map->work_buf = map->selector_work_buf; | ||
773 | 846 | ||
774 | ret = _regmap_update_bits(map, range->selector_reg, | 847 | /* It is possible to have selector register inside data window. |
775 | range->selector_mask, | 848 | In that case, selector register is located on every page and |
776 | win_page << range->selector_shift, | 849 | it needs no page switching, when accessed alone. */ |
777 | &page_chg); | 850 | if (val_num > 1 || |
851 | range->window_start + win_offset != range->selector_reg) { | ||
852 | /* Use separate work_buf during page switching */ | ||
853 | orig_work_buf = map->work_buf; | ||
854 | map->work_buf = map->selector_work_buf; | ||
778 | 855 | ||
779 | map->work_buf = orig_work_buf; | 856 | ret = _regmap_update_bits(map, range->selector_reg, |
857 | range->selector_mask, | ||
858 | win_page << range->selector_shift, | ||
859 | &page_chg); | ||
780 | 860 | ||
781 | if (ret < 0) | 861 | map->work_buf = orig_work_buf; |
782 | return ret; | ||
783 | } | ||
784 | 862 | ||
785 | *reg = range->window_start + win_offset; | 863 | if (ret != 0) |
864 | return ret; | ||
786 | } | 865 | } |
787 | 866 | ||
867 | *reg = range->window_start + win_offset; | ||
868 | |||
788 | return 0; | 869 | return 0; |
789 | } | 870 | } |
790 | 871 | ||
791 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, | 872 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, |
792 | const void *val, size_t val_len) | 873 | const void *val, size_t val_len) |
793 | { | 874 | { |
875 | struct regmap_range_node *range; | ||
794 | u8 *u8 = map->work_buf; | 876 | u8 *u8 = map->work_buf; |
795 | void *buf; | 877 | void *buf; |
796 | int ret = -ENOTSUPP; | 878 | int ret = -ENOTSUPP; |
@@ -814,7 +896,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
814 | ival); | 896 | ival); |
815 | if (ret) { | 897 | if (ret) { |
816 | dev_err(map->dev, | 898 | dev_err(map->dev, |
817 | "Error in caching of register: %u ret: %d\n", | 899 | "Error in caching of register: %x ret: %d\n", |
818 | reg + i, ret); | 900 | reg + i, ret); |
819 | return ret; | 901 | return ret; |
820 | } | 902 | } |
@@ -825,9 +907,35 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
825 | } | 907 | } |
826 | } | 908 | } |
827 | 909 | ||
828 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | 910 | range = _regmap_range_lookup(map, reg); |
829 | if (ret < 0) | 911 | if (range) { |
830 | return ret; | 912 | int val_num = val_len / map->format.val_bytes; |
913 | int win_offset = (reg - range->range_min) % range->window_len; | ||
914 | int win_residue = range->window_len - win_offset; | ||
915 | |||
916 | /* If the write goes beyond the end of the window split it */ | ||
917 | while (val_num > win_residue) { | ||
918 | dev_dbg(map->dev, "Writing window %d/%zu\n", | ||
919 | win_residue, val_len / map->format.val_bytes); | ||
920 | ret = _regmap_raw_write(map, reg, val, win_residue * | ||
921 | map->format.val_bytes); | ||
922 | if (ret != 0) | ||
923 | return ret; | ||
924 | |||
925 | reg += win_residue; | ||
926 | val_num -= win_residue; | ||
927 | val += win_residue * map->format.val_bytes; | ||
928 | val_len -= win_residue * map->format.val_bytes; | ||
929 | |||
930 | win_offset = (reg - range->range_min) % | ||
931 | range->window_len; | ||
932 | win_residue = range->window_len - win_offset; | ||
933 | } | ||
934 | |||
935 | ret = _regmap_select_page(map, ®, range, val_num); | ||
936 | if (ret != 0) | ||
937 | return ret; | ||
938 | } | ||
831 | 939 | ||
832 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 940 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
833 | 941 | ||
@@ -876,6 +984,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
876 | int _regmap_write(struct regmap *map, unsigned int reg, | 984 | int _regmap_write(struct regmap *map, unsigned int reg, |
877 | unsigned int val) | 985 | unsigned int val) |
878 | { | 986 | { |
987 | struct regmap_range_node *range; | ||
879 | int ret; | 988 | int ret; |
880 | BUG_ON(!map->format.format_write && !map->format.format_val); | 989 | BUG_ON(!map->format.format_write && !map->format.format_val); |
881 | 990 | ||
@@ -897,9 +1006,12 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
897 | trace_regmap_reg_write(map->dev, reg, val); | 1006 | trace_regmap_reg_write(map->dev, reg, val); |
898 | 1007 | ||
899 | if (map->format.format_write) { | 1008 | if (map->format.format_write) { |
900 | ret = _regmap_select_page(map, ®, 1); | 1009 | range = _regmap_range_lookup(map, reg); |
901 | if (ret < 0) | 1010 | if (range) { |
902 | return ret; | 1011 | ret = _regmap_select_page(map, ®, range, 1); |
1012 | if (ret != 0) | ||
1013 | return ret; | ||
1014 | } | ||
903 | 1015 | ||
904 | map->format.format_write(map, reg, val); | 1016 | map->format.format_write(map, reg, val); |
905 | 1017 | ||
@@ -939,11 +1051,11 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) | |||
939 | if (reg % map->reg_stride) | 1051 | if (reg % map->reg_stride) |
940 | return -EINVAL; | 1052 | return -EINVAL; |
941 | 1053 | ||
942 | map->lock(map); | 1054 | map->lock(map->lock_arg); |
943 | 1055 | ||
944 | ret = _regmap_write(map, reg, val); | 1056 | ret = _regmap_write(map, reg, val); |
945 | 1057 | ||
946 | map->unlock(map); | 1058 | map->unlock(map->lock_arg); |
947 | 1059 | ||
948 | return ret; | 1060 | return ret; |
949 | } | 1061 | } |
@@ -975,11 +1087,11 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, | |||
975 | if (reg % map->reg_stride) | 1087 | if (reg % map->reg_stride) |
976 | return -EINVAL; | 1088 | return -EINVAL; |
977 | 1089 | ||
978 | map->lock(map); | 1090 | map->lock(map->lock_arg); |
979 | 1091 | ||
980 | ret = _regmap_raw_write(map, reg, val, val_len); | 1092 | ret = _regmap_raw_write(map, reg, val, val_len); |
981 | 1093 | ||
982 | map->unlock(map); | 1094 | map->unlock(map->lock_arg); |
983 | 1095 | ||
984 | return ret; | 1096 | return ret; |
985 | } | 1097 | } |
@@ -1011,7 +1123,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1011 | if (reg % map->reg_stride) | 1123 | if (reg % map->reg_stride) |
1012 | return -EINVAL; | 1124 | return -EINVAL; |
1013 | 1125 | ||
1014 | map->lock(map); | 1126 | map->lock(map->lock_arg); |
1015 | 1127 | ||
1016 | /* No formatting is require if val_byte is 1 */ | 1128 | /* No formatting is require if val_byte is 1 */ |
1017 | if (val_bytes == 1) { | 1129 | if (val_bytes == 1) { |
@@ -1047,7 +1159,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1047 | kfree(wval); | 1159 | kfree(wval); |
1048 | 1160 | ||
1049 | out: | 1161 | out: |
1050 | map->unlock(map); | 1162 | map->unlock(map->lock_arg); |
1051 | return ret; | 1163 | return ret; |
1052 | } | 1164 | } |
1053 | EXPORT_SYMBOL_GPL(regmap_bulk_write); | 1165 | EXPORT_SYMBOL_GPL(regmap_bulk_write); |
@@ -1055,12 +1167,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); | |||
1055 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | 1167 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, |
1056 | unsigned int val_len) | 1168 | unsigned int val_len) |
1057 | { | 1169 | { |
1170 | struct regmap_range_node *range; | ||
1058 | u8 *u8 = map->work_buf; | 1171 | u8 *u8 = map->work_buf; |
1059 | int ret; | 1172 | int ret; |
1060 | 1173 | ||
1061 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | 1174 | range = _regmap_range_lookup(map, reg); |
1062 | if (ret < 0) | 1175 | if (range) { |
1063 | return ret; | 1176 | ret = _regmap_select_page(map, ®, range, |
1177 | val_len / map->format.val_bytes); | ||
1178 | if (ret != 0) | ||
1179 | return ret; | ||
1180 | } | ||
1064 | 1181 | ||
1065 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 1182 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
1066 | 1183 | ||
@@ -1137,11 +1254,11 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) | |||
1137 | if (reg % map->reg_stride) | 1254 | if (reg % map->reg_stride) |
1138 | return -EINVAL; | 1255 | return -EINVAL; |
1139 | 1256 | ||
1140 | map->lock(map); | 1257 | map->lock(map->lock_arg); |
1141 | 1258 | ||
1142 | ret = _regmap_read(map, reg, val); | 1259 | ret = _regmap_read(map, reg, val); |
1143 | 1260 | ||
1144 | map->unlock(map); | 1261 | map->unlock(map->lock_arg); |
1145 | 1262 | ||
1146 | return ret; | 1263 | return ret; |
1147 | } | 1264 | } |
@@ -1171,7 +1288,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | |||
1171 | if (reg % map->reg_stride) | 1288 | if (reg % map->reg_stride) |
1172 | return -EINVAL; | 1289 | return -EINVAL; |
1173 | 1290 | ||
1174 | map->lock(map); | 1291 | map->lock(map->lock_arg); |
1175 | 1292 | ||
1176 | if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass || | 1293 | if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass || |
1177 | map->cache_type == REGCACHE_NONE) { | 1294 | map->cache_type == REGCACHE_NONE) { |
@@ -1193,7 +1310,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | |||
1193 | } | 1310 | } |
1194 | 1311 | ||
1195 | out: | 1312 | out: |
1196 | map->unlock(map); | 1313 | map->unlock(map->lock_arg); |
1197 | 1314 | ||
1198 | return ret; | 1315 | return ret; |
1199 | } | 1316 | } |
@@ -1300,9 +1417,9 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, | |||
1300 | bool change; | 1417 | bool change; |
1301 | int ret; | 1418 | int ret; |
1302 | 1419 | ||
1303 | map->lock(map); | 1420 | map->lock(map->lock_arg); |
1304 | ret = _regmap_update_bits(map, reg, mask, val, &change); | 1421 | ret = _regmap_update_bits(map, reg, mask, val, &change); |
1305 | map->unlock(map); | 1422 | map->unlock(map->lock_arg); |
1306 | 1423 | ||
1307 | return ret; | 1424 | return ret; |
1308 | } | 1425 | } |
@@ -1326,9 +1443,9 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
1326 | { | 1443 | { |
1327 | int ret; | 1444 | int ret; |
1328 | 1445 | ||
1329 | map->lock(map); | 1446 | map->lock(map->lock_arg); |
1330 | ret = _regmap_update_bits(map, reg, mask, val, change); | 1447 | ret = _regmap_update_bits(map, reg, mask, val, change); |
1331 | map->unlock(map); | 1448 | map->unlock(map->lock_arg); |
1332 | return ret; | 1449 | return ret; |
1333 | } | 1450 | } |
1334 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); | 1451 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); |
@@ -1357,7 +1474,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | |||
1357 | if (map->patch) | 1474 | if (map->patch) |
1358 | return -EBUSY; | 1475 | return -EBUSY; |
1359 | 1476 | ||
1360 | map->lock(map); | 1477 | map->lock(map->lock_arg); |
1361 | 1478 | ||
1362 | bypass = map->cache_bypass; | 1479 | bypass = map->cache_bypass; |
1363 | 1480 | ||
@@ -1385,7 +1502,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | |||
1385 | out: | 1502 | out: |
1386 | map->cache_bypass = bypass; | 1503 | map->cache_bypass = bypass; |
1387 | 1504 | ||
1388 | map->unlock(map); | 1505 | map->unlock(map->lock_arg); |
1389 | 1506 | ||
1390 | return ret; | 1507 | return ret; |
1391 | } | 1508 | } |