diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/internal.h | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 9 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 6 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 56 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 336 |
5 files changed, 341 insertions, 68 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 33414b1de201..7d1326985bee 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -134,6 +134,8 @@ struct regmap { | |||
134 | 134 | ||
135 | /* if set, converts bulk rw to single rw */ | 135 | /* if set, converts bulk rw to single rw */ |
136 | bool use_single_rw; | 136 | bool use_single_rw; |
137 | /* if set, the device supports multi write mode */ | ||
138 | bool can_multi_write; | ||
137 | 139 | ||
138 | struct rb_root range_tree; | 140 | struct rb_root range_tree; |
139 | void *selector_work_buf; /* Scratch buffer used for selector */ | 141 | void *selector_work_buf; /* Scratch buffer used for selector */ |
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index dd56177b7010..29b4128da0b0 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -249,11 +249,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, | |||
249 | { | 249 | { |
250 | unsigned int reg; | 250 | unsigned int reg; |
251 | 251 | ||
252 | for (reg = min; reg <= max; reg++) { | 252 | for (reg = min; reg <= max; reg += map->reg_stride) { |
253 | unsigned int val; | 253 | unsigned int val; |
254 | int ret; | 254 | int ret; |
255 | 255 | ||
256 | if (regmap_volatile(map, reg)) | 256 | if (regmap_volatile(map, reg) || |
257 | !regmap_writeable(map, reg)) | ||
257 | continue; | 258 | continue; |
258 | 259 | ||
259 | ret = regcache_read(map, reg, &val); | 260 | ret = regcache_read(map, reg, &val); |
@@ -312,10 +313,6 @@ int regcache_sync(struct regmap *map) | |||
312 | /* Apply any patch first */ | 313 | /* Apply any patch first */ |
313 | map->cache_bypass = 1; | 314 | map->cache_bypass = 1; |
314 | for (i = 0; i < map->patch_regs; i++) { | 315 | for (i = 0; i < map->patch_regs; i++) { |
315 | if (map->patch[i].reg % map->reg_stride) { | ||
316 | ret = -EINVAL; | ||
317 | goto out; | ||
318 | } | ||
319 | ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); | 316 | ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); |
320 | if (ret != 0) { | 317 | if (ret != 0) { |
321 | dev_err(map->dev, "Failed to write %x = %x: %d\n", | 318 | dev_err(map->dev, "Failed to write %x = %x: %d\n", |
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 82692068d3cb..edf88f20cbce 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -368,8 +368,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
368 | if (!d) | 368 | if (!d) |
369 | return -ENOMEM; | 369 | return -ENOMEM; |
370 | 370 | ||
371 | *data = d; | ||
372 | |||
373 | d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, | 371 | d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, |
374 | GFP_KERNEL); | 372 | GFP_KERNEL); |
375 | if (!d->status_buf) | 373 | if (!d->status_buf) |
@@ -506,6 +504,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
506 | goto err_domain; | 504 | goto err_domain; |
507 | } | 505 | } |
508 | 506 | ||
507 | *data = d; | ||
508 | |||
509 | return 0; | 509 | return 0; |
510 | 510 | ||
511 | err_domain: | 511 | err_domain: |
@@ -533,7 +533,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) | |||
533 | return; | 533 | return; |
534 | 534 | ||
535 | free_irq(irq, d); | 535 | free_irq(irq, d); |
536 | /* We should unmap the domain but... */ | 536 | irq_domain_remove(d->domain); |
537 | kfree(d->wake_buf); | 537 | kfree(d->wake_buf); |
538 | kfree(d->mask_buf_def); | 538 | kfree(d->mask_buf_def); |
539 | kfree(d->mask_buf); | 539 | kfree(d->mask_buf); |
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 81f977510775..de45a1e1548f 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c | |||
@@ -26,10 +26,47 @@ | |||
26 | 26 | ||
27 | struct regmap_mmio_context { | 27 | struct regmap_mmio_context { |
28 | void __iomem *regs; | 28 | void __iomem *regs; |
29 | unsigned reg_bytes; | ||
29 | unsigned val_bytes; | 30 | unsigned val_bytes; |
31 | unsigned pad_bytes; | ||
30 | struct clk *clk; | 32 | struct clk *clk; |
31 | }; | 33 | }; |
32 | 34 | ||
35 | static inline void regmap_mmio_regsize_check(size_t reg_size) | ||
36 | { | ||
37 | switch (reg_size) { | ||
38 | case 1: | ||
39 | case 2: | ||
40 | case 4: | ||
41 | #ifdef CONFIG_64BIT | ||
42 | case 8: | ||
43 | #endif | ||
44 | break; | ||
45 | default: | ||
46 | BUG(); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | static int regmap_mmio_regbits_check(size_t reg_bits) | ||
51 | { | ||
52 | switch (reg_bits) { | ||
53 | case 8: | ||
54 | case 16: | ||
55 | case 32: | ||
56 | #ifdef CONFIG_64BIT | ||
57 | case 64: | ||
58 | #endif | ||
59 | return 0; | ||
60 | default: | ||
61 | return -EINVAL; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | static inline void regmap_mmio_count_check(size_t count) | ||
66 | { | ||
67 | BUG_ON(count % 2 != 0); | ||
68 | } | ||
69 | |||
33 | static int regmap_mmio_gather_write(void *context, | 70 | static int regmap_mmio_gather_write(void *context, |
34 | const void *reg, size_t reg_size, | 71 | const void *reg, size_t reg_size, |
35 | const void *val, size_t val_size) | 72 | const void *val, size_t val_size) |
@@ -38,7 +75,7 @@ static int regmap_mmio_gather_write(void *context, | |||
38 | u32 offset; | 75 | u32 offset; |
39 | int ret; | 76 | int ret; |
40 | 77 | ||
41 | BUG_ON(reg_size != 4); | 78 | regmap_mmio_regsize_check(reg_size); |
42 | 79 | ||
43 | if (!IS_ERR(ctx->clk)) { | 80 | if (!IS_ERR(ctx->clk)) { |
44 | ret = clk_enable(ctx->clk); | 81 | ret = clk_enable(ctx->clk); |
@@ -81,9 +118,13 @@ static int regmap_mmio_gather_write(void *context, | |||
81 | 118 | ||
82 | static int regmap_mmio_write(void *context, const void *data, size_t count) | 119 | static int regmap_mmio_write(void *context, const void *data, size_t count) |
83 | { | 120 | { |
84 | BUG_ON(count < 4); | 121 | struct regmap_mmio_context *ctx = context; |
122 | u32 offset = ctx->reg_bytes + ctx->pad_bytes; | ||
123 | |||
124 | regmap_mmio_count_check(count); | ||
85 | 125 | ||
86 | return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4); | 126 | return regmap_mmio_gather_write(context, data, ctx->reg_bytes, |
127 | data + offset, count - offset); | ||
87 | } | 128 | } |
88 | 129 | ||
89 | static int regmap_mmio_read(void *context, | 130 | static int regmap_mmio_read(void *context, |
@@ -94,7 +135,7 @@ static int regmap_mmio_read(void *context, | |||
94 | u32 offset; | 135 | u32 offset; |
95 | int ret; | 136 | int ret; |
96 | 137 | ||
97 | BUG_ON(reg_size != 4); | 138 | regmap_mmio_regsize_check(reg_size); |
98 | 139 | ||
99 | if (!IS_ERR(ctx->clk)) { | 140 | if (!IS_ERR(ctx->clk)) { |
100 | ret = clk_enable(ctx->clk); | 141 | ret = clk_enable(ctx->clk); |
@@ -165,8 +206,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, | |||
165 | int min_stride; | 206 | int min_stride; |
166 | int ret; | 207 | int ret; |
167 | 208 | ||
168 | if (config->reg_bits != 32) | 209 | ret = regmap_mmio_regbits_check(config->reg_bits); |
169 | return ERR_PTR(-EINVAL); | 210 | if (ret) |
211 | return ERR_PTR(ret); | ||
170 | 212 | ||
171 | if (config->pad_bits) | 213 | if (config->pad_bits) |
172 | return ERR_PTR(-EINVAL); | 214 | return ERR_PTR(-EINVAL); |
@@ -209,6 +251,8 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, | |||
209 | 251 | ||
210 | ctx->regs = regs; | 252 | ctx->regs = regs; |
211 | ctx->val_bytes = config->val_bits / 8; | 253 | ctx->val_bytes = config->val_bits / 8; |
254 | ctx->reg_bytes = config->reg_bits / 8; | ||
255 | ctx->pad_bytes = config->pad_bits / 8; | ||
212 | ctx->clk = ERR_PTR(-ENODEV); | 256 | ctx->clk = ERR_PTR(-ENODEV); |
213 | 257 | ||
214 | if (clk_id == NULL) | 258 | if (clk_id == NULL) |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 92d9b79ff93e..d0a072463a04 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -380,6 +380,28 @@ static void regmap_range_exit(struct regmap *map) | |||
380 | kfree(map->selector_work_buf); | 380 | kfree(map->selector_work_buf); |
381 | } | 381 | } |
382 | 382 | ||
383 | int regmap_attach_dev(struct device *dev, struct regmap *map, | ||
384 | const struct regmap_config *config) | ||
385 | { | ||
386 | struct regmap **m; | ||
387 | |||
388 | map->dev = dev; | ||
389 | |||
390 | regmap_debugfs_init(map, config->name); | ||
391 | |||
392 | /* Add a devres resource for dev_get_regmap() */ | ||
393 | m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); | ||
394 | if (!m) { | ||
395 | regmap_debugfs_exit(map); | ||
396 | return -ENOMEM; | ||
397 | } | ||
398 | *m = map; | ||
399 | devres_add(dev, m); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | EXPORT_SYMBOL_GPL(regmap_attach_dev); | ||
404 | |||
383 | /** | 405 | /** |
384 | * regmap_init(): Initialise register map | 406 | * regmap_init(): Initialise register map |
385 | * | 407 | * |
@@ -397,7 +419,7 @@ struct regmap *regmap_init(struct device *dev, | |||
397 | void *bus_context, | 419 | void *bus_context, |
398 | const struct regmap_config *config) | 420 | const struct regmap_config *config) |
399 | { | 421 | { |
400 | struct regmap *map, **m; | 422 | struct regmap *map; |
401 | int ret = -EINVAL; | 423 | int ret = -EINVAL; |
402 | enum regmap_endian reg_endian, val_endian; | 424 | enum regmap_endian reg_endian, val_endian; |
403 | int i, j; | 425 | int i, j; |
@@ -439,6 +461,7 @@ struct regmap *regmap_init(struct device *dev, | |||
439 | else | 461 | else |
440 | map->reg_stride = 1; | 462 | map->reg_stride = 1; |
441 | map->use_single_rw = config->use_single_rw; | 463 | map->use_single_rw = config->use_single_rw; |
464 | map->can_multi_write = config->can_multi_write; | ||
442 | map->dev = dev; | 465 | map->dev = dev; |
443 | map->bus = bus; | 466 | map->bus = bus; |
444 | map->bus_context = bus_context; | 467 | map->bus_context = bus_context; |
@@ -734,25 +757,18 @@ skip_format_initialization: | |||
734 | } | 757 | } |
735 | } | 758 | } |
736 | 759 | ||
737 | regmap_debugfs_init(map, config->name); | ||
738 | |||
739 | ret = regcache_init(map, config); | 760 | ret = regcache_init(map, config); |
740 | if (ret != 0) | 761 | if (ret != 0) |
741 | goto err_range; | 762 | goto err_range; |
742 | 763 | ||
743 | /* Add a devres resource for dev_get_regmap() */ | 764 | if (dev) |
744 | m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); | 765 | ret = regmap_attach_dev(dev, map, config); |
745 | if (!m) { | 766 | if (ret != 0) |
746 | ret = -ENOMEM; | 767 | goto err_regcache; |
747 | goto err_debugfs; | ||
748 | } | ||
749 | *m = map; | ||
750 | devres_add(dev, m); | ||
751 | 768 | ||
752 | return map; | 769 | return map; |
753 | 770 | ||
754 | err_debugfs: | 771 | err_regcache: |
755 | regmap_debugfs_exit(map); | ||
756 | regcache_exit(map); | 772 | regcache_exit(map); |
757 | err_range: | 773 | err_range: |
758 | regmap_range_exit(map); | 774 | regmap_range_exit(map); |
@@ -1520,12 +1536,12 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1520 | if (reg % map->reg_stride) | 1536 | if (reg % map->reg_stride) |
1521 | return -EINVAL; | 1537 | return -EINVAL; |
1522 | 1538 | ||
1523 | map->lock(map->lock_arg); | ||
1524 | /* | 1539 | /* |
1525 | * Some devices don't support bulk write, for | 1540 | * Some devices don't support bulk write, for |
1526 | * them we have a series of single write operations. | 1541 | * them we have a series of single write operations. |
1527 | */ | 1542 | */ |
1528 | if (!map->bus || map->use_single_rw) { | 1543 | if (!map->bus || map->use_single_rw) { |
1544 | map->lock(map->lock_arg); | ||
1529 | for (i = 0; i < val_count; i++) { | 1545 | for (i = 0; i < val_count; i++) { |
1530 | unsigned int ival; | 1546 | unsigned int ival; |
1531 | 1547 | ||
@@ -1554,31 +1570,239 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1554 | if (ret != 0) | 1570 | if (ret != 0) |
1555 | goto out; | 1571 | goto out; |
1556 | } | 1572 | } |
1573 | out: | ||
1574 | map->unlock(map->lock_arg); | ||
1557 | } else { | 1575 | } else { |
1558 | void *wval; | 1576 | void *wval; |
1559 | 1577 | ||
1560 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); | 1578 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); |
1561 | if (!wval) { | 1579 | if (!wval) { |
1562 | ret = -ENOMEM; | ||
1563 | dev_err(map->dev, "Error in memory allocation\n"); | 1580 | dev_err(map->dev, "Error in memory allocation\n"); |
1564 | goto out; | 1581 | return -ENOMEM; |
1565 | } | 1582 | } |
1566 | for (i = 0; i < val_count * val_bytes; i += val_bytes) | 1583 | for (i = 0; i < val_count * val_bytes; i += val_bytes) |
1567 | map->format.parse_inplace(wval + i); | 1584 | map->format.parse_inplace(wval + i); |
1568 | 1585 | ||
1586 | map->lock(map->lock_arg); | ||
1569 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); | 1587 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); |
1588 | map->unlock(map->lock_arg); | ||
1570 | 1589 | ||
1571 | kfree(wval); | 1590 | kfree(wval); |
1572 | } | 1591 | } |
1573 | out: | ||
1574 | map->unlock(map->lock_arg); | ||
1575 | return ret; | 1592 | return ret; |
1576 | } | 1593 | } |
1577 | EXPORT_SYMBOL_GPL(regmap_bulk_write); | 1594 | EXPORT_SYMBOL_GPL(regmap_bulk_write); |
1578 | 1595 | ||
1579 | /* | 1596 | /* |
1597 | * _regmap_raw_multi_reg_write() | ||
1598 | * | ||
1599 | * the (register,newvalue) pairs in regs have not been formatted, but | ||
1600 | * they are all in the same page and have been changed to being page | ||
1601 | * relative. The page register has been written if that was neccessary. | ||
1602 | */ | ||
1603 | static int _regmap_raw_multi_reg_write(struct regmap *map, | ||
1604 | const struct reg_default *regs, | ||
1605 | size_t num_regs) | ||
1606 | { | ||
1607 | int ret; | ||
1608 | void *buf; | ||
1609 | int i; | ||
1610 | u8 *u8; | ||
1611 | size_t val_bytes = map->format.val_bytes; | ||
1612 | size_t reg_bytes = map->format.reg_bytes; | ||
1613 | size_t pad_bytes = map->format.pad_bytes; | ||
1614 | size_t pair_size = reg_bytes + pad_bytes + val_bytes; | ||
1615 | size_t len = pair_size * num_regs; | ||
1616 | |||
1617 | buf = kzalloc(len, GFP_KERNEL); | ||
1618 | if (!buf) | ||
1619 | return -ENOMEM; | ||
1620 | |||
1621 | /* We have to linearise by hand. */ | ||
1622 | |||
1623 | u8 = buf; | ||
1624 | |||
1625 | for (i = 0; i < num_regs; i++) { | ||
1626 | int reg = regs[i].reg; | ||
1627 | int val = regs[i].def; | ||
1628 | trace_regmap_hw_write_start(map->dev, reg, 1); | ||
1629 | map->format.format_reg(u8, reg, map->reg_shift); | ||
1630 | u8 += reg_bytes + pad_bytes; | ||
1631 | map->format.format_val(u8, val, 0); | ||
1632 | u8 += val_bytes; | ||
1633 | } | ||
1634 | u8 = buf; | ||
1635 | *u8 |= map->write_flag_mask; | ||
1636 | |||
1637 | ret = map->bus->write(map->bus_context, buf, len); | ||
1638 | |||
1639 | kfree(buf); | ||
1640 | |||
1641 | for (i = 0; i < num_regs; i++) { | ||
1642 | int reg = regs[i].reg; | ||
1643 | trace_regmap_hw_write_done(map->dev, reg, 1); | ||
1644 | } | ||
1645 | return ret; | ||
1646 | } | ||
1647 | |||
1648 | static unsigned int _regmap_register_page(struct regmap *map, | ||
1649 | unsigned int reg, | ||
1650 | struct regmap_range_node *range) | ||
1651 | { | ||
1652 | unsigned int win_page = (reg - range->range_min) / range->window_len; | ||
1653 | |||
1654 | return win_page; | ||
1655 | } | ||
1656 | |||
1657 | static int _regmap_range_multi_paged_reg_write(struct regmap *map, | ||
1658 | struct reg_default *regs, | ||
1659 | size_t num_regs) | ||
1660 | { | ||
1661 | int ret; | ||
1662 | int i, n; | ||
1663 | struct reg_default *base; | ||
1664 | unsigned int this_page; | ||
1665 | /* | ||
1666 | * the set of registers are not neccessarily in order, but | ||
1667 | * since the order of write must be preserved this algorithm | ||
1668 | * chops the set each time the page changes | ||
1669 | */ | ||
1670 | base = regs; | ||
1671 | for (i = 0, n = 0; i < num_regs; i++, n++) { | ||
1672 | unsigned int reg = regs[i].reg; | ||
1673 | struct regmap_range_node *range; | ||
1674 | |||
1675 | range = _regmap_range_lookup(map, reg); | ||
1676 | if (range) { | ||
1677 | unsigned int win_page = _regmap_register_page(map, reg, | ||
1678 | range); | ||
1679 | |||
1680 | if (i == 0) | ||
1681 | this_page = win_page; | ||
1682 | if (win_page != this_page) { | ||
1683 | this_page = win_page; | ||
1684 | ret = _regmap_raw_multi_reg_write(map, base, n); | ||
1685 | if (ret != 0) | ||
1686 | return ret; | ||
1687 | base += n; | ||
1688 | n = 0; | ||
1689 | } | ||
1690 | ret = _regmap_select_page(map, &base[n].reg, range, 1); | ||
1691 | if (ret != 0) | ||
1692 | return ret; | ||
1693 | } | ||
1694 | } | ||
1695 | if (n > 0) | ||
1696 | return _regmap_raw_multi_reg_write(map, base, n); | ||
1697 | return 0; | ||
1698 | } | ||
1699 | |||
1700 | static int _regmap_multi_reg_write(struct regmap *map, | ||
1701 | const struct reg_default *regs, | ||
1702 | size_t num_regs) | ||
1703 | { | ||
1704 | int i; | ||
1705 | int ret; | ||
1706 | |||
1707 | if (!map->can_multi_write) { | ||
1708 | for (i = 0; i < num_regs; i++) { | ||
1709 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | ||
1710 | if (ret != 0) | ||
1711 | return ret; | ||
1712 | } | ||
1713 | return 0; | ||
1714 | } | ||
1715 | |||
1716 | if (!map->format.parse_inplace) | ||
1717 | return -EINVAL; | ||
1718 | |||
1719 | if (map->writeable_reg) | ||
1720 | for (i = 0; i < num_regs; i++) { | ||
1721 | int reg = regs[i].reg; | ||
1722 | if (!map->writeable_reg(map->dev, reg)) | ||
1723 | return -EINVAL; | ||
1724 | if (reg % map->reg_stride) | ||
1725 | return -EINVAL; | ||
1726 | } | ||
1727 | |||
1728 | if (!map->cache_bypass) { | ||
1729 | for (i = 0; i < num_regs; i++) { | ||
1730 | unsigned int val = regs[i].def; | ||
1731 | unsigned int reg = regs[i].reg; | ||
1732 | ret = regcache_write(map, reg, val); | ||
1733 | if (ret) { | ||
1734 | dev_err(map->dev, | ||
1735 | "Error in caching of register: %x ret: %d\n", | ||
1736 | reg, ret); | ||
1737 | return ret; | ||
1738 | } | ||
1739 | } | ||
1740 | if (map->cache_only) { | ||
1741 | map->cache_dirty = true; | ||
1742 | return 0; | ||
1743 | } | ||
1744 | } | ||
1745 | |||
1746 | WARN_ON(!map->bus); | ||
1747 | |||
1748 | for (i = 0; i < num_regs; i++) { | ||
1749 | unsigned int reg = regs[i].reg; | ||
1750 | struct regmap_range_node *range; | ||
1751 | range = _regmap_range_lookup(map, reg); | ||
1752 | if (range) { | ||
1753 | size_t len = sizeof(struct reg_default)*num_regs; | ||
1754 | struct reg_default *base = kmemdup(regs, len, | ||
1755 | GFP_KERNEL); | ||
1756 | if (!base) | ||
1757 | return -ENOMEM; | ||
1758 | ret = _regmap_range_multi_paged_reg_write(map, base, | ||
1759 | num_regs); | ||
1760 | kfree(base); | ||
1761 | |||
1762 | return ret; | ||
1763 | } | ||
1764 | } | ||
1765 | return _regmap_raw_multi_reg_write(map, regs, num_regs); | ||
1766 | } | ||
1767 | |||
1768 | /* | ||
1580 | * regmap_multi_reg_write(): Write multiple registers to the device | 1769 | * regmap_multi_reg_write(): Write multiple registers to the device |
1581 | * | 1770 | * |
1771 | * where the set of register,value pairs are supplied in any order, | ||
1772 | * possibly not all in a single range. | ||
1773 | * | ||
1774 | * @map: Register map to write to | ||
1775 | * @regs: Array of structures containing register,value to be written | ||
1776 | * @num_regs: Number of registers to write | ||
1777 | * | ||
1778 | * The 'normal' block write mode will send ultimately send data on the | ||
1779 | * target bus as R,V1,V2,V3,..,Vn where successively higer registers are | ||
1780 | * addressed. However, this alternative block multi write mode will send | ||
1781 | * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device | ||
1782 | * must of course support the mode. | ||
1783 | * | ||
1784 | * A value of zero will be returned on success, a negative errno will be | ||
1785 | * returned in error cases. | ||
1786 | */ | ||
1787 | int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, | ||
1788 | int num_regs) | ||
1789 | { | ||
1790 | int ret; | ||
1791 | |||
1792 | map->lock(map->lock_arg); | ||
1793 | |||
1794 | ret = _regmap_multi_reg_write(map, regs, num_regs); | ||
1795 | |||
1796 | map->unlock(map->lock_arg); | ||
1797 | |||
1798 | return ret; | ||
1799 | } | ||
1800 | EXPORT_SYMBOL_GPL(regmap_multi_reg_write); | ||
1801 | |||
1802 | /* | ||
1803 | * regmap_multi_reg_write_bypassed(): Write multiple registers to the | ||
1804 | * device but not the cache | ||
1805 | * | ||
1582 | * where the set of register are supplied in any order | 1806 | * where the set of register are supplied in any order |
1583 | * | 1807 | * |
1584 | * @map: Register map to write to | 1808 | * @map: Register map to write to |
@@ -1592,30 +1816,27 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); | |||
1592 | * A value of zero will be returned on success, a negative errno will | 1816 | * A value of zero will be returned on success, a negative errno will |
1593 | * be returned in error cases. | 1817 | * be returned in error cases. |
1594 | */ | 1818 | */ |
1595 | int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs, | 1819 | int regmap_multi_reg_write_bypassed(struct regmap *map, |
1596 | int num_regs) | 1820 | const struct reg_default *regs, |
1821 | int num_regs) | ||
1597 | { | 1822 | { |
1598 | int ret = 0, i; | 1823 | int ret; |
1599 | 1824 | bool bypass; | |
1600 | for (i = 0; i < num_regs; i++) { | ||
1601 | int reg = regs[i].reg; | ||
1602 | if (reg % map->reg_stride) | ||
1603 | return -EINVAL; | ||
1604 | } | ||
1605 | 1825 | ||
1606 | map->lock(map->lock_arg); | 1826 | map->lock(map->lock_arg); |
1607 | 1827 | ||
1608 | for (i = 0; i < num_regs; i++) { | 1828 | bypass = map->cache_bypass; |
1609 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | 1829 | map->cache_bypass = true; |
1610 | if (ret != 0) | 1830 | |
1611 | goto out; | 1831 | ret = _regmap_multi_reg_write(map, regs, num_regs); |
1612 | } | 1832 | |
1613 | out: | 1833 | map->cache_bypass = bypass; |
1834 | |||
1614 | map->unlock(map->lock_arg); | 1835 | map->unlock(map->lock_arg); |
1615 | 1836 | ||
1616 | return ret; | 1837 | return ret; |
1617 | } | 1838 | } |
1618 | EXPORT_SYMBOL_GPL(regmap_multi_reg_write); | 1839 | EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed); |
1619 | 1840 | ||
1620 | /** | 1841 | /** |
1621 | * regmap_raw_write_async(): Write raw values to one or more registers | 1842 | * regmap_raw_write_async(): Write raw values to one or more registers |
@@ -2176,35 +2397,21 @@ EXPORT_SYMBOL_GPL(regmap_async_complete); | |||
2176 | * apply them immediately. Typically this is used to apply | 2397 | * apply them immediately. Typically this is used to apply |
2177 | * corrections to be applied to the device defaults on startup, such | 2398 | * corrections to be applied to the device defaults on startup, such |
2178 | * as the updates some vendors provide to undocumented registers. | 2399 | * as the updates some vendors provide to undocumented registers. |
2400 | * | ||
2401 | * The caller must ensure that this function cannot be called | ||
2402 | * concurrently with either itself or regcache_sync(). | ||
2179 | */ | 2403 | */ |
2180 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | 2404 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, |
2181 | int num_regs) | 2405 | int num_regs) |
2182 | { | 2406 | { |
2183 | struct reg_default *p; | 2407 | struct reg_default *p; |
2184 | int i, ret; | 2408 | int ret; |
2185 | bool bypass; | 2409 | bool bypass; |
2186 | 2410 | ||
2187 | if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n", | 2411 | if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n", |
2188 | num_regs)) | 2412 | num_regs)) |
2189 | return 0; | 2413 | return 0; |
2190 | 2414 | ||
2191 | map->lock(map->lock_arg); | ||
2192 | |||
2193 | bypass = map->cache_bypass; | ||
2194 | |||
2195 | map->cache_bypass = true; | ||
2196 | map->async = true; | ||
2197 | |||
2198 | /* Write out first; it's useful to apply even if we fail later. */ | ||
2199 | for (i = 0; i < num_regs; i++) { | ||
2200 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | ||
2201 | if (ret != 0) { | ||
2202 | dev_err(map->dev, "Failed to write %x = %x: %d\n", | ||
2203 | regs[i].reg, regs[i].def, ret); | ||
2204 | goto out; | ||
2205 | } | ||
2206 | } | ||
2207 | |||
2208 | p = krealloc(map->patch, | 2415 | p = krealloc(map->patch, |
2209 | sizeof(struct reg_default) * (map->patch_regs + num_regs), | 2416 | sizeof(struct reg_default) * (map->patch_regs + num_regs), |
2210 | GFP_KERNEL); | 2417 | GFP_KERNEL); |
@@ -2213,9 +2420,20 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | |||
2213 | map->patch = p; | 2420 | map->patch = p; |
2214 | map->patch_regs += num_regs; | 2421 | map->patch_regs += num_regs; |
2215 | } else { | 2422 | } else { |
2216 | ret = -ENOMEM; | 2423 | return -ENOMEM; |
2217 | } | 2424 | } |
2218 | 2425 | ||
2426 | map->lock(map->lock_arg); | ||
2427 | |||
2428 | bypass = map->cache_bypass; | ||
2429 | |||
2430 | map->cache_bypass = true; | ||
2431 | map->async = true; | ||
2432 | |||
2433 | ret = _regmap_multi_reg_write(map, regs, num_regs); | ||
2434 | if (ret != 0) | ||
2435 | goto out; | ||
2436 | |||
2219 | out: | 2437 | out: |
2220 | map->async = false; | 2438 | map->async = false; |
2221 | map->cache_bypass = bypass; | 2439 | map->cache_bypass = bypass; |
@@ -2243,6 +2461,18 @@ int regmap_get_val_bytes(struct regmap *map) | |||
2243 | } | 2461 | } |
2244 | EXPORT_SYMBOL_GPL(regmap_get_val_bytes); | 2462 | EXPORT_SYMBOL_GPL(regmap_get_val_bytes); |
2245 | 2463 | ||
2464 | int regmap_parse_val(struct regmap *map, const void *buf, | ||
2465 | unsigned int *val) | ||
2466 | { | ||
2467 | if (!map->format.parse_val) | ||
2468 | return -EINVAL; | ||
2469 | |||
2470 | *val = map->format.parse_val(buf); | ||
2471 | |||
2472 | return 0; | ||
2473 | } | ||
2474 | EXPORT_SYMBOL_GPL(regmap_parse_val); | ||
2475 | |||
2246 | static int __init regmap_initcall(void) | 2476 | static int __init regmap_initcall(void) |
2247 | { | 2477 | { |
2248 | regmap_debugfs_initcall(); | 2478 | regmap_debugfs_initcall(); |