sysfs_slave_dpn.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright(c) 2015-2020 Intel Corporation.
  3. #include <linux/device.h>
  4. #include <linux/mod_devicetable.h>
  5. #include <linux/slab.h>
  6. #include <linux/sysfs.h>
  7. #include <linux/soundwire/sdw.h>
  8. #include <linux/soundwire/sdw_type.h>
  9. #include "bus.h"
  10. #include "sysfs_local.h"
  11. struct dpn_attribute {
  12. struct device_attribute dev_attr;
  13. int N;
  14. int dir;
  15. const char *format_string;
  16. };
  17. /*
  18. * Since we can't use ARRAY_SIZE, hard-code number of dpN attributes.
  19. * This needs to be updated when adding new attributes - an error will be
  20. * flagged on a mismatch.
  21. */
  22. #define SDW_DPN_ATTRIBUTES 15
  23. #define sdw_dpn_attribute_alloc(field) \
  24. static int field##_attribute_alloc(struct device *dev, \
  25. struct attribute **res, \
  26. int N, int dir, \
  27. const char *format_string) \
  28. { \
  29. struct dpn_attribute *dpn_attr; \
  30. \
  31. dpn_attr = devm_kzalloc(dev, sizeof(*dpn_attr), GFP_KERNEL); \
  32. if (!dpn_attr) \
  33. return -ENOMEM; \
  34. dpn_attr->N = N; \
  35. dpn_attr->dir = dir; \
  36. sysfs_attr_init(&dpn_attr->dev_attr.attr); \
  37. dpn_attr->format_string = format_string; \
  38. dpn_attr->dev_attr.attr.name = __stringify(field); \
  39. dpn_attr->dev_attr.attr.mode = 0444; \
  40. dpn_attr->dev_attr.show = field##_show; \
  41. \
  42. *res = &dpn_attr->dev_attr.attr; \
  43. \
  44. return 0; \
  45. }
  46. #define sdw_dpn_attr(field) \
  47. \
  48. static ssize_t field##_dpn_show(struct sdw_slave *slave, \
  49. int N, \
  50. int dir, \
  51. const char *format_string, \
  52. char *buf) \
  53. { \
  54. struct sdw_dpn_prop *dpn; \
  55. unsigned long mask; \
  56. int bit; \
  57. int i; \
  58. \
  59. if (dir) { \
  60. dpn = slave->prop.src_dpn_prop; \
  61. mask = slave->prop.source_ports; \
  62. } else { \
  63. dpn = slave->prop.sink_dpn_prop; \
  64. mask = slave->prop.sink_ports; \
  65. } \
  66. \
  67. i = 0; \
  68. for_each_set_bit(bit, &mask, 32) { \
  69. if (bit == N) { \
  70. return sprintf(buf, format_string, \
  71. dpn[i].field); \
  72. } \
  73. i++; \
  74. } \
  75. return -EINVAL; \
  76. } \
  77. \
  78. static ssize_t field##_show(struct device *dev, \
  79. struct device_attribute *attr, \
  80. char *buf) \
  81. { \
  82. struct sdw_slave *slave = dev_to_sdw_dev(dev); \
  83. struct dpn_attribute *dpn_attr = \
  84. container_of(attr, struct dpn_attribute, dev_attr); \
  85. \
  86. return field##_dpn_show(slave, \
  87. dpn_attr->N, dpn_attr->dir, \
  88. dpn_attr->format_string, \
  89. buf); \
  90. } \
  91. sdw_dpn_attribute_alloc(field)
  92. sdw_dpn_attr(imp_def_interrupts);
  93. sdw_dpn_attr(max_word);
  94. sdw_dpn_attr(min_word);
  95. sdw_dpn_attr(type);
  96. sdw_dpn_attr(max_grouping);
  97. sdw_dpn_attr(simple_ch_prep_sm);
  98. sdw_dpn_attr(ch_prep_timeout);
  99. sdw_dpn_attr(max_ch);
  100. sdw_dpn_attr(min_ch);
  101. sdw_dpn_attr(max_async_buffer);
  102. sdw_dpn_attr(block_pack_mode);
  103. sdw_dpn_attr(port_encoding);
  104. #define sdw_dpn_array_attr(field) \
  105. \
  106. static ssize_t field##_dpn_show(struct sdw_slave *slave, \
  107. int N, \
  108. int dir, \
  109. const char *format_string, \
  110. char *buf) \
  111. { \
  112. struct sdw_dpn_prop *dpn; \
  113. unsigned long mask; \
  114. ssize_t size = 0; \
  115. int bit; \
  116. int i; \
  117. int j; \
  118. \
  119. if (dir) { \
  120. dpn = slave->prop.src_dpn_prop; \
  121. mask = slave->prop.source_ports; \
  122. } else { \
  123. dpn = slave->prop.sink_dpn_prop; \
  124. mask = slave->prop.sink_ports; \
  125. } \
  126. \
  127. i = 0; \
  128. for_each_set_bit(bit, &mask, 32) { \
  129. if (bit == N) { \
  130. for (j = 0; j < dpn[i].num_##field; j++) \
  131. size += sprintf(buf + size, \
  132. format_string, \
  133. dpn[i].field[j]); \
  134. size += sprintf(buf + size, "\n"); \
  135. return size; \
  136. } \
  137. i++; \
  138. } \
  139. return -EINVAL; \
  140. } \
  141. static ssize_t field##_show(struct device *dev, \
  142. struct device_attribute *attr, \
  143. char *buf) \
  144. { \
  145. struct sdw_slave *slave = dev_to_sdw_dev(dev); \
  146. struct dpn_attribute *dpn_attr = \
  147. container_of(attr, struct dpn_attribute, dev_attr); \
  148. \
  149. return field##_dpn_show(slave, \
  150. dpn_attr->N, dpn_attr->dir, \
  151. dpn_attr->format_string, \
  152. buf); \
  153. } \
  154. sdw_dpn_attribute_alloc(field)
  155. sdw_dpn_array_attr(words);
  156. sdw_dpn_array_attr(ch_combinations);
  157. sdw_dpn_array_attr(channels);
  158. static int add_all_attributes(struct device *dev, int N, int dir)
  159. {
  160. struct attribute **dpn_attrs;
  161. struct attribute_group *dpn_group;
  162. int i = 0;
  163. int ret;
  164. /* allocate attributes, last one is NULL */
  165. dpn_attrs = devm_kcalloc(dev, SDW_DPN_ATTRIBUTES + 1,
  166. sizeof(struct attribute *),
  167. GFP_KERNEL);
  168. if (!dpn_attrs)
  169. return -ENOMEM;
  170. ret = max_word_attribute_alloc(dev, &dpn_attrs[i++],
  171. N, dir, "%d\n");
  172. if (ret < 0)
  173. return ret;
  174. ret = min_word_attribute_alloc(dev, &dpn_attrs[i++],
  175. N, dir, "%d\n");
  176. if (ret < 0)
  177. return ret;
  178. ret = words_attribute_alloc(dev, &dpn_attrs[i++],
  179. N, dir, "%d\n");
  180. if (ret < 0)
  181. return ret;
  182. ret = type_attribute_alloc(dev, &dpn_attrs[i++],
  183. N, dir, "%d\n");
  184. if (ret < 0)
  185. return ret;
  186. ret = max_grouping_attribute_alloc(dev, &dpn_attrs[i++],
  187. N, dir, "%d\n");
  188. if (ret < 0)
  189. return ret;
  190. ret = simple_ch_prep_sm_attribute_alloc(dev, &dpn_attrs[i++],
  191. N, dir, "%d\n");
  192. if (ret < 0)
  193. return ret;
  194. ret = ch_prep_timeout_attribute_alloc(dev, &dpn_attrs[i++],
  195. N, dir, "%d\n");
  196. if (ret < 0)
  197. return ret;
  198. ret = imp_def_interrupts_attribute_alloc(dev, &dpn_attrs[i++],
  199. N, dir, "0x%x\n");
  200. if (ret < 0)
  201. return ret;
  202. ret = min_ch_attribute_alloc(dev, &dpn_attrs[i++],
  203. N, dir, "%d\n");
  204. if (ret < 0)
  205. return ret;
  206. ret = max_ch_attribute_alloc(dev, &dpn_attrs[i++],
  207. N, dir, "%d\n");
  208. if (ret < 0)
  209. return ret;
  210. ret = channels_attribute_alloc(dev, &dpn_attrs[i++],
  211. N, dir, "%d\n");
  212. if (ret < 0)
  213. return ret;
  214. ret = ch_combinations_attribute_alloc(dev, &dpn_attrs[i++],
  215. N, dir, "%d\n");
  216. if (ret < 0)
  217. return ret;
  218. ret = max_async_buffer_attribute_alloc(dev, &dpn_attrs[i++],
  219. N, dir, "%d\n");
  220. if (ret < 0)
  221. return ret;
  222. ret = block_pack_mode_attribute_alloc(dev, &dpn_attrs[i++],
  223. N, dir, "%d\n");
  224. if (ret < 0)
  225. return ret;
  226. ret = port_encoding_attribute_alloc(dev, &dpn_attrs[i++],
  227. N, dir, "%d\n");
  228. if (ret < 0)
  229. return ret;
  230. /* paranoia check for editing mistakes */
  231. if (i != SDW_DPN_ATTRIBUTES) {
  232. dev_err(dev, "mismatch in attributes, allocated %d got %d\n",
  233. SDW_DPN_ATTRIBUTES, i);
  234. return -EINVAL;
  235. }
  236. dpn_group = devm_kzalloc(dev, sizeof(*dpn_group), GFP_KERNEL);
  237. if (!dpn_group)
  238. return -ENOMEM;
  239. dpn_group->attrs = dpn_attrs;
  240. dpn_group->name = devm_kasprintf(dev, GFP_KERNEL, "dp%d_%s",
  241. N, dir ? "src" : "sink");
  242. if (!dpn_group->name)
  243. return -ENOMEM;
  244. ret = devm_device_add_group(dev, dpn_group);
  245. if (ret < 0)
  246. return ret;
  247. return 0;
  248. }
  249. int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
  250. {
  251. unsigned long mask;
  252. int ret;
  253. int i;
  254. mask = slave->prop.source_ports;
  255. for_each_set_bit(i, &mask, 32) {
  256. ret = add_all_attributes(&slave->dev, i, 1);
  257. if (ret < 0)
  258. return ret;
  259. }
  260. mask = slave->prop.sink_ports;
  261. for_each_set_bit(i, &mask, 32) {
  262. ret = add_all_attributes(&slave->dev, i, 0);
  263. if (ret < 0)
  264. return ret;
  265. }
  266. return 0;
  267. }