diff options
author | Opensource [Anthony Olech] <anthony.olech.opensource@diasemi.com> | 2014-03-04 08:54:02 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-03-10 13:09:32 -0400 |
commit | e894c3f46c302716d2f156b1f3339e2f96ceb65c (patch) | |
tree | d051cf7865aa21b8af4dd6a921c71efde418cfa1 /drivers/base/regmap | |
parent | 1c18d2ca104c36fc2ce147cce053c62f61d2ea68 (diff) |
regmap: Implementation for regmap_multi_reg_write
This is the implementation of regmap_multi_reg_write()
There is a new capability 'can_multi_write' that device drivers
must set in order to use this multi reg write mode.
This replaces the first definition, which just defined the API.
Signed-off-by: Anthony Olech <anthony.olech.opensource@diasemi.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r-- | drivers/base/regmap/internal.h | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 188 |
2 files changed, 174 insertions, 16 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/regmap.c b/drivers/base/regmap/regmap.c index 35ab7baffcc5..c69bbc06dfbb 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -439,6 +439,7 @@ struct regmap *regmap_init(struct device *dev, | |||
439 | else | 439 | else |
440 | map->reg_stride = 1; | 440 | map->reg_stride = 1; |
441 | map->use_single_rw = config->use_single_rw; | 441 | map->use_single_rw = config->use_single_rw; |
442 | map->can_multi_write = config->can_multi_write; | ||
442 | map->dev = dev; | 443 | map->dev = dev; |
443 | map->bus = bus; | 444 | map->bus = bus; |
444 | map->bus_context = bus_context; | 445 | map->bus_context = bus_context; |
@@ -1576,41 +1577,196 @@ out: | |||
1576 | } | 1577 | } |
1577 | EXPORT_SYMBOL_GPL(regmap_bulk_write); | 1578 | EXPORT_SYMBOL_GPL(regmap_bulk_write); |
1578 | 1579 | ||
1580 | /* | ||
1581 | * _regmap_raw_multi_reg_write() | ||
1582 | * | ||
1583 | * the (register,newvalue) pairs in regs have not been formatted, but | ||
1584 | * they are all in the same page and have been changed to being page | ||
1585 | * relative. The page register has been written if that was neccessary. | ||
1586 | */ | ||
1587 | static int _regmap_raw_multi_reg_write(struct regmap *map, | ||
1588 | const struct reg_default *regs, | ||
1589 | size_t num_regs) | ||
1590 | { | ||
1591 | int ret; | ||
1592 | void *buf; | ||
1593 | int i; | ||
1594 | u8 *u8; | ||
1595 | size_t val_bytes = map->format.val_bytes; | ||
1596 | size_t reg_bytes = map->format.reg_bytes; | ||
1597 | size_t pad_bytes = map->format.pad_bytes; | ||
1598 | size_t pair_size = reg_bytes + pad_bytes + val_bytes; | ||
1599 | size_t len = pair_size * num_regs; | ||
1600 | |||
1601 | buf = kzalloc(len, GFP_KERNEL); | ||
1602 | if (!buf) | ||
1603 | return -ENOMEM; | ||
1604 | |||
1605 | /* We have to linearise by hand. */ | ||
1606 | |||
1607 | u8 = buf; | ||
1608 | |||
1609 | for (i = 0; i < num_regs; i++) { | ||
1610 | int reg = regs[i].reg; | ||
1611 | int val = regs[i].def; | ||
1612 | trace_regmap_hw_write_start(map->dev, reg, 1); | ||
1613 | map->format.format_reg(u8, reg, map->reg_shift); | ||
1614 | u8 += reg_bytes + pad_bytes; | ||
1615 | map->format.format_val(u8, val, 0); | ||
1616 | u8 += val_bytes; | ||
1617 | } | ||
1618 | u8 = buf; | ||
1619 | *u8 |= map->write_flag_mask; | ||
1620 | |||
1621 | ret = map->bus->write(map->bus_context, buf, len); | ||
1622 | |||
1623 | kfree(buf); | ||
1624 | |||
1625 | for (i = 0; i < num_regs; i++) { | ||
1626 | int reg = regs[i].reg; | ||
1627 | trace_regmap_hw_write_done(map->dev, reg, 1); | ||
1628 | } | ||
1629 | return ret; | ||
1630 | } | ||
1631 | |||
1632 | static unsigned int _regmap_register_page(struct regmap *map, | ||
1633 | unsigned int reg, | ||
1634 | struct regmap_range_node *range) | ||
1635 | { | ||
1636 | unsigned int win_page = (reg - range->range_min) / range->window_len; | ||
1637 | |||
1638 | return win_page; | ||
1639 | } | ||
1640 | |||
1641 | static int _regmap_range_multi_paged_reg_write(struct regmap *map, | ||
1642 | struct reg_default *regs, | ||
1643 | size_t num_regs) | ||
1644 | { | ||
1645 | int ret; | ||
1646 | int i, n; | ||
1647 | struct reg_default *base; | ||
1648 | unsigned int this_page; | ||
1649 | /* | ||
1650 | * the set of registers are not neccessarily in order, but | ||
1651 | * since the order of write must be preserved this algorithm | ||
1652 | * chops the set each time the page changes | ||
1653 | */ | ||
1654 | base = regs; | ||
1655 | for (i = 0, n = 0; i < num_regs; i++, n++) { | ||
1656 | unsigned int reg = regs[i].reg; | ||
1657 | struct regmap_range_node *range; | ||
1658 | |||
1659 | range = _regmap_range_lookup(map, reg); | ||
1660 | if (range) { | ||
1661 | unsigned int win_page = _regmap_register_page(map, reg, | ||
1662 | range); | ||
1663 | |||
1664 | if (i == 0) | ||
1665 | this_page = win_page; | ||
1666 | if (win_page != this_page) { | ||
1667 | this_page = win_page; | ||
1668 | ret = _regmap_raw_multi_reg_write(map, base, n); | ||
1669 | if (ret != 0) | ||
1670 | return ret; | ||
1671 | base += n; | ||
1672 | n = 0; | ||
1673 | } | ||
1674 | ret = _regmap_select_page(map, &base[n].reg, range, 1); | ||
1675 | if (ret != 0) | ||
1676 | return ret; | ||
1677 | } | ||
1678 | } | ||
1679 | if (n > 0) | ||
1680 | return _regmap_raw_multi_reg_write(map, base, n); | ||
1681 | return 0; | ||
1682 | } | ||
1683 | |||
1579 | static int _regmap_multi_reg_write(struct regmap *map, | 1684 | static int _regmap_multi_reg_write(struct regmap *map, |
1580 | const struct reg_default *regs, | 1685 | const struct reg_default *regs, |
1581 | int num_regs) | 1686 | size_t num_regs) |
1582 | { | 1687 | { |
1583 | int i, ret; | 1688 | int i; |
1689 | int ret; | ||
1690 | |||
1691 | if (!map->can_multi_write) { | ||
1692 | for (i = 0; i < num_regs; i++) { | ||
1693 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | ||
1694 | if (ret != 0) | ||
1695 | return ret; | ||
1696 | } | ||
1697 | return 0; | ||
1698 | } | ||
1699 | |||
1700 | if (!map->format.parse_inplace) | ||
1701 | return -EINVAL; | ||
1702 | |||
1703 | if (map->writeable_reg) | ||
1704 | for (i = 0; i < num_regs; i++) { | ||
1705 | int reg = regs[i].reg; | ||
1706 | if (!map->writeable_reg(map->dev, reg)) | ||
1707 | return -EINVAL; | ||
1708 | if (reg % map->reg_stride) | ||
1709 | return -EINVAL; | ||
1710 | } | ||
1711 | |||
1712 | if (!map->cache_bypass) { | ||
1713 | for (i = 0; i < num_regs; i++) { | ||
1714 | unsigned int val = regs[i].def; | ||
1715 | unsigned int reg = regs[i].reg; | ||
1716 | ret = regcache_write(map, reg, val); | ||
1717 | if (ret) { | ||
1718 | dev_err(map->dev, | ||
1719 | "Error in caching of register: %x ret: %d\n", | ||
1720 | reg, ret); | ||
1721 | return ret; | ||
1722 | } | ||
1723 | } | ||
1724 | if (map->cache_only) { | ||
1725 | map->cache_dirty = true; | ||
1726 | return 0; | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | WARN_ON(!map->bus); | ||
1584 | 1731 | ||
1585 | for (i = 0; i < num_regs; i++) { | 1732 | for (i = 0; i < num_regs; i++) { |
1586 | if (regs[i].reg % map->reg_stride) | 1733 | unsigned int reg = regs[i].reg; |
1587 | return -EINVAL; | 1734 | struct regmap_range_node *range; |
1588 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | 1735 | range = _regmap_range_lookup(map, reg); |
1589 | if (ret != 0) { | 1736 | if (range) { |
1590 | dev_err(map->dev, "Failed to write %x = %x: %d\n", | 1737 | size_t len = sizeof(struct reg_default)*num_regs; |
1591 | regs[i].reg, regs[i].def, ret); | 1738 | struct reg_default *base = kmemdup(regs, len, |
1739 | GFP_KERNEL); | ||
1740 | if (!base) | ||
1741 | return -ENOMEM; | ||
1742 | ret = _regmap_range_multi_paged_reg_write(map, base, | ||
1743 | num_regs); | ||
1744 | kfree(base); | ||
1745 | |||
1592 | return ret; | 1746 | return ret; |
1593 | } | 1747 | } |
1594 | } | 1748 | } |
1595 | 1749 | return _regmap_raw_multi_reg_write(map, regs, num_regs); | |
1596 | return 0; | ||
1597 | } | 1750 | } |
1598 | 1751 | ||
1599 | /* | 1752 | /* |
1600 | * regmap_multi_reg_write(): Write multiple registers to the device | 1753 | * regmap_multi_reg_write(): Write multiple registers to the device |
1601 | * | 1754 | * |
1602 | * where the set of register are supplied in any order | 1755 | * where the set of register,value pairs are supplied in any order, |
1756 | * possibly not all in a single range. | ||
1603 | * | 1757 | * |
1604 | * @map: Register map to write to | 1758 | * @map: Register map to write to |
1605 | * @regs: Array of structures containing register,value to be written | 1759 | * @regs: Array of structures containing register,value to be written |
1606 | * @num_regs: Number of registers to write | 1760 | * @num_regs: Number of registers to write |
1607 | * | 1761 | * |
1608 | * This function is intended to be used for writing a large block of data | 1762 | * The 'normal' block write mode will send ultimately send data on the |
1609 | * atomically to the device in single transfer for those I2C client devices | 1763 | * target bus as R,V1,V2,V3,..,Vn where successively higer registers are |
1610 | * that implement this alternative block write mode. | 1764 | * addressed. However, this alternative block multi write mode will send |
1765 | * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device | ||
1766 | * must of course support the mode. | ||
1611 | * | 1767 | * |
1612 | * A value of zero will be returned on success, a negative errno will | 1768 | * A value of zero will be returned on success, a negative errno will be |
1613 | * be returned in error cases. | 1769 | * returned in error cases. |
1614 | */ | 1770 | */ |
1615 | int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, | 1771 | int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, |
1616 | int num_regs) | 1772 | int num_regs) |