diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-02 19:16:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-02 19:16:24 -0500 |
commit | 5062ecdb662bf3aed6dc975019c53ffcd3b01d1c (patch) | |
tree | b03fcaa4f72617938ccc7c711ccbbc91fb2d98a1 /drivers/base | |
parent | e86328c489d7ecdca99410a06a3f448caf7857bf (diff) | |
parent | d4a1a317e7478b70e18b9cc8eac7d29090121b6e (diff) |
Merge tag 'regmap-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown:
"Quite a few new features for regmap this time, mostly expanding things
around the edges of the existing functionality to cover more devices
rather than thinsg with wide applicability:
- Support for offload of the update_bits() operation to hardware
where devices implement bit level access.
- Support for a few extra operations that need scratch buffers on
fast_io devices where we can't sleep.
- Expanded the feature set of regmap_irq to cope with some extra
register layouts.
- Cleanups to the debugfs code"
* tag 'regmap-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
regmap: Allow installing custom reg_update_bits function
regmap: debugfs: simplify regmap_reg_ranges_read_file() slightly
regmap: debugfs: use memcpy instead of snprintf
regmap: debugfs: use snprintf return value in regmap_reg_ranges_read_file()
regmap: Add generic macro to define regmap_irq
regmap: debugfs: Remove scratch buffer for register length calculation
regmap: irq: add ack_invert flag for chips using cleared bits as ack
regmap: irq: add support for chips who have separate unmask registers
regmap: Allocate buffers with GFP_ATOMIC when fast_io == true
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/internal.h | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 23 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 43 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 41 |
4 files changed, 80 insertions, 30 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index cc557886ab23..3250e53473a3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -59,6 +59,7 @@ struct regmap { | |||
59 | regmap_lock lock; | 59 | regmap_lock lock; |
60 | regmap_unlock unlock; | 60 | regmap_unlock unlock; |
61 | void *lock_arg; /* This is passed to lock/unlock functions */ | 61 | void *lock_arg; /* This is passed to lock/unlock functions */ |
62 | gfp_t alloc_flags; | ||
62 | 63 | ||
63 | struct device *dev; /* Device we do I/O on */ | 64 | struct device *dev; /* Device we do I/O on */ |
64 | void *work_buf; /* Scratch buffer used to format I/O */ | 65 | void *work_buf; /* Scratch buffer used to format I/O */ |
@@ -98,6 +99,8 @@ struct regmap { | |||
98 | 99 | ||
99 | int (*reg_read)(void *context, unsigned int reg, unsigned int *val); | 100 | int (*reg_read)(void *context, unsigned int reg, unsigned int *val); |
100 | int (*reg_write)(void *context, unsigned int reg, unsigned int val); | 101 | int (*reg_write)(void *context, unsigned int reg, unsigned int val); |
102 | int (*reg_update_bits)(void *context, unsigned int reg, | ||
103 | unsigned int mask, unsigned int val); | ||
101 | 104 | ||
102 | bool defer_caching; | 105 | bool defer_caching; |
103 | 106 | ||
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 4c55cfbad19e..3f0a7e262d69 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -30,7 +30,7 @@ static LIST_HEAD(regmap_debugfs_early_list); | |||
30 | static DEFINE_MUTEX(regmap_debugfs_early_lock); | 30 | static DEFINE_MUTEX(regmap_debugfs_early_lock); |
31 | 31 | ||
32 | /* Calculate the length of a fixed format */ | 32 | /* Calculate the length of a fixed format */ |
33 | static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) | 33 | static size_t regmap_calc_reg_len(int max_val) |
34 | { | 34 | { |
35 | return snprintf(NULL, 0, "%x", max_val); | 35 | return snprintf(NULL, 0, "%x", max_val); |
36 | } | 36 | } |
@@ -173,8 +173,7 @@ static inline void regmap_calc_tot_len(struct regmap *map, | |||
173 | { | 173 | { |
174 | /* Calculate the length of a fixed format */ | 174 | /* Calculate the length of a fixed format */ |
175 | if (!map->debugfs_tot_len) { | 175 | if (!map->debugfs_tot_len) { |
176 | map->debugfs_reg_len = regmap_calc_reg_len(map->max_register, | 176 | map->debugfs_reg_len = regmap_calc_reg_len(map->max_register), |
177 | buf, count); | ||
178 | map->debugfs_val_len = 2 * map->format.val_bytes; | 177 | map->debugfs_val_len = 2 * map->format.val_bytes; |
179 | map->debugfs_tot_len = map->debugfs_reg_len + | 178 | map->debugfs_tot_len = map->debugfs_reg_len + |
180 | map->debugfs_val_len + 3; /* : \n */ | 179 | map->debugfs_val_len + 3; /* : \n */ |
@@ -338,6 +337,7 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file, | |||
338 | char *buf; | 337 | char *buf; |
339 | char *entry; | 338 | char *entry; |
340 | int ret; | 339 | int ret; |
340 | unsigned entry_len; | ||
341 | 341 | ||
342 | if (*ppos < 0 || !count) | 342 | if (*ppos < 0 || !count) |
343 | return -EINVAL; | 343 | return -EINVAL; |
@@ -365,18 +365,15 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file, | |||
365 | p = 0; | 365 | p = 0; |
366 | mutex_lock(&map->cache_lock); | 366 | mutex_lock(&map->cache_lock); |
367 | list_for_each_entry(c, &map->debugfs_off_cache, list) { | 367 | list_for_each_entry(c, &map->debugfs_off_cache, list) { |
368 | snprintf(entry, PAGE_SIZE, "%x-%x", | 368 | entry_len = snprintf(entry, PAGE_SIZE, "%x-%x\n", |
369 | c->base_reg, c->max_reg); | 369 | c->base_reg, c->max_reg); |
370 | if (p >= *ppos) { | 370 | if (p >= *ppos) { |
371 | if (buf_pos + 1 + strlen(entry) > count) | 371 | if (buf_pos + entry_len > count) |
372 | break; | 372 | break; |
373 | snprintf(buf + buf_pos, count - buf_pos, | 373 | memcpy(buf + buf_pos, entry, entry_len); |
374 | "%s", entry); | 374 | buf_pos += entry_len; |
375 | buf_pos += strlen(entry); | ||
376 | buf[buf_pos] = '\n'; | ||
377 | buf_pos++; | ||
378 | } | 375 | } |
379 | p += strlen(entry) + 1; | 376 | p += entry_len; |
380 | } | 377 | } |
381 | mutex_unlock(&map->cache_lock); | 378 | mutex_unlock(&map->cache_lock); |
382 | 379 | ||
@@ -420,7 +417,7 @@ static ssize_t regmap_access_read_file(struct file *file, | |||
420 | return -ENOMEM; | 417 | return -ENOMEM; |
421 | 418 | ||
422 | /* Calculate the length of a fixed format */ | 419 | /* Calculate the length of a fixed format */ |
423 | reg_len = regmap_calc_reg_len(map->max_register, buf, count); | 420 | reg_len = regmap_calc_reg_len(map->max_register); |
424 | tot_len = reg_len + 10; /* ': R W V P\n' */ | 421 | tot_len = reg_len + 10; /* ': R W V P\n' */ |
425 | 422 | ||
426 | for (i = 0; i <= map->max_register; i += map->reg_stride) { | 423 | for (i = 0; i <= map->max_register; i += map->reg_stride) { |
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 38d1f72d869c..8d16db533527 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -63,6 +63,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
63 | struct regmap *map = d->map; | 63 | struct regmap *map = d->map; |
64 | int i, ret; | 64 | int i, ret; |
65 | u32 reg; | 65 | u32 reg; |
66 | u32 unmask_offset; | ||
66 | 67 | ||
67 | if (d->chip->runtime_pm) { | 68 | if (d->chip->runtime_pm) { |
68 | ret = pm_runtime_get_sync(map->dev); | 69 | ret = pm_runtime_get_sync(map->dev); |
@@ -79,12 +80,28 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
79 | for (i = 0; i < d->chip->num_regs; i++) { | 80 | for (i = 0; i < d->chip->num_regs; i++) { |
80 | reg = d->chip->mask_base + | 81 | reg = d->chip->mask_base + |
81 | (i * map->reg_stride * d->irq_reg_stride); | 82 | (i * map->reg_stride * d->irq_reg_stride); |
82 | if (d->chip->mask_invert) | 83 | if (d->chip->mask_invert) { |
83 | ret = regmap_update_bits(d->map, reg, | 84 | ret = regmap_update_bits(d->map, reg, |
84 | d->mask_buf_def[i], ~d->mask_buf[i]); | 85 | d->mask_buf_def[i], ~d->mask_buf[i]); |
85 | else | 86 | } else if (d->chip->unmask_base) { |
87 | /* set mask with mask_base register */ | ||
88 | ret = regmap_update_bits(d->map, reg, | ||
89 | d->mask_buf_def[i], ~d->mask_buf[i]); | ||
90 | if (ret < 0) | ||
91 | dev_err(d->map->dev, | ||
92 | "Failed to sync unmasks in %x\n", | ||
93 | reg); | ||
94 | unmask_offset = d->chip->unmask_base - | ||
95 | d->chip->mask_base; | ||
96 | /* clear mask with unmask_base register */ | ||
97 | ret = regmap_update_bits(d->map, | ||
98 | reg + unmask_offset, | ||
99 | d->mask_buf_def[i], | ||
100 | d->mask_buf[i]); | ||
101 | } else { | ||
86 | ret = regmap_update_bits(d->map, reg, | 102 | ret = regmap_update_bits(d->map, reg, |
87 | d->mask_buf_def[i], d->mask_buf[i]); | 103 | d->mask_buf_def[i], d->mask_buf[i]); |
104 | } | ||
88 | if (ret != 0) | 105 | if (ret != 0) |
89 | dev_err(d->map->dev, "Failed to sync masks in %x\n", | 106 | dev_err(d->map->dev, "Failed to sync masks in %x\n", |
90 | reg); | 107 | reg); |
@@ -116,7 +133,11 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
116 | if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) { | 133 | if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) { |
117 | reg = d->chip->ack_base + | 134 | reg = d->chip->ack_base + |
118 | (i * map->reg_stride * d->irq_reg_stride); | 135 | (i * map->reg_stride * d->irq_reg_stride); |
119 | ret = regmap_write(map, reg, d->mask_buf[i]); | 136 | /* some chips ack by write 0 */ |
137 | if (d->chip->ack_invert) | ||
138 | ret = regmap_write(map, reg, ~d->mask_buf[i]); | ||
139 | else | ||
140 | ret = regmap_write(map, reg, d->mask_buf[i]); | ||
120 | if (ret != 0) | 141 | if (ret != 0) |
121 | dev_err(d->map->dev, "Failed to ack 0x%x: %d\n", | 142 | dev_err(d->map->dev, "Failed to ack 0x%x: %d\n", |
122 | reg, ret); | 143 | reg, ret); |
@@ -339,6 +360,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
339 | int i; | 360 | int i; |
340 | int ret = -ENOMEM; | 361 | int ret = -ENOMEM; |
341 | u32 reg; | 362 | u32 reg; |
363 | u32 unmask_offset; | ||
342 | 364 | ||
343 | if (chip->num_regs <= 0) | 365 | if (chip->num_regs <= 0) |
344 | return -EINVAL; | 366 | return -EINVAL; |
@@ -420,7 +442,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
420 | if (chip->mask_invert) | 442 | if (chip->mask_invert) |
421 | ret = regmap_update_bits(map, reg, | 443 | ret = regmap_update_bits(map, reg, |
422 | d->mask_buf[i], ~d->mask_buf[i]); | 444 | d->mask_buf[i], ~d->mask_buf[i]); |
423 | else | 445 | else if (d->chip->unmask_base) { |
446 | unmask_offset = d->chip->unmask_base - | ||
447 | d->chip->mask_base; | ||
448 | ret = regmap_update_bits(d->map, | ||
449 | reg + unmask_offset, | ||
450 | d->mask_buf[i], | ||
451 | d->mask_buf[i]); | ||
452 | } else | ||
424 | ret = regmap_update_bits(map, reg, | 453 | ret = regmap_update_bits(map, reg, |
425 | d->mask_buf[i], d->mask_buf[i]); | 454 | d->mask_buf[i], d->mask_buf[i]); |
426 | if (ret != 0) { | 455 | if (ret != 0) { |
@@ -445,7 +474,11 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
445 | if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) { | 474 | if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) { |
446 | reg = chip->ack_base + | 475 | reg = chip->ack_base + |
447 | (i * map->reg_stride * d->irq_reg_stride); | 476 | (i * map->reg_stride * d->irq_reg_stride); |
448 | ret = regmap_write(map, reg, | 477 | if (chip->ack_invert) |
478 | ret = regmap_write(map, reg, | ||
479 | ~(d->status_buf[i] & d->mask_buf[i])); | ||
480 | else | ||
481 | ret = regmap_write(map, reg, | ||
449 | d->status_buf[i] & d->mask_buf[i]); | 482 | d->status_buf[i] & d->mask_buf[i]); |
450 | if (ret != 0) { | 483 | if (ret != 0) { |
451 | dev_err(map->dev, "Failed to ack 0x%x: %d\n", | 484 | dev_err(map->dev, "Failed to ack 0x%x: %d\n", |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index afaf56200674..4ac63c0e50c7 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -561,6 +561,16 @@ struct regmap *__regmap_init(struct device *dev, | |||
561 | } | 561 | } |
562 | map->lock_arg = map; | 562 | map->lock_arg = map; |
563 | } | 563 | } |
564 | |||
565 | /* | ||
566 | * When we write in fast-paths with regmap_bulk_write() don't allocate | ||
567 | * scratch buffers with sleeping allocations. | ||
568 | */ | ||
569 | if ((bus && bus->fast_io) || config->fast_io) | ||
570 | map->alloc_flags = GFP_ATOMIC; | ||
571 | else | ||
572 | map->alloc_flags = GFP_KERNEL; | ||
573 | |||
564 | map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); | 574 | map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); |
565 | map->format.pad_bytes = config->pad_bits / 8; | 575 | map->format.pad_bytes = config->pad_bits / 8; |
566 | map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); | 576 | map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); |
@@ -619,6 +629,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
619 | goto skip_format_initialization; | 629 | goto skip_format_initialization; |
620 | } else { | 630 | } else { |
621 | map->reg_read = _regmap_bus_read; | 631 | map->reg_read = _regmap_bus_read; |
632 | map->reg_update_bits = bus->reg_update_bits; | ||
622 | } | 633 | } |
623 | 634 | ||
624 | reg_endian = regmap_get_reg_endian(bus, config); | 635 | reg_endian = regmap_get_reg_endian(bus, config); |
@@ -1786,7 +1797,7 @@ out: | |||
1786 | if (!val_count) | 1797 | if (!val_count) |
1787 | return -EINVAL; | 1798 | return -EINVAL; |
1788 | 1799 | ||
1789 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); | 1800 | wval = kmemdup(val, val_count * val_bytes, map->alloc_flags); |
1790 | if (!wval) { | 1801 | if (!wval) { |
1791 | dev_err(map->dev, "Error in memory allocation\n"); | 1802 | dev_err(map->dev, "Error in memory allocation\n"); |
1792 | return -ENOMEM; | 1803 | return -ENOMEM; |
@@ -2509,20 +2520,26 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
2509 | int ret; | 2520 | int ret; |
2510 | unsigned int tmp, orig; | 2521 | unsigned int tmp, orig; |
2511 | 2522 | ||
2512 | ret = _regmap_read(map, reg, &orig); | 2523 | if (change) |
2513 | if (ret != 0) | 2524 | *change = false; |
2514 | return ret; | ||
2515 | 2525 | ||
2516 | tmp = orig & ~mask; | 2526 | if (regmap_volatile(map, reg) && map->reg_update_bits) { |
2517 | tmp |= val & mask; | 2527 | ret = map->reg_update_bits(map->bus_context, reg, mask, val); |
2518 | 2528 | if (ret == 0 && change) | |
2519 | if (force_write || (tmp != orig)) { | ||
2520 | ret = _regmap_write(map, reg, tmp); | ||
2521 | if (change) | ||
2522 | *change = true; | 2529 | *change = true; |
2523 | } else { | 2530 | } else { |
2524 | if (change) | 2531 | ret = _regmap_read(map, reg, &orig); |
2525 | *change = false; | 2532 | if (ret != 0) |
2533 | return ret; | ||
2534 | |||
2535 | tmp = orig & ~mask; | ||
2536 | tmp |= val & mask; | ||
2537 | |||
2538 | if (force_write || (tmp != orig)) { | ||
2539 | ret = _regmap_write(map, reg, tmp); | ||
2540 | if (ret == 0 && change) | ||
2541 | *change = true; | ||
2542 | } | ||
2526 | } | 2543 | } |
2527 | 2544 | ||
2528 | return ret; | 2545 | return ret; |