Merge branch 'pci/vmd'
[linux-2.6-microblaze.git] / drivers / soundwire / sysfs_slave_dpn.c
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
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
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 }