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 *
  21 * Base file is device
  22 *      |---- modalias
  23 *      |---- dev-properties
  24 *              |---- mipi_revision
  25 *              |---- wake_capable
  26 *              |---- test_mode_capable
  27 *              |---- clk_stop_mode1
  28 *              |---- simple_clk_stop_capable
  29 *              |---- clk_stop_timeout
  30 *              |---- ch_prep_timeout
  31 *              |---- reset_behave
  32 *              |---- high_PHY_capable
  33 *              |---- paging_support
  34 *              |---- bank_delay_support
  35 *              |---- p15_behave
  36 *              |---- master_count
  37 *              |---- source_ports
  38 *              |---- sink_ports
  39 *      |---- dp0
  40 *              |---- max_word
  41 *              |---- min_word
  42 *              |---- words
  43 *              |---- BRA_flow_controlled
  44 *              |---- simple_ch_prep_sm
  45 *              |---- imp_def_interrupts
  46 *      |---- dpN_<sink/src>
  47 *              |---- max_word
  48 *              |---- min_word
  49 *              |---- words
  50 *              |---- type
  51 *              |---- max_grouping
  52 *              |---- simple_ch_prep_sm
  53 *              |---- ch_prep_timeout
  54 *              |---- imp_def_interrupts
  55 *              |---- min_ch
  56 *              |---- max_ch
  57 *              |---- channels
  58 *              |---- ch_combinations
  59 *              |---- max_async_buffer
  60 *              |---- block_pack_mode
  61 *              |---- port_encoding
  62 *
  63 */
  64
  65#define sdw_slave_attr(field, format_string)                    \
  66static ssize_t field##_show(struct device *dev,                 \
  67                            struct device_attribute *attr,      \
  68                            char *buf)                          \
  69{                                                               \
  70        struct sdw_slave *slave = dev_to_sdw_dev(dev);          \
  71        return sprintf(buf, format_string, slave->prop.field);  \
  72}                                                               \
  73static DEVICE_ATTR_RO(field)
  74
  75sdw_slave_attr(mipi_revision, "0x%x\n");
  76sdw_slave_attr(wake_capable, "%d\n");
  77sdw_slave_attr(test_mode_capable, "%d\n");
  78sdw_slave_attr(clk_stop_mode1, "%d\n");
  79sdw_slave_attr(simple_clk_stop_capable, "%d\n");
  80sdw_slave_attr(clk_stop_timeout, "%d\n");
  81sdw_slave_attr(ch_prep_timeout, "%d\n");
  82sdw_slave_attr(reset_behave, "%d\n");
  83sdw_slave_attr(high_PHY_capable, "%d\n");
  84sdw_slave_attr(paging_support, "%d\n");
  85sdw_slave_attr(bank_delay_support, "%d\n");
  86sdw_slave_attr(p15_behave, "%d\n");
  87sdw_slave_attr(master_count, "%d\n");
  88sdw_slave_attr(source_ports, "0x%x\n");
  89sdw_slave_attr(sink_ports, "0x%x\n");
  90
  91static ssize_t modalias_show(struct device *dev,
  92                             struct device_attribute *attr, char *buf)
  93{
  94        struct sdw_slave *slave = dev_to_sdw_dev(dev);
  95
  96        return sdw_slave_modalias(slave, buf, 256);
  97}
  98static DEVICE_ATTR_RO(modalias);
  99
 100static struct attribute *slave_attrs[] = {
 101        &dev_attr_modalias.attr,
 102        NULL,
 103};
 104ATTRIBUTE_GROUPS(slave);
 105
 106static struct attribute *slave_dev_attrs[] = {
 107        &dev_attr_mipi_revision.attr,
 108        &dev_attr_wake_capable.attr,
 109        &dev_attr_test_mode_capable.attr,
 110        &dev_attr_clk_stop_mode1.attr,
 111        &dev_attr_simple_clk_stop_capable.attr,
 112        &dev_attr_clk_stop_timeout.attr,
 113        &dev_attr_ch_prep_timeout.attr,
 114        &dev_attr_reset_behave.attr,
 115        &dev_attr_high_PHY_capable.attr,
 116        &dev_attr_paging_support.attr,
 117        &dev_attr_bank_delay_support.attr,
 118        &dev_attr_p15_behave.attr,
 119        &dev_attr_master_count.attr,
 120        &dev_attr_source_ports.attr,
 121        &dev_attr_sink_ports.attr,
 122        NULL,
 123};
 124
 125/*
 126 * we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory
 127 * for device-level properties
 128 */
 129static struct attribute_group sdw_slave_dev_attr_group = {
 130        .attrs  = slave_dev_attrs,
 131        .name = "dev-properties",
 132};
 133
 134/*
 135 * DP0 sysfs
 136 */
 137
 138#define sdw_dp0_attr(field, format_string)                              \
 139static ssize_t field##_show(struct device *dev,                         \
 140                            struct device_attribute *attr,              \
 141                            char *buf)                                  \
 142{                                                                       \
 143        struct sdw_slave *slave = dev_to_sdw_dev(dev);                  \
 144        return sprintf(buf, format_string, slave->prop.dp0_prop->field);\
 145}                                                                       \
 146static DEVICE_ATTR_RO(field)
 147
 148sdw_dp0_attr(max_word, "%d\n");
 149sdw_dp0_attr(min_word, "%d\n");
 150sdw_dp0_attr(BRA_flow_controlled, "%d\n");
 151sdw_dp0_attr(simple_ch_prep_sm, "%d\n");
 152sdw_dp0_attr(imp_def_interrupts, "0x%x\n");
 153
 154static ssize_t words_show(struct device *dev,
 155                          struct device_attribute *attr, char *buf)
 156{
 157        struct sdw_slave *slave = dev_to_sdw_dev(dev);
 158        ssize_t size = 0;
 159        int i;
 160
 161        for (i = 0; i < slave->prop.dp0_prop->num_words; i++)
 162                size += sprintf(buf + size, "%d ",
 163                                slave->prop.dp0_prop->words[i]);
 164        size += sprintf(buf + size, "\n");
 165
 166        return size;
 167}
 168static DEVICE_ATTR_RO(words);
 169
 170static struct attribute *dp0_attrs[] = {
 171        &dev_attr_max_word.attr,
 172        &dev_attr_min_word.attr,
 173        &dev_attr_words.attr,
 174        &dev_attr_BRA_flow_controlled.attr,
 175        &dev_attr_simple_ch_prep_sm.attr,
 176        &dev_attr_imp_def_interrupts.attr,
 177        NULL,
 178};
 179
 180/*
 181 * we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory
 182 * for dp0-level properties
 183 */
 184static const struct attribute_group dp0_group = {
 185        .attrs = dp0_attrs,
 186        .name = "dp0",
 187};
 188
 189int sdw_slave_sysfs_init(struct sdw_slave *slave)
 190{
 191        int ret;
 192
 193        ret = devm_device_add_groups(&slave->dev, slave_groups);
 194        if (ret < 0)
 195                return ret;
 196
 197        ret = devm_device_add_group(&slave->dev, &sdw_slave_dev_attr_group);
 198        if (ret < 0)
 199                return ret;
 200
 201        if (slave->prop.dp0_prop) {
 202                ret = devm_device_add_group(&slave->dev, &dp0_group);
 203                if (ret < 0)
 204                        return ret;
 205        }
 206
 207        if (slave->prop.source_ports || slave->prop.sink_ports) {
 208                ret = sdw_slave_sysfs_dpn_init(slave);
 209                if (ret < 0)
 210                        return ret;
 211        }
 212
 213        return 0;
 214}
 215