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 sysfs_attr_init(&dpn_attr->dev_attr.attr); \
41 dpn_attr->format_string = format_string; \
42 dpn_attr->dev_attr.attr.name = __stringify(field); \
43 dpn_attr->dev_attr.attr.mode = 0444; \
44 dpn_attr->dev_attr.show = field##_show; \
46 *res = &dpn_attr->dev_attr.attr; \
51 #define sdw_dpn_attr(field) \
53 static ssize_t field##_dpn_show(struct sdw_slave *slave, \
56 const char *format_string, \
59 struct sdw_dpn_prop *dpn; \
65 dpn = slave->prop.src_dpn_prop; \
66 mask = slave->prop.source_ports; \
68 dpn = slave->prop.sink_dpn_prop; \
69 mask = slave->prop.sink_ports; \
73 for_each_set_bit(bit, &mask, 32) { \
75 return sprintf(buf, format_string, \
83 static ssize_t field##_show(struct device *dev, \
84 struct device_attribute *attr, \
87 struct sdw_slave *slave = dev_to_sdw_dev(dev); \
88 struct dpn_attribute *dpn_attr = \
89 container_of(attr, struct dpn_attribute, dev_attr); \
91 return field##_dpn_show(slave, \
92 dpn_attr->N, dpn_attr->dir, \
93 dpn_attr->format_string, \
96 sdw_dpn_attribute_alloc(field)
98 sdw_dpn_attr(imp_def_interrupts
);
99 sdw_dpn_attr(max_word
);
100 sdw_dpn_attr(min_word
);
102 sdw_dpn_attr(max_grouping
);
103 sdw_dpn_attr(simple_ch_prep_sm
);
104 sdw_dpn_attr(ch_prep_timeout
);
105 sdw_dpn_attr(max_ch
);
106 sdw_dpn_attr(min_ch
);
107 sdw_dpn_attr(max_async_buffer
);
108 sdw_dpn_attr(block_pack_mode
);
109 sdw_dpn_attr(port_encoding
);
111 #define sdw_dpn_array_attr(field) \
113 static ssize_t field##_dpn_show(struct sdw_slave *slave, \
116 const char *format_string, \
119 struct sdw_dpn_prop *dpn; \
120 unsigned long mask; \
127 dpn = slave->prop.src_dpn_prop; \
128 mask = slave->prop.source_ports; \
130 dpn = slave->prop.sink_dpn_prop; \
131 mask = slave->prop.sink_ports; \
135 for_each_set_bit(bit, &mask, 32) { \
137 for (j = 0; j < dpn[i].num_##field; j++) \
138 size += sprintf(buf + size, \
141 size += sprintf(buf + size, "\n"); \
148 static ssize_t field##_show(struct device *dev, \
149 struct device_attribute *attr, \
152 struct sdw_slave *slave = dev_to_sdw_dev(dev); \
153 struct dpn_attribute *dpn_attr = \
154 container_of(attr, struct dpn_attribute, dev_attr); \
156 return field##_dpn_show(slave, \
157 dpn_attr->N, dpn_attr->dir, \
158 dpn_attr->format_string, \
161 sdw_dpn_attribute_alloc(field)
163 sdw_dpn_array_attr(words
);
164 sdw_dpn_array_attr(ch_combinations
);
165 sdw_dpn_array_attr(channels
);
167 static int add_all_attributes(struct device
*dev
, int N
, int dir
)
169 struct attribute
**dpn_attrs
;
170 struct attribute_group
*dpn_group
;
174 /* allocate attributes, last one is NULL */
175 dpn_attrs
= devm_kcalloc(dev
, SDW_DPN_ATTRIBUTES
+ 1,
176 sizeof(struct attribute
*),
181 ret
= max_word_attribute_alloc(dev
, &dpn_attrs
[i
++],
186 ret
= min_word_attribute_alloc(dev
, &dpn_attrs
[i
++],
191 ret
= words_attribute_alloc(dev
, &dpn_attrs
[i
++],
196 ret
= type_attribute_alloc(dev
, &dpn_attrs
[i
++],
201 ret
= max_grouping_attribute_alloc(dev
, &dpn_attrs
[i
++],
206 ret
= simple_ch_prep_sm_attribute_alloc(dev
, &dpn_attrs
[i
++],
211 ret
= ch_prep_timeout_attribute_alloc(dev
, &dpn_attrs
[i
++],
216 ret
= imp_def_interrupts_attribute_alloc(dev
, &dpn_attrs
[i
++],
221 ret
= min_ch_attribute_alloc(dev
, &dpn_attrs
[i
++],
226 ret
= max_ch_attribute_alloc(dev
, &dpn_attrs
[i
++],
231 ret
= channels_attribute_alloc(dev
, &dpn_attrs
[i
++],
236 ret
= ch_combinations_attribute_alloc(dev
, &dpn_attrs
[i
++],
241 ret
= max_async_buffer_attribute_alloc(dev
, &dpn_attrs
[i
++],
246 ret
= block_pack_mode_attribute_alloc(dev
, &dpn_attrs
[i
++],
251 ret
= port_encoding_attribute_alloc(dev
, &dpn_attrs
[i
++],
256 /* paranoia check for editing mistakes */
257 if (i
!= SDW_DPN_ATTRIBUTES
) {
258 dev_err(dev
, "mismatch in attributes, allocated %d got %d\n",
259 SDW_DPN_ATTRIBUTES
, i
);
263 dpn_group
= devm_kzalloc(dev
, sizeof(*dpn_group
), GFP_KERNEL
);
267 dpn_group
->attrs
= dpn_attrs
;
268 dpn_group
->name
= devm_kasprintf(dev
, GFP_KERNEL
, "dp%d_%s",
269 N
, dir
? "src" : "sink");
270 if (!dpn_group
->name
)
273 ret
= devm_device_add_group(dev
, dpn_group
);
280 int sdw_slave_sysfs_dpn_init(struct sdw_slave
*slave
)
286 mask
= slave
->prop
.source_ports
;
287 for_each_set_bit(i
, &mask
, 32) {
288 ret
= add_all_attributes(&slave
->dev
, i
, 1);
293 mask
= slave
->prop
.sink_ports
;
294 for_each_set_bit(i
, &mask
, 32) {
295 ret
= add_all_attributes(&slave
->dev
, i
, 0);