2019-05-02 10:59:18 +00:00
|
|
|
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
|
|
|
|
/* Copyright(c) 2015-17 Intel Corporation. */
|
2017-12-14 05:49:33 +00:00
|
|
|
|
|
|
|
#ifndef __SOUNDWIRE_H
|
|
|
|
#define __SOUNDWIRE_H
|
|
|
|
|
2019-08-06 00:55:12 +00:00
|
|
|
#include <linux/mod_devicetable.h>
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
struct sdw_bus;
|
|
|
|
struct sdw_slave;
|
|
|
|
|
2017-12-14 05:49:34 +00:00
|
|
|
/* SDW spec defines and enums, as defined by MIPI 1.1. Spec */
|
|
|
|
|
|
|
|
/* SDW Broadcast Device Number */
|
|
|
|
#define SDW_BROADCAST_DEV_NUM 15
|
|
|
|
|
|
|
|
/* SDW Enumeration Device Number */
|
|
|
|
#define SDW_ENUM_DEV_NUM 0
|
|
|
|
|
|
|
|
/* SDW Group Device Numbers */
|
|
|
|
#define SDW_GROUP12_DEV_NUM 12
|
|
|
|
#define SDW_GROUP13_DEV_NUM 13
|
|
|
|
|
|
|
|
/* SDW Master Device Number, not supported yet */
|
|
|
|
#define SDW_MASTER_DEV_NUM 14
|
|
|
|
|
2017-12-14 05:49:39 +00:00
|
|
|
#define SDW_NUM_DEV_ID_REGISTERS 6
|
2018-04-26 13:08:28 +00:00
|
|
|
/* frame shape defines */
|
2017-12-14 05:49:39 +00:00
|
|
|
|
2018-04-26 13:08:28 +00:00
|
|
|
/*
|
|
|
|
* Note: The maximum row define in SoundWire spec 1.1 is 23. In order to
|
|
|
|
* fill hole with 0, one more dummy entry is added
|
|
|
|
*/
|
|
|
|
#define SDW_FRAME_ROWS 24
|
|
|
|
#define SDW_FRAME_COLS 8
|
|
|
|
#define SDW_FRAME_ROW_COLS (SDW_FRAME_ROWS * SDW_FRAME_COLS)
|
|
|
|
|
|
|
|
#define SDW_FRAME_CTRL_BITS 48
|
2017-12-14 05:49:33 +00:00
|
|
|
#define SDW_MAX_DEVICES 11
|
|
|
|
|
2019-05-02 10:59:28 +00:00
|
|
|
#define SDW_VALID_PORT_RANGE(n) ((n) <= 14 && (n) >= 1)
|
2018-04-26 13:08:13 +00:00
|
|
|
|
2019-05-22 19:47:19 +00:00
|
|
|
enum {
|
|
|
|
SDW_PORT_DIRN_SINK = 0,
|
|
|
|
SDW_PORT_DIRN_SOURCE,
|
|
|
|
SDW_PORT_DIRN_MAX,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* constants for flow control, ports and transport
|
|
|
|
*
|
|
|
|
* these are bit masks as devices can have multiple capabilities
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* flow modes for SDW port. These can be isochronous, tx controlled,
|
|
|
|
* rx controlled or async
|
|
|
|
*/
|
|
|
|
#define SDW_PORT_FLOW_MODE_ISOCH 0
|
|
|
|
#define SDW_PORT_FLOW_MODE_TX_CNTRL BIT(0)
|
|
|
|
#define SDW_PORT_FLOW_MODE_RX_CNTRL BIT(1)
|
|
|
|
#define SDW_PORT_FLOW_MODE_ASYNC GENMASK(1, 0)
|
|
|
|
|
|
|
|
/* sample packaging for block. It can be per port or per channel */
|
|
|
|
#define SDW_BLOCK_PACKG_PER_PORT BIT(0)
|
|
|
|
#define SDW_BLOCK_PACKG_PER_CH BIT(1)
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
/**
|
|
|
|
* enum sdw_slave_status - Slave status
|
|
|
|
* @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus.
|
|
|
|
* @SDW_SLAVE_ATTACHED: Slave is attached with bus.
|
|
|
|
* @SDW_SLAVE_ALERT: Some alert condition on the Slave
|
|
|
|
* @SDW_SLAVE_RESERVED: Reserved for future use
|
|
|
|
*/
|
|
|
|
enum sdw_slave_status {
|
|
|
|
SDW_SLAVE_UNATTACHED = 0,
|
|
|
|
SDW_SLAVE_ATTACHED = 1,
|
|
|
|
SDW_SLAVE_ALERT = 2,
|
|
|
|
SDW_SLAVE_RESERVED = 3,
|
|
|
|
};
|
|
|
|
|
2020-01-15 00:08:43 +00:00
|
|
|
/**
|
|
|
|
* enum sdw_clk_stop_type: clock stop operations
|
|
|
|
*
|
|
|
|
* @SDW_CLK_PRE_PREPARE: pre clock stop prepare
|
|
|
|
* @SDW_CLK_POST_PREPARE: post clock stop prepare
|
|
|
|
* @SDW_CLK_PRE_DEPREPARE: pre clock stop de-prepare
|
|
|
|
* @SDW_CLK_POST_DEPREPARE: post clock stop de-prepare
|
|
|
|
*/
|
|
|
|
enum sdw_clk_stop_type {
|
2020-07-14 21:37:44 +00:00
|
|
|
SDW_CLK_PRE_PREPARE = 0,
|
|
|
|
SDW_CLK_POST_PREPARE,
|
|
|
|
SDW_CLK_PRE_DEPREPARE,
|
|
|
|
SDW_CLK_POST_DEPREPARE,
|
2020-01-15 00:08:43 +00:00
|
|
|
};
|
|
|
|
|
2017-12-14 05:49:37 +00:00
|
|
|
/**
|
|
|
|
* enum sdw_command_response - Command response as defined by SDW spec
|
|
|
|
* @SDW_CMD_OK: cmd was successful
|
|
|
|
* @SDW_CMD_IGNORED: cmd was ignored
|
|
|
|
* @SDW_CMD_FAIL: cmd was NACKed
|
|
|
|
* @SDW_CMD_TIMEOUT: cmd timedout
|
|
|
|
* @SDW_CMD_FAIL_OTHER: cmd failed due to other reason than above
|
|
|
|
*
|
|
|
|
* NOTE: The enum is different than actual Spec as response in the Spec is
|
|
|
|
* combination of ACK/NAK bits
|
|
|
|
*
|
|
|
|
* SDW_CMD_TIMEOUT/FAIL_OTHER is defined for SW use, not in spec
|
|
|
|
*/
|
|
|
|
enum sdw_command_response {
|
|
|
|
SDW_CMD_OK = 0,
|
|
|
|
SDW_CMD_IGNORED = 1,
|
|
|
|
SDW_CMD_FAIL = 2,
|
|
|
|
SDW_CMD_TIMEOUT = 3,
|
|
|
|
SDW_CMD_FAIL_OTHER = 4,
|
|
|
|
};
|
|
|
|
|
2019-05-22 19:47:19 +00:00
|
|
|
/* block group count enum */
|
|
|
|
enum sdw_dpn_grouping {
|
|
|
|
SDW_BLK_GRP_CNT_1 = 0,
|
|
|
|
SDW_BLK_GRP_CNT_2 = 1,
|
|
|
|
SDW_BLK_GRP_CNT_3 = 2,
|
|
|
|
SDW_BLK_GRP_CNT_4 = 3,
|
|
|
|
};
|
|
|
|
|
2018-04-26 13:08:08 +00:00
|
|
|
/**
|
|
|
|
* enum sdw_stream_type: data stream type
|
|
|
|
*
|
|
|
|
* @SDW_STREAM_PCM: PCM data stream
|
|
|
|
* @SDW_STREAM_PDM: PDM data stream
|
|
|
|
*
|
|
|
|
* spec doesn't define this, but is used in implementation
|
|
|
|
*/
|
|
|
|
enum sdw_stream_type {
|
|
|
|
SDW_STREAM_PCM = 0,
|
|
|
|
SDW_STREAM_PDM = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* enum sdw_data_direction: Data direction
|
|
|
|
*
|
|
|
|
* @SDW_DATA_DIR_RX: Data into Port
|
|
|
|
* @SDW_DATA_DIR_TX: Data out of Port
|
|
|
|
*/
|
|
|
|
enum sdw_data_direction {
|
|
|
|
SDW_DATA_DIR_RX = 0,
|
|
|
|
SDW_DATA_DIR_TX = 1,
|
|
|
|
};
|
|
|
|
|
2019-05-22 19:47:19 +00:00
|
|
|
/**
|
|
|
|
* enum sdw_port_data_mode: Data Port mode
|
|
|
|
*
|
|
|
|
* @SDW_PORT_DATA_MODE_NORMAL: Normal data mode where audio data is received
|
|
|
|
* and transmitted.
|
2020-07-14 21:37:43 +00:00
|
|
|
* @SDW_PORT_DATA_MODE_PRBS: Test mode which uses a PRBS generator to produce
|
|
|
|
* a pseudo random data pattern that is transferred
|
|
|
|
* @SDW_PORT_DATA_MODE_STATIC_0: Simple test mode which uses static value of
|
|
|
|
* logic 0. The encoding will result in no signal transitions
|
2019-05-22 19:47:19 +00:00
|
|
|
* @SDW_PORT_DATA_MODE_STATIC_1: Simple test mode which uses static value of
|
|
|
|
* logic 1. The encoding will result in signal transitions at every bitslot
|
|
|
|
* owned by this Port
|
|
|
|
*/
|
|
|
|
enum sdw_port_data_mode {
|
|
|
|
SDW_PORT_DATA_MODE_NORMAL = 0,
|
2020-07-14 21:37:43 +00:00
|
|
|
SDW_PORT_DATA_MODE_PRBS = 1,
|
2019-05-22 19:47:19 +00:00
|
|
|
SDW_PORT_DATA_MODE_STATIC_0 = 2,
|
2020-07-14 21:37:43 +00:00
|
|
|
SDW_PORT_DATA_MODE_STATIC_1 = 3,
|
2019-05-22 19:47:19 +00:00
|
|
|
};
|
|
|
|
|
2017-12-14 05:49:35 +00:00
|
|
|
/*
|
|
|
|
* SDW properties, defined in MIPI DisCo spec v1.0
|
|
|
|
*/
|
|
|
|
enum sdw_clk_stop_reset_behave {
|
|
|
|
SDW_CLK_STOP_KEEP_STATUS = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* enum sdw_p15_behave - Slave Port 15 behaviour when the Master attempts a
|
|
|
|
* read
|
|
|
|
* @SDW_P15_READ_IGNORED: Read is ignored
|
|
|
|
* @SDW_P15_CMD_OK: Command is ok
|
|
|
|
*/
|
|
|
|
enum sdw_p15_behave {
|
|
|
|
SDW_P15_READ_IGNORED = 0,
|
|
|
|
SDW_P15_CMD_OK = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* enum sdw_dpn_type - Data port types
|
|
|
|
* @SDW_DPN_FULL: Full Data Port is supported
|
|
|
|
* @SDW_DPN_SIMPLE: Simplified Data Port as defined in spec.
|
|
|
|
* DPN_SampleCtrl2, DPN_OffsetCtrl2, DPN_HCtrl and DPN_BlockCtrl3
|
|
|
|
* are not implemented.
|
|
|
|
* @SDW_DPN_REDUCED: Reduced Data Port as defined in spec.
|
|
|
|
* DPN_SampleCtrl2, DPN_HCtrl are not implemented.
|
|
|
|
*/
|
|
|
|
enum sdw_dpn_type {
|
|
|
|
SDW_DPN_FULL = 0,
|
|
|
|
SDW_DPN_SIMPLE = 1,
|
|
|
|
SDW_DPN_REDUCED = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* enum sdw_clk_stop_mode - Clock Stop modes
|
|
|
|
* @SDW_CLK_STOP_MODE0: Slave can continue operation seamlessly on clock
|
|
|
|
* restart
|
|
|
|
* @SDW_CLK_STOP_MODE1: Slave may have entered a deeper power-saving mode,
|
|
|
|
* not capable of continuing operation seamlessly when the clock restarts
|
|
|
|
*/
|
|
|
|
enum sdw_clk_stop_mode {
|
|
|
|
SDW_CLK_STOP_MODE0 = 0,
|
|
|
|
SDW_CLK_STOP_MODE1 = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_dp0_prop - DP0 properties
|
|
|
|
* @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64
|
|
|
|
* (inclusive)
|
|
|
|
* @min_word: Minimum number of bits in a Payload Channel Sample, 1 to 64
|
|
|
|
* (inclusive)
|
|
|
|
* @num_words: number of wordlengths supported
|
|
|
|
* @words: wordlengths supported
|
2019-05-22 19:47:25 +00:00
|
|
|
* @BRA_flow_controlled: Slave implementation results in an OK_NotReady
|
2017-12-14 05:49:35 +00:00
|
|
|
* response
|
|
|
|
* @simple_ch_prep_sm: If channel prepare sequence is required
|
2019-05-22 19:47:25 +00:00
|
|
|
* @imp_def_interrupts: If set, each bit corresponds to support for
|
|
|
|
* implementation-defined interrupts
|
2017-12-14 05:49:35 +00:00
|
|
|
*
|
|
|
|
* The wordlengths are specified by Spec as max, min AND number of
|
|
|
|
* discrete values, implementation can define based on the wordlengths they
|
|
|
|
* support
|
|
|
|
*/
|
|
|
|
struct sdw_dp0_prop {
|
|
|
|
u32 max_word;
|
|
|
|
u32 min_word;
|
|
|
|
u32 num_words;
|
|
|
|
u32 *words;
|
2019-05-22 19:47:25 +00:00
|
|
|
bool BRA_flow_controlled;
|
2017-12-14 05:49:35 +00:00
|
|
|
bool simple_ch_prep_sm;
|
2019-05-22 19:47:25 +00:00
|
|
|
bool imp_def_interrupts;
|
2017-12-14 05:49:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_dpn_audio_mode - Audio mode properties for DPn
|
|
|
|
* @bus_min_freq: Minimum bus frequency, in Hz
|
|
|
|
* @bus_max_freq: Maximum bus frequency, in Hz
|
|
|
|
* @bus_num_freq: Number of discrete frequencies supported
|
|
|
|
* @bus_freq: Discrete bus frequencies, in Hz
|
|
|
|
* @min_freq: Minimum sampling frequency, in Hz
|
|
|
|
* @max_freq: Maximum sampling bus frequency, in Hz
|
|
|
|
* @num_freq: Number of discrete sampling frequency supported
|
|
|
|
* @freq: Discrete sampling frequencies, in Hz
|
|
|
|
* @prep_ch_behave: Specifies the dependencies between Channel Prepare
|
|
|
|
* sequence and bus clock configuration
|
|
|
|
* If 0, Channel Prepare can happen at any Bus clock rate
|
|
|
|
* If 1, Channel Prepare sequence shall happen only after Bus clock is
|
|
|
|
* changed to a frequency supported by this mode or compatible modes
|
|
|
|
* described by the next field
|
|
|
|
* @glitchless: Bitmap describing possible glitchless transitions from this
|
|
|
|
* Audio Mode to other Audio Modes
|
|
|
|
*/
|
|
|
|
struct sdw_dpn_audio_mode {
|
|
|
|
u32 bus_min_freq;
|
|
|
|
u32 bus_max_freq;
|
|
|
|
u32 bus_num_freq;
|
|
|
|
u32 *bus_freq;
|
|
|
|
u32 max_freq;
|
|
|
|
u32 min_freq;
|
|
|
|
u32 num_freq;
|
|
|
|
u32 *freq;
|
|
|
|
u32 prep_ch_behave;
|
|
|
|
u32 glitchless;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_dpn_prop - Data Port DPn properties
|
|
|
|
* @num: port number
|
|
|
|
* @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64
|
|
|
|
* (inclusive)
|
|
|
|
* @min_word: Minimum number of bits in a Payload Channel Sample, 1 to 64
|
|
|
|
* (inclusive)
|
|
|
|
* @num_words: Number of discrete supported wordlengths
|
|
|
|
* @words: Discrete supported wordlength
|
|
|
|
* @type: Data port type. Full, Simplified or Reduced
|
|
|
|
* @max_grouping: Maximum number of samples that can be grouped together for
|
|
|
|
* a full data port
|
|
|
|
* @simple_ch_prep_sm: If the port supports simplified channel prepare state
|
|
|
|
* machine
|
|
|
|
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
|
2019-05-22 19:47:25 +00:00
|
|
|
* @imp_def_interrupts: If set, each bit corresponds to support for
|
2017-12-14 05:49:35 +00:00
|
|
|
* implementation-defined interrupts
|
|
|
|
* @max_ch: Maximum channels supported
|
|
|
|
* @min_ch: Minimum channels supported
|
2020-05-18 20:35:49 +00:00
|
|
|
* @num_channels: Number of discrete channels supported
|
|
|
|
* @channels: Discrete channels supported
|
2017-12-14 05:49:35 +00:00
|
|
|
* @num_ch_combinations: Number of channel combinations supported
|
|
|
|
* @ch_combinations: Channel combinations supported
|
|
|
|
* @modes: SDW mode supported
|
|
|
|
* @max_async_buffer: Number of samples that this port can buffer in
|
|
|
|
* asynchronous modes
|
|
|
|
* @block_pack_mode: Type of block port mode supported
|
2020-03-11 11:35:44 +00:00
|
|
|
* @read_only_wordlength: Read Only wordlength field in DPN_BlockCtrl1 register
|
2017-12-14 05:49:35 +00:00
|
|
|
* @port_encoding: Payload Channel Sample encoding schemes supported
|
|
|
|
* @audio_modes: Audio modes supported
|
|
|
|
*/
|
|
|
|
struct sdw_dpn_prop {
|
|
|
|
u32 num;
|
|
|
|
u32 max_word;
|
|
|
|
u32 min_word;
|
|
|
|
u32 num_words;
|
|
|
|
u32 *words;
|
|
|
|
enum sdw_dpn_type type;
|
|
|
|
u32 max_grouping;
|
|
|
|
bool simple_ch_prep_sm;
|
|
|
|
u32 ch_prep_timeout;
|
2019-05-22 19:47:25 +00:00
|
|
|
u32 imp_def_interrupts;
|
2017-12-14 05:49:35 +00:00
|
|
|
u32 max_ch;
|
|
|
|
u32 min_ch;
|
2020-05-18 20:35:49 +00:00
|
|
|
u32 num_channels;
|
|
|
|
u32 *channels;
|
2017-12-14 05:49:35 +00:00
|
|
|
u32 num_ch_combinations;
|
|
|
|
u32 *ch_combinations;
|
|
|
|
u32 modes;
|
|
|
|
u32 max_async_buffer;
|
|
|
|
bool block_pack_mode;
|
2020-03-11 11:35:44 +00:00
|
|
|
bool read_only_wordlength;
|
2017-12-14 05:49:35 +00:00
|
|
|
u32 port_encoding;
|
|
|
|
struct sdw_dpn_audio_mode *audio_modes;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_slave_prop - SoundWire Slave properties
|
|
|
|
* @mipi_revision: Spec version of the implementation
|
|
|
|
* @wake_capable: Wake-up events are supported
|
|
|
|
* @test_mode_capable: If test mode is supported
|
|
|
|
* @clk_stop_mode1: Clock-Stop Mode 1 is supported
|
|
|
|
* @simple_clk_stop_capable: Simple clock mode is supported
|
|
|
|
* @clk_stop_timeout: Worst-case latency of the Clock Stop Prepare State
|
|
|
|
* Machine transitions, in milliseconds
|
|
|
|
* @ch_prep_timeout: Worst-case latency of the Channel Prepare State Machine
|
|
|
|
* transitions, in milliseconds
|
|
|
|
* @reset_behave: Slave keeps the status of the SlaveStopClockPrepare
|
|
|
|
* state machine (P=1 SCSP_SM) after exit from clock-stop mode1
|
|
|
|
* @high_PHY_capable: Slave is HighPHY capable
|
|
|
|
* @paging_support: Slave implements paging registers SCP_AddrPage1 and
|
|
|
|
* SCP_AddrPage2
|
|
|
|
* @bank_delay_support: Slave implements bank delay/bridge support registers
|
|
|
|
* SCP_BankDelay and SCP_NextFrame
|
|
|
|
* @p15_behave: Slave behavior when the Master attempts a read to the Port15
|
|
|
|
* alias
|
|
|
|
* @lane_control_support: Slave supports lane control
|
|
|
|
* @master_count: Number of Masters present on this Slave
|
|
|
|
* @source_ports: Bitmap identifying source ports
|
|
|
|
* @sink_ports: Bitmap identifying sink ports
|
|
|
|
* @dp0_prop: Data Port 0 properties
|
|
|
|
* @src_dpn_prop: Source Data Port N properties
|
|
|
|
* @sink_dpn_prop: Sink Data Port N properties
|
|
|
|
*/
|
|
|
|
struct sdw_slave_prop {
|
|
|
|
u32 mipi_revision;
|
|
|
|
bool wake_capable;
|
|
|
|
bool test_mode_capable;
|
|
|
|
bool clk_stop_mode1;
|
|
|
|
bool simple_clk_stop_capable;
|
|
|
|
u32 clk_stop_timeout;
|
|
|
|
u32 ch_prep_timeout;
|
|
|
|
enum sdw_clk_stop_reset_behave reset_behave;
|
|
|
|
bool high_PHY_capable;
|
|
|
|
bool paging_support;
|
|
|
|
bool bank_delay_support;
|
|
|
|
enum sdw_p15_behave p15_behave;
|
|
|
|
bool lane_control_support;
|
|
|
|
u32 master_count;
|
|
|
|
u32 source_ports;
|
|
|
|
u32 sink_ports;
|
|
|
|
struct sdw_dp0_prop *dp0_prop;
|
|
|
|
struct sdw_dpn_prop *src_dpn_prop;
|
|
|
|
struct sdw_dpn_prop *sink_dpn_prop;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_master_prop - Master properties
|
|
|
|
* @revision: MIPI spec version of the implementation
|
2019-05-22 19:47:23 +00:00
|
|
|
* @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported
|
2019-05-22 19:47:22 +00:00
|
|
|
* @max_clk_freq: Maximum Bus clock frequency, in Hz
|
2017-12-14 05:49:35 +00:00
|
|
|
* @num_clk_gears: Number of clock gears supported
|
|
|
|
* @clk_gears: Clock gears supported
|
2019-05-22 19:47:22 +00:00
|
|
|
* @num_clk_freq: Number of clock frequencies supported, in Hz
|
|
|
|
* @clk_freq: Clock frequencies supported, in Hz
|
2017-12-14 05:49:35 +00:00
|
|
|
* @default_frame_rate: Controller default Frame rate, in Hz
|
|
|
|
* @default_row: Number of rows
|
|
|
|
* @default_col: Number of columns
|
2019-05-22 19:47:24 +00:00
|
|
|
* @dynamic_frame: Dynamic frame shape supported
|
2017-12-14 05:49:35 +00:00
|
|
|
* @err_threshold: Number of times that software may retry sending a single
|
|
|
|
* command
|
2019-08-06 00:55:15 +00:00
|
|
|
* @mclk_freq: clock reference passed to SoundWire Master, in Hz.
|
2019-08-21 18:58:21 +00:00
|
|
|
* @hw_disabled: if true, the Master is not functional, typically due to pin-mux
|
2017-12-14 05:49:35 +00:00
|
|
|
*/
|
|
|
|
struct sdw_master_prop {
|
|
|
|
u32 revision;
|
2019-05-22 19:47:23 +00:00
|
|
|
u32 clk_stop_modes;
|
2019-05-22 19:47:22 +00:00
|
|
|
u32 max_clk_freq;
|
2017-12-14 05:49:35 +00:00
|
|
|
u32 num_clk_gears;
|
|
|
|
u32 *clk_gears;
|
2019-05-22 19:47:22 +00:00
|
|
|
u32 num_clk_freq;
|
|
|
|
u32 *clk_freq;
|
2017-12-14 05:49:35 +00:00
|
|
|
u32 default_frame_rate;
|
|
|
|
u32 default_row;
|
|
|
|
u32 default_col;
|
|
|
|
bool dynamic_frame;
|
|
|
|
u32 err_threshold;
|
2019-08-06 00:55:15 +00:00
|
|
|
u32 mclk_freq;
|
2019-08-21 18:58:21 +00:00
|
|
|
bool hw_disabled;
|
2017-12-14 05:49:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int sdw_master_read_prop(struct sdw_bus *bus);
|
|
|
|
int sdw_slave_read_prop(struct sdw_slave *slave);
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
/*
|
|
|
|
* SDW Slave Structures and APIs
|
|
|
|
*/
|
|
|
|
|
2019-10-22 23:48:06 +00:00
|
|
|
#define SDW_IGNORED_UNIQUE_ID 0xFF
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_slave_id - Slave ID
|
|
|
|
* @mfg_id: MIPI Manufacturer ID
|
|
|
|
* @part_id: Device Part ID
|
2020-06-08 20:54:35 +00:00
|
|
|
* @class_id: MIPI Class ID (defined starting with SoundWire 1.2 spec)
|
2017-12-14 05:49:33 +00:00
|
|
|
* @unique_id: Device unique ID
|
|
|
|
* @sdw_version: SDW version implemented
|
|
|
|
*
|
|
|
|
* The order of the IDs here does not follow the DisCo spec definitions
|
|
|
|
*/
|
|
|
|
struct sdw_slave_id {
|
|
|
|
__u16 mfg_id;
|
|
|
|
__u16 part_id;
|
|
|
|
__u8 class_id;
|
2019-10-22 23:48:06 +00:00
|
|
|
__u8 unique_id;
|
2017-12-14 05:49:33 +00:00
|
|
|
__u8 sdw_version:4;
|
|
|
|
};
|
|
|
|
|
2020-02-25 17:00:41 +00:00
|
|
|
/*
|
|
|
|
* Helper macros to extract the MIPI-defined IDs
|
|
|
|
*
|
|
|
|
* Spec definition
|
|
|
|
* Register Bit Contents
|
|
|
|
* DevId_0 [7:4] 47:44 sdw_version
|
|
|
|
* DevId_0 [3:0] 43:40 unique_id
|
|
|
|
* DevId_1 39:32 mfg_id [15:8]
|
|
|
|
* DevId_2 31:24 mfg_id [7:0]
|
|
|
|
* DevId_3 23:16 part_id [15:8]
|
|
|
|
* DevId_4 15:08 part_id [7:0]
|
|
|
|
* DevId_5 07:00 class_id
|
|
|
|
*
|
|
|
|
* The MIPI DisCo for SoundWire defines in addition the link_id as bits 51:48
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define SDW_DISCO_LINK_ID(adr) (((adr) >> 48) & GENMASK(3, 0))
|
|
|
|
#define SDW_VERSION(adr) (((adr) >> 44) & GENMASK(3, 0))
|
|
|
|
#define SDW_UNIQUE_ID(adr) (((adr) >> 40) & GENMASK(3, 0))
|
|
|
|
#define SDW_MFG_ID(adr) (((adr) >> 24) & GENMASK(15, 0))
|
|
|
|
#define SDW_PART_ID(adr) (((adr) >> 8) & GENMASK(15, 0))
|
|
|
|
#define SDW_CLASS_ID(adr) ((adr) & GENMASK(7, 0))
|
|
|
|
|
2017-12-14 05:49:40 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_slave_intr_status - Slave interrupt status
|
|
|
|
* @control_port: control port status
|
|
|
|
* @port: data port status
|
|
|
|
*/
|
|
|
|
struct sdw_slave_intr_status {
|
|
|
|
u8 control_port;
|
|
|
|
u8 port[15];
|
|
|
|
};
|
|
|
|
|
2017-12-14 05:49:35 +00:00
|
|
|
/**
|
2018-04-26 13:08:17 +00:00
|
|
|
* sdw_reg_bank - SoundWire register banks
|
|
|
|
* @SDW_BANK0: Soundwire register bank 0
|
|
|
|
* @SDW_BANK1: Soundwire register bank 1
|
|
|
|
*/
|
|
|
|
enum sdw_reg_bank {
|
|
|
|
SDW_BANK0,
|
|
|
|
SDW_BANK1,
|
|
|
|
};
|
|
|
|
|
2018-04-26 13:08:28 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_bus_conf: Bus configuration
|
|
|
|
*
|
|
|
|
* @clk_freq: Clock frequency, in Hz
|
|
|
|
* @num_rows: Number of rows in frame
|
|
|
|
* @num_cols: Number of columns in frame
|
|
|
|
* @bank: Next register bank
|
|
|
|
*/
|
|
|
|
struct sdw_bus_conf {
|
|
|
|
unsigned int clk_freq;
|
|
|
|
unsigned int num_rows;
|
|
|
|
unsigned int num_cols;
|
|
|
|
unsigned int bank;
|
|
|
|
};
|
|
|
|
|
2018-04-26 13:08:23 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_prepare_ch: Prepare/De-prepare Data Port channel
|
|
|
|
*
|
|
|
|
* @num: Port number
|
|
|
|
* @ch_mask: Active channel mask
|
|
|
|
* @prepare: Prepare (true) /de-prepare (false) channel
|
|
|
|
* @bank: Register bank, which bank Slave/Master driver should program for
|
|
|
|
* implementation defined registers. This is always updated to next_bank
|
|
|
|
* value read from bus params.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
struct sdw_prepare_ch {
|
|
|
|
unsigned int num;
|
|
|
|
unsigned int ch_mask;
|
|
|
|
bool prepare;
|
|
|
|
unsigned int bank;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* enum sdw_port_prep_ops: Prepare operations for Data Port
|
|
|
|
*
|
|
|
|
* @SDW_OPS_PORT_PRE_PREP: Pre prepare operation for the Port
|
|
|
|
* @SDW_OPS_PORT_PREP: Prepare operation for the Port
|
|
|
|
* @SDW_OPS_PORT_POST_PREP: Post prepare operation for the Port
|
|
|
|
*/
|
|
|
|
enum sdw_port_prep_ops {
|
|
|
|
SDW_OPS_PORT_PRE_PREP = 0,
|
|
|
|
SDW_OPS_PORT_PREP = 1,
|
|
|
|
SDW_OPS_PORT_POST_PREP = 2,
|
|
|
|
};
|
|
|
|
|
2018-04-26 13:08:17 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_bus_params: Structure holding bus configuration
|
|
|
|
*
|
|
|
|
* @curr_bank: Current bank in use (BANK0/BANK1)
|
|
|
|
* @next_bank: Next bank to use (BANK0/BANK1). next_bank will always be
|
|
|
|
* set to !curr_bank
|
2018-04-26 13:08:28 +00:00
|
|
|
* @max_dr_freq: Maximum double rate clock frequency supported, in Hz
|
|
|
|
* @curr_dr_freq: Current double rate clock frequency, in Hz
|
|
|
|
* @bandwidth: Current bandwidth
|
|
|
|
* @col: Active columns
|
|
|
|
* @row: Active rows
|
2018-04-26 13:08:17 +00:00
|
|
|
*/
|
|
|
|
struct sdw_bus_params {
|
|
|
|
enum sdw_reg_bank curr_bank;
|
|
|
|
enum sdw_reg_bank next_bank;
|
2018-04-26 13:08:28 +00:00
|
|
|
unsigned int max_dr_freq;
|
|
|
|
unsigned int curr_dr_freq;
|
|
|
|
unsigned int bandwidth;
|
|
|
|
unsigned int col;
|
|
|
|
unsigned int row;
|
2018-04-26 13:08:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_slave_ops: Slave driver callback ops
|
|
|
|
*
|
2017-12-14 05:49:35 +00:00
|
|
|
* @read_prop: Read Slave properties
|
2017-12-14 05:49:40 +00:00
|
|
|
* @interrupt_callback: Device interrupt notification (invoked in thread
|
|
|
|
* context)
|
|
|
|
* @update_status: Update Slave status
|
2018-04-26 13:08:28 +00:00
|
|
|
* @bus_config: Update the bus config for Slave
|
2018-04-26 13:08:23 +00:00
|
|
|
* @port_prep: Prepare the port with parameters
|
2017-12-14 05:49:35 +00:00
|
|
|
*/
|
|
|
|
struct sdw_slave_ops {
|
|
|
|
int (*read_prop)(struct sdw_slave *sdw);
|
2017-12-14 05:49:40 +00:00
|
|
|
int (*interrupt_callback)(struct sdw_slave *slave,
|
2019-05-02 10:59:24 +00:00
|
|
|
struct sdw_slave_intr_status *status);
|
2017-12-14 05:49:40 +00:00
|
|
|
int (*update_status)(struct sdw_slave *slave,
|
2019-05-02 10:59:24 +00:00
|
|
|
enum sdw_slave_status status);
|
2018-04-26 13:08:28 +00:00
|
|
|
int (*bus_config)(struct sdw_slave *slave,
|
2019-05-02 10:59:24 +00:00
|
|
|
struct sdw_bus_params *params);
|
2018-04-26 13:08:23 +00:00
|
|
|
int (*port_prep)(struct sdw_slave *slave,
|
2019-05-02 10:59:24 +00:00
|
|
|
struct sdw_prepare_ch *prepare_ch,
|
|
|
|
enum sdw_port_prep_ops pre_ops);
|
2020-01-15 00:08:43 +00:00
|
|
|
int (*get_clk_stop_mode)(struct sdw_slave *slave);
|
|
|
|
int (*clk_stop)(struct sdw_slave *slave,
|
|
|
|
enum sdw_clk_stop_mode mode,
|
|
|
|
enum sdw_clk_stop_type type);
|
|
|
|
|
2017-12-14 05:49:35 +00:00
|
|
|
};
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_slave - SoundWire Slave
|
|
|
|
* @id: MIPI device ID
|
|
|
|
* @dev: Linux device
|
|
|
|
* @status: Status reported by the Slave
|
|
|
|
* @bus: Bus handle
|
2017-12-14 05:49:35 +00:00
|
|
|
* @ops: Slave callback ops
|
|
|
|
* @prop: Slave properties
|
2019-08-21 18:58:18 +00:00
|
|
|
* @debugfs: Slave debugfs
|
2017-12-14 05:49:33 +00:00
|
|
|
* @node: node for bus list
|
2017-12-14 05:49:35 +00:00
|
|
|
* @port_ready: Port ready completion flag for each Slave port
|
2020-01-13 22:56:37 +00:00
|
|
|
* @dev_num: Current Device Number, values can be 0 or dev_num_sticky
|
|
|
|
* @dev_num_sticky: one-time static Device Number assigned by Bus
|
soundwire: sdw_slave: add probe_complete structure and new fields
When a Slave device becomes synchronized with the bus, it may report
its presence in PING frames, as well as optionally asserting an
in-band PREQ signal.
The bus driver will detect a new Device0, start the enumeration
process and assign it a non-zero device number. The SoundWire
enumeration provides an arbitration to deal with multiple Slaves
reporting ATTACHED at the same time. The bus driver will also invoke
the driver .probe() callback associated with this device. The probe()
depends on the Linux device core, which handles the match operations
and may result in modules being loaded.
Once the non-zero device number is programmed, the Slave will report
its new status in PING frames and the Master hardware will typically
report this status change with an interrupt. At this point, the
.update_status() callback of the codec driver will be invoked (usually
from an interrupt thread or workqueue scheduled from the interrupt
thread).
The first race condition which can happen is between the .probe(),
which allocates the resources, and .update_status() where
initializations are typically handled. The .probe() is only called
once during the initial boot, while .update_status() will be called
for every bus hardware reset and if the Slave device loses
synchronization (an unlikely event but with non-zero probability).
The time difference between the end of the enumeration process and a
change of status reported by the hardware may be as small as one
SoundWire PING frame. The scheduling of the interrupt thread, which
invokes .update_status() is not deterministic, but can be small enough
to create a race condition. With a 48 kHz frame rate and ideal
scheduling cases, the .probe() may be pre-empted within double-digit
microseconds.
Since there is no guarantee that the .probe() completes by the time
.update_status() is invoked as a result of an interrupt, it's not
unusual for the .update_status() to rely on data structures that have
not been allocated yet, leading to kernel oopses.
This patch adds a probe_complete utility, which is used in the
sdw_update_slave_status() routine. The codec driver does not need to
do anything and can safely assume all resources are allocated in its
update_status() callback.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-2-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:44:57 +00:00
|
|
|
* @probed: boolean tracking driver state
|
|
|
|
* @probe_complete: completion utility to control potential races
|
|
|
|
* on startup between driver probe/initialization and SoundWire
|
|
|
|
* Slave state changes/implementation-defined interrupts
|
soundwire: sdw_slave: add enumeration_complete structure
When the Master starts the bus (be it during the initial boot or
system resume), it usually performs a HardReset to make sure
electrical levels are correct, then enables the control channel.
While the PM framework guarantees that the Slave devices will only
become 'active' once the Master completes the bus initialization,
there is still a risk of a race condition: the Slave enumeration is
handled in a separate interrupt thread triggered by hardware status
changes, so the Slave device may not be ready to accept commands when
the Slave driver tries to access the registers and restore settings in
its resume or pm_runtime_resume callbacks. In those cases, any
read/write commands from/to the Slave device will result in a timeout.
This patch adds an enumeration_complete structure. When the bus is
goes through a HardReset sequence and restarted, the Slave will be
marked as UNATTACHED, which will result in a call to
init_completion().
When the Slave reports its presence during PING frames as a non-zero
Device, the Master hardware will issue an interrupt and the bus driver
will invoke complete(). The order between init_completion()/complete()
is predictable since this is a Master-initiated transition.
The Slave driver may use wait_for_completion() in its resume callback.
When regmap is used, the Slave driver will typically set its regmap in
cache-only mode on suspend, then on resume block on
wait_for_completion(&enumeration_complete) to guarantee it is safe to
start read/write transactions. It may then exit the cache-only mode
and use a regmap_sync to restore settings. All these steps are
optional, their use completely depends on the Slave device
capabilities and how the Slave driver is implemented.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-3-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:44:58 +00:00
|
|
|
* @enumeration_complete: completion utility to control potential races
|
|
|
|
* on startup between device enumeration and read/write access to the
|
|
|
|
* Slave device
|
soundwire: sdw_slave: add initialization_complete definition
Slave drivers may have different ways of handling their settings, with
or without regmap.
During the integration of codec drivers, done in partnership between
Intel and Realtek, it became desirable to implement a predictable
order between low-level initializations performed in .update_status()
(invoked by an interrupt thread) and the settings restored in the
resume steps (invoked by the PM core).
This patch builds on the previous solution to wait for the Slave
device to be fully enumerated. The complete() in this case is signaled
not before the .update_status() is called, but after .update_status()
returns. Without this patch, the settings were not properly restored,
leading to timing-dependent 'no sound after resume' or 'no headset
detected after resume' bug reports.
Depending on how initialization is handled, a Slave device driver may
wait for enumeration_complete, or for initialization_complete, both
are valid synchronization points. They are initialized at the same
time, they only differ on when complete() is invoked.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-4-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:44:59 +00:00
|
|
|
* @initialization_complete: completion utility to control potential races
|
|
|
|
* on startup between device enumeration and settings being restored
|
soundwire: sdw_slave: track unattach_request to handle all init sequences
The Slave device initialization can be split in 4 different cases:
1. Master-initiated hardware reset, system suspend-resume and
pm_runtime based on clock-stop mode1. To avoid timeouts and a bad
audio experience, the Slave device resume operations need to wait for
the Slave device to be re-enumerated and its settings restored.
2. Exit from clock-stop mode0. In this case, the Slave device is
required to remain enumerated and its context preserved while the
clock is stopped, so no re-initialization or wait_for_completion() is
necessary.
3. Slave-initiated pm_runtime D3 transition. With the parent child
relationship, it is possible that a Slave device becomes 'suspended'
while its parent is still 'active' with the bus clock still
toggling. In this case, during the pm_runtime resume operation, there
is no need to wait for any settings to be restored.
4. Slave reset (sync loss or implementation-defined). In that case the
bus remains operational and the Slave device will be re-initialized
when it becomes ATTACHED again.
In previous patches, we suggested the use of wait_for_completion() to
deal with the case #1, but case #2 and #3 do not need any wait.
To account for those differences, this patch adds an unattach_request
field. The field is explicitly set by the Master for the case #1, and
if non-zero the Slave device shall wait on resume. In all other cases,
the Slave resume operations can proceed without wait.
The only request tracked so far is Master HardReset, but the request
is declared as a bit mask for future extensions (if needed). The
definition for this value is added in bus.h and does not need to be
exposed in sdw.h
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-5-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:45:00 +00:00
|
|
|
* @unattach_request: mask field to keep track why the Slave re-attached and
|
|
|
|
* was re-initialized. This is useful to deal with potential race conditions
|
|
|
|
* between the Master suspending and the codec resuming, and make sure that
|
|
|
|
* when the Master triggered a reset the Slave is properly enumerated and
|
|
|
|
* initialized
|
2017-12-14 05:49:33 +00:00
|
|
|
*/
|
|
|
|
struct sdw_slave {
|
|
|
|
struct sdw_slave_id id;
|
|
|
|
struct device dev;
|
|
|
|
enum sdw_slave_status status;
|
|
|
|
struct sdw_bus *bus;
|
2017-12-14 05:49:35 +00:00
|
|
|
const struct sdw_slave_ops *ops;
|
|
|
|
struct sdw_slave_prop prop;
|
2019-08-21 18:58:18 +00:00
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
struct dentry *debugfs;
|
|
|
|
#endif
|
2017-12-14 05:49:33 +00:00
|
|
|
struct list_head node;
|
2017-12-14 05:49:35 +00:00
|
|
|
struct completion *port_ready;
|
2020-01-15 00:08:43 +00:00
|
|
|
enum sdw_clk_stop_mode curr_clk_stop_mode;
|
2017-12-14 05:49:33 +00:00
|
|
|
u16 dev_num;
|
2020-01-13 22:56:37 +00:00
|
|
|
u16 dev_num_sticky;
|
soundwire: sdw_slave: add probe_complete structure and new fields
When a Slave device becomes synchronized with the bus, it may report
its presence in PING frames, as well as optionally asserting an
in-band PREQ signal.
The bus driver will detect a new Device0, start the enumeration
process and assign it a non-zero device number. The SoundWire
enumeration provides an arbitration to deal with multiple Slaves
reporting ATTACHED at the same time. The bus driver will also invoke
the driver .probe() callback associated with this device. The probe()
depends on the Linux device core, which handles the match operations
and may result in modules being loaded.
Once the non-zero device number is programmed, the Slave will report
its new status in PING frames and the Master hardware will typically
report this status change with an interrupt. At this point, the
.update_status() callback of the codec driver will be invoked (usually
from an interrupt thread or workqueue scheduled from the interrupt
thread).
The first race condition which can happen is between the .probe(),
which allocates the resources, and .update_status() where
initializations are typically handled. The .probe() is only called
once during the initial boot, while .update_status() will be called
for every bus hardware reset and if the Slave device loses
synchronization (an unlikely event but with non-zero probability).
The time difference between the end of the enumeration process and a
change of status reported by the hardware may be as small as one
SoundWire PING frame. The scheduling of the interrupt thread, which
invokes .update_status() is not deterministic, but can be small enough
to create a race condition. With a 48 kHz frame rate and ideal
scheduling cases, the .probe() may be pre-empted within double-digit
microseconds.
Since there is no guarantee that the .probe() completes by the time
.update_status() is invoked as a result of an interrupt, it's not
unusual for the .update_status() to rely on data structures that have
not been allocated yet, leading to kernel oopses.
This patch adds a probe_complete utility, which is used in the
sdw_update_slave_status() routine. The codec driver does not need to
do anything and can safely assume all resources are allocated in its
update_status() callback.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-2-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:44:57 +00:00
|
|
|
bool probed;
|
|
|
|
struct completion probe_complete;
|
soundwire: sdw_slave: add enumeration_complete structure
When the Master starts the bus (be it during the initial boot or
system resume), it usually performs a HardReset to make sure
electrical levels are correct, then enables the control channel.
While the PM framework guarantees that the Slave devices will only
become 'active' once the Master completes the bus initialization,
there is still a risk of a race condition: the Slave enumeration is
handled in a separate interrupt thread triggered by hardware status
changes, so the Slave device may not be ready to accept commands when
the Slave driver tries to access the registers and restore settings in
its resume or pm_runtime_resume callbacks. In those cases, any
read/write commands from/to the Slave device will result in a timeout.
This patch adds an enumeration_complete structure. When the bus is
goes through a HardReset sequence and restarted, the Slave will be
marked as UNATTACHED, which will result in a call to
init_completion().
When the Slave reports its presence during PING frames as a non-zero
Device, the Master hardware will issue an interrupt and the bus driver
will invoke complete(). The order between init_completion()/complete()
is predictable since this is a Master-initiated transition.
The Slave driver may use wait_for_completion() in its resume callback.
When regmap is used, the Slave driver will typically set its regmap in
cache-only mode on suspend, then on resume block on
wait_for_completion(&enumeration_complete) to guarantee it is safe to
start read/write transactions. It may then exit the cache-only mode
and use a regmap_sync to restore settings. All these steps are
optional, their use completely depends on the Slave device
capabilities and how the Slave driver is implemented.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-3-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:44:58 +00:00
|
|
|
struct completion enumeration_complete;
|
soundwire: sdw_slave: add initialization_complete definition
Slave drivers may have different ways of handling their settings, with
or without regmap.
During the integration of codec drivers, done in partnership between
Intel and Realtek, it became desirable to implement a predictable
order between low-level initializations performed in .update_status()
(invoked by an interrupt thread) and the settings restored in the
resume steps (invoked by the PM core).
This patch builds on the previous solution to wait for the Slave
device to be fully enumerated. The complete() in this case is signaled
not before the .update_status() is called, but after .update_status()
returns. Without this patch, the settings were not properly restored,
leading to timing-dependent 'no sound after resume' or 'no headset
detected after resume' bug reports.
Depending on how initialization is handled, a Slave device driver may
wait for enumeration_complete, or for initialization_complete, both
are valid synchronization points. They are initialized at the same
time, they only differ on when complete() is invoked.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-4-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:44:59 +00:00
|
|
|
struct completion initialization_complete;
|
soundwire: sdw_slave: track unattach_request to handle all init sequences
The Slave device initialization can be split in 4 different cases:
1. Master-initiated hardware reset, system suspend-resume and
pm_runtime based on clock-stop mode1. To avoid timeouts and a bad
audio experience, the Slave device resume operations need to wait for
the Slave device to be re-enumerated and its settings restored.
2. Exit from clock-stop mode0. In this case, the Slave device is
required to remain enumerated and its context preserved while the
clock is stopped, so no re-initialization or wait_for_completion() is
necessary.
3. Slave-initiated pm_runtime D3 transition. With the parent child
relationship, it is possible that a Slave device becomes 'suspended'
while its parent is still 'active' with the bus clock still
toggling. In this case, during the pm_runtime resume operation, there
is no need to wait for any settings to be restored.
4. Slave reset (sync loss or implementation-defined). In that case the
bus remains operational and the Slave device will be re-initialized
when it becomes ATTACHED again.
In previous patches, we suggested the use of wait_for_completion() to
deal with the case #1, but case #2 and #3 do not need any wait.
To account for those differences, this patch adds an unattach_request
field. The field is explicitly set by the Master for the case #1, and
if non-zero the Slave device shall wait on resume. In all other cases,
the Slave resume operations can proceed without wait.
The only request tracked so far is Master HardReset, but the request
is declared as a bit mask for future extensions (if needed). The
definition for this value is added in bus.h and does not need to be
exposed in sdw.h
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191212014507.28050-5-pierre-louis.bossart@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:45:00 +00:00
|
|
|
u32 unattach_request;
|
2017-12-14 05:49:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
|
|
|
|
|
2020-05-18 17:43:21 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_master_device - SoundWire 'Master Device' representation
|
|
|
|
* @dev: Linux device for this Master
|
|
|
|
* @bus: Bus handle shortcut
|
|
|
|
*/
|
|
|
|
struct sdw_master_device {
|
|
|
|
struct device dev;
|
|
|
|
struct sdw_bus *bus;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define dev_to_sdw_master_device(d) \
|
|
|
|
container_of(d, struct sdw_master_device, dev)
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
struct sdw_driver {
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
int (*probe)(struct sdw_slave *sdw,
|
|
|
|
const struct sdw_device_id *id);
|
|
|
|
int (*remove)(struct sdw_slave *sdw);
|
|
|
|
void (*shutdown)(struct sdw_slave *sdw);
|
|
|
|
|
|
|
|
const struct sdw_device_id *id_table;
|
|
|
|
const struct sdw_slave_ops *ops;
|
|
|
|
|
|
|
|
struct device_driver driver;
|
|
|
|
};
|
|
|
|
|
2020-06-08 20:54:35 +00:00
|
|
|
#define SDW_SLAVE_ENTRY_EXT(_mfg_id, _part_id, _version, _c_id, _drv_data) \
|
|
|
|
{ .mfg_id = (_mfg_id), .part_id = (_part_id), \
|
|
|
|
.sdw_version = (_version), .class_id = (_c_id), \
|
2017-12-14 05:49:33 +00:00
|
|
|
.driver_data = (unsigned long)(_drv_data) }
|
|
|
|
|
2020-06-08 20:54:35 +00:00
|
|
|
#define SDW_SLAVE_ENTRY(_mfg_id, _part_id, _drv_data) \
|
|
|
|
SDW_SLAVE_ENTRY_EXT((_mfg_id), (_part_id), 0, 0, (_drv_data))
|
|
|
|
|
2017-12-14 05:49:40 +00:00
|
|
|
int sdw_handle_slave_status(struct sdw_bus *bus,
|
|
|
|
enum sdw_slave_status status[]);
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
/*
|
|
|
|
* SDW master structures and APIs
|
|
|
|
*/
|
|
|
|
|
2018-04-26 13:08:13 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_port_params: Data Port parameters
|
|
|
|
*
|
|
|
|
* @num: Port number
|
|
|
|
* @bps: Word length of the Port
|
|
|
|
* @flow_mode: Port Data flow mode
|
|
|
|
* @data_mode: Test modes or normal mode
|
|
|
|
*
|
|
|
|
* This is used to program the Data Port based on Data Port stream
|
|
|
|
* parameters.
|
|
|
|
*/
|
|
|
|
struct sdw_port_params {
|
|
|
|
unsigned int num;
|
|
|
|
unsigned int bps;
|
|
|
|
unsigned int flow_mode;
|
|
|
|
unsigned int data_mode;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_transport_params: Data Port Transport Parameters
|
|
|
|
*
|
|
|
|
* @blk_grp_ctrl_valid: Port implements block group control
|
|
|
|
* @num: Port number
|
|
|
|
* @blk_grp_ctrl: Block group control value
|
|
|
|
* @sample_interval: Sample interval
|
|
|
|
* @offset1: Blockoffset of the payload data
|
|
|
|
* @offset2: Blockoffset of the payload data
|
|
|
|
* @hstart: Horizontal start of the payload data
|
|
|
|
* @hstop: Horizontal stop of the payload data
|
|
|
|
* @blk_pkg_mode: Block per channel or block per port
|
|
|
|
* @lane_ctrl: Data lane Port uses for Data transfer. Currently only single
|
|
|
|
* data lane is supported in bus
|
|
|
|
*
|
|
|
|
* This is used to program the Data Port based on Data Port transport
|
|
|
|
* parameters. All these parameters are banked and can be modified
|
|
|
|
* during a bank switch without any artifacts in audio stream.
|
|
|
|
*/
|
|
|
|
struct sdw_transport_params {
|
|
|
|
bool blk_grp_ctrl_valid;
|
|
|
|
unsigned int port_num;
|
|
|
|
unsigned int blk_grp_ctrl;
|
|
|
|
unsigned int sample_interval;
|
|
|
|
unsigned int offset1;
|
|
|
|
unsigned int offset2;
|
|
|
|
unsigned int hstart;
|
|
|
|
unsigned int hstop;
|
|
|
|
unsigned int blk_pkg_mode;
|
|
|
|
unsigned int lane_ctrl;
|
|
|
|
};
|
|
|
|
|
2018-04-26 13:08:23 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_enable_ch: Enable/disable Data Port channel
|
|
|
|
*
|
|
|
|
* @num: Port number
|
|
|
|
* @ch_mask: Active channel mask
|
|
|
|
* @enable: Enable (true) /disable (false) channel
|
|
|
|
*/
|
|
|
|
struct sdw_enable_ch {
|
|
|
|
unsigned int port_num;
|
|
|
|
unsigned int ch_mask;
|
|
|
|
bool enable;
|
|
|
|
};
|
|
|
|
|
2018-04-26 13:08:17 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_master_port_ops: Callback functions from bus to Master
|
|
|
|
* driver to set Master Data ports.
|
|
|
|
*
|
|
|
|
* @dpn_set_port_params: Set the Port parameters for the Master Port.
|
|
|
|
* Mandatory callback
|
|
|
|
* @dpn_set_port_transport_params: Set transport parameters for the Master
|
|
|
|
* Port. Mandatory callback
|
2018-04-26 13:08:23 +00:00
|
|
|
* @dpn_port_prep: Port prepare operations for the Master Data Port.
|
|
|
|
* @dpn_port_enable_ch: Enable the channels of Master Port.
|
2018-04-26 13:08:17 +00:00
|
|
|
*/
|
|
|
|
struct sdw_master_port_ops {
|
|
|
|
int (*dpn_set_port_params)(struct sdw_bus *bus,
|
|
|
|
struct sdw_port_params *port_params,
|
|
|
|
unsigned int bank);
|
|
|
|
int (*dpn_set_port_transport_params)(struct sdw_bus *bus,
|
|
|
|
struct sdw_transport_params *transport_params,
|
|
|
|
enum sdw_reg_bank bank);
|
2018-04-26 13:08:23 +00:00
|
|
|
int (*dpn_port_prep)(struct sdw_bus *bus,
|
|
|
|
struct sdw_prepare_ch *prepare_ch);
|
|
|
|
int (*dpn_port_enable_ch)(struct sdw_bus *bus,
|
|
|
|
struct sdw_enable_ch *enable_ch, unsigned int bank);
|
2018-04-26 13:08:17 +00:00
|
|
|
};
|
|
|
|
|
2017-12-14 05:49:37 +00:00
|
|
|
struct sdw_msg;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct sdw_defer - SDW deffered message
|
|
|
|
* @length: message length
|
|
|
|
* @complete: message completion
|
|
|
|
* @msg: SDW message
|
|
|
|
*/
|
|
|
|
struct sdw_defer {
|
|
|
|
int length;
|
|
|
|
struct completion complete;
|
|
|
|
struct sdw_msg *msg;
|
|
|
|
};
|
|
|
|
|
2017-12-14 05:49:35 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_master_ops - Master driver ops
|
|
|
|
* @read_prop: Read Master properties
|
2017-12-14 05:49:37 +00:00
|
|
|
* @xfer_msg: Transfer message callback
|
|
|
|
* @xfer_msg_defer: Defer version of transfer message callback
|
|
|
|
* @reset_page_addr: Reset the SCP page address registers
|
2018-04-26 13:08:28 +00:00
|
|
|
* @set_bus_conf: Set the bus configuration
|
|
|
|
* @pre_bank_switch: Callback for pre bank switch
|
|
|
|
* @post_bank_switch: Callback for post bank switch
|
2017-12-14 05:49:35 +00:00
|
|
|
*/
|
|
|
|
struct sdw_master_ops {
|
|
|
|
int (*read_prop)(struct sdw_bus *bus);
|
2017-12-14 05:49:37 +00:00
|
|
|
|
|
|
|
enum sdw_command_response (*xfer_msg)
|
|
|
|
(struct sdw_bus *bus, struct sdw_msg *msg);
|
|
|
|
enum sdw_command_response (*xfer_msg_defer)
|
|
|
|
(struct sdw_bus *bus, struct sdw_msg *msg,
|
|
|
|
struct sdw_defer *defer);
|
|
|
|
enum sdw_command_response (*reset_page_addr)
|
|
|
|
(struct sdw_bus *bus, unsigned int dev_num);
|
2018-04-26 13:08:28 +00:00
|
|
|
int (*set_bus_conf)(struct sdw_bus *bus,
|
|
|
|
struct sdw_bus_params *params);
|
|
|
|
int (*pre_bank_switch)(struct sdw_bus *bus);
|
|
|
|
int (*post_bank_switch)(struct sdw_bus *bus);
|
|
|
|
|
2017-12-14 05:49:35 +00:00
|
|
|
};
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
/**
|
|
|
|
* struct sdw_bus - SoundWire bus
|
2020-05-18 17:43:21 +00:00
|
|
|
* @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
|
|
|
|
* @md: Master device
|
2017-12-14 05:49:33 +00:00
|
|
|
* @link_id: Link id number, can be 0 to N, unique for each Master
|
2020-05-18 17:43:20 +00:00
|
|
|
* @id: bus system-wide unique id
|
2017-12-14 05:49:33 +00:00
|
|
|
* @slaves: list of Slaves on this bus
|
|
|
|
* @assigned: Bitmap for Slave device numbers.
|
|
|
|
* Bit set implies used number, bit clear implies unused number.
|
|
|
|
* @bus_lock: bus lock
|
2017-12-14 05:49:37 +00:00
|
|
|
* @msg_lock: message lock
|
2019-08-13 08:35:46 +00:00
|
|
|
* @compute_params: points to Bus resource management implementation
|
2017-12-14 05:49:35 +00:00
|
|
|
* @ops: Master callback ops
|
2018-04-26 13:08:17 +00:00
|
|
|
* @port_ops: Master port callback ops
|
|
|
|
* @params: Current bus parameters
|
2017-12-14 05:49:35 +00:00
|
|
|
* @prop: Master properties
|
2018-04-26 13:08:08 +00:00
|
|
|
* @m_rt_list: List of Master instance of all stream(s) running on Bus. This
|
|
|
|
* is used to compute and program bus bandwidth, clock, frame shape,
|
|
|
|
* transport and port parameters
|
2019-08-21 18:58:18 +00:00
|
|
|
* @debugfs: Bus debugfs
|
2017-12-14 05:49:37 +00:00
|
|
|
* @defer_msg: Defer message
|
2017-12-14 05:49:35 +00:00
|
|
|
* @clk_stop_timeout: Clock stop timeout computed
|
2018-04-26 13:08:28 +00:00
|
|
|
* @bank_switch_timeout: Bank switch timeout computed
|
2018-07-27 09:14:16 +00:00
|
|
|
* @multi_link: Store bus property that indicates if multi links
|
|
|
|
* are supported. This flag is populated by drivers after reading
|
|
|
|
* appropriate firmware (ACPI/DT).
|
2017-12-14 05:49:33 +00:00
|
|
|
*/
|
|
|
|
struct sdw_bus {
|
|
|
|
struct device *dev;
|
2020-05-18 17:43:21 +00:00
|
|
|
struct sdw_master_device *md;
|
2017-12-14 05:49:33 +00:00
|
|
|
unsigned int link_id;
|
2020-05-18 17:43:20 +00:00
|
|
|
int id;
|
2017-12-14 05:49:33 +00:00
|
|
|
struct list_head slaves;
|
|
|
|
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
|
|
|
|
struct mutex bus_lock;
|
2017-12-14 05:49:37 +00:00
|
|
|
struct mutex msg_lock;
|
2019-08-13 08:35:46 +00:00
|
|
|
int (*compute_params)(struct sdw_bus *bus);
|
2017-12-14 05:49:35 +00:00
|
|
|
const struct sdw_master_ops *ops;
|
2018-04-26 13:08:17 +00:00
|
|
|
const struct sdw_master_port_ops *port_ops;
|
|
|
|
struct sdw_bus_params params;
|
2017-12-14 05:49:35 +00:00
|
|
|
struct sdw_master_prop prop;
|
2018-04-26 13:08:08 +00:00
|
|
|
struct list_head m_rt_list;
|
2019-08-21 18:58:18 +00:00
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
struct dentry *debugfs;
|
|
|
|
#endif
|
2017-12-14 05:49:37 +00:00
|
|
|
struct sdw_defer defer_msg;
|
2017-12-14 05:49:35 +00:00
|
|
|
unsigned int clk_stop_timeout;
|
2018-04-26 13:08:28 +00:00
|
|
|
u32 bank_switch_timeout;
|
2018-07-27 09:14:16 +00:00
|
|
|
bool multi_link;
|
2017-12-14 05:49:33 +00:00
|
|
|
};
|
|
|
|
|
2020-05-18 17:43:18 +00:00
|
|
|
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
|
|
|
|
struct fwnode_handle *fwnode);
|
|
|
|
void sdw_bus_master_delete(struct sdw_bus *bus);
|
2017-12-14 05:49:34 +00:00
|
|
|
|
2018-04-26 13:08:13 +00:00
|
|
|
/**
|
|
|
|
* sdw_port_config: Master or Slave Port configuration
|
|
|
|
*
|
|
|
|
* @num: Port number
|
|
|
|
* @ch_mask: channels mask for port
|
|
|
|
*/
|
|
|
|
struct sdw_port_config {
|
|
|
|
unsigned int num;
|
|
|
|
unsigned int ch_mask;
|
|
|
|
};
|
|
|
|
|
2018-04-26 13:08:08 +00:00
|
|
|
/**
|
|
|
|
* sdw_stream_config: Master or Slave stream configuration
|
|
|
|
*
|
|
|
|
* @frame_rate: Audio frame rate of the stream, in Hz
|
|
|
|
* @ch_count: Channel count of the stream
|
|
|
|
* @bps: Number of bits per audio sample
|
|
|
|
* @direction: Data direction
|
|
|
|
* @type: Stream type PCM or PDM
|
|
|
|
*/
|
|
|
|
struct sdw_stream_config {
|
|
|
|
unsigned int frame_rate;
|
|
|
|
unsigned int ch_count;
|
|
|
|
unsigned int bps;
|
|
|
|
enum sdw_data_direction direction;
|
|
|
|
enum sdw_stream_type type;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sdw_stream_state: Stream states
|
|
|
|
*
|
|
|
|
* @SDW_STREAM_ALLOCATED: New stream allocated.
|
|
|
|
* @SDW_STREAM_CONFIGURED: Stream configured
|
|
|
|
* @SDW_STREAM_PREPARED: Stream prepared
|
|
|
|
* @SDW_STREAM_ENABLED: Stream enabled
|
|
|
|
* @SDW_STREAM_DISABLED: Stream disabled
|
|
|
|
* @SDW_STREAM_DEPREPARED: Stream de-prepared
|
|
|
|
* @SDW_STREAM_RELEASED: Stream released
|
|
|
|
*/
|
|
|
|
enum sdw_stream_state {
|
|
|
|
SDW_STREAM_ALLOCATED = 0,
|
|
|
|
SDW_STREAM_CONFIGURED = 1,
|
|
|
|
SDW_STREAM_PREPARED = 2,
|
|
|
|
SDW_STREAM_ENABLED = 3,
|
|
|
|
SDW_STREAM_DISABLED = 4,
|
|
|
|
SDW_STREAM_DEPREPARED = 5,
|
|
|
|
SDW_STREAM_RELEASED = 6,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sdw_stream_params: Stream parameters
|
|
|
|
*
|
|
|
|
* @rate: Sampling frequency, in Hz
|
|
|
|
* @ch_count: Number of channels
|
|
|
|
* @bps: bits per channel sample
|
|
|
|
*/
|
|
|
|
struct sdw_stream_params {
|
|
|
|
unsigned int rate;
|
|
|
|
unsigned int ch_count;
|
|
|
|
unsigned int bps;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sdw_stream_runtime: Runtime stream parameters
|
|
|
|
*
|
|
|
|
* @name: SoundWire stream name
|
|
|
|
* @params: Stream parameters
|
|
|
|
* @state: Current state of the stream
|
|
|
|
* @type: Stream type PCM or PDM
|
2018-07-27 09:14:13 +00:00
|
|
|
* @master_list: List of Master runtime(s) in this stream.
|
|
|
|
* master_list can contain only one m_rt per Master instance
|
|
|
|
* for a stream
|
2018-07-27 09:14:15 +00:00
|
|
|
* @m_rt_count: Count of Master runtime(s) in this stream
|
2018-04-26 13:08:08 +00:00
|
|
|
*/
|
|
|
|
struct sdw_stream_runtime {
|
2019-08-13 08:35:47 +00:00
|
|
|
const char *name;
|
2018-04-26 13:08:08 +00:00
|
|
|
struct sdw_stream_params params;
|
|
|
|
enum sdw_stream_state state;
|
|
|
|
enum sdw_stream_type type;
|
2018-07-27 09:14:13 +00:00
|
|
|
struct list_head master_list;
|
2018-07-27 09:14:15 +00:00
|
|
|
int m_rt_count;
|
2018-04-26 13:08:08 +00:00
|
|
|
};
|
|
|
|
|
2019-08-13 08:35:47 +00:00
|
|
|
struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name);
|
2018-04-26 13:08:08 +00:00
|
|
|
void sdw_release_stream(struct sdw_stream_runtime *stream);
|
|
|
|
int sdw_stream_add_master(struct sdw_bus *bus,
|
|
|
|
struct sdw_stream_config *stream_config,
|
2018-04-26 13:08:13 +00:00
|
|
|
struct sdw_port_config *port_config,
|
|
|
|
unsigned int num_ports,
|
2018-04-26 13:08:08 +00:00
|
|
|
struct sdw_stream_runtime *stream);
|
|
|
|
int sdw_stream_add_slave(struct sdw_slave *slave,
|
|
|
|
struct sdw_stream_config *stream_config,
|
2018-04-26 13:08:13 +00:00
|
|
|
struct sdw_port_config *port_config,
|
|
|
|
unsigned int num_ports,
|
2018-04-26 13:08:08 +00:00
|
|
|
struct sdw_stream_runtime *stream);
|
|
|
|
int sdw_stream_remove_master(struct sdw_bus *bus,
|
|
|
|
struct sdw_stream_runtime *stream);
|
|
|
|
int sdw_stream_remove_slave(struct sdw_slave *slave,
|
|
|
|
struct sdw_stream_runtime *stream);
|
2020-06-30 18:43:53 +00:00
|
|
|
int sdw_startup_stream(void *sdw_substream);
|
2018-04-26 13:08:33 +00:00
|
|
|
int sdw_prepare_stream(struct sdw_stream_runtime *stream);
|
|
|
|
int sdw_enable_stream(struct sdw_stream_runtime *stream);
|
|
|
|
int sdw_disable_stream(struct sdw_stream_runtime *stream);
|
|
|
|
int sdw_deprepare_stream(struct sdw_stream_runtime *stream);
|
2020-06-30 18:43:53 +00:00
|
|
|
void sdw_shutdown_stream(void *sdw_substream);
|
2020-01-15 00:08:43 +00:00
|
|
|
int sdw_bus_prep_clk_stop(struct sdw_bus *bus);
|
|
|
|
int sdw_bus_clk_stop(struct sdw_bus *bus);
|
|
|
|
int sdw_bus_exit_clk_stop(struct sdw_bus *bus);
|
2018-04-26 13:08:08 +00:00
|
|
|
|
2017-12-14 05:49:37 +00:00
|
|
|
/* messaging and data APIs */
|
|
|
|
|
|
|
|
int sdw_read(struct sdw_slave *slave, u32 addr);
|
|
|
|
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
|
|
|
|
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
|
|
|
|
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
|
|
|
|
|
2017-12-14 05:49:33 +00:00
|
|
|
#endif /* __SOUNDWIRE_H */
|