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 
13 struct 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)					\
28 static 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 									\
52 static 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 									\
82 static 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 }									\
95 sdw_dpn_attribute_alloc(field)
96 
97 sdw_dpn_attr(imp_def_interrupts);
98 sdw_dpn_attr(max_word);
99 sdw_dpn_attr(min_word);
100 sdw_dpn_attr(type);
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);
109 
110 #define sdw_dpn_array_attr(field)					\
111 									\
112 static 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 }									\
147 static 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 }									\
160 sdw_dpn_attribute_alloc(field)
161 
162 sdw_dpn_array_attr(words);
163 sdw_dpn_array_attr(ch_combinations);
164 sdw_dpn_array_attr(channels);
165 
add_all_attributes(struct device * dev,int N,int dir)166 static 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 
sdw_slave_sysfs_dpn_init(struct sdw_slave * slave)279 int 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 }
301