si476x-prop.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * drivers/mfd/si476x-prop.c -- Subroutines to access
  4. * properties of si476x chips
  5. *
  6. * Copyright (C) 2012 Innovative Converged Devices(ICD)
  7. * Copyright (C) 2013 Andrey Smirnov
  8. *
  9. * Author: Andrey Smirnov <[email protected]>
  10. */
  11. #include <linux/module.h>
  12. #include <linux/mfd/si476x-core.h>
  13. struct si476x_property_range {
  14. u16 low, high;
  15. };
  16. static bool si476x_core_element_is_in_array(u16 element,
  17. const u16 array[],
  18. size_t size)
  19. {
  20. int i;
  21. for (i = 0; i < size; i++)
  22. if (element == array[i])
  23. return true;
  24. return false;
  25. }
  26. static bool si476x_core_element_is_in_range(u16 element,
  27. const struct si476x_property_range range[],
  28. size_t size)
  29. {
  30. int i;
  31. for (i = 0; i < size; i++)
  32. if (element <= range[i].high && element >= range[i].low)
  33. return true;
  34. return false;
  35. }
  36. static bool si476x_core_is_valid_property_a10(struct si476x_core *core,
  37. u16 property)
  38. {
  39. static const u16 valid_properties[] = {
  40. 0x0000,
  41. 0x0500, 0x0501,
  42. 0x0600,
  43. 0x0709, 0x070C, 0x070D, 0x70E, 0x710,
  44. 0x0718,
  45. 0x1207, 0x1208,
  46. 0x2007,
  47. 0x2300,
  48. };
  49. static const struct si476x_property_range valid_ranges[] = {
  50. { 0x0200, 0x0203 },
  51. { 0x0300, 0x0303 },
  52. { 0x0400, 0x0404 },
  53. { 0x0700, 0x0707 },
  54. { 0x1100, 0x1102 },
  55. { 0x1200, 0x1204 },
  56. { 0x1300, 0x1306 },
  57. { 0x2000, 0x2005 },
  58. { 0x2100, 0x2104 },
  59. { 0x2106, 0x2106 },
  60. { 0x2200, 0x220E },
  61. { 0x3100, 0x3104 },
  62. { 0x3207, 0x320F },
  63. { 0x3300, 0x3304 },
  64. { 0x3500, 0x3517 },
  65. { 0x3600, 0x3617 },
  66. { 0x3700, 0x3717 },
  67. { 0x4000, 0x4003 },
  68. };
  69. return si476x_core_element_is_in_range(property, valid_ranges,
  70. ARRAY_SIZE(valid_ranges)) ||
  71. si476x_core_element_is_in_array(property, valid_properties,
  72. ARRAY_SIZE(valid_properties));
  73. }
  74. static bool si476x_core_is_valid_property_a20(struct si476x_core *core,
  75. u16 property)
  76. {
  77. static const u16 valid_properties[] = {
  78. 0x071B,
  79. 0x1006,
  80. 0x2210,
  81. 0x3401,
  82. };
  83. static const struct si476x_property_range valid_ranges[] = {
  84. { 0x2215, 0x2219 },
  85. };
  86. return si476x_core_is_valid_property_a10(core, property) ||
  87. si476x_core_element_is_in_range(property, valid_ranges,
  88. ARRAY_SIZE(valid_ranges)) ||
  89. si476x_core_element_is_in_array(property, valid_properties,
  90. ARRAY_SIZE(valid_properties));
  91. }
  92. static bool si476x_core_is_valid_property_a30(struct si476x_core *core,
  93. u16 property)
  94. {
  95. static const u16 valid_properties[] = {
  96. 0x071C, 0x071D,
  97. 0x1007, 0x1008,
  98. 0x220F, 0x2214,
  99. 0x2301,
  100. 0x3105, 0x3106,
  101. 0x3402,
  102. };
  103. static const struct si476x_property_range valid_ranges[] = {
  104. { 0x0405, 0x0411 },
  105. { 0x2008, 0x200B },
  106. { 0x2220, 0x2223 },
  107. { 0x3100, 0x3106 },
  108. };
  109. return si476x_core_is_valid_property_a20(core, property) ||
  110. si476x_core_element_is_in_range(property, valid_ranges,
  111. ARRAY_SIZE(valid_ranges)) ||
  112. si476x_core_element_is_in_array(property, valid_properties,
  113. ARRAY_SIZE(valid_properties));
  114. }
  115. typedef bool (*valid_property_pred_t) (struct si476x_core *, u16);
  116. static bool si476x_core_is_valid_property(struct si476x_core *core,
  117. u16 property)
  118. {
  119. static const valid_property_pred_t is_valid_property[] = {
  120. [SI476X_REVISION_A10] = si476x_core_is_valid_property_a10,
  121. [SI476X_REVISION_A20] = si476x_core_is_valid_property_a20,
  122. [SI476X_REVISION_A30] = si476x_core_is_valid_property_a30,
  123. };
  124. BUG_ON(core->revision > SI476X_REVISION_A30 ||
  125. core->revision == -1);
  126. return is_valid_property[core->revision](core, property);
  127. }
  128. static bool si476x_core_is_readonly_property(struct si476x_core *core,
  129. u16 property)
  130. {
  131. BUG_ON(core->revision > SI476X_REVISION_A30 ||
  132. core->revision == -1);
  133. switch (core->revision) {
  134. case SI476X_REVISION_A10:
  135. return (property == 0x3200);
  136. case SI476X_REVISION_A20:
  137. return (property == 0x1006 ||
  138. property == 0x2210 ||
  139. property == 0x3200);
  140. case SI476X_REVISION_A30:
  141. return false;
  142. }
  143. return false;
  144. }
  145. static bool si476x_core_regmap_readable_register(struct device *dev,
  146. unsigned int reg)
  147. {
  148. struct i2c_client *client = to_i2c_client(dev);
  149. struct si476x_core *core = i2c_get_clientdata(client);
  150. return si476x_core_is_valid_property(core, (u16) reg);
  151. }
  152. static bool si476x_core_regmap_writable_register(struct device *dev,
  153. unsigned int reg)
  154. {
  155. struct i2c_client *client = to_i2c_client(dev);
  156. struct si476x_core *core = i2c_get_clientdata(client);
  157. return si476x_core_is_valid_property(core, (u16) reg) &&
  158. !si476x_core_is_readonly_property(core, (u16) reg);
  159. }
  160. static int si476x_core_regmap_write(void *context, unsigned int reg,
  161. unsigned int val)
  162. {
  163. return si476x_core_cmd_set_property(context, reg, val);
  164. }
  165. static int si476x_core_regmap_read(void *context, unsigned int reg,
  166. unsigned *val)
  167. {
  168. struct si476x_core *core = context;
  169. int err;
  170. err = si476x_core_cmd_get_property(core, reg);
  171. if (err < 0)
  172. return err;
  173. *val = err;
  174. return 0;
  175. }
  176. static const struct regmap_config si476x_regmap_config = {
  177. .reg_bits = 16,
  178. .val_bits = 16,
  179. .max_register = 0x4003,
  180. .writeable_reg = si476x_core_regmap_writable_register,
  181. .readable_reg = si476x_core_regmap_readable_register,
  182. .reg_read = si476x_core_regmap_read,
  183. .reg_write = si476x_core_regmap_write,
  184. .cache_type = REGCACHE_RBTREE,
  185. };
  186. struct regmap *devm_regmap_init_si476x(struct si476x_core *core)
  187. {
  188. return devm_regmap_init(&core->client->dev, NULL,
  189. core, &si476x_regmap_config);
  190. }
  191. EXPORT_SYMBOL_GPL(devm_regmap_init_si476x);