diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index 447a31c235f872..fc6ad9d322401f 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -18,24 +18,98 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include "ssp.h" -#define DT_DRV_COMPAT intel_ssp_dai #define dai_set_drvdata(dai, data) (dai->priv_data = data) #define dai_get_drvdata(dai) dai->priv_data -#define dai_get_mn(dai) dai->plat_data.mn_inst -#define dai_get_ftable(dai) dai->plat_data.ftable -#define dai_get_fsources(dai) dai->plat_data.fsources -#define dai_mn_base(dai) dai->plat_data.mn_inst->base -#define dai_base(dai) dai->plat_data.base -#define dai_ip_base(dai) dai->plat_data.ip_base -#define dai_shim_base(dai) dai->plat_data.shim_base -#define dai_hdamlssp_base(dai) dai->plat_data.hdamlssp_base -#define dai_i2svss_base(dai) dai->plat_data.i2svss_base +#define dai_get_ssp_link(dai) dai->ssp_link +#define dai_get_mn(dai) dai->ssp_link->ssp_plat_data.mn_inst +#define dai_get_ftable(dai) dai->ssp_link->ssp_plat_data.ftable +#define dai_get_fsources(dai) dai->ssp_link->ssp_plat_data.fsources +#define dai_mn_base(dai) dai->ssp_link->ssp_plat_data.mn_inst->base +#define dai_base(dai) dai->ssp_link->ssp_plat_data.base +#define dai_ip_base(dai) dai->ssp_link->ssp_plat_data.ip_base +#define dai_shim_base(dai) dai->ssp_link->ssp_plat_data.shim_base +#define dai_hdamlssp_base(dai) dai->ssp_link->ssp_plat_data.hdamlssp_base +#define dai_i2svss_base(dai) dai->ssp_link->ssp_plat_data.i2svss_base #define DAI_DIR_PLAYBACK 0 #define DAI_DIR_CAPTURE 1 #define SSP_ARRAY_INDEX(dir) dir == DAI_DIR_RX ? DAI_DIR_CAPTURE : DAI_DIR_PLAYBACK +static const char irq_name_level5_z[] = "level5"; + +static struct dai_intel_ssp_freq_table ssp_freq_table[] = { + { DT_PROP(DT_NODELABEL(audioclk), clock_frequency), + DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000}, + { DT_PROP(DT_NODELABEL(sysclk), clock_frequency), + DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000}, + { DT_PROP(DT_NODELABEL(pllclk), clock_frequency), + DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000}, +}; + +static uint32_t ssp_freq_sources[] = { + DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL, + DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR, + DAI_INTEL_SSP_CLOCK_PLL_FIXED, +}; + +static struct dai_intel_ssp_mn ssp_mn_divider = { + .base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssplink0), 1), +}; + +#define INTEL_SSP_LINK_INST_DEFINE(node_id) { \ + .link_idx = DT_PROP(node_id, link), \ + .acquire_count = 0, \ + .is_initialized = false, \ + .ssp_plat_data = { \ + .base = DT_REG_ADDR_BY_IDX(node_id, 0), \ + IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(sspbase)), \ + (.ip_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(sspbase), 0),)) \ + .shim_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(shim), 0), \ + IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)), \ + (.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),)) \ + IF_ENABLED(DT_PROP_HAS_IDX(node_id, i2svss, 0), \ + (.i2svss_base = DT_PROP_BY_IDX(node_id, i2svss, 0),)) \ + .irq = DT_NUM_IRQS(node_id), \ + .irq_name = irq_name_level5_z, \ + .fifo[DAI_DIR_PLAYBACK].offset = \ + DT_REG_ADDR_BY_IDX(node_id, 0) + SSDR, \ + .fifo[DAI_DIR_PLAYBACK].handshake = \ + DT_DMAS_CELL_BY_NAME(node_id, tx, channel), \ + .fifo[DAI_DIR_CAPTURE].offset = \ + DT_REG_ADDR_BY_IDX(node_id, 0) + SSDR, \ + .fifo[DAI_DIR_CAPTURE].handshake = \ + DT_DMAS_CELL_BY_NAME(node_id, rx, channel), \ + .mn_inst = &ssp_mn_divider, \ + .ftable = ssp_freq_table, \ + .fsources = ssp_freq_sources, \ + }, \ +}, + +static struct intel_ssp_link ssp_link_table[] = { + DT_FOREACH_STATUS_OKAY(intel_ssp_link, INTEL_SSP_LINK_INST_DEFINE) +}; + +static uint32_t ssp_get_link_count(void) +{ + return ARRAY_SIZE(ssp_link_table); +} + + +static struct intel_ssp_link *ssp_get_link(uint32_t link_idx) +{ + uint32_t link_count = ssp_get_link_count(); + uint32_t i; + + for (i = 0; i < link_count; i++) { + if (ssp_link_table[i].link_idx == link_idx) { + return &ssp_link_table[i]; + } + } + + return NULL; +} + static void dai_ssp_update_bits(struct dai_intel_ssp *dp, uint32_t reg, uint32_t mask, uint32_t val) { uint32_t dest = dai_base(dp) + reg; @@ -45,6 +119,25 @@ static void dai_ssp_update_bits(struct dai_intel_ssp *dp, uint32_t reg, uint32_t sys_write32((sys_read32(dest) & (~mask)) | (val & mask), dest); } +static void ssp_acquire_link(struct intel_ssp_link *link) +{ + link->acquire_count++; +} + +static void ssp_release_link(struct intel_ssp_link *link) +{ + if (link->acquire_count == 0) { + return; + } + + --link->acquire_count; +} + +static bool ssp_link_is_acquired(struct intel_ssp_link *link) +{ + return (link->acquire_count != 0); +} + #if CONFIG_INTEL_MN static int dai_ssp_gcd(int a, int b) { @@ -706,27 +799,27 @@ static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp #endif } -static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t index) +static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t link_idx) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; LOG_INF("SSP%d", dp->index); #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS - sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(index), + sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(link_idx), dai_ip_base(dp) + I2SLCTL_OFFSET); /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(link_idx), I2SLCTL_CPA(link_idx), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) | - I2SLCTL_SPA(index), + I2SLCTL_SPA(link_idx), dai_hdamlssp_base(dp) + I2SLCTL_OFFSET); /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(link_idx), I2SLCTL_CPA(link_idx), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC @@ -736,31 +829,31 @@ static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t i } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(link_idx); #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */ } -static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t index) +static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t link_idx) { #if CONFIG_DAI_SSP_HAS_POWER_CONTROL int ret; LOG_INF("SSP%d", dp->index); #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS - sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)), + sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(link_idx)), dai_ip_base(dp) + I2SLCTL_OFFSET); /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(link_idx), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL - sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)), + sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(link_idx)), dai_hdamlssp_base(dp) + I2SLCTL_OFFSET); /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(link_idx), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC @@ -770,7 +863,7 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t } #else ARG_UNUSED(dp); - ARG_UNUSED(index); + ARG_UNUSED(link_idx); #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */ } @@ -779,12 +872,10 @@ static void dai_ssp_program_channel_map(struct dai_intel_ssp *dp, { #ifdef CONFIG_SOC_INTEL_ACE20_LNL uint16_t pcmsycm = cfg->link_config; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + /* Set upper slot number from configuration */ + pcmsycm = pcmsycm | (dp->ssp_link->params.tdm_slots - 1) << 4; - /* Set upper slot number from configuration */ - pcmsycm = pcmsycm | (ssp->params.tdm_slots - 1) << 4; - - if (DAI_INTEL_SSP_IS_BIT_SET(pcmsycm, 15)) { + if (DAI_INTEL_SSP_IS_BIT_SET(cfg->link_config, 15)) { uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS0CM_OFFSET; /* Program HDA output stream parameters */ sys_write16((pcmsycm & 0xffff), reg_add); @@ -859,8 +950,9 @@ static void ssp_empty_rx_fifo_on_start(struct dai_intel_ssp *dp) static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - uint64_t sample_ticks = ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0; + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); + uint64_t sample_ticks = ssp_link->params.fsync_rate ? 1000000 / + ssp_link->params.fsync_rate : 0; uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX; uint32_t entries[2]; uint32_t i, sssr; @@ -900,20 +992,20 @@ static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp) static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); int ret; - if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE) { + if (ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ACTIVE) { return 0; } /* MCLK config */ - ret = dai_ssp_mn_set_mclk(dp, ssp->params.mclk_id, ssp->params.mclk_rate); + ret = dai_ssp_mn_set_mclk(dp, ssp_link->params.mclk_id, ssp_link->params.mclk_rate); if (ret < 0) { - LOG_ERR("invalid mclk_rate = %d for mclk_id = %d", ssp->params.mclk_rate, - ssp->params.mclk_id); + LOG_ERR("invalid mclk_rate = %d for mclk_id = %d", ssp_link->params.mclk_rate, + ssp_link->params.mclk_id); } else { - ssp->clk_active |= SSP_CLK_MCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_MCLK_ACTIVE; } return ret; @@ -921,15 +1013,15 @@ static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp) static void dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); - if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ACTIVE)) { return; } - dai_ssp_mn_release_mclk(dp, ssp->params.mclk_id); + dai_ssp_mn_release_mclk(dp, ssp_link->params.mclk_id); - ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_MCLK_ACTIVE; } static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) @@ -937,14 +1029,13 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) #if !(CONFIG_INTEL_MN) struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp); #endif - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - struct dai_config *config = &ssp->config; + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); uint32_t sscr0; uint32_t mdiv; bool need_ecs = false; int ret = 0; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE) { return 0; } @@ -952,22 +1043,22 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) #if CONFIG_INTEL_MN /* BCLK config */ - ret = dai_ssp_mn_set_bclk(dp, config->dai_index, ssp->params.bclk_rate, + ret = dai_ssp_mn_set_bclk(dp, ssp_link->link_idx, ssp_link->params.bclk_rate, &mdiv, &need_ecs); if (ret < 0) { - LOG_ERR("invalid bclk_rate = %d for dai_index = %d", - ssp->params.bclk_rate, config->dai_index); + LOG_ERR("invalid bclk_rate = %d for link_idx = %d", + ssp_link->params.bclk_rate, ssp_link->link_idx); goto out; } #else - if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp->params.bclk_rate != 0) { - LOG_ERR("invalid bclk_rate = %d for dai_index = %d", - ssp->params.bclk_rate, config->dai_index); + if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp_link->params.bclk_rate != 0) { + LOG_ERR("invalid bclk_rate = %d for link_idx = %d", + ssp_link->params.bclk_rate, ssp_link->link_idx); ret = -EINVAL; goto out; } - mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp->params.bclk_rate; + mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp_link->params.bclk_rate; #endif if (need_ecs) { @@ -993,7 +1084,7 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) LOG_INF("sscr0 = 0x%08x", sscr0); out: if (!ret) { - ssp->clk_active |= SSP_CLK_BCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_BCLK_ACTIVE; } return ret; @@ -1001,29 +1092,30 @@ static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp) static void dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE)) { return; } #if CONFIG_INTEL_MN - dai_ssp_mn_release_bclk(dp, dp->index); + dai_ssp_mn_release_bclk(dp, ssp_link->link_idx); #endif - ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE; + ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_BCLK_ACTIVE; } static void dai_ssp_log_ssp_data(struct dai_intel_ssp *dp) { LOG_INF("dai index: %u", dp->index); - LOG_INF("plat_data base: %u", dp->plat_data.base); - LOG_INF("plat_data irq: %u", dp->plat_data.irq); - LOG_INF("plat_data fifo playback offset: %u", dp->plat_data.fifo[DAI_DIR_PLAYBACK].offset); + LOG_INF("plat_data base: %u", dp->ssp_link->ssp_plat_data.base); + LOG_INF("plat_data irq: %u", dp->ssp_link->ssp_plat_data.irq); + LOG_INF("plat_data fifo playback offset: %u", + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_PLAYBACK].offset); LOG_INF("plat_data fifo playback handshake: %u", - dp->plat_data.fifo[DAI_DIR_PLAYBACK].handshake); + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_PLAYBACK].handshake); LOG_INF("plat_data fifo capture offset: %u", - dp->plat_data.fifo[DAI_DIR_CAPTURE].offset); + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_CAPTURE].offset); LOG_INF("plat_data fifo capture handshake: %u", - dp->plat_data.fifo[DAI_DIR_CAPTURE].handshake); + dp->ssp_link->ssp_plat_data.fifo[DAI_DIR_CAPTURE].handshake); } /* Digital Audio interface formatting */ @@ -1066,14 +1158,16 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co key = k_spin_lock(&dp->lock); /* ignore config if SSP is already configured */ - if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || - ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) { - if (!memcmp(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params))) { + if (dp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || + dp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) { + if (!memcmp(&dp->ssp_link->params, bespoke_cfg, + sizeof(struct dai_intel_ipc3_ssp_params))) { LOG_INF("Already configured. Ignore config"); goto clk; } - if (ssp->clk_active & (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) { + if (dp->ssp_link->ssp_plat_data.clk_active & + (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) { LOG_WRN("SSP active, cannot change config"); goto clk; } @@ -1104,7 +1198,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sspsp = 0; ssp->config = *config; - memcpy(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params)); + memcpy(&dp->ssp_link->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params)); /* sspsp2 no dynamic setting */ sspsp2 = 0x0; @@ -1116,10 +1210,10 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co ssto = 0x0; /* sstsa dynamic setting is TTSA, default 2 slots */ - sstsa = SSTSA_SSTSA(ssp->params.tx_slots); + sstsa = SSTSA_SSTSA(dp->ssp_link->params.tx_slots); /* ssrsa dynamic setting is RTSA, default 2 slots */ - ssrsa = SSRSA_SSRSA(ssp->params.rx_slots); + ssrsa = SSRSA_SSRSA(dp->ssp_link->params.rx_slots); switch (config->format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) { case DAI_INTEL_IPC3_SSP_FMT_CBP_CFP: @@ -1166,7 +1260,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co } /* supporting bclk idle state */ - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) { + if (dp->ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) { /* bclk idle state high */ sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3); } else { @@ -1179,20 +1273,20 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* Additional hardware settings */ /* Receiver Time-out Interrupt Disabled/Enabled */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ? + sscr1 |= (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ? SSCR1_TINTE : 0; /* Peripheral Trailing Byte Interrupts Disable/Enable */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ? + sscr1 |= (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ? SSCR1_PINTE : 0; /* Enable/disable internal loopback. Output of transmit serial * shifter connected to input of receive serial shifter, internally. */ - sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ? + sscr1 |= (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ? SSCR1_LBM : 0; - if (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { + if (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) { LOG_INF("going for loopback!"); } else { LOG_INF("no loopback!"); @@ -1201,69 +1295,70 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* Transmit data are driven at the same/opposite clock edge specified * in SSPSP.SCMODE[1:0] */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ? + sscr2 |= (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ? SSCR2_SMTATF : 0; /* Receive data are sampled at the same/opposite clock edge specified * in SSPSP.SCMODE[1:0] */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ? + sscr2 |= (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ? SSCR2_MMRATF : 0; /* Enable/disable the fix for PSP consumer mode TXD wait for frame * de-assertion before starting the second channel */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ? + sscr2 |= (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ? SSCR2_PSPSTWFDFD : 0; /* Enable/disable the fix for PSP provider mode FSRT with dummy stop & * frame end padding capability */ - sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ? + sscr2 |= (dp->ssp_link->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ? SSCR2_PSPSRWFDFD : 0; - if (!ssp->params.mclk_rate || - ssp->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) { - LOG_ERR("invalid MCLK = %d Hz (valid < %d)", ssp->params.mclk_rate, + if (!dp->ssp_link->params.mclk_rate || + dp->ssp_link->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) { + LOG_ERR("invalid MCLK = %d Hz (valid < %d)", dp->ssp_link->params.mclk_rate, ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq); ret = -EINVAL; goto out; } - if (!ssp->params.bclk_rate || ssp->params.bclk_rate > ssp->params.mclk_rate) { - LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", ssp->params.bclk_rate, - ssp->params.mclk_rate); + if (!dp->ssp_link->params.bclk_rate || + dp->ssp_link->params.bclk_rate > dp->ssp_link->params.mclk_rate) { + LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", dp->ssp_link->params.bclk_rate, + dp->ssp_link->params.mclk_rate); ret = -EINVAL; goto out; } /* calc frame width based on BCLK and rate - must be divisible */ - if (ssp->params.bclk_rate % ssp->params.fsync_rate) { - LOG_ERR("BCLK %d is not divisible by rate %d", ssp->params.bclk_rate, - ssp->params.fsync_rate); + if (dp->ssp_link->params.bclk_rate % dp->ssp_link->params.fsync_rate) { + LOG_ERR("BCLK %d is not divisible by rate %d", dp->ssp_link->params.bclk_rate, + dp->ssp_link->params.fsync_rate); ret = -EINVAL; goto out; } /* must be enough BCLKs for data */ - bdiv = ssp->params.bclk_rate / ssp->params.fsync_rate; - if (bdiv < ssp->params.tdm_slot_width * ssp->params.tdm_slots) { + bdiv = dp->ssp_link->params.bclk_rate / dp->ssp_link->params.fsync_rate; + if (bdiv < dp->ssp_link->params.tdm_slot_width * dp->ssp_link->params.tdm_slots) { LOG_ERR("not enough BCLKs need %d", - ssp->params.tdm_slot_width * ssp->params.tdm_slots); + dp->ssp_link->params.tdm_slot_width * dp->ssp_link->params.tdm_slots); ret = -EINVAL; goto out; } /* tdm_slot_width must be <= 38 for SSP */ - if (ssp->params.tdm_slot_width > 38) { - LOG_ERR("tdm_slot_width %d > 38", ssp->params.tdm_slot_width); + if (dp->ssp_link->params.tdm_slot_width > 38) { + LOG_ERR("tdm_slot_width %d > 38", dp->ssp_link->params.tdm_slot_width); ret = -EINVAL; goto out; } - bdiv_min = ssp->params.tdm_slots * - (ssp->params.tdm_per_slot_padding_flag ? - ssp->params.tdm_slot_width : ssp->params.sample_valid_bits); + bdiv_min = dp->ssp_link->params.tdm_slots * + (dp->ssp_link->params.tdm_per_slot_padding_flag ? + dp->ssp_link->params.tdm_slot_width : dp->ssp_link->params.sample_valid_bits); if (bdiv < bdiv_min) { LOG_ERR("bdiv(%d) < bdiv_min(%d)", bdiv, bdiv_min); ret = -EINVAL; @@ -1283,7 +1378,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co start_delay = true; - sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_FRDC(dp->ssp_link->params.tdm_slots); if (bdiv % 2) { LOG_ERR("bdiv %d is not divisible by 2", bdiv); @@ -1331,7 +1426,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* default start_delay value is set to false */ - sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_FRDC(dp->ssp_link->params.tdm_slots); /* LJDFD enable */ sscr2 &= ~SSCR2_LJDFD; @@ -1387,19 +1482,19 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co /* default start_delay value is set to false */ - sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp->params.tdm_slots); + sscr0 |= SSCR0_MOD | SSCR0_FRDC(dp->ssp_link->params.tdm_slots); /* set asserted frame length */ frame_len = 1; /* default */ - if (cfs && ssp->params.frame_pulse_width > 0 && - ssp->params.frame_pulse_width <= + if (cfs && dp->ssp_link->params.frame_pulse_width > 0 && + dp->ssp_link->params.frame_pulse_width <= DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) { - frame_len = ssp->params.frame_pulse_width; + frame_len = dp->ssp_link->params.frame_pulse_width; } /* frame_pulse_width must less or equal 38 */ - if (ssp->params.frame_pulse_width > + if (dp->ssp_link->params.frame_pulse_width > DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) { LOG_ERR("frame_pulse_width > %d", DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX); ret = -EINVAL; @@ -1413,20 +1508,20 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co */ sspsp |= SSPSP_SFRMP(!inverted_frame); - active_tx_slots = POPCOUNT(ssp->params.tx_slots); - active_rx_slots = POPCOUNT(ssp->params.rx_slots); + active_tx_slots = POPCOUNT(dp->ssp_link->params.tx_slots); + active_rx_slots = POPCOUNT(dp->ssp_link->params.rx_slots); /* * handle TDM mode, TDM mode has padding at the end of * each slot. The amount of padding is equal to result of * subtracting slot width and valid bits per slot. */ - if (ssp->params.tdm_per_slot_padding_flag) { - frame_end_padding = bdiv - ssp->params.tdm_slots * - ssp->params.tdm_slot_width; + if (dp->ssp_link->params.tdm_per_slot_padding_flag) { + frame_end_padding = bdiv - dp->ssp_link->params.tdm_slots * + dp->ssp_link->params.tdm_slot_width; - slot_end_padding = ssp->params.tdm_slot_width - - ssp->params.sample_valid_bits; + slot_end_padding = dp->ssp_link->params.tdm_slot_width - + dp->ssp_link->params.sample_valid_bits; if (slot_end_padding > DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) { @@ -1456,7 +1551,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sspsp |= SSPSP_SFRMWDTH(frame_len); - data_size = ssp->params.sample_valid_bits; + data_size = dp->ssp_link->params.sample_valid_bits; if (data_size > 16) { sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16)); @@ -1465,7 +1560,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co } /* setting TFT and RFT */ - switch (ssp->params.sample_valid_bits) { + switch (dp->ssp_link->params.sample_valid_bits) { case 16: /* use 2 bytes for each slot */ sample_width = 2; @@ -1476,7 +1571,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co sample_width = 4; break; default: - LOG_ERR("sample_valid_bits %d", ssp->params.sample_valid_bits); + LOG_ERR("sample_valid_bits %d", dp->ssp_link->params.sample_valid_bits); ret = -EINVAL; goto out; } @@ -1506,27 +1601,27 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co LOG_INF("ssrsa = 0x%08x, sstsa = 0x%08x", ssrsa, sstsa); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; clk: switch (config->options & DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_CMD_MASK) { case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS: - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { + if (dp->ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { ret = dai_ssp_mclk_prepare_enable(dp); if (ret < 0) { goto out; } - ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; + dp->ssp_link->ssp_plat_data.clk_active |= SSP_CLK_MCLK_ES_REQ; LOG_INF("hw_params stage: enabled MCLK clocks for SSP%d...", dp->index); } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + if (dp->ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { bool enable_sse = false; - if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) { + if (!(dp->ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE)) { enable_sse = true; } @@ -1535,7 +1630,7 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co goto out; } - ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + dp->ssp_link->ssp_plat_data.clk_active |= SSP_CLK_BCLK_ES_REQ; if (enable_sse) { /* enable port */ @@ -1549,25 +1644,25 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co break; case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_FREE: /* disable SSP port if no users */ - if (ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING || - ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + if (dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING || + dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { LOG_INF("hw_free stage: ignore since SSP%d still in use", dp->index); break; } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { + if (dp->ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) { LOG_INF("hw_free stage: releasing BCLK clocks for SSP%d...", dp->index); - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (dp->ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE) { dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); LOG_INF("SSE clear for SSP%d", dp->index); } dai_ssp_bclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ; + dp->ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_BCLK_ES_REQ; } - if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { + if (dp->ssp_link->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) { LOG_INF("hw_free stage: releasing MCLK clocks for SSP%d...", dp->index); dai_ssp_mclk_disable_unprepare(dp); - ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ; + dp->ssp_link->ssp_plat_data.clk_active &= ~SSP_CLK_MCLK_ES_REQ; } break; default: @@ -1756,7 +1851,6 @@ static int dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp *dp, static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_config *cfg, const struct dai_intel_ipc4_ssp_config *regs) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); uint32_t ssc0, sstsa, ssrsa, sscr1; ssc0 = regs->ssc0; @@ -1794,18 +1888,18 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co LOG_INF(" ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x", regs->ssioc, ssrsa, sstsa); - ssp->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0); + dp->ssp_link->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0); if (ssc0 & SSCR0_EDSS) { - ssp->params.sample_valid_bits += 16; + dp->ssp_link->params.sample_valid_bits += 16; } - ssp->params.tdm_slots = SSCR0_FRDC_GET(ssc0); - ssp->params.tx_slots = SSTSA_GET(sstsa); - ssp->params.rx_slots = SSRSA_GET(ssrsa); - ssp->params.fsync_rate = cfg->rate; + dp->ssp_link->params.tdm_slots = SSCR0_FRDC_GET(ssc0); + dp->ssp_link->params.tx_slots = SSTSA_GET(sstsa); + dp->ssp_link->params.rx_slots = SSRSA_GET(ssrsa); + dp->ssp_link->params.fsync_rate = cfg->rate; - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; } static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_config *cfg, @@ -1813,13 +1907,15 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co { const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob15 = spec_config; const struct dai_intel_ipc4_ssp_configuration_blob *blob = spec_config; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); int err; /* set config only once for playback or capture */ - if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY || - ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) + if (ssp_link->is_initialized) { + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; return 0; + } if (blob15->version == SSP_BLOB_VER_1_5) { err = dai_ssp_parse_aux_data(dp, spec_config); @@ -1836,11 +1932,12 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co return err; } - ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_MCLK_ES_REQ; /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); - ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_link->ssp_plat_data.clk_active |= SSP_CLK_BCLK_ES_REQ; + ssp_link->is_initialized = true; return 0; } @@ -1852,14 +1949,14 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co */ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); int ret = 0; /* * We will test if mclk/bclk is configured in * ssp_mclk/bclk_prepare_enable/disable functions */ - if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ES_REQ)) { /* MCLK config */ ret = dai_ssp_mclk_prepare_enable(dp); if (ret < 0) { @@ -1867,7 +1964,7 @@ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) } } - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)) { ret = dai_ssp_bclk_prepare_enable(dp); } @@ -1881,16 +1978,16 @@ static int dai_ssp_pre_start(struct dai_intel_ssp *dp) */ static void dai_ssp_post_stop(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); /* release clocks if SSP is inactive */ - if (ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING && - ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) { - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING && + dp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)) { LOG_INF("releasing BCLK clocks for SSP%d...", dp->index); dai_ssp_bclk_disable_unprepare(dp); } - if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_MCLK_ES_REQ)) { LOG_INF("releasing MCLK clocks for SSP%d...", dp->index); dai_ssp_mclk_disable_unprepare(dp); } @@ -1899,7 +1996,7 @@ static void dai_ssp_post_stop(struct dai_intel_ssp *dp) static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); k_spinlock_key_t key; key = k_spin_lock(&dp->lock); @@ -1915,7 +2012,7 @@ static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction) /* request mclk/bclk */ dai_ssp_pre_start(dp); - if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { + if (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)) { /* enable port */ LOG_INF("SSP%d: set SSE", dp->index); dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); @@ -1944,7 +2041,7 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN); } - ssp->state[direction] = DAI_STATE_RUNNING; + dp->state[direction] = DAI_STATE_RUNNING; /* * Wait to get valid fifo status in clock consumer mode. TODO it's @@ -1968,6 +2065,7 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) { struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); k_spinlock_key_t key; key = k_spin_lock(&dp->lock); @@ -1988,64 +2086,68 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) /* stop Rx if neeed */ if (direction == DAI_DIR_CAPTURE && - ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { + dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { LOG_INF("SSP%d RX", dp->index); dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0); dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, 0); ssp_empty_rx_fifo_on_stop(dp); - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; + ssp_release_link(ssp_link); } /* stop Tx if needed */ if (direction == DAI_DIR_PLAYBACK && - ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { LOG_INF("SSP%d TX", dp->index); dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, 0); dai_ssp_empty_tx_fifo(dp); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, 0); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; + ssp_release_link(ssp_link); } /* disable SSP port if no users */ - if (ssp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING && - ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING && + if (dp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING && + dp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING && COND_CODE_1(CONFIG_INTEL_ADSP_CAVS, - (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { - LOG_INF("SSP%d: clear SSE", dp->index); - dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + (!(ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { + + if (!ssp_link_is_acquired(ssp_link)) { + dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + LOG_INF("%s SSE clear SSP%d", __func__, dp->index); + } } - dai_ssp_post_stop(dp); + if (!ssp_link_is_acquired(ssp_link)) { + dai_ssp_post_stop(dp); + } k_spin_unlock(&dp->lock, key); } static void dai_ssp_pause(struct dai_intel_ssp *dp, int direction) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - if (direction == DAI_DIR_CAPTURE) { LOG_INF("SSP%d RX", dp->index); } else { LOG_INF("SSP%d TX", dp->index); } - ssp->state[direction] = DAI_STATE_PAUSED; + dp->state[direction] = DAI_STATE_PAUSED; } static int dai_ssp_trigger(const struct device *dev, enum dai_dir dir, enum dai_trigger_cmd cmd) { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); int array_index = SSP_ARRAY_INDEX(dir); LOG_DBG("SSP%d: cmd %d", dp->index, cmd); switch (cmd) { case DAI_TRIGGER_START: - if (ssp->state[array_index] == DAI_STATE_PAUSED || - ssp->state[array_index] == DAI_STATE_PRE_RUNNING) { + if (dp->state[array_index] == DAI_STATE_PAUSED || + dp->state[array_index] == DAI_STATE_PRE_RUNNING) { dai_ssp_start(dp, array_index); } break; @@ -2070,6 +2172,7 @@ static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, struct dai_config *params = (struct dai_config *)dev->config; struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); if (!cfg) { return -EINVAL; @@ -2080,15 +2183,15 @@ static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, return 0; } - params->rate = ssp->params.fsync_rate; + params->rate = ssp_link->params.fsync_rate; if (dir == DAI_DIR_PLAYBACK) { - params->channels = POPCOUNT(ssp->params.tx_slots); + params->channels = POPCOUNT(ssp_link->params.tx_slots); } else { - params->channels = POPCOUNT(ssp->params.rx_slots); + params->channels = POPCOUNT(ssp_link->params.rx_slots); } - params->word_size = ssp->params.sample_valid_bits; + params->word_size = ssp_link->params.sample_valid_bits; *cfg = *params; @@ -2101,6 +2204,8 @@ static int dai_ssp_config_set(const struct device *dev, const struct dai_config struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; int ret; + ssp_acquire_link(dp->ssp_link); + if (cfg->type == DAI_INTEL_SSP) { ret = dai_ssp_set_config_tplg(dp, cfg, bespoke_cfg); } else { @@ -2115,16 +2220,17 @@ static const struct dai_properties *dai_ssp_get_properties(const struct device * { struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); struct dai_properties *prop = &ssp->props; int array_index = SSP_ARRAY_INDEX(dir); - prop->fifo_address = dp->plat_data.fifo[array_index].offset; - prop->dma_hs_id = dp->plat_data.fifo[array_index].handshake; + prop->fifo_address = ssp_link->ssp_plat_data.fifo[array_index].offset; + prop->dma_hs_id = dp->ssp_link->ssp_plat_data.fifo[array_index].handshake; - if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { + if (ssp_link->ssp_plat_data.clk_active & SSP_CLK_BCLK_ACTIVE) { prop->reg_init_delay = 0; } else { - prop->reg_init_delay = ssp->params.bclk_delay; + prop->reg_init_delay = ssp_link->params.bclk_delay; } LOG_INF("SSP%u: fifo %u, handshake %u, init delay %u", dp->index, prop->fifo_address, @@ -2135,6 +2241,7 @@ static const struct dai_properties *dai_ssp_get_properties(const struct device * static int dai_ssp_probe(struct dai_intel_ssp *dp) { + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); struct dai_intel_ssp_pdata *ssp; if (dai_get_drvdata(dp)) { @@ -2144,41 +2251,58 @@ static int dai_ssp_probe(struct dai_intel_ssp *dp) /* allocate private data */ ssp = k_calloc(1, sizeof(*ssp)); if (!ssp) { - LOG_ERR("SSP%d: alloc failed", dp->index); + LOG_ERR("SSP%d: alloc failed", ssp_link->link_idx); return -ENOMEM; } dai_set_drvdata(dp, ssp); - ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY; - ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY; + dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY; + dp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY; + + if (ssp_link->is_power_en) { + return 0; + } #if CONFIG_INTEL_MN /* Reset M/N, power-gating functions need it */ - dai_ssp_mn_reset_bclk_divider(dp, dp->index); + dai_ssp_mn_reset_bclk_divider(dp, ssp_link->link_idx); #endif /* Enable SSP power */ - dai_ssp_pm_runtime_en_ssp_power(dp, dp->index); + dai_ssp_pm_runtime_en_ssp_power(dp, ssp_link->link_idx); /* Disable dynamic clock gating before touching any register */ - dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, dp->index); + dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, ssp_link->link_idx); + + ssp_link->is_power_en = true; return 0; } static int dai_ssp_remove(struct dai_intel_ssp *dp) { - dai_ssp_pm_runtime_en_ssp_clk_gating(dp, dp->index); + struct intel_ssp_link *ssp_link = dai_get_ssp_link(dp); + + if (ssp_link_is_acquired(dp->ssp_link)) { + k_free(dai_get_drvdata(dp)); + dai_set_drvdata(dp, NULL); + return 0; + } + + dai_ssp_pm_runtime_en_ssp_clk_gating(dp, ssp_link->link_idx); dai_ssp_mclk_disable_unprepare(dp); dai_ssp_bclk_disable_unprepare(dp); /* Disable SSP power */ - dai_ssp_pm_runtime_dis_ssp_power(dp, dp->index); + dai_ssp_pm_runtime_dis_ssp_power(dp, ssp_link->link_idx); k_free(dai_get_drvdata(dp)); dai_set_drvdata(dp, NULL); + ssp_link->is_initialized = false; + ssp_link->is_power_en = false; + return 0; } @@ -2203,8 +2327,19 @@ static int ssp_pm_action(const struct device *dev, enum pm_device_action action) return 0; } +static int dai_intel_ssp_init_device(const struct device *dev) +{ + struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data; + + dp->ssp_link = ssp_get_link(dp->index); + + return 0; +}; + static int ssp_init(const struct device *dev) { + dai_intel_ssp_init_device(dev); + if (pm_device_on_power_domain(dev)) { pm_device_init_off(dev); } else { @@ -2223,66 +2358,26 @@ static struct dai_driver_api dai_intel_ssp_api_funcs = { .get_properties = dai_ssp_get_properties, }; -static struct dai_intel_ssp_freq_table ssp_freq_table[] = { - { DT_PROP(DT_NODELABEL(audioclk), clock_frequency), - DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000}, - { DT_PROP(DT_NODELABEL(sysclk), clock_frequency), - DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000}, - { DT_PROP(DT_NODELABEL(pllclk), clock_frequency), - DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000}, -}; - -static uint32_t ssp_freq_sources[] = { - DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL, - DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR, - DAI_INTEL_SSP_CLOCK_PLL_FIXED, -}; -static struct dai_intel_ssp_mn ssp_mn_divider = { - .base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssp0), 1), -}; +#define DT_DRV_COMPAT intel_ssp_dai -static const char irq_name_level5_z[] = "level5"; #define DAI_INTEL_SSP_DEVICE_INIT(n) \ - static struct dai_config dai_intel_ssp_config_##n = { \ - .type = DAI_INTEL_SSP, \ - .dai_index = n, \ - }; \ - static struct dai_intel_ssp dai_intel_ssp_data_##n = { \ - .index = n, \ - .plat_data = { \ - .base = DT_INST_REG_ADDR_BY_IDX(n, 0), \ - IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(sspbase)), \ - (.ip_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(sspbase), 0),))\ - .shim_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(shim), 0), \ - IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)), \ - (.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),))\ - IF_ENABLED(DT_INST_PROP_HAS_IDX(n, i2svss, 0), \ - (.i2svss_base = DT_INST_PROP_BY_IDX(n, i2svss, 0),))\ - .irq = n, \ - .irq_name = irq_name_level5_z, \ - .fifo[DAI_DIR_PLAYBACK].offset = \ - DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \ - .fifo[DAI_DIR_PLAYBACK].handshake = \ - DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ - .fifo[DAI_DIR_CAPTURE].offset = \ - DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \ - .fifo[DAI_DIR_CAPTURE].handshake = \ - DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ - .mn_inst = &ssp_mn_divider, \ - .ftable = ssp_freq_table, \ - .fsources = ssp_freq_sources, \ - }, \ - }; \ - \ + static struct dai_config dai_intel_ssp_config_##n = { \ + .type = DAI_INTEL_SSP, \ + .dai_index = DT_INST_REG_ADDR(n), \ + }; \ + static struct dai_intel_ssp dai_intel_ssp_data_##n = { \ + .index = DT_INST_PROP(n, link), \ + }; \ + \ PM_DEVICE_DT_INST_DEFINE(n, ssp_pm_action); \ - \ + \ DEVICE_DT_INST_DEFINE(n, \ - ssp_init, PM_DEVICE_DT_INST_GET(n), \ + ssp_init, PM_DEVICE_DT_INST_GET(n), \ &dai_intel_ssp_data_##n, \ &dai_intel_ssp_config_##n, \ - POST_KERNEL, 42, \ + POST_KERNEL, 42, \ &dai_intel_ssp_api_funcs); DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_SSP_DEVICE_INIT) diff --git a/drivers/dai/intel/ssp/ssp.h b/drivers/dai/intel/ssp/ssp.h index 5a187730dd538b..84b0d64a9be0d4 100644 --- a/drivers/dai/intel/ssp/ssp.h +++ b/drivers/dai/intel/ssp/ssp.h @@ -330,24 +330,32 @@ struct dai_intel_ssp_plat_data { struct dai_intel_ssp_mn *mn_inst; struct dai_intel_ssp_freq_table *ftable; uint32_t *fsources; + uint32_t clk_active; }; 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 intel_ssp_link { + uint32_t link_idx; + int acquire_count; + bool is_initialized; + bool is_power_en; + struct dai_intel_ssp_plat_data ssp_plat_data; struct dai_intel_ipc3_ssp_params params; }; struct dai_intel_ssp { uint32_t index; /**< index */ + uint32_t state[2]; struct k_spinlock lock; /**< locking mechanism */ int sref; /**< simple ref counter, guarded by lock */ - struct dai_intel_ssp_plat_data plat_data; + struct intel_ssp_link *ssp_link; void *priv_data; }; diff --git a/dts/bindings/i2s/intel,ssp-dai.yaml b/dts/bindings/i2s/intel,ssp-dai.yaml index 59a778baa1f580..262c3e4273e760 100644 --- a/dts/bindings/i2s/intel,ssp-dai.yaml +++ b/dts/bindings/i2s/intel,ssp-dai.yaml @@ -1,8 +1,7 @@ -# Copyright (c) 2022 Intel Corporation -# +# Copyright (c) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -description: Intel SSP DAI controller +description: Intel SSP DAI node compatible: "intel,ssp-dai" @@ -12,17 +11,6 @@ properties: reg: required: true - interrupts: + link: + type: int required: true - - interrupt-parent: - required: true - - dmas: - required: true - - dma-names: - required: true - - i2svss: - type: array diff --git a/dts/bindings/i2s/intel,ssp-link.yaml b/dts/bindings/i2s/intel,ssp-link.yaml new file mode 100644 index 00000000000000..e3786427ea2cb3 --- /dev/null +++ b/dts/bindings/i2s/intel,ssp-link.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Intel SSP DAI controller + +compatible: "intel,ssp-link" + +include: base.yaml + +properties: + reg: + required: true + + link: + type: int + required: true + + interrupts: + required: true + + interrupt-parent: + required: true + + dmas: + required: true + + dma-names: + required: true + + i2svss: + type: array \ No newline at end of file diff --git a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index a6fac22ba066a4..bbeb4adf15871c 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -242,10 +242,11 @@ status = "okay"; }; - ssp0: ssp@28000 { - compatible = "intel,ssp-dai"; + ssplink0: ssp-link@28000 { #address-cells = <1>; #size-cells = <0>; + compatible = "intel,ssp-link"; + link = <0>; reg = <0x00028000 0x1000 0x00079C00 0x200>; interrupts = <0x00 0 0>; @@ -262,10 +263,11 @@ reg = <0x28800 0x1000>; }; - ssp1: ssp@29000 { - compatible = "intel,ssp-dai"; + ssplink1: ssp-link@29000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <1>; reg = <0x00029000 0x1000 0x00079C00 0x200>; interrupts = <0x01 0 0>; @@ -277,10 +279,11 @@ status = "okay"; }; - ssp2: ssp@2a000 { - compatible = "intel,ssp-dai"; + ssplink2: ssp-link@2a000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <2>; reg = <0x0002a000 0x1000 0x00079C00 0x200>; interrupts = <0x02 0 0>; @@ -292,10 +295,11 @@ status = "okay"; }; - ssp3: ssp@2b000 { - compatible = "intel,ssp-dai"; + ssplink3: ssp-link@2b000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <3>; reg = <0x0002b000 0x1000 0x00079C00 0x200>; interrupts = <0x03 0 0>; @@ -307,10 +311,11 @@ status = "okay"; }; - ssp4: ssp@2c000 { - compatible = "intel,ssp-dai"; + ssplink4: ssp-link@2c000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <4>; reg = <0x0002c000 0x1000 0x00079C00 0x200>; interrupts = <0x04 0 0>; @@ -322,10 +327,11 @@ status = "okay"; }; - ssp5: ssp@2d000 { - compatible = "intel,ssp-dai"; + ssplink5: ssp-link@2d000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <5>; reg = <0x0002d000 0x1000 0x00079C00 0x200>; interrupts = <0x04 0 0>; @@ -689,4 +695,52 @@ reg = <0x12>; }; }; + + ssps { + #address-cells = <1>; + #size-cells = <0>; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + link = <0>; + status = "okay"; + }; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + link = <1>; + status = "okay"; + }; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + link = <2>; + status = "okay"; + }; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + link = <3>; + status = "okay"; + }; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + link = <4>; + status = "okay"; + }; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + link = <5>; + status = "okay"; + }; + + }; }; diff --git a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi index f654133f0ef582..2caad5bece377e 100644 --- a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi @@ -176,10 +176,11 @@ status = "okay"; }; - ssp0: ssp@28100 { - compatible = "intel,ssp-dai"; + ssplink0: ssp-link@28100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <0>; reg = <0x00028100 0x1000 0x00079C00 0x200>; i2svss = <0x00028C00 0x1000>; @@ -192,10 +193,11 @@ status = "okay"; }; - ssp1: ssp@29100 { - compatible = "intel,ssp-dai"; + ssplink1: ssp-link@29100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <1>; reg = <0x00029100 0x1000 0x00079C00 0x200>; i2svss = <0x00029C00 0x1000>; @@ -208,10 +210,11 @@ status = "okay"; }; - ssp2: ssp@2a100 { - compatible = "intel,ssp-dai"; + ssplink2: ssp-link@2a100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <2>; reg = <0x0002a100 0x1000 0x00079C00 0x200>; i2svss = <0x0002AC00 0x1000>; @@ -224,10 +227,11 @@ status = "okay"; }; - ssp3: ssp@2b100 { - compatible = "intel,ssp-dai"; + ssplink3: ssp-link@2b100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <3>; reg = <0x0002b100 0x1000 0x00079C00 0x200>; i2svss = <0x0002BC00 0x1000>; @@ -240,10 +244,11 @@ status = "okay"; }; - ssp4: ssp@2c100 { - compatible = "intel,ssp-dai"; + ssplink4: ssp-link@2c100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <4>; reg = <0x0002c100 0x1000 0x00079C00 0x200>; i2svss = <0x0002CC00 0x1000>; @@ -256,10 +261,11 @@ status = "okay"; }; - ssp5: ssp@2d100 { - compatible = "intel,ssp-dai"; + ssplink5: ssp-link@2d100 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <5>; reg = <0x0002d100 0x1000 0x00079C00 0x200>; i2svss = <0x0002DC00 0x1000>; @@ -549,4 +555,50 @@ reg = <0x12>; }; }; + + ssps { + #address-cells = <1>; + #size-cells = <0>; + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + link = <0>; + status = "okay"; + }; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + link = <1>; + status = "okay"; + }; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + link = <2>; + status = "okay"; + }; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + link = <3>; + status = "okay"; + }; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + link = <4>; + status = "okay"; + }; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + link = <5>; + status = "okay"; + }; + }; }; diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index 36ad7afa218640..06b7499a49c9c7 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -216,10 +216,11 @@ paddr-size = <11>; }; - ssp0: ssp@77000 { - compatible = "intel,ssp-dai"; + ssplink0: ssp-link@77000 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <0>; reg = <0x00077000 0x200 0x00078C00 0x008>; interrupts = <0x01 0 0>; @@ -231,10 +232,11 @@ status = "okay"; }; - ssp1: ssp@77200 { - compatible = "intel,ssp-dai"; + ssplink1: ssp-link@77200 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <1>; reg = <0x00077200 0x200 0x00078C00 0x008>; interrupts = <0x01 0 0>; @@ -246,10 +248,11 @@ status = "okay"; }; - ssp2: ssp@77400 { - compatible = "intel,ssp-dai"; + ssplink2: ssp-link@77400 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <2>; reg = <0x00077400 0x200 0x00078C00 0x008>; interrupts = <0x02 0 0>; @@ -261,10 +264,11 @@ status = "okay"; }; - ssp3: ssp@77600 { - compatible = "intel,ssp-dai"; + ssplink3: ssp-link@77600 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <3>; reg = <0x00077600 0x200 0x00078C00 0x008>; interrupts = <0x03 0 0>; @@ -276,10 +280,11 @@ status = "okay"; }; - ssp4: ssp@77800 { - compatible = "intel,ssp-dai"; + ssplink4: ssp-link@77800 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <4>; reg = <0x00077800 0x200 0x00078C00 0x008>; interrupts = <0x03 0 0>; @@ -291,10 +296,11 @@ status = "okay"; }; - ssp5: ssp@77a00 { - compatible = "intel,ssp-dai"; + ssplink5: ssp-link@77a00 { + compatible = "intel,ssp-link"; #address-cells = <1>; #size-cells = <0>; + link = <5>; reg = <0x00077A00 0x200 0x00078C00 0x008>; interrupts = <0x03 0 0>; @@ -513,4 +519,51 @@ reg = <0x0f>; }; }; + + ssps { + #address-cells = <1>; + #size-cells = <0>; + + ssp00: ssp@0 { + compatible = "intel,ssp-dai"; + reg = <0x0>; + link = <0>; + status = "okay"; + }; + + ssp10: ssp@10 { + compatible = "intel,ssp-dai"; + reg = <0x10>; + link = <1>; + status = "okay"; + }; + + ssp20: ssp@20 { + compatible = "intel,ssp-dai"; + reg = <0x20>; + link = <2>; + status = "okay"; + }; + + ssp30: ssp@30 { + compatible = "intel,ssp-dai"; + reg = <0x30>; + link = <3>; + status = "okay"; + }; + + ssp40: ssp@40 { + compatible = "intel,ssp-dai"; + reg = <0x40>; + link = <4>; + status = "okay"; + }; + + ssp50: ssp@50 { + compatible = "intel,ssp-dai"; + reg = <0x50>; + link = <5>; + status = "okay"; + }; + }; };