1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2015-2020 Intel Corporation.
4 #include <linux/device.h>
5 #include <linux/mod_devicetable.h>
6 #include <linux/slab.h>
7 #include <linux/sysfs.h>
8 #include <linux/soundwire/sdw.h>
9 #include <linux/soundwire/sdw_type.h>
11 #include "sysfs_local.h"
13 struct dpn_attribute {
14 struct device_attribute dev_attr;
17 const char *format_string;
21 * Since we can't use ARRAY_SIZE, hard-code number of dpN attributes.
22 * This needs to be updated when adding new attributes - an error will be
23 * flagged on a mismatch.
25 #define SDW_DPN_ATTRIBUTES 15
27 #define sdw_dpn_attribute_alloc(field) \
28 static int field##_attribute_alloc(struct device *dev, \
29 struct attribute **res, \
31 const char *format_string) \
33 struct dpn_attribute *dpn_attr; \
35 dpn_attr = devm_kzalloc(dev, sizeof(*dpn_attr), GFP_KERNEL); \
39 dpn_attr->dir = dir; \
40 dpn_attr->format_string = format_string; \
41 dpn_attr->dev_attr.attr.name = __stringify(field); \
42 dpn_attr->dev_attr.attr.mode = 0444; \
43 dpn_attr->dev_attr.show = field##_show; \
45 *res = &dpn_attr->dev_attr.attr; \
50 #define sdw_dpn_attr(field) \
52 static ssize_t field##_dpn_show(struct sdw_slave *slave, \
55 const char *format_string, \
58 struct sdw_dpn_prop *dpn; \
64 dpn = slave->prop.src_dpn_prop; \
65 mask = slave->prop.source_ports; \
67 dpn = slave->prop.sink_dpn_prop; \
68 mask = slave->prop.sink_ports; \
72 for_each_set_bit(bit, &mask, 32) { \
74 return sprintf(buf, format_string, \
82 static ssize_t field##_show(struct device *dev, \
83 struct device_attribute *attr, \
86 struct sdw_slave *slave = dev_to_sdw_dev(dev); \
87 struct dpn_attribute *dpn_attr = \
88 container_of(attr, struct dpn_attribute, dev_attr); \
90 return field##_dpn_show(slave, \
91 dpn_attr->N, dpn_attr->dir, \
92 dpn_attr->format_string, \
95 sdw_dpn_attribute_alloc(field)
97 sdw_dpn_attr(imp_def_interrupts);
98 sdw_dpn_attr(max_word);
99 sdw_dpn_attr(min_word);
101 sdw_dpn_attr(max_grouping);
102 sdw_dpn_attr(simple_ch_prep_sm);
103 sdw_dpn_attr(ch_prep_timeout);
104 sdw_dpn_attr(max_ch);
105 sdw_dpn_attr(min_ch);
106 sdw_dpn_attr(max_async_buffer);
107 sdw_dpn_attr(block_pack_mode);
108 sdw_dpn_attr(port_encoding);
110 #define sdw_dpn_array_attr(field) \
112 static ssize_t field##_dpn_show(struct sdw_slave *slave, \
115 const char *format_string, \
118 struct sdw_dpn_prop *dpn; \
119 unsigned long mask; \
126 dpn = slave->prop.src_dpn_prop; \
127 mask = slave->prop.source_ports; \
129 dpn = slave->prop.sink_dpn_prop; \
130 mask = slave->prop.sink_ports; \
134 for_each_set_bit(bit, &mask, 32) { \
136 for (j = 0; j < dpn[i].num_##field; j++) \
137 size += sprintf(buf + size, \
140 size += sprintf(buf + size, "\n"); \
147 static ssize_t field##_show(struct device *dev, \
148 struct device_attribute *attr, \
151 struct sdw_slave *slave = dev_to_sdw_dev(dev); \
152 struct dpn_attribute *dpn_attr = \
153 container_of(attr, struct dpn_attribute, dev_attr); \
155 return field##_dpn_show(slave, \
156 dpn_attr->N, dpn_attr->dir, \
157 dpn_attr->format_string, \
160 sdw_dpn_attribute_alloc(field)
162 sdw_dpn_array_attr(words);
163 sdw_dpn_array_attr(ch_combinations);
164 sdw_dpn_array_attr(channels);
166 static int add_all_attributes(struct device *dev, int N, int dir)
168 struct attribute **dpn_attrs;
169 struct attribute_group *dpn_group;
173 /* allocate attributes, last one is NULL */
174 dpn_attrs = devm_kcalloc(dev, SDW_DPN_ATTRIBUTES + 1,
175 sizeof(struct attribute *),
180 ret = max_word_attribute_alloc(dev, &dpn_attrs[i++],
185 ret = min_word_attribute_alloc(dev, &dpn_attrs[i++],
190 ret = words_attribute_alloc(dev, &dpn_attrs[i++],
195 ret = type_attribute_alloc(dev, &dpn_attrs[i++],
200 ret = max_grouping_attribute_alloc(dev, &dpn_attrs[i++],
205 ret = simple_ch_prep_sm_attribute_alloc(dev, &dpn_attrs[i++],
210 ret = ch_prep_timeout_attribute_alloc(dev, &dpn_attrs[i++],
215 ret = imp_def_interrupts_attribute_alloc(dev, &dpn_attrs[i++],
220 ret = min_ch_attribute_alloc(dev, &dpn_attrs[i++],
225 ret = max_ch_attribute_alloc(dev, &dpn_attrs[i++],
230 ret = channels_attribute_alloc(dev, &dpn_attrs[i++],
235 ret = ch_combinations_attribute_alloc(dev, &dpn_attrs[i++],
240 ret = max_async_buffer_attribute_alloc(dev, &dpn_attrs[i++],
245 ret = block_pack_mode_attribute_alloc(dev, &dpn_attrs[i++],
250 ret = port_encoding_attribute_alloc(dev, &dpn_attrs[i++],
255 /* paranoia check for editing mistakes */
256 if (i != SDW_DPN_ATTRIBUTES) {
257 dev_err(dev, "mismatch in attributes, allocated %d got %d\n",
258 SDW_DPN_ATTRIBUTES, i);
262 dpn_group = devm_kzalloc(dev, sizeof(*dpn_group), GFP_KERNEL);
266 dpn_group->attrs = dpn_attrs;
267 dpn_group->name = devm_kasprintf(dev, GFP_KERNEL, "dp%d_%s",
268 N, dir ? "src" : "sink");
269 if (!dpn_group->name)
272 ret = devm_device_add_group(dev, dpn_group);
279 int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
285 mask = slave->prop.source_ports;
286 for_each_set_bit(i, &mask, 32) {
287 ret = add_all_attributes(&slave->dev, i, 1);
292 mask = slave->prop.sink_ports;
293 for_each_set_bit(i, &mask, 32) {
294 ret = add_all_attributes(&slave->dev, i, 0);