regmap-spmi.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. /**
  81. * regmap_init_spmi_base(): Create regmap for the Base register space
  82. * @sdev: SPMI device that will be interacted with
  83. * @config: Configuration for register map
  84. *
  85. * The return value will be an ERR_PTR() on error or a valid pointer to
  86. * a struct regmap.
  87. */
  88. struct regmap *regmap_init_spmi_base(struct spmi_device *sdev,
  89. const struct regmap_config *config)
  90. {
  91. return regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
  92. }
  93. EXPORT_SYMBOL_GPL(regmap_init_spmi_base);
  94. /**
  95. * devm_regmap_init_spmi_base(): Create managed regmap for Base register space
  96. * @sdev: SPMI device that will be interacted with
  97. * @config: Configuration for register map
  98. *
  99. * The return value will be an ERR_PTR() on error or a valid pointer
  100. * to a struct regmap. The regmap will be automatically freed by the
  101. * device management code.
  102. */
  103. struct regmap *devm_regmap_init_spmi_base(struct spmi_device *sdev,
  104. const struct regmap_config *config)
  105. {
  106. return devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config);
  107. }
  108. EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_base);
  109. static int regmap_spmi_ext_read(void *context,
  110. const void *reg, size_t reg_size,
  111. void *val, size_t val_size)
  112. {
  113. int err = 0;
  114. size_t len;
  115. u16 addr;
  116. BUG_ON(reg_size != 2);
  117. addr = *(u16 *)reg;
  118. /*
  119. * Split accesses into two to take advantage of the more
  120. * bandwidth-efficient 'Extended Register Read' command when possible
  121. */
  122. while (addr <= 0xFF && val_size) {
  123. len = min_t(size_t, val_size, 16);
  124. err = spmi_ext_register_read(context, addr, val, len);
  125. if (err)
  126. goto err_out;
  127. addr += len;
  128. val += len;
  129. val_size -= len;
  130. }
  131. while (val_size) {
  132. len = min_t(size_t, val_size, 8);
  133. err = spmi_ext_register_readl(context, addr, val, val_size);
  134. if (err)
  135. goto err_out;
  136. addr += len;
  137. val += len;
  138. val_size -= len;
  139. }
  140. err_out:
  141. return err;
  142. }
  143. static int regmap_spmi_ext_gather_write(void *context,
  144. const void *reg, size_t reg_size,
  145. const void *val, size_t val_size)
  146. {
  147. int err = 0;
  148. size_t len;
  149. u16 addr;
  150. BUG_ON(reg_size != 2);
  151. addr = *(u16 *)reg;
  152. while (addr <= 0xFF && val_size) {
  153. len = min_t(size_t, val_size, 16);
  154. err = spmi_ext_register_write(context, addr, val, len);
  155. if (err)
  156. goto err_out;
  157. addr += len;
  158. val += len;
  159. val_size -= len;
  160. }
  161. while (val_size) {
  162. len = min_t(size_t, val_size, 8);
  163. err = spmi_ext_register_writel(context, addr, val, len);
  164. if (err)
  165. goto err_out;
  166. addr += len;
  167. val += len;
  168. val_size -= len;
  169. }
  170. err_out:
  171. return err;
  172. }
  173. static int regmap_spmi_ext_write(void *context, const void *data,
  174. size_t count)
  175. {
  176. BUG_ON(count < 2);
  177. return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
  178. count - 2);
  179. }
  180. static struct regmap_bus regmap_spmi_ext = {
  181. .read = regmap_spmi_ext_read,
  182. .write = regmap_spmi_ext_write,
  183. .gather_write = regmap_spmi_ext_gather_write,
  184. .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
  185. .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
  186. };
  187. /**
  188. * regmap_init_spmi_ext(): Create regmap for Ext register space
  189. * @sdev: Device that will be interacted with
  190. * @config: Configuration for register map
  191. *
  192. * The return value will be an ERR_PTR() on error or a valid pointer to
  193. * a struct regmap.
  194. */
  195. struct regmap *regmap_init_spmi_ext(struct spmi_device *sdev,
  196. const struct regmap_config *config)
  197. {
  198. return regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
  199. }
  200. EXPORT_SYMBOL_GPL(regmap_init_spmi_ext);
  201. /**
  202. * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space
  203. * @sdev: SPMI device that will be interacted with
  204. * @config: Configuration for register map
  205. *
  206. * The return value will be an ERR_PTR() on error or a valid pointer
  207. * to a struct regmap. The regmap will be automatically freed by the
  208. * device management code.
  209. */
  210. struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *sdev,
  211. const struct regmap_config *config)
  212. {
  213. return devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config);
  214. }
  215. EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_ext);
  216. MODULE_LICENSE("GPL");