linux/drivers/soundwire/sysfs_slave.c
<<
>>
Prefs
   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/*
  14 * Slave sysfs
  15 */
  16
  17/*
  18 * The sysfs for Slave reflects the MIPI description as given
  19 * in the MIPI DisCo spec.
  20 * status and device_number come directly from the MIPI SoundWire
  21 * 1.x specification.
  22 *
  23 * Base file is device
  24 *      |---- status
  25 *      |---- device_number
  26 *      |---- modalias
  27 *      |---- dev-properties
  28 *              |---- mipi_revision
  29 *              |---- wake_capable
  30 *              |---- test_mode_capable
  31 *              |---- clk_stop_mode1
  32 *              |---- simple_clk_stop_capable
  33 *              |---- clk_stop_timeout
  34 *              |---- ch_prep_timeout
  35 *              |---- reset_behave
  36 *              |---- high_PHY_capable
  37 *              |---- paging_support
  38 *              |---- bank_delay_support
  39 *              |---- p15_behave
  40 *              |---- master_count
  41 *              |---- source_ports
  42 *              |---- sink_ports
  43 *      |---- dp0
  44 *              |---- max_word
  45 *              |---- min_word
  46 *              |---- words
  47 *              |---- BRA_flow_controlled
  48 *              |---- simple_ch_prep_sm
  49 *              |---- imp_def_interrupts
  50 *      |---- dpN_<sink/src>
  51 *              |---- max_word
  52 *              |---- min_word
  53 *              |---- words
  54 *              |---- type
  55 *              |---- max_grouping
  56 *              |---- simple_ch_prep_sm
  57 *              |---- ch_prep_timeout
  58 *              |---- imp_def_interrupts
  59 *              |---- min_ch
  60 *              |---- max_ch
  61 *              |---- channels
  62 *              |---- ch_combinations
  63 *              |---- max_async_buffer
  64 *              |---- block_pack_mode
  65 *              |---- port_encoding
  66 *
  67 */
  68
  69#define sdw_slave_attr(field, format_string)                    \
  70static ssize_t field##_show(struct device *dev,                 \
  71                            struct device_attribute *attr,      \
  72                            char *buf)                          \
  73{                                                               \
  74        struct sdw_slave *slave = dev_to_sdw_dev(dev);          \
  75        return sprintf(buf, format_string, slave->prop.field);  \
  76}                                                               \
  77static DEVICE_ATTR_RO(field)
  78
  79sdw_slave_attr(mipi_revision, "0x%x\n");
  80sdw_slave_attr(wake_capable, "%d\n");
  81sdw_slave_attr(test_mode_capable, "%d\n");
  82sdw_slave_attr(clk_stop_mode1, "%d\n");
  83sdw_slave_attr(simple_clk_stop_capable, "%d\n");
  84sdw_slave_attr(clk_stop_timeout, "%d\n");
  85sdw_slave_attr(ch_prep_timeout, "%d\n");
  86sdw_slave_attr(reset_behave, "%d\n");
  87sdw_slave_attr(high_PHY_capable, "%d\n");
  88sdw_slave_attr(paging_support, "%d\n");
  89sdw_slave_attr(bank_delay_support, "%d\n");
  90sdw_slave_attr(p15_behave, "%d\n");
  91sdw_slave_attr(master_count, "%d\n");
  92sdw_slave_attr(source_ports, "0x%x\n");
  93sdw_slave_attr(sink_ports, "0x%x\n");
  94
  95static ssize_t modalias_show(struct device *dev,
  96                             struct device_attribute *attr, char *buf)
  97{
  98        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  99
 100        return sdw_slave_modalias(slave, buf, 256);
 101}
 102static DEVICE_ATTR_RO(modalias);
 103
 104static struct attribute *slave_attrs[] = {
 105        &dev_attr_modalias.attr,
 106        NULL,
 107};
 108ATTRIBUTE_GROUPS(slave);
 109
 110static struct attribute *slave_dev_attrs[] = {
 111        &dev_attr_mipi_revision.attr,
 112        &dev_attr_wake_capable.attr,
 113        &dev_attr_test_mode_capable.attr,
 114        &dev_attr_clk_stop_mode1.attr,
 115        &dev_attr_simple_clk_stop_capable.attr,
 116        &dev_attr_clk_stop_timeout.attr,
 117        &dev_attr_ch_prep_timeout.attr,
 118        &dev_attr_reset_behave.attr,
 119        &dev_attr_high_PHY_capable.attr,
 120        &dev_attr_paging_support.attr,
 121        &dev_attr_bank_delay_support.attr,
 122        &dev_attr_p15_behave.attr,
 123        &dev_attr_master_count.attr,
 124        &dev_attr_source_ports.attr,
 125        &dev_attr_sink_ports.attr,
 126        NULL,
 127};
 128
 129/*
 130 * we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory
 131 * for device-level properties
 132 */
 133static struct attribute_group sdw_slave_dev_attr_group = {
 134        .attrs  = slave_dev_attrs,
 135        .name = "dev-properties",
 136};
 137
 138/*
 139 * DP0 sysfs
 140 */
 141
 142#define sdw_dp0_attr(field, format_string)                              \
 143static ssize_t field##_show(struct device *dev,                         \
 144                            struct device_attribute *attr,              \
 145                            char *buf)                                  \
 146{                                                                       \
 147        struct sdw_slave *slave = dev_to_sdw_dev(dev);                  \
 148        return sprintf(buf, format_string, slave->prop.dp0_prop->field);\
 149}                                                                       \
 150static DEVICE_ATTR_RO(field)
 151
 152sdw_dp0_attr(max_word, "%d\n");
 153sdw_dp0_attr(min_word, "%d\n");
 154sdw_dp0_attr(BRA_flow_controlled, "%d\n");
 155sdw_dp0_attr(simple_ch_prep_sm, "%d\n");
 156sdw_dp0_attr(imp_def_interrupts, "0x%x\n");
 157
 158static ssize_t words_show(struct device *dev,
 159                          struct device_attribute *attr, char *buf)
 160{
 161        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 162        ssize_t size = 0;
 163        int i;
 164
 165        for (i = 0; i < slave->prop.dp0_prop->num_words; i++)
 166                size += sprintf(buf + size, "%d ",
 167                                slave->prop.dp0_prop->words[i]);
 168        size += sprintf(buf + size, "\n");
 169
 170        return size;
 171}
 172static DEVICE_ATTR_RO(words);
 173
 174static struct attribute *dp0_attrs[] = {
 175        &dev_attr_max_word.attr,
 176        &dev_attr_min_word.attr,
 177        &dev_attr_words.attr,
 178        &dev_attr_BRA_flow_controlled.attr,
 179        &dev_attr_simple_ch_prep_sm.attr,
 180        &dev_attr_imp_def_interrupts.attr,
 181        NULL,
 182};
 183
 184/*
 185 * we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory
 186 * for dp0-level properties
 187 */
 188static const struct attribute_group dp0_group = {
 189        .attrs = dp0_attrs,
 190        .name = "dp0",
 191};
 192
 193int sdw_slave_sysfs_init(struct sdw_slave *slave)
 194{
 195        int ret;
 196
 197        ret = devm_device_add_groups(&slave->dev, slave_groups);
 198        if (ret < 0)
 199                return ret;
 200
 201        ret = devm_device_add_group(&slave->dev, &sdw_slave_dev_attr_group);
 202        if (ret < 0)
 203                return ret;
 204
 205        if (slave->prop.dp0_prop) {
 206                ret = devm_device_add_group(&slave->dev, &dp0_group);
 207                if (ret < 0)
 208                        return ret;
 209        }
 210
 211        if (slave->prop.source_ports || slave->prop.sink_ports) {
 212                ret = sdw_slave_sysfs_dpn_init(slave);
 213                if (ret < 0)
 214                        return ret;
 215        }
 216
 217        return 0;
 218}
 219
 220/*
 221 * the status is shown in capital letters for UNATTACHED and RESERVED
 222 * on purpose, to highligh users to the fact that these status values
 223 * are not expected.
 224 */
 225static const char *const slave_status[] = {
 226        [SDW_SLAVE_UNATTACHED] =  "UNATTACHED",
 227        [SDW_SLAVE_ATTACHED] = "Attached",
 228        [SDW_SLAVE_ALERT] = "Alert",
 229        [SDW_SLAVE_RESERVED] = "RESERVED",
 230};
 231
 232static ssize_t status_show(struct device *dev,
 233                           struct device_attribute *attr, char *buf)
 234{
 235        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 236
 237        return sprintf(buf, "%s\n", slave_status[slave->status]);
 238}
 239static DEVICE_ATTR_RO(status);
 240
 241static ssize_t device_number_show(struct device *dev,
 242                                  struct device_attribute *attr, char *buf)
 243{
 244        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 245
 246        if (slave->status == SDW_SLAVE_UNATTACHED)
 247                return sprintf(buf, "%s", "N/A");
 248        else
 249                return sprintf(buf, "%d", slave->dev_num);
 250}
 251static DEVICE_ATTR_RO(device_number);
 252
 253static struct attribute *slave_status_attrs[] = {
 254        &dev_attr_status.attr,
 255        &dev_attr_device_number.attr,
 256        NULL,
 257};
 258
 259/*
 260 * we don't use ATTRIBUTES_GROUP here since the group is used in a
 261 * separate file and can't be handled as a static.
 262 */
 263static const struct attribute_group sdw_slave_status_attr_group = {
 264        .attrs  = slave_status_attrs,
 265};
 266
 267const struct attribute_group *sdw_slave_status_attr_groups[] = {
 268        &sdw_slave_status_attr_group,
 269        NULL
 270};
 271