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 } 301