drivers: dai: add dai driver subdir and ssp driver

Add Intel ssp driver using dai interface.

Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
This commit is contained in:
Jaska Uimonen 2022-03-29 16:38:26 +03:00 committed by Anas Nashif
commit 8d38b64fdc
12 changed files with 2812 additions and 1 deletions

View file

@ -240,6 +240,9 @@
/drivers/crypto/*nrf_ecb* @maciekfabia @anangl /drivers/crypto/*nrf_ecb* @maciekfabia @anangl
/drivers/display/display_framebuf.c @dcpleung /drivers/display/display_framebuf.c @dcpleung
/drivers/dac/ @martinjaeger /drivers/dac/ @martinjaeger
/drivers/dai/ @juimonen
/drivers/dai/intel/ @juimonen
/drivers/dai/intel/ssp/ @juimonen
/drivers/dma/*dw* @tbursztyka /drivers/dma/*dw* @tbursztyka
/drivers/dma/*sam0* @Sizurka /drivers/dma/*sam0* @Sizurka
/drivers/dma/dma_stm32* @cybertale @lowlander /drivers/dma/dma_stm32* @cybertale @lowlander

View file

@ -48,7 +48,7 @@ add_subdirectory_ifdef(CONFIG_MEMC memc)
add_subdirectory_ifdef(CONFIG_VIRTUALIZATION virtualization) add_subdirectory_ifdef(CONFIG_VIRTUALIZATION virtualization)
add_subdirectory_ifdef(CONFIG_PM_CPU_OPS pm_cpu_ops) add_subdirectory_ifdef(CONFIG_PM_CPU_OPS pm_cpu_ops)
add_subdirectory_ifdef(CONFIG_POWER_DOMAIN power_domain) add_subdirectory_ifdef(CONFIG_POWER_DOMAIN power_domain)
add_subdirectory_ifdef(CONFIG_DAI dai)
add_subdirectory_ifdef(CONFIG_FLASH_HAS_DRIVER_ENABLED flash) add_subdirectory_ifdef(CONFIG_FLASH_HAS_DRIVER_ENABLED flash)
add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial) add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial)
add_subdirectory_ifdef(CONFIG_BT_DRIVERS bluetooth) add_subdirectory_ifdef(CONFIG_BT_DRIVERS bluetooth)

View file

@ -43,6 +43,8 @@ source "drivers/i2c/Kconfig"
source "drivers/i2s/Kconfig" source "drivers/i2s/Kconfig"
source "drivers/dai/Kconfig"
source "drivers/pwm/Kconfig" source "drivers/pwm/Kconfig"
source "drivers/pinmux/Kconfig" source "drivers/pinmux/Kconfig"

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
add_subdirectory_ifdef(CONFIG_DAI_INTEL_SSP intel/ssp)

30
drivers/dai/Kconfig Normal file
View file

@ -0,0 +1,30 @@
# Dai driver configuration options
# Copyright (c) 2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
# DAI Drivers
#
menuconfig DAI
bool "DAI drivers"
help
Enable support for the DAI interface drivers.
if DAI
config DAI_INIT_PRIORITY
int "Init priority"
default 70
help
Device driver initialization priority.
module = DAI
module-str = dai
source "subsys/logging/Kconfig.template.log_config"
comment "Device Drivers"
source "drivers/dai/intel/ssp/Kconfig.ssp"
endif # DAI

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_DAI_INTEL_SSP ssp.c)
zephyr_library_compile_options(-std=gnu99)

View file

@ -0,0 +1,11 @@
# SOF SSP configuration options
# Copyright (c) 2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
config DAI_INTEL_SSP
bool "Intel I2S (SSP) Bus Driver for Dai interface"
select DMA
help
Enable Inter Sound (I2S) bus driver based on
Synchronous Serial Port (SSP) module.

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2022 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __DAI_PARAMS_INTEL_IPC3_H__
#define __DAI_PARAMS_INTEL_IPC3_H__
#include <stdint.h>
#define DAI_INTEL_IPC3_SSP_FMT_I2S 1 /**< I2S mode */
#define DAI_INTEL_IPC3_SSP_FMT_RIGHT_J 2 /**< Right Justified mode */
#define DAI_INTEL_IPC3_SSP_FMT_LEFT_J 3 /**< Left Justified mode */
#define DAI_INTEL_IPC3_SSP_FMT_DSP_A 4 /**< L data MSB after FRM LRC */
#define DAI_INTEL_IPC3_SSP_FMT_DSP_B 5 /**< L data MSB during FRM LRC */
#define DAI_INTEL_IPC3_SSP_FMT_PDM 6 /**< Pulse density modulation */
#define DAI_INTEL_IPC3_SSP_FMT_CONT (1 << 4) /**< continuous clock */
#define DAI_INTEL_IPC3_SSP_FMT_GATED (0 << 4) /**< clock is gated */
#define DAI_INTEL_IPC3_SSP_FMT_NB_NF (0 << 8) /**< normal bit clock + frame */
#define DAI_INTEL_IPC3_SSP_FMT_NB_IF (2 << 8) /**< normal BCLK + inv FRM */
#define DAI_INTEL_IPC3_SSP_FMT_IB_NF (3 << 8) /**< invert BCLK + nor FRM */
#define DAI_INTEL_IPC3_SSP_FMT_IB_IF (4 << 8) /**< invert BCLK + FRM */
#define DAI_INTEL_IPC3_SSP_FMT_CBP_CFP (0 << 12) /**< codec bclk provider & frame provider */
#define DAI_INTEL_IPC3_SSP_FMT_CBC_CFP (2 << 12) /**< codec bclk consumer & frame provider */
#define DAI_INTEL_IPC3_SSP_FMT_CBP_CFC (3 << 12) /**< codec bclk provider & frame consumer */
#define DAI_INTEL_IPC3_SSP_FMT_CBC_CFC (4 << 12) /**< codec bclk consumer & frame consumer */
#define DAI_INTEL_IPC3_SSP_FMT_FORMAT_MASK 0x000f
#define DAI_INTEL_IPC3_SSP_FMT_CLOCK_MASK 0x00f0
#define DAI_INTEL_IPC3_SSP_FMT_INV_MASK 0x0f00
#define DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK 0xf000
/*
* DAI_CONFIG flags. The 4 LSB bits are used for the commands, HW_PARAMS, HW_FREE and PAUSE
* representing when the IPC is sent. The 4 MSB bits are used to add quirks along with the above
* commands.
*/
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_CMD_MASK 0xF
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_NONE 0 /**< config without stage information */
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS BIT(0) /**< config during hw_params stage */
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_FREE BIT(1) /**< config during hw_free stage */
/**< DAI_CONFIG sent during pause trigger. Only available ABI 3.20 onwards */
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_PAUSE BIT(2)
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_QUIRK_SHIFT 4
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_QUIRK_MASK (0xF << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT)
/*
* This should be used along with the DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS to indicate that
* pipeline stop/pause and DAI DMA stop/pause should happen in two steps. This change is only
* available ABI 3.20 onwards.
*/
#define DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_2_STEP_STOP BIT(0)
/* ssc1: TINTE */
#define DAI_INTEL_IPC3_SSP_QUIRK_TINTE (1 << 0)
/* ssc1: PINTE */
#define DAI_INTEL_IPC3_SSP_QUIRK_PINTE (1 << 1)
/* ssc2: SMTATF */
#define DAI_INTEL_IPC3_SSP_QUIRK_SMTATF (1 << 2)
/* ssc2: MMRATF */
#define DAI_INTEL_IPC3_SSP_QUIRK_MMRATF (1 << 3)
/* ssc2: PSPSTWFDFD */
#define DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD (1 << 4)
/* ssc2: PSPSRWFDFD */
#define DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD (1 << 5)
/* ssc1: LBM */
#define DAI_INTEL_IPC3_SSP_QUIRK_LBM (1 << 6)
/* here is the possibility to define others aux macros */
#define DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX 38
#define DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX 31
/* SSP clocks control settings
*
* Macros for clks_control field in sof_dai_ssp_params struct.
*/
/* mclk 0 disable */
#define DAI_INTEL_IPC3_SSP_MCLK_0_DISABLE BIT(0)
/* mclk 1 disable */
#define DAI_INTEL_IPC3_SSP_MCLK_1_DISABLE BIT(1)
/* mclk keep active */
#define DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_KA BIT(2)
/* bclk keep active */
#define DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_KA BIT(3)
/* fs keep active */
#define DAI_INTEL_IPC3_SSP_CLKCTRL_FS_KA BIT(4)
/* bclk idle */
#define DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5)
/* mclk early start */
#define DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES BIT(6)
/* bclk early start */
#define DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES BIT(7)
/* SSP Configuration Request - SOF_DAI_SSP_CONFIG */
struct dai_intel_ipc3_ssp_params {
uint32_t reserved0;
uint16_t reserved1;
uint16_t mclk_id;
uint32_t mclk_rate; /* mclk frequency in Hz */
uint32_t fsync_rate; /* fsync frequency in Hz */
uint32_t bclk_rate; /* bclk frequency in Hz */
/* TDM */
uint32_t tdm_slots;
uint32_t rx_slots;
uint32_t tx_slots;
/* data */
uint32_t sample_valid_bits;
uint16_t tdm_slot_width;
uint16_t reserved2; /* alignment */
/* MCLK */
uint32_t mclk_direction;
uint16_t frame_pulse_width;
uint16_t tdm_per_slot_padding_flag;
uint32_t clks_control;
uint32_t quirks;
uint32_t bclk_delay; /* guaranteed time (ms) for which BCLK
* will be driven, before sending data
*/
} __packed;
#endif /* __DAI_PARAMS_INTEL_IPC3_H__ */

