regmap-spmi.c 5.4 KB

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