regmap-spmi.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Register map access API - SPMI support
  4. //
  5. // Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  6. //
  7. // Based on regmap-i2c.c:
  8. // Copyright 2011 Wolfson Microelectronics plc
  9. // Author: Mark Brown <[email protected]>
  10. #include <linux/regmap.h>
  11. #include <linux/spmi.h>
  12. #include <linux/module.h>
  13. #include <linux/init.h>
  14. static int regmap_spmi_base_read(void *context,
  15. const void *reg, size_t reg_size,
  16. void *val, size_t val_size)
  17. {
  18. u8 addr = *(u8 *)reg;
  19. int err = 0;
  20. BUG_ON(reg_size != 1);
  21. while (val_size-- && !err)
  22. err = spmi_register_read(context, addr++, val++);
  23. return err;
  24. }
  25. static int regmap_spmi_base_gather_write(void *context,
  26. const void *reg, size_t reg_size,
  27. const void *val, size_t val_size)
  28. {
  29. const u8 *data = val;
  30. u8 addr = *(u8 *)reg;
  31. int err = 0;
  32. BUG_ON(reg_size != 1);
  33. /*
  34. * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
  35. * use it when possible.
  36. */
  37. if (addr == 0 && val_size) {
  38. err = spmi_register_zero_write(context, *data);
  39. if (err)
  40. goto err_out;
  41. data++;
  42. addr++;
  43. val_size--;
  44. }
  45. while (val_size) {
  46. err = spmi_register_write(context, addr, *data);
  47. if (err)
  48. goto err_out;
  49. data++;
  50. addr++;
  51. val_size--;
  52. }
  53. err_out:
  54. return err;
  55. }
  56. static int regmap_spmi_base_write(void *context, const void *data,
  57. size_t count)
  58. {
  59. BUG_ON(count < 1);
  60. return regmap_spmi_base_gather_write(context, data, 1, data + 1,
  61. count - 1);
  62. }
  63. static const struct regmap_bus regmap_spmi_base = {
  64. .read = regmap_spmi_base_read,
  65. .write = regmap_spmi_base_write,
  66. .gather_write = regmap_spmi_base_gather_write,
  67. .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
  68. .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
  69. };
  70. struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,
  71. const struct regmap_config *config,
  72. struct lock_class_key *lock_key,
  73. const char *lock_name)
  74. {
  75. return __regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
  76. lock_key, lock_name);
  77. }
  78. EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);
  79. struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,
  80. const struct regmap_config *config,
  81. struct lock_class_key *lock_key,
  82. const char *lock_name)
  83. {
  84. return __devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
  85. lock_key, lock_name);
  86. }
  87. EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);
  88. static int regmap_spmi_ext_read(void *context,
  89. const void *reg, size_t reg_size,
  90. void *val, size_t val_size)
  91. {
  92. int err = 0;
  93. size_t len;
  94. u16 addr;
  95. BUG_ON(reg_size != 2);
  96. addr = *(u16 *)reg;
  97. /*
  98. * Split accesses into two to take advantage of the more
  99. * bandwidth-efficient 'Extended Register Read' command when possible
  100. */
  101. while (addr <= 0xFF && val_size) {
  102. len = min_t(size_t, val_size, 16);
  103. err = spmi_ext_register_read(context, addr, val, len);
  104. if (err)
  105. goto err_out;
  106. addr += len;
  107. val += len;
  108. val_size -= len;
  109. }
  110. while (val_size) {
  111. len = min_t(size_t, val_size, 8);
  112. err = spmi_ext_register_readl(context, addr, val, len);
  113. if (err)
  114. goto err_out;
  115. addr += len;
  116. val += len;
  117. val_size -= len;
  118. }
  119. err_out:
  120. return err;
  121. }
  122. static int regmap_spmi_ext_gather_write(void *context,
  123. const void *reg, size_t reg_size,
  124. const void *val, size_t val_size)
  125. {
  126. int err = 0;
  127. size_t len;
  128. u16 addr;
  129. BUG_ON(reg_size != 2);
  130. addr = *(u16 *)reg;
  131. while (addr <= 0xFF && val_size) {
  132. len = min_t(size_t, val_size, 16);
  133. err = spmi_ext_register_write(context, addr, val, len);
  134. if (err)
  135. goto err_out;
  136. addr += len;
  137. val += len;
  138. val_size -= len;
  139. }
  140. while (val_size) {
  141. len = min_t(size_t, val_size, 8);
  142. err = spmi_ext_register_writel(context, addr, val, len);
  143. if (err)
  144. goto err_out;
  145. addr += len;
  146. val += len;
  147. val_size -= len;
  148. }
  149. err_out:
  150. return err;
  151. }
  152. static int regmap_spmi_ext_write(void *context, const void *data,
  153. size_t count)
  154. {
  155. BUG_ON(count < 2);
  156. return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
  157. count - 2);
  158. }
  159. static const struct regmap_bus regmap_spmi_ext = {
  160. .read = regmap_spmi_ext_read,
  161. .write = regmap_spmi_ext_write,
  162. .gather_write = regmap_spmi_ext_gather_write,
  163. .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
  164. .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
  165. };
  166. struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,
  167. const struct regmap_config *config,
  168. struct lock_class_key *lock_key,
  169. const char *lock_name)
  170. {
  171. return __regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
  172. lock_key, lock_name);
  173. }
  174. EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);
  175. struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,
  176. const struct regmap_config *config,
  177. struct lock_class_key *lock_key,
  178. const char *lock_name)
  179. {
  180. return __devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
  181. lock_key, lock_name);
  182. }
  183. EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);
  184. MODULE_LICENSE("GPL");