diff options
author | Mark Brown <broonie@linaro.org> | 2013-09-24 14:53:26 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-09-24 14:53:26 -0400 |
commit | ef85b642460a4cc84086a7fe20915dae58dabcb2 (patch) | |
tree | 20cb7e3610702c0afb334907b9f93a0c32ad01d3 | |
parent | d3be689e6a07c00123786659b4429b07cf4272ac (diff) | |
parent | a0102375ee82db1e08324b1a21484854cf2c1677 (diff) |
Merge tag 'regmap-fields' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap into asoc-rcar
regmap: Add support for repeated blocks of fields
Save duplication for devices using the regmap field APIs by allowing
repeated blocks to be described once and referred to with an index.
-rw-r--r-- | drivers/base/regmap/internal.h | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 103 | ||||
-rw-r--r-- | include/linux/regmap.h | 13 |
3 files changed, 119 insertions, 0 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 57f777835d97..9010614f7793 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -179,6 +179,9 @@ struct regmap_field { | |||
179 | /* lsb */ | 179 | /* lsb */ |
180 | unsigned int shift; | 180 | unsigned int shift; |
181 | unsigned int reg; | 181 | unsigned int reg; |
182 | |||
183 | unsigned int id_size; | ||
184 | unsigned int id_offset; | ||
182 | }; | 185 | }; |
183 | 186 | ||
184 | #ifdef CONFIG_DEBUG_FS | 187 | #ifdef CONFIG_DEBUG_FS |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7d689a15c500..00152bf7ab12 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -821,6 +821,8 @@ static void regmap_field_init(struct regmap_field *rm_field, | |||
821 | rm_field->reg = reg_field.reg; | 821 | rm_field->reg = reg_field.reg; |
822 | rm_field->shift = reg_field.lsb; | 822 | rm_field->shift = reg_field.lsb; |
823 | rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); | 823 | rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); |
824 | rm_field->id_size = reg_field.id_size; | ||
825 | rm_field->id_offset = reg_field.id_offset; | ||
824 | } | 826 | } |
825 | 827 | ||
826 | /** | 828 | /** |
@@ -1369,6 +1371,74 @@ int regmap_field_write(struct regmap_field *field, unsigned int val) | |||
1369 | } | 1371 | } |
1370 | EXPORT_SYMBOL_GPL(regmap_field_write); | 1372 | EXPORT_SYMBOL_GPL(regmap_field_write); |
1371 | 1373 | ||
1374 | /** | ||
1375 | * regmap_field_update_bits(): Perform a read/modify/write cycle | ||
1376 | * on the register field | ||
1377 | * | ||
1378 | * @field: Register field to write to | ||
1379 | * @mask: Bitmask to change | ||
1380 | * @val: Value to be written | ||
1381 | * | ||
1382 | * A value of zero will be returned on success, a negative errno will | ||
1383 | * be returned in error cases. | ||
1384 | */ | ||
1385 | int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) | ||
1386 | { | ||
1387 | mask = (mask << field->shift) & field->mask; | ||
1388 | |||
1389 | return regmap_update_bits(field->regmap, field->reg, | ||
1390 | mask, val << field->shift); | ||
1391 | } | ||
1392 | EXPORT_SYMBOL_GPL(regmap_field_update_bits); | ||
1393 | |||
1394 | /** | ||
1395 | * regmap_fields_write(): Write a value to a single register field with port ID | ||
1396 | * | ||
1397 | * @field: Register field to write to | ||
1398 | * @id: port ID | ||
1399 | * @val: Value to be written | ||
1400 | * | ||
1401 | * A value of zero will be returned on success, a negative errno will | ||
1402 | * be returned in error cases. | ||
1403 | */ | ||
1404 | int regmap_fields_write(struct regmap_field *field, unsigned int id, | ||
1405 | unsigned int val) | ||
1406 | { | ||
1407 | if (id >= field->id_size) | ||
1408 | return -EINVAL; | ||
1409 | |||
1410 | return regmap_update_bits(field->regmap, | ||
1411 | field->reg + (field->id_offset * id), | ||
1412 | field->mask, val << field->shift); | ||
1413 | } | ||
1414 | EXPORT_SYMBOL_GPL(regmap_fields_write); | ||
1415 | |||
1416 | /** | ||
1417 | * regmap_fields_update_bits(): Perform a read/modify/write cycle | ||
1418 | * on the register field | ||
1419 | * | ||
1420 | * @field: Register field to write to | ||
1421 | * @id: port ID | ||
1422 | * @mask: Bitmask to change | ||
1423 | * @val: Value to be written | ||
1424 | * | ||
1425 | * A value of zero will be returned on success, a negative errno will | ||
1426 | * be returned in error cases. | ||
1427 | */ | ||
1428 | int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, | ||
1429 | unsigned int mask, unsigned int val) | ||
1430 | { | ||
1431 | if (id >= field->id_size) | ||
1432 | return -EINVAL; | ||
1433 | |||
1434 | mask = (mask << field->shift) & field->mask; | ||
1435 | |||
1436 | return regmap_update_bits(field->regmap, | ||
1437 | field->reg + (field->id_offset * id), | ||
1438 | mask, val << field->shift); | ||
1439 | } | ||
1440 | EXPORT_SYMBOL_GPL(regmap_fields_update_bits); | ||
1441 | |||
1372 | /* | 1442 | /* |
1373 | * regmap_bulk_write(): Write multiple registers to the device | 1443 | * regmap_bulk_write(): Write multiple registers to the device |
1374 | * | 1444 | * |
@@ -1677,6 +1747,39 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val) | |||
1677 | EXPORT_SYMBOL_GPL(regmap_field_read); | 1747 | EXPORT_SYMBOL_GPL(regmap_field_read); |
1678 | 1748 | ||
1679 | /** | 1749 | /** |
1750 | * regmap_fields_read(): Read a value to a single register field with port ID | ||
1751 | * | ||
1752 | * @field: Register field to read from | ||
1753 | * @id: port ID | ||
1754 | * @val: Pointer to store read value | ||
1755 | * | ||
1756 | * A value of zero will be returned on success, a negative errno will | ||
1757 | * be returned in error cases. | ||
1758 | */ | ||
1759 | int regmap_fields_read(struct regmap_field *field, unsigned int id, | ||
1760 | unsigned int *val) | ||
1761 | { | ||
1762 | int ret; | ||
1763 | unsigned int reg_val; | ||
1764 | |||
1765 | if (id >= field->id_size) | ||
1766 | return -EINVAL; | ||
1767 | |||
1768 | ret = regmap_read(field->regmap, | ||
1769 | field->reg + (field->id_offset * id), | ||
1770 | ®_val); | ||
1771 | if (ret != 0) | ||
1772 | return ret; | ||
1773 | |||
1774 | reg_val &= field->mask; | ||
1775 | reg_val >>= field->shift; | ||
1776 | *val = reg_val; | ||
1777 | |||
1778 | return ret; | ||
1779 | } | ||
1780 | EXPORT_SYMBOL_GPL(regmap_fields_read); | ||
1781 | |||
1782 | /** | ||
1680 | * regmap_bulk_read(): Read multiple registers from the device | 1783 | * regmap_bulk_read(): Read multiple registers from the device |
1681 | * | 1784 | * |
1682 | * @map: Register map to write to | 1785 | * @map: Register map to write to |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index a10380bfbeac..a12bea07f79e 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -425,11 +425,15 @@ bool regmap_reg_in_ranges(unsigned int reg, | |||
425 | * @reg: Offset of the register within the regmap bank | 425 | * @reg: Offset of the register within the regmap bank |
426 | * @lsb: lsb of the register field. | 426 | * @lsb: lsb of the register field. |
427 | * @reg: msb of the register field. | 427 | * @reg: msb of the register field. |
428 | * @id_size: port size if it has some ports | ||
429 | * @id_offset: address offset for each ports | ||
428 | */ | 430 | */ |
429 | struct reg_field { | 431 | struct reg_field { |
430 | unsigned int reg; | 432 | unsigned int reg; |
431 | unsigned int lsb; | 433 | unsigned int lsb; |
432 | unsigned int msb; | 434 | unsigned int msb; |
435 | unsigned int id_size; | ||
436 | unsigned int id_offset; | ||
433 | }; | 437 | }; |
434 | 438 | ||
435 | #define REG_FIELD(_reg, _lsb, _msb) { \ | 439 | #define REG_FIELD(_reg, _lsb, _msb) { \ |
@@ -448,6 +452,15 @@ void devm_regmap_field_free(struct device *dev, struct regmap_field *field); | |||
448 | 452 | ||
449 | int regmap_field_read(struct regmap_field *field, unsigned int *val); | 453 | int regmap_field_read(struct regmap_field *field, unsigned int *val); |
450 | int regmap_field_write(struct regmap_field *field, unsigned int val); | 454 | int regmap_field_write(struct regmap_field *field, unsigned int val); |
455 | int regmap_field_update_bits(struct regmap_field *field, | ||
456 | unsigned int mask, unsigned int val); | ||
457 | |||
458 | int regmap_fields_write(struct regmap_field *field, unsigned int id, | ||
459 | unsigned int val); | ||
460 | int regmap_fields_read(struct regmap_field *field, unsigned int id, | ||
461 | unsigned int *val); | ||
462 | int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, | ||
463 | unsigned int mask, unsigned int val); | ||
451 | 464 | ||
452 | /** | 465 | /** |
453 | * Description of an IRQ for the generic regmap irq_chip. | 466 | * Description of an IRQ for the generic regmap irq_chip. |