View file

@ -0,0 +1,255 @@
/*
* Copyright (c) 2022 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __DAI_PARAMS_INTEL_IPC4_H__
#define __DAI_PARAMS_INTEL_IPC4_H__
#include <stdint.h>
#define DAI_INTEL_I2S_TDM_MAX_SLOT_MAP_COUNT 8
/**< Type of the gateway. */
enum dai_intel_ipc4_connector_node_id_type {
/**< HD/A host output (-> DSP). */
dai_intel_ipc4_hda_host_output_class = 0,
/**< HD/A host input (<- DSP). */
dai_intel_ipc4_hda_host_input_class = 1,
/**< HD/A host input/output (rsvd for future use). */
dai_intel_ipc4_hda_host_inout_class = 2,
/**< HD/A link output (DSP ->). */
dai_intel_ipc4_hda_link_output_class = 8,
/**< HD/A link input (DSP <-). */
dai_intel_ipc4_hda_link_input_class = 9,
/**< HD/A link input/output (rsvd for future use). */
dai_intel_ipc4_hda_link_inout_class = 10,
/**< DMIC link input (DSP <-). */
dai_intel_ipc4_dmic_link_input_class = 11,
/**< I2S link output (DSP ->). */
dai_intel_ipc4_i2s_link_output_class = 12,
/**< I2S link input (DSP <-). */
dai_intel_ipc4_i2s_link_input_class = 13,
/**< ALH link output, legacy for SNDW (DSP ->). */
dai_intel_ipc4_alh_link_output_class = 16,
/**< ALH link input, legacy for SNDW (DSP <-). */
dai_intel_ipc4_alh_link_input_class = 17,
/**< SNDW link output (DSP ->). */
dai_intel_ipc4_alh_snd_wire_stream_link_output_class = 16,
/**< SNDW link input (DSP <-). */
dai_intel_ipc4_alh_snd_wire_stream_link_input_class = 17,
/**< UAOL link output (DSP ->). */
dai_intel_ipc4_alh_uaol_stream_link_output_class = 18,
/**< UAOL link input (DSP <-). */
dai_intel_ipc4_alh_uaol_stream_link_input_class = 19,
/**< IPC output (DSP ->). */
dai_intel_ipc4_ipc_output_class = 20,
/**< IPC input (DSP <-). */
dai_intel_ipc4_ipc_input_class = 21,
/**< I2S Multi gtw output (DSP ->). */
dai_intel_ipc4_i2s_multi_link_output_class = 22,
/**< I2S Multi gtw input (DSP <-). */
dai_intel_ipc4_i2s_multi_link_input_class = 23,
/**< GPIO */
dai_intel_ipc4_gpio_class = 24,
/**< SPI */
dai_intel_ipc4_spi_output_class = 25,
dai_intel_ipc4_spi_input_class = 26,
dai_intel_ipc4_max_connector_node_id_type
};
/**< Base top-level structure of an address of a gateway. */
/*!
* The virtual index value, presented on the top level as raw 8 bits,
* is expected to be encoded in a gateway specific way depending on
* the actual type of gateway.
*/
union dai_intel_ipc4_connector_node_id {
/**< Raw 32-bit value of node id. */
uint32_t dw;
/**< Bit fields */
struct {
/**< Index of the virtual DMA at the gateway. */
uint32_t v_index : 8;
/**< Type of the gateway, one of ConnectorNodeId::Type values. */
uint32_t dma_type : 5;
/**< Rsvd field. */
uint32_t _rsvd : 19;
} f; /**<< Bits */
} __packed;
/*!
* Attributes are usually provided along with the gateway configuration
* BLOB when the FW is requested to instantiate that gateway.
*
* There are flags which requests FW to allocate gateway related data
* (buffers and other items used while transferring data, like linked list)
* to be allocated from a special memory area, e.g low power memory.
*/
union dai_intel_ipc4_gateway_attributes {
/**< Raw value */
uint32_t dw;
/**< Access to the fields */
struct {
/**< Gateway data requested in low power memory. */
uint32_t lp_buffer_alloc : 1;
/**< Gateway data requested in register file memory. */
uint32_t alloc_from_reg_file : 1;
/**< Reserved field */
uint32_t _rsvd : 30;
} bits; /**<< Bits */
} __packed;
/**< Configuration for the IPC Gateway */
struct dai_intel_ipc4_gateway_config_blob {
/**< Size of the gateway buffer, specified in bytes */
uint32_t buffer_size;
/**< Flags */
union flags {
struct bits {
/**< Activates high threshold notification */
/*!
* Indicates whether notification should be sent to the host
* when the size of data in the buffer reaches the high threshold
* specified by threshold_high parameter.
*/
uint32_t notif_high : 1;
/**< Activates low threshold notification */
/*!
* Indicates whether notification should be sent to the host
* when the size of data in the buffer reaches the low threshold
* specified by threshold_low parameter.
*/
uint32_t notif_low : 1;
/**< Reserved field */
uint32_t rsvd : 30;
} f; /**<< Bits */
/**< Raw value of flags */
uint32_t flags_raw;
} u; /**<< Flags */
/**< High threshold */
/*!
* Specifies the high threshold (in bytes) for notifying the host
* about the buffered data level.
*/
uint32_t threshold_high;
/**< Low threshold */
/*!
* Specifies the low threshold (in bytes) for notifying the host
* about the buffered data level.
*/
uint32_t threshold_low;
} __packed;
/* i2s Configuration BLOB building blocks */
/* i2s registers for i2s Configuration */
struct dai_intel_ipc4_ssp_config {
uint32_t ssc0;
uint32_t ssc1;
uint32_t sscto;
uint32_t sspsp;
uint32_t sstsa;
uint32_t ssrsa;
uint32_t ssc2;
uint32_t sspsp2;
uint32_t ssc3;
uint32_t ssioc;
} __packed;
struct dai_intel_ipc4_ssp_mclk_config {
/* master clock divider control register */
uint32_t mdivc;
/* master clock divider ratio register */
uint32_t mdivr;
} __packed;
struct dai_intel_ipc4_ssp_driver_config {
struct dai_intel_ipc4_ssp_config i2s_config;
struct dai_intel_ipc4_ssp_mclk_config mclk_config;
} __packed;
struct dai_intel_ipc4_ssp_start_control {
/* delay in msec between enabling interface (moment when
* Copier instance is being attached to the interface) and actual
* interface start. Value of 0 means no delay.
*/
uint32_t clock_warm_up : 16;
/* specifies if parameters target MCLK (1) or SCLK (0) */
uint32_t mclk : 1;
/* value of 1 means that clock should be started immediately
* even if no Copier instance is currently attached to the interface.
*/
uint32_t warm_up_ovr : 1;
uint32_t rsvd0 : 14;
} __packed;
struct dai_intel_ipc4_ssp_stop_control {
/* delay in msec between stopping the interface
* (moment when Copier instance is being detached from the interface)
* and interface clock stop. Value of 0 means no delay.
*/
uint32_t clock_stop_delay : 16;
/* value of 1 means that clock should be kept running (infinite
* stop delay) after Copier instance detaches from the interface.
*/
uint32_t keep_running : 1;
/* value of 1 means that clock should be stopped immediately */
uint32_t clock_stop_ovr : 1;
uint32_t rsvd1 : 14;
} __packed;
union dai_intel_ipc4_ssp_dma_control {
struct dai_intel_ipc4_ssp_control {
struct dai_intel_ipc4_ssp_start_control start_control;
struct dai_intel_ipc4_ssp_stop_control stop_control;
} control_data;
struct dai_intel_ipc4_mn_div_config {
uint32_t mval;
uint32_t nval;
} mndiv_control_data;
} __packed;
struct dai_intel_ipc4_ssp_configuration_blob {
union dai_intel_ipc4_gateway_attributes gw_attr;
/* TDM time slot mappings */
uint32_t tdm_ts_group[DAI_INTEL_I2S_TDM_MAX_SLOT_MAP_COUNT];
/* i2s port configuration */
struct dai_intel_ipc4_ssp_driver_config i2s_driver_config;
/* optional configuration parameters */
union dai_intel_ipc4_ssp_dma_control i2s_dma_control[0];
} __packed;
#endif

