diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/internal.h | 17 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 51 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 226 |
3 files changed, 279 insertions, 15 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index b986b8660b0c..80f9ab9c3aa4 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -95,6 +95,9 @@ struct regmap { | |||
95 | 95 | ||
96 | /* if set, converts bulk rw to single rw */ | 96 | /* if set, converts bulk rw to single rw */ |
97 | bool use_single_rw; | 97 | bool use_single_rw; |
98 | |||
99 | struct rb_root range_tree; | ||
100 | void *selector_work_buf; /* Scratch buffer used for selector */ | ||
98 | }; | 101 | }; |
99 | 102 | ||
100 | struct regcache_ops { | 103 | struct regcache_ops { |
@@ -115,6 +118,20 @@ bool regmap_precious(struct regmap *map, unsigned int reg); | |||
115 | int _regmap_write(struct regmap *map, unsigned int reg, | 118 | int _regmap_write(struct regmap *map, unsigned int reg, |
116 | unsigned int val); | 119 | unsigned int val); |
117 | 120 | ||
121 | struct regmap_range_node { | ||
122 | struct rb_node node; | ||
123 | |||
124 | unsigned int range_min; | ||
125 | unsigned int range_max; | ||
126 | |||
127 | unsigned int selector_reg; | ||
128 | unsigned int selector_mask; | ||
129 | int selector_shift; | ||
130 | |||
131 | unsigned int window_start; | ||
132 | unsigned int window_len; | ||
133 | }; | ||
134 | |||
118 | #ifdef CONFIG_DEBUG_FS | 135 | #ifdef CONFIG_DEBUG_FS |
119 | extern void regmap_debugfs_initcall(void); | 136 | extern void regmap_debugfs_initcall(void); |
120 | extern void regmap_debugfs_init(struct regmap *map, const char *name); | 137 | extern void regmap_debugfs_init(struct regmap *map, const char *name); |
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index c190229daa59..a89734621e51 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -29,9 +29,13 @@ struct regmap_irq_chip_data { | |||
29 | int irq_base; | 29 | int irq_base; |
30 | struct irq_domain *domain; | 30 | struct irq_domain *domain; |
31 | 31 | ||
32 | int irq; | ||
33 | int wake_count; | ||
34 | |||
32 | unsigned int *status_buf; | 35 | unsigned int *status_buf; |
33 | unsigned int *mask_buf; | 36 | unsigned int *mask_buf; |
34 | unsigned int *mask_buf_def; | 37 | unsigned int *mask_buf_def; |
38 | unsigned int *wake_buf; | ||
35 | 39 | ||
36 | unsigned int irq_reg_stride; | 40 | unsigned int irq_reg_stride; |
37 | }; | 41 | }; |
@@ -71,6 +75,16 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
71 | d->chip->mask_base + (i * map->reg_stride)); | 75 | d->chip->mask_base + (i * map->reg_stride)); |
72 | } | 76 | } |
73 | 77 | ||
78 | /* If we've changed our wakeup count propagate it to the parent */ | ||
79 | if (d->wake_count < 0) | ||
80 | for (i = d->wake_count; i < 0; i++) | ||
81 | irq_set_irq_wake(d->irq, 0); | ||
82 | else if (d->wake_count > 0) | ||
83 | for (i = 0; i < d->wake_count; i++) | ||
84 | irq_set_irq_wake(d->irq, 1); | ||
85 | |||
86 | d->wake_count = 0; | ||
87 | |||
74 | mutex_unlock(&d->lock); | 88 | mutex_unlock(&d->lock); |
75 | } | 89 | } |
76 | 90 | ||
@@ -92,12 +106,35 @@ static void regmap_irq_disable(struct irq_data *data) | |||
92 | d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; | 106 | d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; |
93 | } | 107 | } |
94 | 108 | ||
109 | static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) | ||
110 | { | ||
111 | struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); | ||
112 | struct regmap *map = d->map; | ||
113 | const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq); | ||
114 | |||
115 | if (!d->chip->wake_base) | ||
116 | return -EINVAL; | ||
117 | |||
118 | if (on) { | ||
119 | d->wake_buf[irq_data->reg_offset / map->reg_stride] | ||
120 | &= ~irq_data->mask; | ||
121 | d->wake_count++; | ||
122 | } else { | ||
123 | d->wake_buf[irq_data->reg_offset / map->reg_stride] | ||
124 | |= irq_data->mask; | ||
125 | d->wake_count--; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
95 | static struct irq_chip regmap_irq_chip = { | 131 | static struct irq_chip regmap_irq_chip = { |
96 | .name = "regmap", | 132 | .name = "regmap", |
97 | .irq_bus_lock = regmap_irq_lock, | 133 | .irq_bus_lock = regmap_irq_lock, |
98 | .irq_bus_sync_unlock = regmap_irq_sync_unlock, | 134 | .irq_bus_sync_unlock = regmap_irq_sync_unlock, |
99 | .irq_disable = regmap_irq_disable, | 135 | .irq_disable = regmap_irq_disable, |
100 | .irq_enable = regmap_irq_enable, | 136 | .irq_enable = regmap_irq_enable, |
137 | .irq_set_wake = regmap_irq_set_wake, | ||
101 | }; | 138 | }; |
102 | 139 | ||
103 | static irqreturn_t regmap_irq_thread(int irq, void *d) | 140 | static irqreturn_t regmap_irq_thread(int irq, void *d) |
@@ -240,6 +277,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
240 | if (!d->mask_buf_def) | 277 | if (!d->mask_buf_def) |
241 | goto err_alloc; | 278 | goto err_alloc; |
242 | 279 | ||
280 | if (chip->wake_base) { | ||
281 | d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, | ||
282 | GFP_KERNEL); | ||
283 | if (!d->wake_buf) | ||
284 | goto err_alloc; | ||
285 | } | ||
286 | |||
287 | d->irq = irq; | ||
243 | d->map = map; | 288 | d->map = map; |
244 | d->chip = chip; | 289 | d->chip = chip; |
245 | d->irq_base = irq_base; | 290 | d->irq_base = irq_base; |
@@ -294,6 +339,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
294 | err_domain: | 339 | err_domain: |
295 | /* Should really dispose of the domain but... */ | 340 | /* Should really dispose of the domain but... */ |
296 | err_alloc: | 341 | err_alloc: |
342 | kfree(d->wake_buf); | ||
297 | kfree(d->mask_buf_def); | 343 | kfree(d->mask_buf_def); |
298 | kfree(d->mask_buf); | 344 | kfree(d->mask_buf); |
299 | kfree(d->status_buf); | 345 | kfree(d->status_buf); |
@@ -315,6 +361,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) | |||
315 | 361 | ||
316 | free_irq(irq, d); | 362 | free_irq(irq, d); |
317 | /* We should unmap the domain but... */ | 363 | /* We should unmap the domain but... */ |
364 | kfree(d->wake_buf); | ||
318 | kfree(d->mask_buf_def); | 365 | kfree(d->mask_buf_def); |
319 | kfree(d->mask_buf); | 366 | kfree(d->mask_buf); |
320 | kfree(d->status_buf); | 367 | kfree(d->status_buf); |
@@ -346,6 +393,10 @@ EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); | |||
346 | */ | 393 | */ |
347 | int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) | 394 | int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) |
348 | { | 395 | { |
396 | /* Handle holes in the IRQ list */ | ||
397 | if (!data->chip->irqs[irq].mask) | ||
398 | return -EINVAL; | ||
399 | |||
349 | return irq_create_mapping(data->domain, irq); | 400 | return irq_create_mapping(data->domain, irq); |
350 | } | 401 | } |
351 | EXPORT_SYMBOL_GPL(regmap_irq_get_virq); | 402 | EXPORT_SYMBOL_GPL(regmap_irq_get_virq); |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index f8a937654af2..c241ae2f2f10 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/rbtree.h> | ||
18 | 19 | ||
19 | #define CREATE_TRACE_POINTS | 20 | #define CREATE_TRACE_POINTS |
20 | #include <trace/events/regmap.h> | 21 | #include <trace/events/regmap.h> |
@@ -242,6 +243,67 @@ static void dev_get_regmap_release(struct device *dev, void *res) | |||
242 | */ | 243 | */ |
243 | } | 244 | } |
244 | 245 | ||
246 | static bool _regmap_range_add(struct regmap *map, | ||
247 | struct regmap_range_node *data) | ||
248 | { | ||
249 | struct rb_root *root = &map->range_tree; | ||
250 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
251 | |||
252 | while (*new) { | ||
253 | struct regmap_range_node *this = | ||
254 | container_of(*new, struct regmap_range_node, node); | ||
255 | |||
256 | parent = *new; | ||
257 | if (data->range_max < this->range_min) | ||
258 | new = &((*new)->rb_left); | ||
259 | else if (data->range_min > this->range_max) | ||
260 | new = &((*new)->rb_right); | ||
261 | else | ||
262 | return false; | ||
263 | } | ||
264 | |||
265 | rb_link_node(&data->node, parent, new); | ||
266 | rb_insert_color(&data->node, root); | ||
267 | |||
268 | return true; | ||
269 | } | ||
270 | |||
271 | static struct regmap_range_node *_regmap_range_lookup(struct regmap *map, | ||
272 | unsigned int reg) | ||
273 | { | ||
274 | struct rb_node *node = map->range_tree.rb_node; | ||
275 | |||
276 | while (node) { | ||
277 | struct regmap_range_node *this = | ||
278 | container_of(node, struct regmap_range_node, node); | ||
279 | |||
280 | if (reg < this->range_min) | ||
281 | node = node->rb_left; | ||
282 | else if (reg > this->range_max) | ||
283 | node = node->rb_right; | ||
284 | else | ||
285 | return this; | ||
286 | } | ||
287 | |||
288 | return NULL; | ||
289 | } | ||
290 | |||
291 | static void regmap_range_exit(struct regmap *map) | ||
292 | { | ||
293 | struct rb_node *next; | ||
294 | struct regmap_range_node *range_node; | ||
295 | |||
296 | next = rb_first(&map->range_tree); | ||
297 | while (next) { | ||
298 | range_node = rb_entry(next, struct regmap_range_node, node); | ||
299 | next = rb_next(&range_node->node); | ||
300 | rb_erase(&range_node->node, &map->range_tree); | ||
301 | kfree(range_node); | ||
302 | } | ||
303 | |||
304 | kfree(map->selector_work_buf); | ||
305 | } | ||
306 | |||
245 | /** | 307 | /** |
246 | * regmap_init(): Initialise register map | 308 | * regmap_init(): Initialise register map |
247 | * | 309 | * |
@@ -262,6 +324,7 @@ struct regmap *regmap_init(struct device *dev, | |||
262 | struct regmap *map, **m; | 324 | struct regmap *map, **m; |
263 | int ret = -EINVAL; | 325 | int ret = -EINVAL; |
264 | enum regmap_endian reg_endian, val_endian; | 326 | enum regmap_endian reg_endian, val_endian; |
327 | int i, j; | ||
265 | 328 | ||
266 | if (!bus || !config) | 329 | if (!bus || !config) |
267 | goto err; | 330 | goto err; |
@@ -281,11 +344,11 @@ struct regmap *regmap_init(struct device *dev, | |||
281 | map->lock = regmap_lock_mutex; | 344 | map->lock = regmap_lock_mutex; |
282 | map->unlock = regmap_unlock_mutex; | 345 | map->unlock = regmap_unlock_mutex; |
283 | } | 346 | } |
284 | map->format.buf_size = (config->reg_bits + config->val_bits) / 8; | ||
285 | map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); | 347 | map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); |
286 | map->format.pad_bytes = config->pad_bits / 8; | 348 | map->format.pad_bytes = config->pad_bits / 8; |
287 | map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); | 349 | map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); |
288 | map->format.buf_size += map->format.pad_bytes; | 350 | map->format.buf_size = DIV_ROUND_UP(config->reg_bits + |
351 | config->val_bits + config->pad_bits, 8); | ||
289 | map->reg_shift = config->pad_bits % 8; | 352 | map->reg_shift = config->pad_bits % 8; |
290 | if (config->reg_stride) | 353 | if (config->reg_stride) |
291 | map->reg_stride = config->reg_stride; | 354 | map->reg_stride = config->reg_stride; |
@@ -455,26 +518,88 @@ struct regmap *regmap_init(struct device *dev, | |||
455 | goto err_map; | 518 | goto err_map; |
456 | } | 519 | } |
457 | 520 | ||
458 | regmap_debugfs_init(map, config->name); | 521 | map->range_tree = RB_ROOT; |
522 | for (i = 0; i < config->n_ranges; i++) { | ||
523 | const struct regmap_range_cfg *range_cfg = &config->ranges[i]; | ||
524 | struct regmap_range_node *new; | ||
525 | |||
526 | /* Sanity check */ | ||
527 | if (range_cfg->range_max < range_cfg->range_min || | ||
528 | range_cfg->range_max > map->max_register || | ||
529 | range_cfg->selector_reg > map->max_register || | ||
530 | range_cfg->window_len == 0) | ||
531 | goto err_range; | ||
532 | |||
533 | /* Make sure, that this register range has no selector | ||
534 | or data window within its boundary */ | ||
535 | for (j = 0; j < config->n_ranges; j++) { | ||
536 | unsigned sel_reg = config->ranges[j].selector_reg; | ||
537 | unsigned win_min = config->ranges[j].window_start; | ||
538 | unsigned win_max = win_min + | ||
539 | config->ranges[j].window_len - 1; | ||
540 | |||
541 | if (range_cfg->range_min <= sel_reg && | ||
542 | sel_reg <= range_cfg->range_max) { | ||
543 | goto err_range; | ||
544 | } | ||
545 | |||
546 | if (!(win_max < range_cfg->range_min || | ||
547 | win_min > range_cfg->range_max)) { | ||
548 | goto err_range; | ||
549 | } | ||
550 | } | ||
551 | |||
552 | new = kzalloc(sizeof(*new), GFP_KERNEL); | ||
553 | if (new == NULL) { | ||
554 | ret = -ENOMEM; | ||
555 | goto err_range; | ||
556 | } | ||
557 | |||
558 | new->range_min = range_cfg->range_min; | ||
559 | new->range_max = range_cfg->range_max; | ||
560 | new->selector_reg = range_cfg->selector_reg; | ||
561 | new->selector_mask = range_cfg->selector_mask; | ||
562 | new->selector_shift = range_cfg->selector_shift; | ||
563 | new->window_start = range_cfg->window_start; | ||
564 | new->window_len = range_cfg->window_len; | ||
565 | |||
566 | if (_regmap_range_add(map, new) == false) { | ||
567 | kfree(new); | ||
568 | goto err_range; | ||
569 | } | ||
570 | |||
571 | if (map->selector_work_buf == NULL) { | ||
572 | map->selector_work_buf = | ||
573 | kzalloc(map->format.buf_size, GFP_KERNEL); | ||
574 | if (map->selector_work_buf == NULL) { | ||
575 | ret = -ENOMEM; | ||
576 | goto err_range; | ||
577 | } | ||
578 | } | ||
579 | } | ||
459 | 580 | ||
460 | ret = regcache_init(map, config); | 581 | ret = regcache_init(map, config); |
461 | if (ret < 0) | 582 | if (ret < 0) |
462 | goto err_free_workbuf; | 583 | goto err_range; |
584 | |||
585 | regmap_debugfs_init(map, config->name); | ||
463 | 586 | ||
464 | /* Add a devres resource for dev_get_regmap() */ | 587 | /* Add a devres resource for dev_get_regmap() */ |
465 | m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); | 588 | m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); |
466 | if (!m) { | 589 | if (!m) { |
467 | ret = -ENOMEM; | 590 | ret = -ENOMEM; |
468 | goto err_cache; | 591 | goto err_debugfs; |
469 | } | 592 | } |
470 | *m = map; | 593 | *m = map; |
471 | devres_add(dev, m); | 594 | devres_add(dev, m); |
472 | 595 | ||
473 | return map; | 596 | return map; |
474 | 597 | ||
475 | err_cache: | 598 | err_debugfs: |
599 | regmap_debugfs_exit(map); | ||
476 | regcache_exit(map); | 600 | regcache_exit(map); |
477 | err_free_workbuf: | 601 | err_range: |
602 | regmap_range_exit(map); | ||
478 | kfree(map->work_buf); | 603 | kfree(map->work_buf); |
479 | err_map: | 604 | err_map: |
480 | kfree(map); | 605 | kfree(map); |
@@ -562,6 +687,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) | |||
562 | 687 | ||
563 | return ret; | 688 | return ret; |
564 | } | 689 | } |
690 | EXPORT_SYMBOL_GPL(regmap_reinit_cache); | ||
565 | 691 | ||
566 | /** | 692 | /** |
567 | * regmap_exit(): Free a previously allocated register map | 693 | * regmap_exit(): Free a previously allocated register map |
@@ -570,6 +696,7 @@ void regmap_exit(struct regmap *map) | |||
570 | { | 696 | { |
571 | regcache_exit(map); | 697 | regcache_exit(map); |
572 | regmap_debugfs_exit(map); | 698 | regmap_debugfs_exit(map); |
699 | regmap_range_exit(map); | ||
573 | if (map->bus->free_context) | 700 | if (map->bus->free_context) |
574 | map->bus->free_context(map->bus_context); | 701 | map->bus->free_context(map->bus_context); |
575 | kfree(map->work_buf); | 702 | kfree(map->work_buf); |
@@ -615,6 +742,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) | |||
615 | } | 742 | } |
616 | EXPORT_SYMBOL_GPL(dev_get_regmap); | 743 | EXPORT_SYMBOL_GPL(dev_get_regmap); |
617 | 744 | ||
745 | static int _regmap_select_page(struct regmap *map, unsigned int *reg, | ||
746 | unsigned int val_num) | ||
747 | { | ||
748 | struct regmap_range_node *range; | ||
749 | void *orig_work_buf; | ||
750 | unsigned int win_offset; | ||
751 | unsigned int win_page; | ||
752 | bool page_chg; | ||
753 | int ret; | ||
754 | |||
755 | range = _regmap_range_lookup(map, *reg); | ||
756 | if (range) { | ||
757 | win_offset = (*reg - range->range_min) % range->window_len; | ||
758 | win_page = (*reg - range->range_min) / range->window_len; | ||
759 | |||
760 | if (val_num > 1) { | ||
761 | /* Bulk write shouldn't cross range boundary */ | ||
762 | if (*reg + val_num - 1 > range->range_max) | ||
763 | return -EINVAL; | ||
764 | |||
765 | /* ... or single page boundary */ | ||
766 | if (val_num > range->window_len - win_offset) | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | |||
770 | /* It is possible to have selector register inside data window. | ||
771 | In that case, selector register is located on every page and | ||
772 | it needs no page switching, when accessed alone. */ | ||
773 | if (val_num > 1 || | ||
774 | range->window_start + win_offset != range->selector_reg) { | ||
775 | /* Use separate work_buf during page switching */ | ||
776 | orig_work_buf = map->work_buf; | ||
777 | map->work_buf = map->selector_work_buf; | ||
778 | |||
779 | ret = _regmap_update_bits(map, range->selector_reg, | ||
780 | range->selector_mask, | ||
781 | win_page << range->selector_shift, | ||
782 | &page_chg); | ||
783 | |||
784 | map->work_buf = orig_work_buf; | ||
785 | |||
786 | if (ret < 0) | ||
787 | return ret; | ||
788 | } | ||
789 | |||
790 | *reg = range->window_start + win_offset; | ||
791 | } | ||
792 | |||
793 | return 0; | ||
794 | } | ||
795 | |||
618 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, | 796 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, |
619 | const void *val, size_t val_len) | 797 | const void *val, size_t val_len) |
620 | { | 798 | { |
@@ -652,6 +830,10 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
652 | } | 830 | } |
653 | } | 831 | } |
654 | 832 | ||
833 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | ||
834 | if (ret < 0) | ||
835 | return ret; | ||
836 | |||
655 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 837 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
656 | 838 | ||
657 | u8[0] |= map->write_flag_mask; | 839 | u8[0] |= map->write_flag_mask; |
@@ -720,6 +902,10 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
720 | trace_regmap_reg_write(map->dev, reg, val); | 902 | trace_regmap_reg_write(map->dev, reg, val); |
721 | 903 | ||
722 | if (map->format.format_write) { | 904 | if (map->format.format_write) { |
905 | ret = _regmap_select_page(map, ®, 1); | ||
906 | if (ret < 0) | ||
907 | return ret; | ||
908 | |||
723 | map->format.format_write(map, reg, val); | 909 | map->format.format_write(map, reg, val); |
724 | 910 | ||
725 | trace_regmap_hw_write_start(map->dev, reg, 1); | 911 | trace_regmap_hw_write_start(map->dev, reg, 1); |
@@ -877,6 +1063,10 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | |||
877 | u8 *u8 = map->work_buf; | 1063 | u8 *u8 = map->work_buf; |
878 | int ret; | 1064 | int ret; |
879 | 1065 | ||
1066 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | ||
1067 | if (ret < 0) | ||
1068 | return ret; | ||
1069 | |||
880 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 1070 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
881 | 1071 | ||
882 | /* | 1072 | /* |
@@ -1082,11 +1272,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
1082 | int ret; | 1272 | int ret; |
1083 | unsigned int tmp, orig; | 1273 | unsigned int tmp, orig; |
1084 | 1274 | ||
1085 | map->lock(map); | ||
1086 | |||
1087 | ret = _regmap_read(map, reg, &orig); | 1275 | ret = _regmap_read(map, reg, &orig); |
1088 | if (ret != 0) | 1276 | if (ret != 0) |
1089 | goto out; | 1277 | return ret; |
1090 | 1278 | ||
1091 | tmp = orig & ~mask; | 1279 | tmp = orig & ~mask; |
1092 | tmp |= val & mask; | 1280 | tmp |= val & mask; |
@@ -1098,9 +1286,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
1098 | *change = false; | 1286 | *change = false; |
1099 | } | 1287 | } |
1100 | 1288 | ||
1101 | out: | ||
1102 | map->unlock(map); | ||
1103 | |||
1104 | return ret; | 1289 | return ret; |
1105 | } | 1290 | } |
1106 | 1291 | ||
@@ -1118,7 +1303,13 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, | |||
1118 | unsigned int mask, unsigned int val) | 1303 | unsigned int mask, unsigned int val) |
1119 | { | 1304 | { |
1120 | bool change; | 1305 | bool change; |
1121 | return _regmap_update_bits(map, reg, mask, val, &change); | 1306 | int ret; |
1307 | |||
1308 | map->lock(map); | ||
1309 | ret = _regmap_update_bits(map, reg, mask, val, &change); | ||
1310 | map->unlock(map); | ||
1311 | |||
1312 | return ret; | ||
1122 | } | 1313 | } |
1123 | EXPORT_SYMBOL_GPL(regmap_update_bits); | 1314 | EXPORT_SYMBOL_GPL(regmap_update_bits); |
1124 | 1315 | ||
@@ -1138,7 +1329,12 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
1138 | unsigned int mask, unsigned int val, | 1329 | unsigned int mask, unsigned int val, |
1139 | bool *change) | 1330 | bool *change) |
1140 | { | 1331 | { |
1141 | return _regmap_update_bits(map, reg, mask, val, change); | 1332 | int ret; |
1333 | |||
1334 | map->lock(map); | ||
1335 | ret = _regmap_update_bits(map, reg, mask, val, change); | ||
1336 | map->unlock(map); | ||
1337 | return ret; | ||
1142 | } | 1338 | } |
1143 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); | 1339 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); |
1144 | 1340 | ||