Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright(c) 2015-2020 Intel Corporation.
0003 
0004 #include <linux/device.h>
0005 #include <linux/mod_devicetable.h>
0006 #include <linux/slab.h>
0007 #include <linux/sysfs.h>
0008 #include <linux/soundwire/sdw.h>
0009 #include <linux/soundwire/sdw_type.h>
0010 #include "bus.h"
0011 #include "sysfs_local.h"
0012 
0013 struct dpn_attribute {
0014     struct device_attribute dev_attr;
0015     int N;
0016     int dir;
0017     const char *format_string;
0018 };
0019 
0020 /*
0021  * Since we can't use ARRAY_SIZE, hard-code number of dpN attributes.
0022  * This needs to be updated when adding new attributes - an error will be
0023  * flagged on a mismatch.
0024  */
0025 #define SDW_DPN_ATTRIBUTES 15
0026 
0027 #define sdw_dpn_attribute_alloc(field)                  \
0028 static int field##_attribute_alloc(struct device *dev,          \
0029                 struct attribute **res,         \
0030                 int N, int dir,             \
0031                 const char *format_string)      \
0032 {                                   \
0033     struct dpn_attribute *dpn_attr;                 \
0034                                     \
0035     dpn_attr = devm_kzalloc(dev, sizeof(*dpn_attr), GFP_KERNEL);    \
0036     if (!dpn_attr)                          \
0037         return -ENOMEM;                     \
0038     dpn_attr->N = N;                        \
0039     dpn_attr->dir = dir;                        \
0040     sysfs_attr_init(&dpn_attr->dev_attr.attr);          \
0041     dpn_attr->format_string = format_string;            \
0042     dpn_attr->dev_attr.attr.name = __stringify(field);      \
0043     dpn_attr->dev_attr.attr.mode = 0444;                \
0044     dpn_attr->dev_attr.show = field##_show;             \
0045                                     \
0046     *res = &dpn_attr->dev_attr.attr;                \
0047                                     \
0048     return 0;                           \
0049 }
0050 
0051 #define sdw_dpn_attr(field)                     \
0052                                     \
0053 static ssize_t field##_dpn_show(struct sdw_slave *slave,        \
0054                 int N,                  \
0055                 int dir,                \
0056                 const char *format_string,      \
0057                 char *buf)              \
0058 {                                   \
0059     struct sdw_dpn_prop *dpn;                   \
0060     unsigned long mask;                     \
0061     int bit;                            \
0062     int i;                              \
0063                                     \
0064     if (dir) {                          \
0065         dpn = slave->prop.src_dpn_prop;             \
0066         mask = slave->prop.source_ports;            \
0067     } else {                            \
0068         dpn = slave->prop.sink_dpn_prop;            \
0069         mask = slave->prop.sink_ports;              \
0070     }                               \
0071                                     \
0072     i = 0;                              \
0073     for_each_set_bit(bit, &mask, 32) {              \
0074         if (bit == N) {                     \
0075             return sprintf(buf, format_string,      \
0076                        dpn[i].field);           \
0077         }                           \
0078         i++;                            \
0079     }                               \
0080     return -EINVAL;                         \
0081 }                                   \
0082                                     \
0083 static ssize_t field##_show(struct device *dev,             \
0084                 struct device_attribute *attr,      \
0085                 char *buf)                  \
0086 {                                   \
0087     struct sdw_slave *slave = dev_to_sdw_dev(dev);          \
0088     struct dpn_attribute *dpn_attr =                \
0089         container_of(attr, struct dpn_attribute, dev_attr); \
0090                                     \
0091     return field##_dpn_show(slave,                  \
0092                 dpn_attr->N, dpn_attr->dir,     \
0093                 dpn_attr->format_string,        \
0094                 buf);                   \
0095 }                                   \
0096 sdw_dpn_attribute_alloc(field)
0097 
0098 sdw_dpn_attr(imp_def_interrupts);
0099 sdw_dpn_attr(max_word);
0100 sdw_dpn_attr(min_word);
0101 sdw_dpn_attr(type);
0102 sdw_dpn_attr(max_grouping);
0103 sdw_dpn_attr(simple_ch_prep_sm);
0104 sdw_dpn_attr(ch_prep_timeout);
0105 sdw_dpn_attr(max_ch);
0106 sdw_dpn_attr(min_ch);
0107 sdw_dpn_attr(max_async_buffer);
0108 sdw_dpn_attr(block_pack_mode);
0109 sdw_dpn_attr(port_encoding);
0110 
0111 #define sdw_dpn_array_attr(field)                   \
0112                                     \
0113 static ssize_t field##_dpn_show(struct sdw_slave *slave,        \
0114                 int N,                  \
0115                 int dir,                \
0116                 const char *format_string,      \
0117                 char *buf)              \
0118 {                                   \
0119     struct sdw_dpn_prop *dpn;                   \
0120     unsigned long mask;                     \
0121     ssize_t size = 0;                       \
0122     int bit;                            \
0123     int i;                              \
0124     int j;                              \
0125                                     \
0126     if (dir) {                          \
0127         dpn = slave->prop.src_dpn_prop;             \
0128         mask = slave->prop.source_ports;            \
0129     } else {                            \
0130         dpn = slave->prop.sink_dpn_prop;            \
0131         mask = slave->prop.sink_ports;              \
0132     }                               \
0133                                     \
0134     i = 0;                              \
0135     for_each_set_bit(bit, &mask, 32) {              \
0136         if (bit == N) {                     \
0137             for (j = 0; j < dpn[i].num_##field; j++)    \
0138                 size += sprintf(buf + size,     \
0139                         format_string,      \
0140                         dpn[i].field[j]);   \
0141             size += sprintf(buf + size, "\n");      \
0142             return size;                    \
0143         }                           \
0144         i++;                            \
0145     }                               \
0146     return -EINVAL;                         \
0147 }                                   \
0148 static ssize_t field##_show(struct device *dev,             \
0149                 struct device_attribute *attr,      \
0150                 char *buf)                  \
0151 {                                   \
0152     struct sdw_slave *slave = dev_to_sdw_dev(dev);          \
0153     struct dpn_attribute *dpn_attr =                \
0154         container_of(attr, struct dpn_attribute, dev_attr); \
0155                                     \
0156     return field##_dpn_show(slave,                  \
0157                 dpn_attr->N, dpn_attr->dir,     \
0158                 dpn_attr->format_string,        \
0159                 buf);                   \
0160 }                                   \
0161 sdw_dpn_attribute_alloc(field)
0162 
0163 sdw_dpn_array_attr(words);
0164 sdw_dpn_array_attr(ch_combinations);
0165 sdw_dpn_array_attr(channels);
0166 
0167 static int add_all_attributes(struct device *dev, int N, int dir)
0168 {
0169     struct attribute **dpn_attrs;
0170     struct attribute_group *dpn_group;
0171     int i = 0;
0172     int ret;
0173 
0174     /* allocate attributes, last one is NULL */
0175     dpn_attrs = devm_kcalloc(dev, SDW_DPN_ATTRIBUTES + 1,
0176                  sizeof(struct attribute *),
0177                  GFP_KERNEL);
0178     if (!dpn_attrs)
0179         return -ENOMEM;
0180 
0181     ret = max_word_attribute_alloc(dev, &dpn_attrs[i++],
0182                        N, dir, "%d\n");
0183     if (ret < 0)
0184         return ret;
0185 
0186     ret = min_word_attribute_alloc(dev, &dpn_attrs[i++],
0187                        N, dir, "%d\n");
0188     if (ret < 0)
0189         return ret;
0190 
0191     ret = words_attribute_alloc(dev, &dpn_attrs[i++],
0192                     N, dir, "%d\n");
0193     if (ret < 0)
0194         return ret;
0195 
0196     ret = type_attribute_alloc(dev, &dpn_attrs[i++],
0197                    N, dir, "%d\n");
0198     if (ret < 0)
0199         return ret;
0200 
0201     ret = max_grouping_attribute_alloc(dev, &dpn_attrs[i++],
0202                        N, dir, "%d\n");
0203     if (ret < 0)
0204         return ret;
0205 
0206     ret = simple_ch_prep_sm_attribute_alloc(dev, &dpn_attrs[i++],
0207                         N, dir, "%d\n");
0208     if (ret < 0)
0209         return ret;
0210 
0211     ret = ch_prep_timeout_attribute_alloc(dev, &dpn_attrs[i++],
0212                           N, dir, "%d\n");
0213     if (ret < 0)
0214         return ret;
0215 
0216     ret = imp_def_interrupts_attribute_alloc(dev, &dpn_attrs[i++],
0217                          N, dir, "0x%x\n");
0218     if (ret < 0)
0219         return ret;
0220 
0221     ret = min_ch_attribute_alloc(dev, &dpn_attrs[i++],
0222                      N, dir, "%d\n");
0223     if (ret < 0)
0224         return ret;
0225 
0226     ret = max_ch_attribute_alloc(dev, &dpn_attrs[i++],
0227                      N, dir, "%d\n");
0228     if (ret < 0)
0229         return ret;
0230 
0231     ret = channels_attribute_alloc(dev, &dpn_attrs[i++],
0232                        N, dir, "%d\n");
0233     if (ret < 0)
0234         return ret;
0235 
0236     ret = ch_combinations_attribute_alloc(dev, &dpn_attrs[i++],
0237                           N, dir, "%d\n");
0238     if (ret < 0)
0239         return ret;
0240 
0241     ret = max_async_buffer_attribute_alloc(dev, &dpn_attrs[i++],
0242                            N, dir, "%d\n");
0243     if (ret < 0)
0244         return ret;
0245 
0246     ret = block_pack_mode_attribute_alloc(dev, &dpn_attrs[i++],
0247                           N, dir, "%d\n");
0248     if (ret < 0)
0249         return ret;
0250 
0251     ret = port_encoding_attribute_alloc(dev, &dpn_attrs[i++],
0252                         N, dir, "%d\n");
0253     if (ret < 0)
0254         return ret;
0255 
0256     /* paranoia check for editing mistakes */
0257     if (i != SDW_DPN_ATTRIBUTES) {
0258         dev_err(dev, "mismatch in attributes, allocated %d got %d\n",
0259             SDW_DPN_ATTRIBUTES, i);
0260         return -EINVAL;
0261     }
0262 
0263     dpn_group = devm_kzalloc(dev, sizeof(*dpn_group), GFP_KERNEL);
0264     if (!dpn_group)
0265         return -ENOMEM;
0266 
0267     dpn_group->attrs = dpn_attrs;
0268     dpn_group->name = devm_kasprintf(dev, GFP_KERNEL, "dp%d_%s",
0269                      N, dir ? "src" : "sink");
0270     if (!dpn_group->name)
0271         return -ENOMEM;
0272 
0273     ret = devm_device_add_group(dev, dpn_group);
0274     if (ret < 0)
0275         return ret;
0276 
0277     return 0;
0278 }
0279 
0280 int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
0281 {
0282     unsigned long mask;
0283     int ret;
0284     int i;
0285 
0286     mask = slave->prop.source_ports;
0287     for_each_set_bit(i, &mask, 32) {
0288         ret = add_all_attributes(&slave->dev, i, 1);
0289         if (ret < 0)
0290             return ret;
0291     }
0292 
0293     mask = slave->prop.sink_ports;
0294     for_each_set_bit(i, &mask, 32) {
0295         ret = add_all_attributes(&slave->dev, i, 0);
0296         if (ret < 0)
0297             return ret;
0298     }
0299 
0300     return 0;
0301 }