2021
drivers/dai/intel/ssp/ssp.c Normal file

File diff suppressed because it is too large Load diff

341
drivers/dai/intel/ssp/ssp.h Normal file
View file

@ -0,0 +1,341 @@
/*
* Copyright (c) 2022 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __INTEL_DAI_DRIVER_SSP_H__
#define __INTEL_DAI_DRIVER_SSP_H__
#include <stdint.h>
#include <drivers/dai.h>
#include "dai-params-intel-ipc3.h"
#include "dai-params-intel-ipc4.h"
#define DAI_INTEL_SSP_MASK(b_hi, b_lo) \
(((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL) << (b_lo))
#define DAI_INTEL_SSP_SET_BIT(b, x) (((x) & 1) << (b))
#define DAI_INTEL_SSP_SET_BITS(b_hi, b_lo, x) \
(((x) & ((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL)) << (b_lo))
#define DAI_INTEL_SSP_GET_BIT(b, x) \
(((x) & (1ULL << (b))) >> (b))
#define DAI_INTEL_SSP_GET_BITS(b_hi, b_lo, x) \
(((x) & MASK(b_hi, b_lo)) >> (b_lo))
/* ssp_freq array constants */
#define DAI_INTEL_SSP_NUM_FREQ 3
#define DAI_INTEL_SSP_MAX_FREQ_INDEX (DAI_INTEL_SSP_NUM_FREQ - 1)
#define DAI_INTEL_SSP_DEFAULT_IDX 1
/* the SSP port fifo depth */
#define DAI_INTEL_SSP_FIFO_DEPTH 16
/* the watermark for the SSP fifo depth setting */
#define DAI_INTEL_SSP_FIFO_WATERMARK 8
/* minimal SSP port delay in cycles */
#define DAI_INTEL_SSP_PLATFORM_DELAY 1600
/* minimal SSP port delay in useconds */
#define DAI_INTEL_SSP_PLATFORM_DELAY_US 42
#define DAI_INTEL_SSP_PLATFORM_DEFAULT_DELAY 12
#define DAI_INTEL_SSP_DEFAULT_TRY_TIMES 8
#if CONFIG_SOC_SERIES_INTEL_CAVS_V15
/** \brief Number of 'base' SSP ports available */
#define DAI_INTEL_SSP_NUM_BASE 4
/** \brief Number of 'extended' SSP ports available */
#define DAI_INTEL_SSP_NUM_EXT 2
#else
/** \brief Number of 'base' SSP ports available */
#define DAI_INTEL_SSP_NUM_BASE 6
/** \brief Number of 'extended' SSP ports available */
#define DAI_INTEL_SSP_NUM_EXT 0
#endif
/** \brief Number of SSP MCLKs available */
#define DAI_INTEL_SSP_NUM_MCLK 2
#define DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR 0x0
#define DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL 0x1
#define DAI_INTEL_SSP_CLOCK_PLL_FIXED 0x2
/* SSP register offsets */
#define SSCR0 0x00
#define SSCR1 0x04
#define SSSR 0x08
#define SSITR 0x0C
#define SSDR 0x10
#define SSTO 0x28
#define SSPSP 0x2C
#define SSTSA 0x30
#define SSRSA 0x34
#define SSTSS 0x38
#define SSCR2 0x40
/* SSCR0 bits */
#define SSCR0_DSIZE(x) DAI_INTEL_SSP_SET_BITS(3, 0, (x) - 1)
#define SSCR0_DSIZE_GET(x) (((x) & DAI_INTEL_SSP_MASK(3, 0)) + 1)
#define SSCR0_FRF DAI_INTEL_SSP_MASK(5, 4)
#define SSCR0_MOT DAI_INTEL_SSP_SET_BITS(5, 4, 0)
#define SSCR0_TI DAI_INTEL_SSP_SET_BITS(5, 4, 1)
#define SSCR0_NAT DAI_INTEL_SSP_SET_BITS(5, 4, 2)
#define SSCR0_PSP DAI_INTEL_SSP_SET_BITS(5, 4, 3)
#define SSCR0_ECS BIT(6)
#define SSCR0_SSE BIT(7)
#define SSCR0_SCR_MASK DAI_INTEL_SSP_MASK(19, 8)
#define SSCR0_SCR(x) DAI_INTEL_SSP_SET_BITS(19, 8, x)
#define SSCR0_EDSS BIT(20)
#define SSCR0_NCS BIT(21)
#define SSCR0_RIM BIT(22)
#define SSCR0_TIM BIT(23)
#define SSCR0_FRDC(x) DAI_INTEL_SSP_SET_BITS(26, 24, (x) - 1)
#define SSCR0_FRDC_GET(x) ((((x) & DAI_INTEL_SSP_MASK(26, 24)) >> 24) + 1)
#define SSCR0_ACS BIT(30)
#define SSCR0_MOD BIT(31)
/* SSCR1 bits */
#define SSCR1_RIE BIT(0)
#define SSCR1_TIE BIT(1)
#define SSCR1_LBM BIT(2)
#define SSCR1_SPO BIT(3)
#define SSCR1_SPH BIT(4)
#define SSCR1_MWDS BIT(5)
#define SSCR1_TFT_MASK DAI_INTEL_SSP_MASK(9, 6)
#define SSCR1_TFT(x) DAI_INTEL_SSP_SET_BITS(9, 6, (x) - 1)
#define SSCR1_RFT_MASK DAI_INTEL_SSP_MASK(13, 10)
#define SSCR1_RFT(x) DAI_INTEL_SSP_SET_BITS(13, 10, (x) - 1)
#define SSCR1_EFWR BIT(14)
#define SSCR1_STRF BIT(15)
#define SSCR1_IFS BIT(16)
#define SSCR1_PINTE BIT(18)
#define SSCR1_TINTE BIT(19)
#define SSCR1_RSRE BIT(20)
#define SSCR1_TSRE BIT(21)
#define SSCR1_TRAIL BIT(22)
#define SSCR1_RWOT BIT(23)
#define SSCR1_SFRMDIR BIT(24)
#define SSCR1_SCLKDIR BIT(25)
#define SSCR1_ECRB BIT(26)
#define SSCR1_ECRA BIT(27)
#define SSCR1_SCFR BIT(28)
#define SSCR1_EBCEI BIT(29)
#define SSCR1_TTE BIT(30)
#define SSCR1_TTELP BIT(31)
#define SSCR2_TURM1 BIT(1)
#define SSCR2_PSPSRWFDFD BIT(3)
#define SSCR2_PSPSTWFDFD BIT(4)
#define SSCR2_SDFD BIT(14)
#define SSCR2_SDPM BIT(16)
#define SSCR2_LJDFD BIT(17)
#define SSCR2_MMRATF BIT(18)
#define SSCR2_SMTATF BIT(19)
/* SSR bits */
#define SSSR_TNF BIT(2)
#define SSSR_RNE BIT(3)
#define SSSR_BSY BIT(4)
#define SSSR_TFS BIT(5)
#define SSSR_RFS BIT(6)
#define SSSR_ROR BIT(7)
#define SSSR_TUR BIT(21)
/* SSPSP bits */
#define SSPSP_SCMODE(x) DAI_INTEL_SSP_SET_BITS(1, 0, x)
#define SSPSP_SFRMP(x) DAI_INTEL_SSP_SET_BIT(2, x)
#define SSPSP_ETDS BIT(3)
#define SSPSP_STRTDLY(x) DAI_INTEL_SSP_SET_BITS(6, 4, x)
#define SSPSP_DMYSTRT(x) DAI_INTEL_SSP_SET_BITS(8, 7, x)
#define SSPSP_SFRMDLY(x) DAI_INTEL_SSP_SET_BITS(15, 9, x)
#define SSPSP_SFRMWDTH(x) DAI_INTEL_SSP_SET_BITS(21, 16, x)
#define SSPSP_DMYSTOP(x) DAI_INTEL_SSP_SET_BITS(24, 23, x)
#define SSPSP_DMYSTOP_BITS 2
#define SSPSP_DMYSTOP_MASK DAI_INTEL_SSP_MASK(SSPSP_DMYSTOP_BITS - 1, 0)
#define SSPSP_FSRT BIT(25)
#define SSPSP_EDMYSTOP(x) DAI_INTEL_SSP_SET_BITS(28, 26, x)
#define SSPSP2 0x44
#define SSPSP2_FEP_MASK 0xff
#define SSCR3 0x48
#define SSIOC 0x4C
#define SSP_REG_MAX SSIOC
/* SSTSA bits */
#define SSTSA_SSTSA(x) DAI_INTEL_SSP_SET_BITS(7, 0, x)
#define SSTSA_GET(x) ((x) & DAI_INTEL_SSP_MASK(7, 0))
#define SSTSA_TXEN BIT(8)
/* SSRSA bits */
#define SSRSA_SSRSA(x) DAI_INTEL_SSP_SET_BITS(7, 0, x)
#define SSRSA_GET(x) ((x) & DAI_INTEL_SSP_MASK(7, 0))
#define SSRSA_RXEN BIT(8)
/* SSCR3 bits */
#define SSCR3_FRM_MST_EN BIT(0)
#define SSCR3_I2S_MODE_EN BIT(1)
#define SSCR3_I2S_FRM_POL(x) DAI_INTEL_SSP_SET_BIT(2, x)
#define SSCR3_I2S_TX_SS_FIX_EN BIT(3)
#define SSCR3_I2S_RX_SS_FIX_EN BIT(4)
#define SSCR3_I2S_TX_EN BIT(9)
#define SSCR3_I2S_RX_EN BIT(10)
#define SSCR3_CLK_EDGE_SEL BIT(12)
#define SSCR3_STRETCH_TX BIT(14)
#define SSCR3_STRETCH_RX BIT(15)
#define SSCR3_MST_CLK_EN BIT(16)
#define SSCR3_SYN_FIX_EN BIT(17)
/* SSCR4 bits */
#define SSCR4_TOT_FRM_PRD(x) ((x) << 7)
/* SSCR5 bits */
#define SSCR5_FRM_ASRT_CLOCKS(x) (((x) - 1) << 1)
#define SSCR5_FRM_POLARITY(x) DAI_INTEL_SSP_SET_BIT(0, x)
/* SFIFOTT bits */
#define SFIFOTT_TX(x) ((x) - 1)
#define SFIFOTT_RX(x) (((x) - 1) << 16)
/* SFIFOL bits */
#define SFIFOL_TFL(x) ((x) & 0xFFFF)
#define SFIFOL_RFL(x) ((x) >> 16)
#define SSTSA_TSEN BIT(8)
#define SSRSA_RSEN BIT(8)
#define SSCR3_TFL_MASK DAI_INTEL_SSP_MASK(5, 0)
#define SSCR3_RFL_MASK DAI_INTEL_SSP_MASK(13, 8)
#define SSCR3_TFL_VAL(scr3_val) (((scr3_val) >> 0) & DAI_INTEL_SSP_MASK(5, 0))
#define SSCR3_RFL_VAL(scr3_val) (((scr3_val) >> 8) & DAI_INTEL_SSP_MASK(5, 0))
#define SSCR3_TX(x) DAI_INTEL_SSP_SET_BITS(21, 16, (x) - 1)
#define SSCR3_RX(x) DAI_INTEL_SSP_SET_BITS(29, 24, (x) - 1)
#define SSIOC_TXDPDEB BIT(1)
#define SSIOC_SFCR BIT(4)
#define SSIOC_SCOE BIT(5)
/* For 8000 Hz rate one sample is transmitted within 125us */
#define DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE 125
/* SSP flush retry counts maximum */
#define DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX 16
#define SSP_CLK_MCLK_ES_REQ BIT(0)
#define SSP_CLK_MCLK_ACTIVE BIT(1)
#define SSP_CLK_BCLK_ES_REQ BIT(2)
#define SSP_CLK_BCLK_ACTIVE BIT(3)
#define I2SLCTL_OFFSET 0x04
#define I2SLCTL_SPA(x) BIT(0 + x)
#define I2SLCTL_CPA(x) BIT(8 + x)
#define SHIM_CLKCTL 0x78
#define SHIM_CLKCTL_I2SFDCGB(x) BIT(20 + x)
#define SHIM_CLKCTL_I2SEFDCGB(x) BIT(18 + x)
/** \brief Offset of MCLK Divider Control Register. */
#define MN_MDIVCTRL 0x0
/** \brief Enables the output of MCLK Divider. */
#define MN_MDIVCTRL_M_DIV_ENABLE(x) BIT(x)
/** \brief Offset of MCLK Divider x Ratio Register. */
#define MN_MDIVR(x) (0x80 + (x) * 0x4)
/** \brief Bits for setting MCLK source clock. */
#define MCDSS(x) DAI_INTEL_SSP_SET_BITS(17, 16, x)
/** \brief Offset of BCLK x M/N Divider M Value Register. */
#define MN_MDIV_M_VAL(x) (0x100 + (x) * 0x8 + 0x0)
/** \brief Offset of BCLK x M/N Divider N Value Register. */
#define MN_MDIV_N_VAL(x) (0x100 + (x) * 0x8 + 0x4)
/** \brief Bits for setting M/N source clock. */
#define MNDSS(x) DAI_INTEL_SSP_SET_BITS(21, 20, x)
/** \brief Mask for clearing mclk and bclk source in MN_MDIVCTRL */
#define MN_SOURCE_CLKS_MASK 0x3
#if CONFIG_INTEL_MN
/** \brief BCLKs can be driven by multiple sources - M/N or XTAL directly.
* Even in the case of M/N, the actual clock source can be XTAL,
* Audio cardinal clock (24.576) or 96 MHz PLL.
* The MN block is not really the source of clocks, but rather
* an intermediate component.
* Input for source is shared by all outputs coming from that source
* and once it's in use, it can be adjusted only with dividers.
* In order to change input, the source should not be in use, that's why
* it's necessary to keep track of BCLKs sources to know when it's safe
* to change shared input clock.
*/
enum bclk_source {
MN_BCLK_SOURCE_NONE = 0, /**< port is not using any clock */
MN_BCLK_SOURCE_MN, /**< port is using clock driven by M/N */
MN_BCLK_SOURCE_XTAL, /**< port is using XTAL directly */
};
#endif
struct dai_intel_ssp_mn {
uint32_t base;
/**< keep track of which MCLKs are in use to know when it's safe to
* change shared clock
*/
int mclk_sources_ref[DAI_INTEL_SSP_NUM_MCLK];
int mclk_rate[DAI_INTEL_SSP_NUM_MCLK];
int mclk_source_clock;
#if CONFIG_INTEL_MN
enum bclk_source bclk_sources[(DAI_INTEL_SSP_NUM_BASE + DAI_INTEL_SSP_NUM_EXT)];
int bclk_source_mn_clock;
#endif
struct k_spinlock lock; /**< lock mechanism */
};
struct dai_intel_ssp_freq_table {
uint32_t freq;
uint32_t ticks_per_msec;
};
struct dai_intel_ssp_plat_fifo_data {
uint32_t offset;
uint32_t width;
uint32_t depth;
uint32_t watermark;
uint32_t handshake;
};
struct dai_intel_ssp_plat_data {
uint32_t base;
uint32_t ip_base;
uint32_t shim_base;
int irq;
const char *irq_name;
uint32_t flags;
struct dai_intel_ssp_plat_fifo_data fifo[2];
struct dai_intel_ssp_mn *mn_inst;
struct dai_intel_ssp_freq_table *ftable;
uint32_t *fsources;
};
struct dai_intel_ssp_pdata {
uint32_t sscr0;
uint32_t sscr1;
uint32_t psp;
uint32_t state[2];
uint32_t clk_active;
struct dai_config config;
struct dai_properties props;
struct dai_intel_ipc3_ssp_params params;
};
struct dai_intel_ssp {
uint32_t index; /**< index */
struct k_spinlock lock; /**< locking mechanism */
int sref; /**< simple ref counter, guarded by lock */
struct dai_intel_ssp_plat_data plat_data;
void *priv_data;
};
#endif

View file

@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(adsp_ssp)
target_sources(app PRIVATE src/main.c)