aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/internal.h17
-rw-r--r--drivers/base/regmap/regmap-irq.c51
-rw-r--r--drivers/base/regmap/regmap.c226
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
100struct regcache_ops { 103struct regcache_ops {
@@ -115,6 +118,20 @@ bool regmap_precious(struct regmap *map, unsigned int reg);
115int _regmap_write(struct regmap *map, unsigned int reg, 118int _regmap_write(struct regmap *map, unsigned int reg,
116 unsigned int val); 119 unsigned int val);
117 120
121struct 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
119extern void regmap_debugfs_initcall(void); 136extern void regmap_debugfs_initcall(void);
120extern void regmap_debugfs_init(struct regmap *map, const char *name); 137extern 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
109static 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
95static struct irq_chip regmap_irq_chip = { 131static 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
103static irqreturn_t regmap_irq_thread(int irq, void *d) 140static 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,
294err_domain: 339err_domain:
295 /* Should really dispose of the domain but... */ 340 /* Should really dispose of the domain but... */
296err_alloc: 341err_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 */
347int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) 394int 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}
351EXPORT_SYMBOL_GPL(regmap_irq_get_virq); 402EXPORT_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
246static 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
271static 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
291static 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
475err_cache: 598err_debugfs:
599 regmap_debugfs_exit(map);
476 regcache_exit(map); 600 regcache_exit(map);
477err_free_workbuf: 601err_range:
602 regmap_range_exit(map);
478 kfree(map->work_buf); 603 kfree(map->work_buf);
479err_map: 604err_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}
690EXPORT_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}
616EXPORT_SYMBOL_GPL(dev_get_regmap); 743EXPORT_SYMBOL_GPL(dev_get_regmap);
617 744
745static 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
618static int _regmap_raw_write(struct regmap *map, unsigned int reg, 796static 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, &reg, 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, &reg, 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, &reg, 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
1101out:
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}
1123EXPORT_SYMBOL_GPL(regmap_update_bits); 1314EXPORT_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}
1143EXPORT_SYMBOL_GPL(regmap_update_bits_check); 1339EXPORT_SYMBOL_GPL(regmap_update_bits_check);
1144 1340