Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright(c) 2015-2020 Intel Corporation.
3
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>
10#include "bus.h"
11#include "sysfs_local.h"
12
13struct dpn_attribute {
14 struct device_attribute dev_attr;
15 int N;
16 int dir;
17 const char *format_string;
18};
19
20/*
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.
24 */
25#define SDW_DPN_ATTRIBUTES 15
26
27#define sdw_dpn_attribute_alloc(field) \
28static int field##_attribute_alloc(struct device *dev, \
29 struct attribute **res, \
30 int N, int dir, \
31 const char *format_string) \
32{ \
33 struct dpn_attribute *dpn_attr; \
34 \
35 dpn_attr = devm_kzalloc(dev, sizeof(*dpn_attr), GFP_KERNEL); \
36 if (!dpn_attr) \
37 return -ENOMEM; \
38 dpn_attr->N = N; \
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; \
45 \
46 *res = &dpn_attr->dev_attr.attr; \
47 \
48 return 0; \
49}
50
51#define sdw_dpn_attr(field) \
52 \
53static ssize_t field##_dpn_show(struct sdw_slave *slave, \
54 int N, \
55 int dir, \
56 const char *format_string, \
57 char *buf) \
58{ \
59 struct sdw_dpn_prop *dpn; \
60 unsigned long mask; \
61 int bit; \
62 int i; \
63 \
64 if (dir) { \
65 dpn = slave->prop.src_dpn_prop; \
66 mask = slave->prop.source_ports; \
67 } else { \
68 dpn = slave->prop.sink_dpn_prop; \
69 mask = slave->prop.sink_ports; \
70 } \
71 \
72 i = 0; \
73 for_each_set_bit(bit, &mask, 32) { \
74 if (bit == N) { \
75 return sprintf(buf, format_string, \
76 dpn[i].field); \
77 } \
78 i++; \
79 } \
80 return -EINVAL; \
81} \
82 \
83static ssize_t field##_show(struct device *dev, \
84 struct device_attribute *attr, \
85 char *buf) \
86{ \
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); \
90 \
91 return field##_dpn_show(slave, \
92 dpn_attr->N, dpn_attr->dir, \
93 dpn_attr->format_string, \
94 buf); \
95} \
96sdw_dpn_attribute_alloc(field)
97
98sdw_dpn_attr(imp_def_interrupts);
99sdw_dpn_attr(max_word);
100sdw_dpn_attr(min_word);
101sdw_dpn_attr(type);
102sdw_dpn_attr(max_grouping);
103sdw_dpn_attr(simple_ch_prep_sm);
104sdw_dpn_attr(ch_prep_timeout);
105sdw_dpn_attr(max_ch);
106sdw_dpn_attr(min_ch);
107sdw_dpn_attr(max_async_buffer);
108sdw_dpn_attr(block_pack_mode);
109sdw_dpn_attr(port_encoding);
110
111#define sdw_dpn_array_attr(field) \
112 \
113static ssize_t field##_dpn_show(struct sdw_slave *slave, \
114 int N, \
115 int dir, \
116 const char *format_string, \
117 char *buf) \
118{ \
119 struct sdw_dpn_prop *dpn; \
120 unsigned long mask; \
121 ssize_t size = 0; \
122 int bit; \
123 int i; \
124 int j; \
125 \
126 if (dir) { \
127 dpn = slave->prop.src_dpn_prop; \
128 mask = slave->prop.source_ports; \
129 } else { \
130 dpn = slave->prop.sink_dpn_prop; \
131 mask = slave->prop.sink_ports; \
132 } \
133 \
134 i = 0; \
135 for_each_set_bit(bit, &mask, 32) { \
136 if (bit == N) { \
137 for (j = 0; j < dpn[i].num_##field; j++) \
138 size += sprintf(buf + size, \
139 format_string, \
140 dpn[i].field[j]); \
141 size += sprintf(buf + size, "\n"); \
142 return size; \
143 } \
144 i++; \
145 } \
146 return -EINVAL; \
147} \
148static ssize_t field##_show(struct device *dev, \
149 struct device_attribute *attr, \
150 char *buf) \
151{ \
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); \
155 \
156 return field##_dpn_show(slave, \
157 dpn_attr->N, dpn_attr->dir, \
158 dpn_attr->format_string, \
159 buf); \
160} \
161sdw_dpn_attribute_alloc(field)
162
163sdw_dpn_array_attr(words);
164sdw_dpn_array_attr(ch_combinations);
165sdw_dpn_array_attr(channels);
166
167static int add_all_attributes(struct device *dev, int N, int dir)
168{
169 struct attribute **dpn_attrs;
170 struct attribute_group *dpn_group;
171 int i = 0;
172 int ret;
173
174 /* allocate attributes, last one is NULL */
175 dpn_attrs = devm_kcalloc(dev, SDW_DPN_ATTRIBUTES + 1,
176 sizeof(struct attribute *),
177 GFP_KERNEL);
178 if (!dpn_attrs)
179 return -ENOMEM;
180
181 ret = max_word_attribute_alloc(dev, &dpn_attrs[i++],
182 N, dir, "%d\n");
183 if (ret < 0)
184 return ret;
185
186 ret = min_word_attribute_alloc(dev, &dpn_attrs[i++],
187 N, dir, "%d\n");
188 if (ret < 0)
189 return ret;
190
191 ret = words_attribute_alloc(dev, &dpn_attrs[i++],
192 N, dir, "%d\n");
193 if (ret < 0)
194 return ret;
195
196 ret = type_attribute_alloc(dev, &dpn_attrs[i++],
197 N, dir, "%d\n");
198 if (ret < 0)
199 return ret;
200
201 ret = max_grouping_attribute_alloc(dev, &dpn_attrs[i++],
202 N, dir, "%d\n");
203 if (ret < 0)
204 return ret;
205
206 ret = simple_ch_prep_sm_attribute_alloc(dev, &dpn_attrs[i++],
207 N, dir, "%d\n");
208 if (ret < 0)
209 return ret;
210
211 ret = ch_prep_timeout_attribute_alloc(dev, &dpn_attrs[i++],
212 N, dir, "%d\n");
213 if (ret < 0)
214 return ret;
215
216 ret = imp_def_interrupts_attribute_alloc(dev, &dpn_attrs[i++],
217 N, dir, "0x%x\n");
218 if (ret < 0)
219 return ret;
220
221 ret = min_ch_attribute_alloc(dev, &dpn_attrs[i++],
222 N, dir, "%d\n");
223 if (ret < 0)
224 return ret;
225
226 ret = max_ch_attribute_alloc(dev, &dpn_attrs[i++],
227 N, dir, "%d\n");
228 if (ret < 0)
229 return ret;
230
231 ret = channels_attribute_alloc(dev, &dpn_attrs[i++],
232 N, dir, "%d\n");
233 if (ret < 0)
234 return ret;
235
236 ret = ch_combinations_attribute_alloc(dev, &dpn_attrs[i++],
237 N, dir, "%d\n");
238 if (ret < 0)
239 return ret;
240
241 ret = max_async_buffer_attribute_alloc(dev, &dpn_attrs[i++],
242 N, dir, "%d\n");
243 if (ret < 0)
244 return ret;
245
246 ret = block_pack_mode_attribute_alloc(dev, &dpn_attrs[i++],
247 N, dir, "%d\n");
248 if (ret < 0)
249 return ret;
250
251 ret = port_encoding_attribute_alloc(dev, &dpn_attrs[i++],
252 N, dir, "%d\n");
253 if (ret < 0)
254 return ret;
255
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);
260 return -EINVAL;
261 }
262
263 dpn_group = devm_kzalloc(dev, sizeof(*dpn_group), GFP_KERNEL);
264 if (!dpn_group)
265 return -ENOMEM;
266
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)
271 return -ENOMEM;
272
273 ret = devm_device_add_group(dev, dpn_group);
274 if (ret < 0)
275 return ret;
276
277 return 0;
278}
279
280int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
281{
282 unsigned long mask;
283 int ret;
284 int i;
285
286 mask = slave->prop.source_ports;
287 for_each_set_bit(i, &mask, 32) {
288 ret = add_all_attributes(&slave->dev, i, 1);
289 if (ret < 0)
290 return ret;
291 }
292
293 mask = slave->prop.sink_ports;
294 for_each_set_bit(i, &mask, 32) {
295 ret = add_all_attributes(&slave->dev, i, 0);
296 if (ret < 0)
297 return ret;
298 }
299
300 return 0;
301}
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright(c) 2015-2020 Intel Corporation.
3
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>
10#include "bus.h"
11#include "sysfs_local.h"
12
13struct dpn_attribute {
14 struct device_attribute dev_attr;
15 int N;
16 int dir;
17 const char *format_string;
18};
19
20/*
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.
24 */
25#define SDW_DPN_ATTRIBUTES 15
26
27#define sdw_dpn_attribute_alloc(field) \
28static int field##_attribute_alloc(struct device *dev, \
29 struct attribute **res, \
30 int N, int dir, \
31 const char *format_string) \
32{ \
33 struct dpn_attribute *dpn_attr; \
34 \
35 dpn_attr = devm_kzalloc(dev, sizeof(*dpn_attr), GFP_KERNEL); \
36 if (!dpn_attr) \
37 return -ENOMEM; \
38 dpn_attr->N = N; \
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; \
44 \
45 *res = &dpn_attr->dev_attr.attr; \
46 \
47 return 0; \
48}
49
50#define sdw_dpn_attr(field) \
51 \
52static ssize_t field##_dpn_show(struct sdw_slave *slave, \
53 int N, \
54 int dir, \
55 const char *format_string, \
56 char *buf) \
57{ \
58 struct sdw_dpn_prop *dpn; \
59 unsigned long mask; \
60 int bit; \
61 int i; \
62 \
63 if (dir) { \
64 dpn = slave->prop.src_dpn_prop; \
65 mask = slave->prop.source_ports; \
66 } else { \
67 dpn = slave->prop.sink_dpn_prop; \
68 mask = slave->prop.sink_ports; \
69 } \
70 \
71 i = 0; \
72 for_each_set_bit(bit, &mask, 32) { \
73 if (bit == N) { \
74 return sprintf(buf, format_string, \
75 dpn[i].field); \
76 } \
77 i++; \
78 } \
79 return -EINVAL; \
80} \
81 \
82static ssize_t field##_show(struct device *dev, \
83 struct device_attribute *attr, \
84 char *buf) \
85{ \
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); \
89 \
90 return field##_dpn_show(slave, \
91 dpn_attr->N, dpn_attr->dir, \
92 dpn_attr->format_string, \
93 buf); \
94} \
95sdw_dpn_attribute_alloc(field)
96
97sdw_dpn_attr(imp_def_interrupts);
98sdw_dpn_attr(max_word);
99sdw_dpn_attr(min_word);
100sdw_dpn_attr(type);
101sdw_dpn_attr(max_grouping);
102sdw_dpn_attr(simple_ch_prep_sm);
103sdw_dpn_attr(ch_prep_timeout);
104sdw_dpn_attr(max_ch);
105sdw_dpn_attr(min_ch);
106sdw_dpn_attr(max_async_buffer);
107sdw_dpn_attr(block_pack_mode);
108sdw_dpn_attr(port_encoding);
109
110#define sdw_dpn_array_attr(field) \
111 \
112static ssize_t field##_dpn_show(struct sdw_slave *slave, \
113 int N, \
114 int dir, \
115 const char *format_string, \
116 char *buf) \
117{ \
118 struct sdw_dpn_prop *dpn; \
119 unsigned long mask; \
120 ssize_t size = 0; \
121 int bit; \
122 int i; \
123 int j; \
124 \
125 if (dir) { \
126 dpn = slave->prop.src_dpn_prop; \
127 mask = slave->prop.source_ports; \
128 } else { \
129 dpn = slave->prop.sink_dpn_prop; \
130 mask = slave->prop.sink_ports; \
131 } \
132 \
133 i = 0; \
134 for_each_set_bit(bit, &mask, 32) { \
135 if (bit == N) { \
136 for (j = 0; j < dpn[i].num_##field; j++) \
137 size += sprintf(buf + size, \
138 format_string, \
139 dpn[i].field[j]); \
140 size += sprintf(buf + size, "\n"); \
141 return size; \
142 } \
143 i++; \
144 } \
145 return -EINVAL; \
146} \
147static ssize_t field##_show(struct device *dev, \
148 struct device_attribute *attr, \
149 char *buf) \
150{ \
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); \
154 \
155 return field##_dpn_show(slave, \
156 dpn_attr->N, dpn_attr->dir, \
157 dpn_attr->format_string, \
158 buf); \
159} \
160sdw_dpn_attribute_alloc(field)
161
162sdw_dpn_array_attr(words);
163sdw_dpn_array_attr(ch_combinations);
164sdw_dpn_array_attr(channels);
165
166static int add_all_attributes(struct device *dev, int N, int dir)
167{
168 struct attribute **dpn_attrs;
169 struct attribute_group *dpn_group;
170 int i = 0;
171 int ret;
172
173 /* allocate attributes, last one is NULL */
174 dpn_attrs = devm_kcalloc(dev, SDW_DPN_ATTRIBUTES + 1,
175 sizeof(struct attribute *),
176 GFP_KERNEL);
177 if (!dpn_attrs)
178 return -ENOMEM;
179
180 ret = max_word_attribute_alloc(dev, &dpn_attrs[i++],
181 N, dir, "%d\n");
182 if (ret < 0)
183 return ret;
184
185 ret = min_word_attribute_alloc(dev, &dpn_attrs[i++],
186 N, dir, "%d\n");
187 if (ret < 0)
188 return ret;
189
190 ret = words_attribute_alloc(dev, &dpn_attrs[i++],
191 N, dir, "%d\n");
192 if (ret < 0)
193 return ret;
194
195 ret = type_attribute_alloc(dev, &dpn_attrs[i++],
196 N, dir, "%d\n");
197 if (ret < 0)
198 return ret;
199
200 ret = max_grouping_attribute_alloc(dev, &dpn_attrs[i++],
201 N, dir, "%d\n");
202 if (ret < 0)
203 return ret;
204
205 ret = simple_ch_prep_sm_attribute_alloc(dev, &dpn_attrs[i++],
206 N, dir, "%d\n");
207 if (ret < 0)
208 return ret;
209
210 ret = ch_prep_timeout_attribute_alloc(dev, &dpn_attrs[i++],
211 N, dir, "%d\n");
212 if (ret < 0)
213 return ret;
214
215 ret = imp_def_interrupts_attribute_alloc(dev, &dpn_attrs[i++],
216 N, dir, "0x%x\n");
217 if (ret < 0)
218 return ret;
219
220 ret = min_ch_attribute_alloc(dev, &dpn_attrs[i++],
221 N, dir, "%d\n");
222 if (ret < 0)
223 return ret;
224
225 ret = max_ch_attribute_alloc(dev, &dpn_attrs[i++],
226 N, dir, "%d\n");
227 if (ret < 0)
228 return ret;
229
230 ret = channels_attribute_alloc(dev, &dpn_attrs[i++],
231 N, dir, "%d\n");
232 if (ret < 0)
233 return ret;
234
235 ret = ch_combinations_attribute_alloc(dev, &dpn_attrs[i++],
236 N, dir, "%d\n");
237 if (ret < 0)
238 return ret;
239
240 ret = max_async_buffer_attribute_alloc(dev, &dpn_attrs[i++],
241 N, dir, "%d\n");
242 if (ret < 0)
243 return ret;
244
245 ret = block_pack_mode_attribute_alloc(dev, &dpn_attrs[i++],
246 N, dir, "%d\n");
247 if (ret < 0)
248 return ret;
249
250 ret = port_encoding_attribute_alloc(dev, &dpn_attrs[i++],
251 N, dir, "%d\n");
252 if (ret < 0)
253 return ret;
254
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);
259 return -EINVAL;
260 }
261
262 dpn_group = devm_kzalloc(dev, sizeof(*dpn_group), GFP_KERNEL);
263 if (!dpn_group)
264 return -ENOMEM;
265
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)
270 return -ENOMEM;
271
272 ret = devm_device_add_group(dev, dpn_group);
273 if (ret < 0)
274 return ret;
275
276 return 0;
277}
278
279int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
280{
281 unsigned long mask;
282 int ret;
283 int i;
284
285 mask = slave->prop.source_ports;
286 for_each_set_bit(i, &mask, 32) {
287 ret = add_all_attributes(&slave->dev, i, 1);
288 if (ret < 0)
289 return ret;
290 }
291
292 mask = slave->prop.sink_ports;
293 for_each_set_bit(i, &mask, 32) {
294 ret = add_all_attributes(&slave->dev, i, 0);
295 if (ret < 0)
296 return ret;
297 }
298
299 return 0;
300}