diff options
Diffstat (limited to 'sound')
75 files changed, 2429 insertions, 1814 deletions
diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 5fb322212938..84c963241dc5 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -73,6 +73,19 @@ config SND_AMD_ASOC_ACP63 Say Y if you want to enable AUDIO on ACP6.3 If unsure select "N". +config SND_AMD_ASOC_ACP70 + tristate "AMD ACP ASOC Acp7.0 Support" + depends on X86 && PCI + depends on ACPI + select SND_SOC_AMD_ACP_PCM + select SND_SOC_AMD_ACP_I2S + select SND_SOC_AMD_ACP_PDM + select SND_SOC_AMD_ACP_LEGACY_COMMON + help + This option enables Acp7.0 PDM support on AMD platform. + Say Y if you want to enable AUDIO on ACP7.0 + If unsure select "N". + config SND_SOC_AMD_MACH_COMMON tristate depends on X86 && PCI && I2C diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index dd85700f1c5f..ff5f7893b81e 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -15,6 +15,7 @@ snd-acp-pci-objs := acp-pci.o snd-acp-renoir-objs := acp-renoir.o snd-acp-rembrandt-objs := acp-rembrandt.o snd-acp63-objs := acp63.o +snd-acp70-objs := acp70.o #machine specific driver snd-acp-mach-objs := acp-mach-common.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o obj-$(CONFIG_SND_AMD_ASOC_ACP63) += snd-acp63.o +obj-$(CONFIG_SND_AMD_ASOC_ACP70) += snd-acp70.o obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index b871a216a6af..4d342441a650 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -283,18 +283,16 @@ static int __maybe_unused acp63_pcm_resume(struct device *dev) spin_lock(&adata->acp_lock); list_for_each_entry(stream, &adata->stream_list, list) { - if (stream) { - substream = stream->substream; - if (substream && substream->runtime) { - buf_in_frames = (substream->runtime->buffer_size); - buf_size = frames_to_bytes(substream->runtime, buf_in_frames); - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, buf_size); - if (stream->dai_id) - restore_acp_i2s_params(substream, adata, stream); - else - restore_acp_pdm_params(substream, adata); - } + substream = stream->substream; + if (substream && substream->runtime) { + buf_in_frames = (substream->runtime->buffer_size); + buf_size = frames_to_bytes(substream->runtime, buf_in_frames); + config_pte_for_stream(adata, stream); + config_acp_dma(adata, stream, buf_size); + if (stream->dai_id) + restore_acp_i2s_params(substream, adata, stream); + else + restore_acp_pdm_params(substream, adata); } } spin_unlock(&adata->acp_lock); diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index dd384c966ae9..0d7cdd4017e5 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -52,8 +52,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .playback = { .stream_name = "I2S SP Playback", .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -62,8 +62,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .capture = { .stream_name = "I2S SP Capture", .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rate_min = 8000, @@ -77,8 +77,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .playback = { .stream_name = "I2S BT Playback", .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -87,8 +87,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .capture = { .stream_name = "I2S BT Capture", .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rate_min = 8000, @@ -102,8 +102,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .playback = { .stream_name = "I2S HS Playback", .rates = SNDRV_PCM_RATE_8000_96000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -112,8 +112,8 @@ static struct snd_soc_dai_driver acp70_dai[] = { .capture = { .stream_name = "I2S HS Capture", .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -229,8 +229,8 @@ static int __maybe_unused acp70_pcm_resume(struct device *dev) } } } - spin_unlock(&adata->acp_lock); - return 0; + spin_unlock(&adata->acp_lock); + return 0; } static const struct dev_pm_ops acp70_dma_pm_ops = { diff --git a/sound/soc/codecs/aw88395/aw88395_device.h b/sound/soc/codecs/aw88395/aw88395_device.h index 791c8c106557..0f750f654f3e 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.h +++ b/sound/soc/codecs/aw88395/aw88395_device.h @@ -146,6 +146,7 @@ struct aw_device { unsigned int channel; unsigned int fade_step; + unsigned int prof_data_type; struct i2c_client *i2c; struct device *dev; diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 9ebe7c510109..f25f6e0d4428 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -11,7 +11,6 @@ #include <linux/i2c.h> #include "aw88395_lib.h" #include "aw88395_device.h" -#include "aw88395_reg.h" #define AW88395_CRC8_POLYNOMIAL 0x8C DECLARE_CRC8_TABLE(aw_crc8_table); @@ -456,14 +455,6 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, goto parse_bin_failed; } - if (aw_dev->chip_id == AW88261_CHIP_ID) { - if (aw_bin->header_info[0].valid_data_len % 4) { - dev_err(aw_dev->dev, "bin data len get error!"); - ret = -EINVAL; - goto parse_bin_failed; - } - } - prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = data + aw_bin->header_info[0].valid_data_addr; prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len = @@ -528,7 +519,7 @@ static int aw_dev_parse_dev_type(struct aw_device *aw_dev, cfg_dde[i].dev_profile); return -EINVAL; } - + aw_dev->prof_data_type = cfg_dde[i].data_type; ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); if (ret < 0) { @@ -564,6 +555,7 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, cfg_dde[i].dev_profile); return -EINVAL; } + aw_dev->prof_data_type = cfg_dde[i].data_type; ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i], &all_prof_info->prof_desc[cfg_dde[i].dev_profile]); if (ret < 0) { @@ -582,7 +574,7 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, return 0; } -static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, +static int aw_dev_cfg_get_reg_valid_prof(struct aw_device *aw_dev, struct aw_all_prof_info *all_prof_info) { struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; @@ -624,7 +616,7 @@ static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, return 0; } -static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev, +static int aw_dev_cfg_get_multiple_valid_prof(struct aw_device *aw_dev, struct aw_all_prof_info *all_prof_info) { struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; @@ -703,26 +695,20 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, goto exit; } - switch (aw_dev->chip_id) { - case AW88395_CHIP_ID: - case AW88399_CHIP_ID: - ret = aw88395_dev_cfg_get_valid_prof(aw_dev, all_prof_info); - if (ret < 0) - goto exit; + switch (aw_dev->prof_data_type) { + case ACF_SEC_TYPE_MULTIPLE_BIN: + ret = aw_dev_cfg_get_multiple_valid_prof(aw_dev, all_prof_info); break; - case AW88261_CHIP_ID: - case AW87390_CHIP_ID: - ret = aw88261_dev_cfg_get_valid_prof(aw_dev, all_prof_info); - if (ret < 0) - goto exit; + case ACF_SEC_TYPE_HDR_REG: + ret = aw_dev_cfg_get_reg_valid_prof(aw_dev, all_prof_info); break; default: - dev_err(aw_dev->dev, "valid prof unsupported"); + dev_err(aw_dev->dev, "unsupport data type\n"); ret = -EINVAL; break; } - - aw_dev->prof_info.prof_name_list = profile_name; + if (!ret) + aw_dev->prof_info.prof_name_list = profile_name; exit: devm_kfree(aw_dev->dev, all_prof_info); @@ -791,39 +777,23 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; - int ret; - switch (aw_dev->chip_id) { - case AW88395_CHIP_ID: - case AW88399_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && - (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) - (*scene_num)++; - } - ret = 0; - break; - case AW88261_CHIP_ID: - case AW87390_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || - (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && - (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) - (*scene_num)++; - } - ret = 0; - break; - default: - dev_err(aw_dev->dev, "unsupported device"); - ret = -EINVAL; - break; + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) && + (aw_dev->i2c->addr == cfg_dde[i].dev_addr)) + (*scene_num)++; } - return ret; + if ((*scene_num) == 0) { + dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num)); + return -EINVAL; + } + + return 0; } static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, @@ -834,37 +804,23 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, struct aw_cfg_dde_v1 *cfg_dde = (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset); unsigned int i; - int ret; - switch (aw_dev->chip_id) { - case AW88395_CHIP_ID: - case AW88399_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->channel == cfg_dde[i].dev_index)) - (*scene_num)++; - } - ret = 0; - break; - case AW88261_CHIP_ID: - case AW87390_CHIP_ID: - for (i = 0; i < cfg_hdr->ddt_num; ++i) { - if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || - (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && - (aw_dev->chip_id == cfg_dde[i].chip_id) && - (aw_dev->channel == cfg_dde[i].dev_index)) - (*scene_num)++; - } - ret = 0; - break; - default: - dev_err(aw_dev->dev, "unsupported device"); - ret = -EINVAL; - break; + + for (i = 0; i < cfg_hdr->ddt_num; ++i) { + if (((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || + (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && + (aw_dev->chip_id == cfg_dde[i].chip_id) && + (aw_dev->channel == cfg_dde[i].dev_index)) + (*scene_num)++; } - return ret; + if ((*scene_num) == 0) { + dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num)); + return -EINVAL; + } + + return 0; } static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev, diff --git a/sound/soc/codecs/aw88395/aw88395_reg.h b/sound/soc/codecs/aw88395/aw88395_reg.h index ede7deab6a9c..e64f24e97150 100644 --- a/sound/soc/codecs/aw88395/aw88395_reg.h +++ b/sound/soc/codecs/aw88395/aw88395_reg.h @@ -95,10 +95,7 @@ #define AW88395_TM_REG (0x7C) enum aw88395_id { - AW88399_CHIP_ID = 0x2183, AW88395_CHIP_ID = 0x2049, - AW88261_CHIP_ID = 0x2113, - AW87390_CHIP_ID = 0x76, }; #define AW88395_REG_MAX (0x7D) diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index 54f8457e8497..9fcb805bf971 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -15,7 +15,6 @@ #include <sound/soc.h> #include "aw88399.h" #include "aw88395/aw88395_device.h" -#include "aw88395/aw88395_reg.h" static const struct regmap_config aw88399_remap_config = { .val_bits = 16, diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h index 4f391099d0f2..5e9cdf725d3d 100644 --- a/sound/soc/codecs/aw88399.h +++ b/sound/soc/codecs/aw88399.h @@ -491,6 +491,7 @@ #define AW88399_CRC_FW_BASE_ADDR (0x4C0) #define AW88399_ACF_FILE "aw88399_acf.bin" #define AW88399_DEV_SYSST_CHECK_MAX (10) +#define AW88399_CHIP_ID 0x2183 #define AW88399_I2C_NAME "aw88399" diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index d62c9f26c632..5c98343ebf71 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2251,8 +2251,8 @@ static int cs42l43_codec_runtime_resume(struct device *dev) return 0; } -DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL, - cs42l43_codec_runtime_resume, NULL); +static DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL, + cs42l43_codec_runtime_resume, NULL); static const struct platform_device_id cs42l43_codec_id_table[] = { { "cs42l43-codec", }, diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 0b40fdfb1825..0f3ead84665f 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -16,7 +16,7 @@ #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/i2c.h> -#include <linux/of.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> @@ -238,7 +238,7 @@ static int cs43130_pll_config(struct snd_soc_component *component) struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); const struct cs43130_pll_params *pll_entry; - dev_dbg(component->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n", + dev_dbg(cs43130->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n", cs43130->mclk, cs43130->mclk_int); pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int); @@ -303,7 +303,7 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int cs43130->mclk = freq_in; break; default: - dev_err(component->dev, + dev_err(cs43130->dev, "unsupported pll input reference clock:%d\n", freq_in); return -EINVAL; } @@ -316,16 +316,44 @@ static int cs43130_set_pll(struct snd_soc_component *component, int pll_id, int cs43130->mclk_int = freq_out; break; default: - dev_err(component->dev, + dev_err(cs43130->dev, "unsupported pll output ref clock: %u\n", freq_out); return -EINVAL; } ret = cs43130_pll_config(component); - dev_dbg(component->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass); + dev_dbg(cs43130->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass); return ret; } +static int cs43130_wait_for_completion(struct cs43130_private *cs43130, struct completion *to_poll, + int time) +{ + int stickies, offset, flag, ret; + + if (cs43130->has_irq_line) { + ret = wait_for_completion_timeout(to_poll, msecs_to_jiffies(time)); + if (ret == 0) + return -ETIMEDOUT; + else + return 0; // Discard number of jiffies left till timeout and return success + } + + if (to_poll == &cs43130->xtal_rdy) { + offset = 0; + flag = CS43130_XTAL_RDY_INT; + } else if (to_poll == &cs43130->pll_rdy) { + offset = 0; + flag = CS43130_PLL_RDY_INT; + } else { + return -EINVAL; + } + + return regmap_read_poll_timeout(cs43130->regmap, CS43130_INT_STATUS_1 + offset, + stickies, (stickies & flag), + 1000, time * 1000); +} + static int cs43130_change_clksrc(struct snd_soc_component *component, enum cs43130_mclk_src_sel src) { @@ -346,7 +374,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, mclk_int_decoded = CS43130_MCLK_24P5; break; default: - dev_err(component->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int); + dev_err(cs43130->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int); return -EINVAL; } @@ -364,14 +392,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_XTAL_RDY_INT_MASK, 0); regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, CS43130_PDN_XTAL_MASK, 0); - ret = wait_for_completion_timeout(&cs43130->xtal_rdy, - msecs_to_jiffies(100)); + ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100); regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, CS43130_XTAL_RDY_INT_MASK, 1 << CS43130_XTAL_RDY_INT_SHIFT); - if (ret == 0) { - dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n"); - return -ETIMEDOUT; + if (ret) { + dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret); + return ret; } } @@ -400,14 +427,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_XTAL_RDY_INT_MASK, 0); regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, CS43130_PDN_XTAL_MASK, 0); - ret = wait_for_completion_timeout(&cs43130->xtal_rdy, - msecs_to_jiffies(100)); + ret = cs43130_wait_for_completion(cs43130, &cs43130->xtal_rdy, 100); regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, CS43130_XTAL_RDY_INT_MASK, 1 << CS43130_XTAL_RDY_INT_SHIFT); - if (ret == 0) { - dev_err(component->dev, "Timeout waiting for XTAL_READY interrupt\n"); - return -ETIMEDOUT; + if (ret) { + dev_err(cs43130->dev, "Error waiting for XTAL_READY interrupt: %d\n", ret); + return ret; } } @@ -416,14 +442,13 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, CS43130_PLL_RDY_INT_MASK, 0); regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, CS43130_PDN_PLL_MASK, 0); - ret = wait_for_completion_timeout(&cs43130->pll_rdy, - msecs_to_jiffies(100)); + ret = cs43130_wait_for_completion(cs43130, &cs43130->pll_rdy, 100); regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, CS43130_PLL_RDY_INT_MASK, 1 << CS43130_PLL_RDY_INT_SHIFT); - if (ret == 0) { - dev_err(component->dev, "Timeout waiting for PLL_READY interrupt\n"); - return -ETIMEDOUT; + if (ret) { + dev_err(cs43130->dev, "Error waiting for PLL_READY interrupt: %d\n", ret); + return ret; } regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, @@ -453,7 +478,7 @@ static int cs43130_change_clksrc(struct snd_soc_component *component, 1 << CS43130_PDN_PLL_SHIFT); break; default: - dev_err(component->dev, "Invalid MCLK source value\n"); + dev_err(cs43130->dev, "Invalid MCLK source value\n"); return -EINVAL; } @@ -578,7 +603,7 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, break; case SND_SOC_DAIFMT_LEFT_J: hi_size = bitwidth_sclk; - frm_delay = 2; + frm_delay = 0; frm_phase = 1; break; case SND_SOC_DAIFMT_DSP_A: @@ -595,6 +620,27 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, return -EINVAL; } + switch (cs43130->dais[dai_id].dai_invert) { + case SND_SOC_DAIFMT_NB_NF: + sclk_edge = 1; + lrck_edge = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + sclk_edge = 0; + lrck_edge = 0; + break; + case SND_SOC_DAIFMT_NB_IF: + sclk_edge = 1; + lrck_edge = 1; + break; + case SND_SOC_DAIFMT_IB_IF: + sclk_edge = 0; + lrck_edge = 1; + break; + default: + return -EINVAL; + } + switch (cs43130->dais[dai_id].dai_mode) { case SND_SOC_DAIFMT_CBS_CFS: dai_mode_val = 0; @@ -607,8 +653,6 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, } frm_size = bitwidth_sclk * params_channels(params); - sclk_edge = 1; - lrck_edge = 0; loc_ch1 = 0; loc_ch2 = bitwidth_sclk * (params_channels(params) - 1); @@ -804,7 +848,7 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, dsd_speed = 1; break; default: - dev_err(component->dev, "Rate(%u) not supported\n", + dev_err(cs43130->dev, "Rate(%u) not supported\n", params_rate(params)); return -EINVAL; } @@ -875,7 +919,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, dsd_speed = 1; break; default: - dev_err(component->dev, "Rate(%u) not supported\n", + dev_err(cs43130->dev, "Rate(%u) not supported\n", params_rate(params)); return -EINVAL; } @@ -892,7 +936,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val); break; default: - dev_err(component->dev, "Invalid DAI (%d)\n", dai->id); + dev_err(cs43130->dev, "Invalid DAI (%d)\n", dai->id); return -EINVAL; } @@ -916,21 +960,21 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, if (!sclk) { /* at this point, SCLK must be set */ - dev_err(component->dev, "SCLK freq is not set\n"); + dev_err(cs43130->dev, "SCLK freq is not set\n"); return -EINVAL; } bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params); if (bitwidth_sclk < bitwidth_dai) { - dev_err(component->dev, "Format not supported: SCLK freq is too low\n"); + dev_err(cs43130->dev, "Format not supported: SCLK freq is too low\n"); return -EINVAL; } - dev_dbg(component->dev, + dev_dbg(cs43130->dev, "sclk = %u, fs = %d, bitwidth_dai = %u\n", sclk, params_rate(params), bitwidth_dai); - dev_dbg(component->dev, + dev_dbg(cs43130->dev, "bitwidth_sclk = %u, num_ch = %u\n", bitwidth_sclk, params_channels(params)); @@ -1189,7 +1233,7 @@ static int cs43130_dsd_event(struct snd_soc_dapm_widget *w, } break; default: - dev_err(component->dev, "Invalid event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid event = 0x%x\n", event); return -EINVAL; } return 0; @@ -1246,7 +1290,7 @@ static int cs43130_pcm_event(struct snd_soc_dapm_widget *w, } break; default: - dev_err(component->dev, "Invalid event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid event = 0x%x\n", event); return -EINVAL; } return 0; @@ -1322,7 +1366,7 @@ static int cs43130_dac_event(struct snd_soc_dapm_widget *w, } break; default: - dev_err(component->dev, "Invalid DAC event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid DAC event = 0x%x\n", event); return -EINVAL; } return 0; @@ -1360,13 +1404,21 @@ static int cs43130_hpin_event(struct snd_soc_dapm_widget *w, ARRAY_SIZE(hpin_postpmu_seq)); break; default: - dev_err(component->dev, "Invalid HPIN event = 0x%x\n", event); + dev_err(cs43130->dev, "Invalid HPIN event = 0x%x\n", event); return -EINVAL; } return 0; } +static const char * const bypass_mux_text[] = { + "Internal", + "Alternative", +}; +static SOC_ENUM_SINGLE_DECL(bypass_enum, SND_SOC_NOPM, 0, bypass_mux_text); +static const struct snd_kcontrol_new bypass_ctrl = SOC_DAPM_ENUM("Switch", bypass_enum); + static const struct snd_soc_dapm_widget digital_hp_widgets[] = { + SND_SOC_DAPM_MUX("Bypass Switch", SND_SOC_NOPM, 0, 0, &bypass_ctrl), SND_SOC_DAPM_OUTPUT("HPOUTA"), SND_SOC_DAPM_OUTPUT("HPOUTB"), @@ -1419,13 +1471,13 @@ static const struct snd_soc_dapm_route digital_hp_routes[] = { {"DSD", NULL, "XSPIN DSD"}, {"HiFi DAC", NULL, "ASPIN PCM"}, {"HiFi DAC", NULL, "DSD"}, - {"HPOUTA", NULL, "HiFi DAC"}, - {"HPOUTB", NULL, "HiFi DAC"}, + {"Bypass Switch", "Internal", "HiFi DAC"}, + {"HPOUTA", NULL, "Bypass Switch"}, + {"HPOUTB", NULL, "Bypass Switch"}, }; static const struct snd_soc_dapm_route analog_hp_routes[] = { - {"HPOUTA", NULL, "Analog Playback"}, - {"HPOUTB", NULL, "Analog Playback"}, + {"Bypass Switch", "Alternative", "Analog Playback"}, }; static struct snd_soc_dapm_route all_hp_routes[ @@ -1479,7 +1531,26 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; break; default: - dev_err(component->dev, "unsupported mode\n"); + dev_err(cs43130->dev, "unsupported mode\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_NB_NF; + break; + case SND_SOC_DAIFMT_IB_NF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_IB_NF; + break; + case SND_SOC_DAIFMT_NB_IF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_NB_IF; + break; + case SND_SOC_DAIFMT_IB_IF: + cs43130->dais[codec_dai->id].dai_invert = SND_SOC_DAIFMT_IB_IF; + break; + default: + dev_err(cs43130->dev, "Unsupported invert mode 0x%x\n", + fmt & SND_SOC_DAIFMT_INV_MASK); return -EINVAL; } @@ -1497,12 +1568,12 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B; break; default: - dev_err(component->dev, + dev_err(cs43130->dev, "unsupported audio format\n"); return -EINVAL; } - dev_dbg(component->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n", + dev_dbg(cs43130->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n", codec_dai->id, cs43130->dais[codec_dai->id].dai_mode, cs43130->dais[codec_dai->id].dai_format); @@ -1523,11 +1594,11 @@ static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; break; default: - dev_err(component->dev, "Unsupported DAI format.\n"); + dev_err(cs43130->dev, "Unsupported DAI format.\n"); return -EINVAL; } - dev_dbg(component->dev, "dai_mode = 0x%x\n", + dev_dbg(cs43130->dev, "dai_mode = 0x%x\n", cs43130->dais[codec_dai->id].dai_mode); return 0; @@ -1540,7 +1611,7 @@ static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai, struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); cs43130->dais[codec_dai->id].sclk = freq; - dev_dbg(component->dev, "dai_id = %d, sclk = %u\n", codec_dai->id, + dev_dbg(cs43130->dev, "dai_id = %d, sclk = %u\n", codec_dai->id, cs43130->dais[codec_dai->id].sclk); return 0; @@ -1630,7 +1701,7 @@ static int cs43130_component_set_sysclk(struct snd_soc_component *component, { struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); - dev_dbg(component->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n", + dev_dbg(cs43130->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n", clk_id, source, freq, dir); switch (freq) { @@ -1639,14 +1710,14 @@ static int cs43130_component_set_sysclk(struct snd_soc_component *component, cs43130->mclk = freq; break; default: - dev_err(component->dev, "Invalid MCLK INT freq: %u\n", freq); + dev_err(cs43130->dev, "Invalid MCLK INT freq: %u\n", freq); return -EINVAL; } if (source == CS43130_MCLK_SRC_EXT) { cs43130->pll_bypass = true; } else { - dev_err(component->dev, "Invalid MCLK source\n"); + dev_err(cs43130->dev, "Invalid MCLK source\n"); return -EINVAL; } @@ -1682,7 +1753,7 @@ static ssize_t hpload_dc_r_show(struct device *dev, return cs43130_show_dc(dev, buf, HP_RIGHT); } -static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = { +static const u16 cs43130_ac_freq[CS43130_AC_FREQ] = { 24, 43, 93, @@ -1933,7 +2004,6 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx, unsigned int reg; u32 addr; u16 impedance; - struct snd_soc_component *component = cs43130->component; switch (msk) { case CS43130_HPLOAD_DC_INT: @@ -1963,7 +2033,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx, else cs43130->hpload_dc[HP_RIGHT] = impedance; - dev_dbg(component->dev, "HP DC impedance (Ch %u): %u\n", !left_ch, + dev_dbg(cs43130->dev, "HP DC impedance (Ch %u): %u\n", !left_ch, impedance); } else { if (left_ch) @@ -1971,7 +2041,7 @@ static int cs43130_update_hpload(unsigned int msk, int ac_idx, else cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance; - dev_dbg(component->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n", + dev_dbg(cs43130->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n", cs43130->ac_freq[ac_idx], !left_ch, impedance); } @@ -1985,7 +2055,6 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130, int ret; unsigned int msk; u16 ac_reg_val; - struct snd_soc_component *component = cs43130->component; reinit_completion(&cs43130->hpload_evt); @@ -2008,17 +2077,17 @@ static int cs43130_hpload_proc(struct cs43130_private *cs43130, msecs_to_jiffies(1000)); regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk); if (!ret) { - dev_err(component->dev, "Timeout waiting for HPLOAD interrupt\n"); - return -1; + dev_err(cs43130->dev, "Timeout waiting for HPLOAD interrupt\n"); + return -ETIMEDOUT; } - dev_dbg(component->dev, "HP load stat: %x, INT_MASK_4: %x\n", + dev_dbg(cs43130->dev, "HP load stat: %x, INT_MASK_4: %x\n", cs43130->hpload_stat, msk); if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT | CS43130_HPLOAD_UNPLUG_INT | CS43130_HPLOAD_OOR_INT)) || !(cs43130->hpload_stat & rslt_msk)) { - dev_dbg(component->dev, "HP load measure failed\n"); + dev_dbg(cs43130->dev, "HP load measure failed\n"); return -1; } @@ -2129,9 +2198,9 @@ static void cs43130_imp_meas(struct work_struct *wk) snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE, CS43130_JACK_MASK); - dev_dbg(component->dev, "Set HP output control. DC threshold\n"); + dev_dbg(cs43130->dev, "Set HP output control. DC threshold\n"); for (i = 0; i < CS43130_DC_THRESHOLD; i++) - dev_dbg(component->dev, "DC threshold[%d]: %u.\n", i, + dev_dbg(cs43130->dev, "DC threshold[%d]: %u.\n", i, cs43130->dc_threshold[i]); cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT], @@ -2165,7 +2234,6 @@ exit: static irqreturn_t cs43130_irq_thread(int irq, void *data) { struct cs43130_private *cs43130 = (struct cs43130_private *)data; - struct snd_soc_component *component = cs43130->component; unsigned int stickies[CS43130_NUM_INT]; unsigned int irq_occurrence = 0; unsigned int masks[CS43130_NUM_INT]; @@ -2183,8 +2251,6 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) for (j = 0; j < 8; j++) irq_occurrence += (stickies[i] >> j) & 1; } - dev_dbg(component->dev, "number of interrupts occurred (%u)\n", - irq_occurrence); if (!irq_occurrence) return IRQ_NONE; @@ -2201,7 +2267,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) { cs43130->hpload_stat = stickies[3]; - dev_err(component->dev, + dev_err(cs43130->dev, "DC load has not completed before AC load (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); @@ -2210,7 +2276,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) { cs43130->hpload_stat = stickies[3]; - dev_err(component->dev, "HP unplugged during measurement (%x)\n", + dev_err(cs43130->dev, "HP unplugged during measurement (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2218,7 +2284,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_OOR_INT) { cs43130->hpload_stat = stickies[3]; - dev_err(component->dev, "HP load out of range (%x)\n", + dev_err(cs43130->dev, "HP load out of range (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2226,7 +2292,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_AC_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP AC load measurement done (%x)\n", + dev_dbg(cs43130->dev, "HP AC load measurement done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2234,7 +2300,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_DC_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP DC load measurement done (%x)\n", + dev_dbg(cs43130->dev, "HP DC load measurement done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2242,7 +2308,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_ON_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP load state machine on done (%x)\n", + dev_dbg(cs43130->dev, "HP load state machine on done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; @@ -2250,19 +2316,19 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[3] & CS43130_HPLOAD_OFF_INT) { cs43130->hpload_stat = stickies[3]; - dev_dbg(component->dev, "HP load state machine off done (%x)\n", + dev_dbg(cs43130->dev, "HP load state machine off done (%x)\n", cs43130->hpload_stat); complete(&cs43130->hpload_evt); return IRQ_HANDLED; } if (stickies[0] & CS43130_XTAL_ERR_INT) { - dev_err(component->dev, "Crystal err: clock is not running\n"); + dev_err(cs43130->dev, "Crystal err: clock is not running\n"); return IRQ_HANDLED; } if (stickies[0] & CS43130_HP_UNPLUG_INT) { - dev_dbg(component->dev, "HP unplugged\n"); + dev_dbg(cs43130->dev, "HP unplugged\n"); cs43130->hpload_done = false; snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK); return IRQ_HANDLED; @@ -2271,7 +2337,7 @@ static irqreturn_t cs43130_irq_thread(int irq, void *data) if (stickies[0] & CS43130_HP_PLUG_INT) { if (cs43130->dc_meas && !cs43130->hpload_done && !work_busy(&cs43130->work)) { - dev_dbg(component->dev, "HP load queue work\n"); + dev_dbg(cs43130->dev, "HP load queue work\n"); queue_work(cs43130->wq, &cs43130->work); } @@ -2303,19 +2369,19 @@ static int cs43130_probe(struct snd_soc_component *component) ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK, &cs43130->jack); if (ret < 0) { - dev_err(component->dev, "Cannot create jack\n"); + dev_err(cs43130->dev, "Cannot create jack\n"); return ret; } cs43130->hpload_done = false; if (cs43130->dc_meas) { - ret = sysfs_create_groups(&component->dev->kobj, hpload_groups); + ret = sysfs_create_groups(&cs43130->dev->kobj, hpload_groups); if (ret) return ret; cs43130->wq = create_singlethread_workqueue("cs43130_hp"); if (!cs43130->wq) { - sysfs_remove_groups(&component->dev->kobj, hpload_groups); + sysfs_remove_groups(&cs43130->dev->kobj, hpload_groups); return -ENOMEM; } INIT_WORK(&cs43130->work, cs43130_imp_meas); @@ -2362,19 +2428,17 @@ static const struct regmap_config cs43130_regmap = { .use_single_write = true, }; -static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = { +static const u16 cs43130_dc_threshold[CS43130_DC_THRESHOLD] = { 50, 120, }; -static int cs43130_handle_device_data(struct i2c_client *i2c_client, - struct cs43130_private *cs43130) +static int cs43130_handle_device_data(struct cs43130_private *cs43130) { - struct device_node *np = i2c_client->dev.of_node; unsigned int val; int i; - if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) { + if (device_property_read_u32(cs43130->dev, "cirrus,xtal-ibias", &val) < 0) { /* Crystal is unused. System clock is used for external MCLK */ cs43130->xtal_ibias = CS43130_XTAL_UNUSED; return 0; @@ -2391,23 +2455,23 @@ static int cs43130_handle_device_data(struct i2c_client *i2c_client, cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA; break; default: - dev_err(&i2c_client->dev, + dev_err(cs43130->dev, "Invalid cirrus,xtal-ibias value: %d\n", val); return -EINVAL; } - cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure"); - cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure"); + cs43130->dc_meas = device_property_read_bool(cs43130->dev, "cirrus,dc-measure"); + cs43130->ac_meas = device_property_read_bool(cs43130->dev, "cirrus,ac-measure"); - if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq, - CS43130_AC_FREQ) < 0) { + if (!device_property_read_u16_array(cs43130->dev, "cirrus,ac-freq", cs43130->ac_freq, + CS43130_AC_FREQ)) { for (i = 0; i < CS43130_AC_FREQ; i++) cs43130->ac_freq[i] = cs43130_ac_freq[i]; } - if (of_property_read_u16_array(np, "cirrus,dc-threshold", + if (!device_property_read_u16_array(cs43130->dev, "cirrus,dc-threshold", cs43130->dc_threshold, - CS43130_DC_THRESHOLD) < 0) { + CS43130_DC_THRESHOLD)) { for (i = 0; i < CS43130_DC_THRESHOLD; i++) cs43130->dc_threshold[i] = cs43130_dc_threshold[i]; } @@ -2426,6 +2490,8 @@ static int cs43130_i2c_probe(struct i2c_client *client) if (!cs43130) return -ENOMEM; + cs43130->dev = &client->dev; + i2c_set_clientdata(client, cs43130); cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap); @@ -2434,29 +2500,30 @@ static int cs43130_i2c_probe(struct i2c_client *client) return ret; } - if (client->dev.of_node) { - ret = cs43130_handle_device_data(client, cs43130); + if (dev_fwnode(cs43130->dev)) { + ret = cs43130_handle_device_data(cs43130); if (ret != 0) return ret; } + for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++) cs43130->supplies[i].supply = cs43130_supply_names[i]; - ret = devm_regulator_bulk_get(&client->dev, + ret = devm_regulator_bulk_get(cs43130->dev, ARRAY_SIZE(cs43130->supplies), cs43130->supplies); if (ret != 0) { - dev_err(&client->dev, "Failed to request supplies: %d\n", ret); + dev_err(cs43130->dev, "Failed to request supplies: %d\n", ret); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies), cs43130->supplies); if (ret != 0) { - dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); + dev_err(cs43130->dev, "Failed to enable supplies: %d\n", ret); return ret; } - cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev, + cs43130->reset_gpio = devm_gpiod_get_optional(cs43130->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(cs43130->reset_gpio)) { ret = PTR_ERR(cs43130->reset_gpio); @@ -2470,7 +2537,7 @@ static int cs43130_i2c_probe(struct i2c_client *client) devid = cirrus_read_device_id(cs43130->regmap, CS43130_DEVID_AB); if (devid < 0) { ret = devid; - dev_err(&client->dev, "Failed to read device ID: %d\n", ret); + dev_err(cs43130->dev, "Failed to read device ID: %d\n", ret); goto err; } @@ -2481,7 +2548,7 @@ static int cs43130_i2c_probe(struct i2c_client *client) case CS43198_CHIP_ID: break; default: - dev_err(&client->dev, + dev_err(cs43130->dev, "CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n", devid, CS43130_CHIP_ID, CS4399_CHIP_ID, CS43131_CHIP_ID, CS43198_CHIP_ID); @@ -2492,11 +2559,11 @@ static int cs43130_i2c_probe(struct i2c_client *client) cs43130->dev_id = devid; ret = regmap_read(cs43130->regmap, CS43130_REV_ID, ®); if (ret < 0) { - dev_err(&client->dev, "Get Revision ID failed\n"); + dev_err(cs43130->dev, "Get Revision ID failed\n"); goto err; } - dev_info(&client->dev, + dev_info(cs43130->dev, "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid, reg & 0xFF); @@ -2506,21 +2573,27 @@ static int cs43130_i2c_probe(struct i2c_client *client) init_completion(&cs43130->pll_rdy); init_completion(&cs43130->hpload_evt); - ret = devm_request_threaded_irq(&client->dev, client->irq, - NULL, cs43130_irq_thread, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs43130", cs43130); - if (ret != 0) { - dev_err(&client->dev, "Failed to request IRQ: %d\n", ret); - goto err; + if (!client->irq) { + dev_dbg(cs43130->dev, "IRQ not found, will poll instead\n"); + cs43130->has_irq_line = 0; + } else { + ret = devm_request_threaded_irq(cs43130->dev, client->irq, + NULL, cs43130_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs43130", cs43130); + if (ret != 0) { + dev_err(cs43130->dev, "Failed to request IRQ: %d\n", ret); + goto err; + } + cs43130->has_irq_line = 1; } cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; - pm_runtime_set_autosuspend_delay(&client->dev, 100); - pm_runtime_use_autosuspend(&client->dev); - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(cs43130->dev, 100); + pm_runtime_use_autosuspend(cs43130->dev); + pm_runtime_set_active(cs43130->dev); + pm_runtime_enable(cs43130->dev); switch (cs43130->dev_id) { case CS43130_CHIP_ID: @@ -2556,11 +2629,11 @@ static int cs43130_i2c_probe(struct i2c_client *client) break; } - ret = devm_snd_soc_register_component(&client->dev, + ret = devm_snd_soc_register_component(cs43130->dev, &soc_component_dev_cs43130, cs43130_dai, ARRAY_SIZE(cs43130_dai)); if (ret < 0) { - dev_err(&client->dev, + dev_err(cs43130->dev, "snd_soc_register_component failed with ret = %d\n", ret); goto err; } @@ -2598,15 +2671,15 @@ static void cs43130_i2c_remove(struct i2c_client *client) cancel_work_sync(&cs43130->work); flush_workqueue(cs43130->wq); - device_remove_file(&client->dev, &dev_attr_hpload_dc_l); - device_remove_file(&client->dev, &dev_attr_hpload_dc_r); - device_remove_file(&client->dev, &dev_attr_hpload_ac_l); - device_remove_file(&client->dev, &dev_attr_hpload_ac_r); + device_remove_file(cs43130->dev, &dev_attr_hpload_dc_l); + device_remove_file(cs43130->dev, &dev_attr_hpload_dc_r); + device_remove_file(cs43130->dev, &dev_attr_hpload_ac_l); + device_remove_file(cs43130->dev, &dev_attr_hpload_ac_r); } gpiod_set_value_cansleep(cs43130->reset_gpio, 0); - pm_runtime_disable(&client->dev); + pm_runtime_disable(cs43130->dev); regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); } @@ -2669,6 +2742,7 @@ static const struct dev_pm_ops cs43130_runtime_pm = { NULL) }; +#if IS_ENABLED(CONFIG_OF) static const struct of_device_id cs43130_of_match[] = { {.compatible = "cirrus,cs43130",}, {.compatible = "cirrus,cs4399",}, @@ -2678,6 +2752,17 @@ static const struct of_device_id cs43130_of_match[] = { }; MODULE_DEVICE_TABLE(of, cs43130_of_match); +#endif + +#if IS_ENABLED(CONFIG_ACPI) +static const struct acpi_device_id cs43130_acpi_match[] = { + { "CSC4399", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(acpi, cs43130_acpi_match); +#endif + static const struct i2c_device_id cs43130_i2c_id[] = { {"cs43130", 0}, @@ -2691,9 +2776,10 @@ MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id); static struct i2c_driver cs43130_i2c_driver = { .driver = { - .name = "cs43130", - .of_match_table = cs43130_of_match, - .pm = &cs43130_runtime_pm, + .name = "cs43130", + .of_match_table = of_match_ptr(cs43130_of_match), + .acpi_match_table = ACPI_PTR(cs43130_acpi_match), + .pm = &cs43130_runtime_pm, }, .id_table = cs43130_i2c_id, .probe = cs43130_i2c_probe, diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h index 90e8895275e7..dbdb5b262f1b 100644 --- a/sound/soc/codecs/cs43130.h +++ b/sound/soc/codecs/cs43130.h @@ -497,15 +497,18 @@ struct cs43130_dai { unsigned int sclk; unsigned int dai_format; unsigned int dai_mode; + unsigned int dai_invert; }; struct cs43130_private { + struct device *dev; struct snd_soc_component *component; struct regmap *regmap; struct regulator_bulk_data supplies[CS43130_NUM_SUPPLIES]; struct gpio_desc *reset_gpio; unsigned int dev_id; /* codec device ID */ int xtal_ibias; + bool has_irq_line; /* shared by both DAIs */ struct mutex clk_mutex; diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 6c263086c44d..fa890f6205e2 100644..100755 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -132,6 +132,11 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = { SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL, + 4, 7, 0, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL, + 0, 7, 0, 0), + SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), }; @@ -156,6 +161,9 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { {"LHPMIX", NULL, "Left DAC"}, {"RHPMIX", NULL, "Right DAC"}, + {"HPOR", NULL, "HPOR Supply"}, + {"HPOL", NULL, "HPOL Supply"}, + {"HPOL", NULL, "LHPMIX"}, {"HPOR", NULL, "RHPMIX"}, }; @@ -198,77 +206,108 @@ struct _coeff_div { /* codec hifi mclk clock divider coefficients */ /* {ratio, LRCK, MCLK, REG04, REG05, REG06, REG07, REG08, REG09, REG10, REG11} */ -static const struct _coeff_div coeff_div[] = { - {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, - {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x23, 0x47}, - {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {64, 8000, 512000, 0x60, 0x00, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - - {64, 44100, 2822400, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {64, 48000, 3072000, 0x00, 0x00, 0x11, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x0A, 0x1B, 0x23, 0x47}, - {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0x38, 0x08, 0x4f, 0x1f}, - {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {128, 8000, 1024000, 0x60, 0x00, 0x13, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {128, 16000, 2048000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - - {128, 44100, 5644800, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {128, 48000, 6144000, 0x00, 0x00, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x3F}, - {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {256, 8000, 2048000, 0x60, 0x00, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - - {256, 44100, 11289600, 0x00, 0x00, 0x10, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {256, 48000, 12288000, 0x00, 0x00, 0x30, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x23, 0x47}, - {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, - {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {400, 48000, 19200000, 0x09, 0x04, 0x0f, 0x6d, 0x3a, 0x0A, 0x4F, 0x1F}, - {500, 48000, 24000000, 0x18, 0x04, 0x1F, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {512, 16000, 8192000, 0x20, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - - {512, 44100, 22579200, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {512, 48000, 24576000, 0x00, 0x00, 0x00, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x0A, 0x0A, 0x1F, 0x1F}, - {1024, 8000, 8192000, 0x60, 0x00, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, +static const struct _coeff_div coeff_div_v0[] = { + {64, 8000, 512000, 0x60, 0x01, 0x0F, 0x75, 0x0A, 0x1B, 0x1F, 0x7F}, + {64, 16000, 1024000, 0x20, 0x00, 0x33, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {64, 44100, 2822400, 0xE0, 0x00, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {64, 48000, 3072000, 0xE0, 0x00, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {128, 8000, 1024000, 0x60, 0x00, 0x33, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {128, 16000, 2048000, 0x20, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {128, 44100, 5644800, 0xE0, 0x01, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {128, 48000, 6144000, 0xE0, 0x01, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + + {192, 32000, 6144000, 0xE0, 0x02, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {256, 8000, 2048000, 0x60, 0x00, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {256, 16000, 4096000, 0x20, 0x01, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {256, 44100, 11289600, 0xE0, 0x00, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {256, 48000, 12288000, 0xE0, 0x00, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {384, 32000, 12288000, 0xE0, 0x05, 0x03, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {400, 48000, 19200000, 0xE9, 0x04, 0x0F, 0x6d, 0x4A, 0x0A, 0x1F, 0x1F}, + + {500, 48000, 24000000, 0xF8, 0x04, 0x3F, 0x6D, 0x4A, 0x0A, 0x1F, 0x1F}, + {512, 8000, 4096000, 0x60, 0x01, 0x03, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, + {512, 16000, 8192000, 0x20, 0x00, 0x30, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, + {512, 44100, 22579200, 0xE0, 0x00, 0x00, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {512, 48000, 24576000, 0xE0, 0x00, 0x00, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {768, 32000, 24576000, 0xE0, 0x02, 0x30, 0x2D, 0x4A, 0x0A, 0x1F, 0x1F}, + {1024, 8000, 8192000, 0x60, 0x00, 0x30, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - - {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x3F}, - {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, - {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x5F}, - {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x0A, 0x1B, 0x1F, 0x7F}, - {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x0A, 0x0A, 0x27, 0x27}, +}; +static const struct _coeff_div coeff_div_v3[] = { + {32, 8000, 256000, 0x60, 0x00, 0x0F, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {32, 16000, 512000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {32, 44100, 1411200, 0x00, 0x00, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + {32, 48000, 1536000, 0x00, 0x00, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + {36, 8000, 288000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x23, 0x47}, + {36, 16000, 576000, 0x20, 0x00, 0x0D, 0x75, 0x8A, 0x1B, 0x23, 0x47}, + {48, 8000, 384000, 0x60, 0x02, 0x1F, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {48, 16000, 768000, 0x20, 0x02, 0x0F, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {48, 48000, 2304000, 0x00, 0x02, 0x0D, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + + {64, 8000, 512000, 0x60, 0x00, 0x35, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {64, 16000, 1024000, 0x20, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {64, 44100, 2822400, 0xE0, 0x00, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {64, 48000, 3072000, 0xE0, 0x00, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {72, 8000, 576000, 0x20, 0x00, 0x13, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {72, 16000, 1152000, 0x20, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x23, 0x47}, + {96, 8000, 768000, 0x60, 0x02, 0x1D, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {96, 16000, 1536000, 0x20, 0x02, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x3F}, + {100, 48000, 4800000, 0x04, 0x04, 0x3F, 0x6D, 0xB8, 0x08, 0x4f, 0x1f}, + {125, 48000, 6000000, 0x04, 0x04, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, + + {128, 8000, 1024000, 0x60, 0x00, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {128, 16000, 2048000, 0x20, 0x00, 0x31, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {128, 44100, 5644800, 0xE0, 0x00, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {128, 48000, 6144000, 0xE0, 0x00, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {144, 8000, 1152000, 0x20, 0x00, 0x03, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {144, 16000, 2304000, 0x20, 0x00, 0x11, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {192, 8000, 1536000, 0x60, 0x02, 0x0D, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {192, 32000, 6144000, 0xE0, 0x02, 0x31, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {192, 16000, 3072000, 0x20, 0x02, 0x05, 0x75, 0xCA, 0x1B, 0x1F, 0x3F}, + + {200, 48000, 9600000, 0x04, 0x04, 0x0F, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {250, 48000, 12000000, 0x04, 0x04, 0x0F, 0x2D, 0xCA, 0x0A, 0x27, 0x27}, + {256, 8000, 2048000, 0x60, 0x00, 0x31, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {256, 44100, 11289600, 0xE0, 0x00, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {256, 48000, 12288000, 0xE0, 0x00, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {288, 8000, 2304000, 0x20, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x23, 0x47}, + {384, 8000, 3072000, 0x60, 0x02, 0x05, 0x75, 0x8A, 0x1B, 0x1F, 0x7F}, + {384, 16000, 6144000, 0x20, 0x02, 0x03, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {384, 32000, 12288000, 0xE0, 0x02, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {384, 48000, 18432000, 0x00, 0x02, 0x01, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + + {400, 48000, 19200000, 0xE4, 0x04, 0x35, 0x6d, 0xCA, 0x0A, 0x1F, 0x1F}, + {500, 48000, 24000000, 0xF8, 0x04, 0x3F, 0x6D, 0xCA, 0x0A, 0x1F, 0x1F}, + {512, 8000, 4096000, 0x60, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {512, 16000, 8192000, 0x20, 0x00, 0x30, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {512, 44100, 22579200, 0xE0, 0x00, 0x00, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {512, 48000, 24576000, 0xE0, 0x00, 0x00, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {768, 8000, 6144000, 0x60, 0x02, 0x11, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {768, 16000, 12288000, 0x20, 0x02, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {768, 32000, 24576000, 0xE0, 0x02, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {800, 48000, 38400000, 0x00, 0x18, 0x13, 0x2D, 0x8A, 0x0A, 0x1F, 0x1F}, + + {1024, 8000, 8192000, 0x60, 0x00, 0x30, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {1024, 16000, 16384000, 0x20, 0x00, 0x00, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {1152, 16000, 18432000, 0x20, 0x08, 0x11, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {1536, 8000, 12288000, 0x60, 0x02, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {1536, 16000, 24576000, 0x20, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, + {1625, 8000, 13000000, 0x0C, 0x18, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, + {1625, 16000, 26000000, 0x0C, 0x18, 0x1F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, + {2048, 8000, 16384000, 0x60, 0x00, 0x00, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {2304, 8000, 18432000, 0x40, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x5F}, + {3072, 8000, 24576000, 0x60, 0x02, 0x10, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, + {3250, 8000, 26000000, 0x0C, 0x18, 0x0F, 0x2D, 0x8A, 0x0A, 0x27, 0x27}, }; -static inline int get_coeff(int mclk, int rate) +static inline int get_coeff(int mclk, int rate, int array, + const struct _coeff_div *coeff_div) { int i; - for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + for (i = 0; i < array; i++) { if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) return i; } @@ -333,11 +372,19 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + const struct _coeff_div *coeff_div; struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); u8 srate = 0; - int coeff; + int coeff, array; - coeff = get_coeff(es8326->sysclk, params_rate(params)); + if (es8326->version == 0) { + coeff_div = coeff_div_v0; + array = ARRAY_SIZE(coeff_div_v0); + } else { + coeff_div = coeff_div_v3; + array = ARRAY_SIZE(coeff_div_v3); + } + coeff = get_coeff(es8326->sysclk, params_rate(params), array, coeff_div); /* bit size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -409,8 +456,8 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r); es8326->calibrated = true; } - regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa0); - regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x91); regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON); regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK, ~(ES8326_MUTE)); @@ -430,8 +477,6 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, if (ret) return ret; - regmap_write(es8326->regmap, ES8326_RESET, 0x9f); - msleep(20); regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00); regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, @@ -440,19 +485,21 @@ static int es8326_set_bias_level(struct snd_soc_component *codec, regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40); regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00); regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x20); - regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON); + + regmap_update_bits(es8326->regmap, ES8326_RESET, + ES8326_CSM_ON, ES8326_CSM_ON); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - break; - case SND_SOC_BIAS_OFF: - clk_disable_unprepare(es8326->mclk); regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b); regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00); regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT); break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(es8326->mclk); + break; } return 0; @@ -594,7 +641,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); - if (es8326->jack_remove_retry == 1) { + if ((es8326->jack_remove_retry == 1) && (es8326->version != ES8326_VERSION_B)) { if (iface & ES8326_HPINSERT_FLAG) es8326->jack_remove_retry = 2; else @@ -628,7 +675,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) /* * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event */ - if (es8326->jack_remove_retry == 0) { + if ((es8326->jack_remove_retry == 0) && (es8326->version != ES8326_VERSION_B)) { es8326->jack_remove_retry = 1; dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n", es8326->jack_remove_retry); @@ -644,14 +691,14 @@ static void es8326_jack_detect_handler(struct work_struct *work) if (es8326->hp == 0) { dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n"); /* - * set auto-check mode, then restart jack_detect_work after 100ms. + * set auto-check mode, then restart jack_detect_work after 400ms. * Don't report jack status. */ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); usleep_range(50000, 70000); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); queue_delayed_work(system_wq, &es8326->jack_detect_work, - msecs_to_jiffies(100)); + msecs_to_jiffies(400)); es8326->hp = 1; goto exit; } @@ -701,7 +748,7 @@ static irqreturn_t es8326_irq(int irq, void *dev_id) msecs_to_jiffies(10)); else queue_delayed_work(system_wq, &es8326->jack_detect_work, - msecs_to_jiffies(600)); + msecs_to_jiffies(300)); out: return IRQ_HANDLED; @@ -722,13 +769,15 @@ static int es8326_calibrate(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x01); regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30); regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed); + regmap_write(es8326->regmap, ES8326_CLK_DAC_SEL, 0x08); regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1); regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03); regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f); - regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x33); + regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x03); regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88); - regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80); + usleep_range(15000, 20000); regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c); + usleep_range(15000, 20000); regmap_write(es8326->regmap, ES8326_RESET, 0xc0); usleep_range(15000, 20000); @@ -766,27 +815,27 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_RESET, 0x1f); regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); usleep_range(10000, 15000); - regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0xe9); + regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4b); /* set headphone default type and detect pin */ - regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x81); + regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x83); regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05); + regmap_write(es8326->regmap, ES8326_HP_MISC, 0x30); /* set internal oscillator as clock source of headpone cp */ - regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x84); + regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x89); regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON); /* clock manager reset release */ regmap_write(es8326->regmap, ES8326_RESET, 0x17); /* set headphone detection as half scan mode */ - regmap_write(es8326->regmap, ES8326_HP_MISC, 0x08); + regmap_write(es8326->regmap, ES8326_HP_MISC, 0x30); regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00); /* enable headphone driver */ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7); usleep_range(2000, 5000); - regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xab); - usleep_range(2000, 5000); - regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xbb); - usleep_range(2000, 5000); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xa3); + regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xb3); regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1); regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00); @@ -800,9 +849,6 @@ static int es8326_resume(struct snd_soc_component *component) /* set ADC and DAC in low power mode */ regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0); - /* force micbias on */ - regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4f); - regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08); regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F); /* select vdda as micbias source */ regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23); @@ -830,6 +876,7 @@ static int es8326_resume(struct snd_soc_component *component) ((es8326->version == ES8326_VERSION_B) ? (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); + regmap_write(es8326->regmap, ES8326_HP_VOL, 0x11); es8326->jack_remove_retry = 0; es8326->hp = 0; diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index 47f000cd4d99..97a54059474c 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -169,6 +169,7 @@ static int nau8810_eq_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *params = (void *)kcontrol->private_value; int i, reg, reg_val; u16 *val; + __be16 tmp; val = (u16 *)ucontrol->value.bytes.data; reg = NAU8810_REG_EQ1; @@ -177,8 +178,8 @@ static int nau8810_eq_get(struct snd_kcontrol *kcontrol, /* conversion of 16-bit integers between native CPU format * and big endian format */ - reg_val = cpu_to_be16(reg_val); - memcpy(val + i, ®_val, sizeof(reg_val)); + tmp = cpu_to_be16(reg_val); + memcpy(val + i, &tmp, sizeof(tmp)); } return 0; @@ -201,6 +202,7 @@ static int nau8810_eq_put(struct snd_kcontrol *kcontrol, void *data; u16 *val, value; int i, reg, ret; + __be16 *tmp; data = kmemdup(ucontrol->value.bytes.data, params->max, GFP_KERNEL | GFP_DMA); @@ -213,7 +215,8 @@ static int nau8810_eq_put(struct snd_kcontrol *kcontrol, /* conversion of 16-bit integers between native CPU format * and big endian format */ - value = be16_to_cpu(*(val + i)); + tmp = (__be16 *)(val + i); + value = be16_to_cpup(tmp); ret = regmap_write(nau8810->regmap, reg + i, value); if (ret) { dev_err(component->dev, "EQ configuration fail, register: %x ret: %d\n", diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index 6e1b6b26298a..012e347e6391 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -1738,6 +1738,10 @@ static int nau8821_read_device_properties(struct device *dev, &nau8821->dmic_clk_threshold); if (ret) nau8821->dmic_clk_threshold = 3072000; + ret = device_property_read_u32(dev, "nuvoton,dmic-slew-rate", + &nau8821->dmic_slew_rate); + if (ret) + nau8821->dmic_slew_rate = 0; return 0; } @@ -1797,6 +1801,9 @@ static void nau8821_init_regs(struct nau8821 *nau8821) NAU8821_ADC_SYNC_DOWN_MASK, NAU8821_ADC_SYNC_DOWN_64); regmap_update_bits(regmap, NAU8821_R2C_DAC_CTRL1, NAU8821_DAC_OVERSAMPLE_MASK, NAU8821_DAC_OVERSAMPLE_64); + regmap_update_bits(regmap, NAU8821_R13_DMIC_CTRL, + NAU8821_DMIC_SLEW_MASK, nau8821->dmic_slew_rate << + NAU8821_DMIC_SLEW_SFT); if (nau8821->left_input_single_end) { regmap_update_bits(regmap, NAU8821_R6B_PGA_MUTE, NAU8821_MUTE_MICNL_EN, NAU8821_MUTE_MICNL_EN); diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h index 00a888ed07ce..62eaad130b2e 100644 --- a/sound/soc/codecs/nau8821.h +++ b/sound/soc/codecs/nau8821.h @@ -236,6 +236,8 @@ #define NAU8821_DMIC_SRC_MASK (0x3 << NAU8821_DMIC_SRC_SFT) #define NAU8821_CLK_DMIC_SRC (0x2 << NAU8821_DMIC_SRC_SFT) #define NAU8821_DMIC_EN_SFT 0 +#define NAU8821_DMIC_SLEW_SFT 8 +#define NAU8821_DMIC_SLEW_MASK (0x7 << NAU8821_DMIC_SLEW_SFT) /* GPIO12_CTRL (0x1a) */ #define NAU8821_JKDET_PULL_UP (0x1 << 11) /* 0 - pull down, 1 - pull up */ @@ -573,6 +575,7 @@ struct nau8821 { int jack_eject_debounce; int fs; int dmic_clk_threshold; + int dmic_slew_rate; int key_enable; }; diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index c261c33c4be7..3322056bbb3b 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -2971,6 +2971,8 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev) &rt5682s->pdata.dmic_delay); device_property_read_u32(dev, "realtek,amic-delay-ms", &rt5682s->pdata.amic_delay); + device_property_read_u32(dev, "realtek,ldo-sel", + &rt5682s->pdata.ldo_dacref); if (device_property_read_string_array(dev, "clock-output-names", rt5682s->pdata.dai_clk_names, @@ -3250,6 +3252,27 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c) break; } + /* LDO output voltage control */ + switch (rt5682s->pdata.ldo_dacref) { + case RT5682S_LDO_1_607V: + break; + case RT5682S_LDO_1_5V: + regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7, + RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_5V); + break; + case RT5682S_LDO_1_406V: + regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7, + RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_406V); + break; + case RT5682S_LDO_1_731V: + regmap_update_bits(rt5682s->regmap, RT5682S_BIAS_CUR_CTRL_7, + RT5682S_LDO_DACREF_MASK, RT5682S_LDO_DACREF_1_731V); + break; + default: + dev_warn(&i2c->dev, "invalid LDO output setting.\n"); + break; + } + INIT_DELAYED_WORK(&rt5682s->jack_detect_work, rt5682s_jack_detect_handler); INIT_DELAYED_WORK(&rt5682s->jd_check_work, rt5682s_jd_check_handler); diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h index 1d79d432d0d8..67f42898de96 100644 --- a/sound/soc/codecs/rt5682s.h +++ b/sound/soc/codecs/rt5682s.h @@ -1263,6 +1263,13 @@ #define RT5682S_JDH_NO_PLUG (0x1 << 4) #define RT5682S_JDH_PLUG (0x0 << 4) +/* Bias current control 7 (0x0110) */ +#define RT5682S_LDO_DACREF_MASK (0x3 << 4) +#define RT5682S_LDO_DACREF_1_607V (0x0 << 4) +#define RT5682S_LDO_DACREF_1_5V (0x1 << 4) +#define RT5682S_LDO_DACREF_1_406V (0x2 << 4) +#define RT5682S_LDO_DACREF_1_731V (0x3 << 4) + /* Charge Pump Internal Register1 (0x0125) */ #define RT5682S_CP_CLK_HP_MASK (0x3 << 4) #define RT5682S_CP_CLK_HP_100KHZ (0x0 << 4) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 725c530a3636..bec2aa561930 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -183,19 +183,6 @@ config SND_SOC_POWERPC_QMC_AUDIO comment "SoC Audio support for Freescale PPC boards:" -config SND_SOC_MPC8610_HPCD - tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" - # I2C is necessary for the CS4270 driver - depends on MPC8610_HPCD && I2C - select SND_SOC_FSL_SSI - select SND_SOC_FSL_UTILS - select SND_SOC_POWERPC_DMA - select SND_SOC_CS4270 - select SND_SOC_CS4270_VD33_ERRATA - default y if MPC8610_HPCD - help - Say Y if you want to enable audio on the Freescale MPC8610 HPCD. - config SND_SOC_P1022_DS tristate "ALSA SoC support for the Freescale P1022 DS board" # I2C is necessary for the WM8776 driver diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8db7e97d0bd5..b45eda80c196 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -1,8 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# MPC8610 HPCD Machine Support -snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o -obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o - # P1022 DS Machine Support snd-soc-p1022-ds-objs := p1022_ds.o obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index f2d74ec05cdf..86704ba5f6f0 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -10,7 +10,6 @@ #include <linux/moduleparam.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> -#include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/pm.h> diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index a0c5c35817dd..e5bd63dab10c 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -2,9 +2,8 @@ // Copyright 2017-2020 NXP #include <linux/module.h> -#include <linux/of.h> +#include <linux/of_platform.h> #include <linux/of_reserved_mem.h> -#include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/of_gpio.h> #include <linux/slab.h> @@ -21,8 +20,11 @@ struct imx_rpmsg { struct snd_soc_dai_link dai; struct snd_soc_card card; unsigned long sysclk; + bool lpa; }; +static struct dev_pm_ops lpa_pm; + static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), @@ -39,6 +41,58 @@ static int imx_rpmsg_late_probe(struct snd_soc_card *card) struct device *dev = card->dev; int ret; + if (data->lpa) { + struct snd_soc_component *codec_comp; + struct device_node *codec_np; + struct device_driver *codec_drv; + struct device *codec_dev = NULL; + + codec_np = data->dai.codecs->of_node; + if (codec_np) { + struct platform_device *codec_pdev; + struct i2c_client *codec_i2c; + + codec_i2c = of_find_i2c_device_by_node(codec_np); + if (codec_i2c) + codec_dev = &codec_i2c->dev; + if (!codec_dev) { + codec_pdev = of_find_device_by_node(codec_np); + if (codec_pdev) + codec_dev = &codec_pdev->dev; + } + } + if (codec_dev) { + codec_comp = snd_soc_lookup_component_nolocked(codec_dev, NULL); + if (codec_comp) { + int i, num_widgets; + const char *widgets; + struct snd_soc_dapm_context *dapm; + + num_widgets = of_property_count_strings(data->card.dev->of_node, + "ignore-suspend-widgets"); + for (i = 0; i < num_widgets; i++) { + of_property_read_string_index(data->card.dev->of_node, + "ignore-suspend-widgets", + i, &widgets); + dapm = snd_soc_component_get_dapm(codec_comp); + snd_soc_dapm_ignore_suspend(dapm, widgets); + } + } + codec_drv = codec_dev->driver; + if (codec_drv->pm) { + memcpy(&lpa_pm, codec_drv->pm, sizeof(lpa_pm)); + lpa_pm.suspend = NULL; + lpa_pm.resume = NULL; + lpa_pm.freeze = NULL; + lpa_pm.thaw = NULL; + lpa_pm.poweroff = NULL; + lpa_pm.restore = NULL; + codec_drv->pm = &lpa_pm; + } + put_device(codec_dev); + } + } + if (!data->sysclk) return 0; @@ -138,6 +192,9 @@ static int imx_rpmsg_probe(struct platform_device *pdev) goto fail; } + if (of_property_read_bool(np, "fsl,enable-lpa")) + data->lpa = true; + data->card.dev = &pdev->dev; data->card.owner = THIS_MODULE; data->card.dapm_widgets = imx_rpmsg_dapm_widgets; diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c deleted file mode 100644 index 52fb9e7bcca4..000000000000 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ /dev/null @@ -1,451 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Freescale MPC8610HPCD ALSA SoC Machine driver -// -// Author: Timur Tabi <timur@freescale.com> -// -// Copyright 2007-2010 Freescale Semiconductor, Inc. - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/fsl/guts.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/slab.h> -#include <sound/soc.h> - -#include "fsl_dma.h" -#include "fsl_ssi.h" -#include "fsl_utils.h" - -/* There's only one global utilities register */ -static phys_addr_t guts_phys; - -/** - * mpc8610_hpcd_data: machine-specific ASoC device data - * - * This structure contains data for a single sound platform device on an - * MPC8610 HPCD. Some of the data is taken from the device tree. - */ -struct mpc8610_hpcd_data { - struct snd_soc_dai_link dai[2]; - struct snd_soc_card card; - unsigned int dai_format; - unsigned int codec_clk_direction; - unsigned int cpu_clk_direction; - unsigned int clk_frequency; - unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */ - unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */ - unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ - char codec_dai_name[DAI_NAME_SIZE]; - char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ -}; - -/** - * mpc8610_hpcd_machine_probe: initialize the board - * - * This function is used to initialize the board-specific hardware. - * - * Here we program the DMACR and PMUXCR registers. - */ -static int mpc8610_hpcd_machine_probe(struct snd_soc_card *card) -{ - struct mpc8610_hpcd_data *machine_data = - container_of(card, struct mpc8610_hpcd_data, card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); - if (!guts) { - dev_err(card->dev, "could not map global utilities\n"); - return -ENOMEM; - } - - /* Program the signal routing between the SSI and the DMA */ - guts_set_dmacr(guts, machine_data->dma_id[0], - machine_data->dma_channel_id[0], - CCSR_GUTS_DMACR_DEV_SSI); - guts_set_dmacr(guts, machine_data->dma_id[1], - machine_data->dma_channel_id[1], - CCSR_GUTS_DMACR_DEV_SSI); - - guts_set_pmuxcr_dma(guts, machine_data->dma_id[0], - machine_data->dma_channel_id[0], 0); - guts_set_pmuxcr_dma(guts, machine_data->dma_id[1], - machine_data->dma_channel_id[1], 0); - - switch (machine_data->ssi_id) { - case 0: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI); - break; - case 1: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI); - break; - } - - iounmap(guts); - - return 0; -} - -/** - * mpc8610_hpcd_startup: program the board with various hardware parameters - * - * This function takes board-specific information, like clock frequencies - * and serial data formats, and passes that information to the codec and - * transport drivers. - */ -static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct mpc8610_hpcd_data *machine_data = - container_of(rtd->card, struct mpc8610_hpcd_data, card); - struct device *dev = rtd->card->dev; - int ret = 0; - - /* Tell the codec driver what the serial protocol is. */ - ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_codec(rtd, 0), machine_data->dai_format); - if (ret < 0) { - dev_err(dev, "could not set codec driver audio format\n"); - return ret; - } - - /* - * Tell the codec driver what the MCLK frequency is, and whether it's - * a slave or master. - */ - ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(rtd, 0), 0, - machine_data->clk_frequency, - machine_data->codec_clk_direction); - if (ret < 0) { - dev_err(dev, "could not set codec driver clock params\n"); - return ret; - } - - return 0; -} - -/** - * mpc8610_hpcd_machine_remove: Remove the sound device - * - * This function is called to remove the sound device for one SSI. We - * de-program the DMACR and PMUXCR register. - */ -static int mpc8610_hpcd_machine_remove(struct snd_soc_card *card) -{ - struct mpc8610_hpcd_data *machine_data = - container_of(card, struct mpc8610_hpcd_data, card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); - if (!guts) { - dev_err(card->dev, "could not map global utilities\n"); - return -ENOMEM; - } - - /* Restore the signal routing */ - - guts_set_dmacr(guts, machine_data->dma_id[0], - machine_data->dma_channel_id[0], 0); - guts_set_dmacr(guts, machine_data->dma_id[1], - machine_data->dma_channel_id[1], 0); - - switch (machine_data->ssi_id) { - case 0: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); - break; - case 1: - clrsetbits_be32(&guts->pmuxcr, - CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA); - break; - } - - iounmap(guts); - - return 0; -} - -/** - * mpc8610_hpcd_ops: ASoC machine driver operations - */ -static const struct snd_soc_ops mpc8610_hpcd_ops = { - .startup = mpc8610_hpcd_startup, -}; - -/** - * mpc8610_hpcd_probe: platform probe function for the machine driver - * - * Although this is a machine driver, the SSI node is the "master" node with - * respect to audio hardware connections. Therefore, we create a new ASoC - * device for each new SSI node that has a codec attached. - */ -static int mpc8610_hpcd_probe(struct platform_device *pdev) -{ - struct device *dev = pdev->dev.parent; - /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = to_platform_device(dev); - struct device_node *np = ssi_pdev->dev.of_node; - struct device_node *codec_np = NULL; - struct mpc8610_hpcd_data *machine_data; - struct snd_soc_dai_link_component *comp; - int ret; - const char *sprop; - const u32 *iprop; - - /* Find the codec node for this SSI. */ - codec_np = of_parse_phandle(np, "codec-handle", 0); - if (!codec_np) { - dev_err(dev, "invalid codec node\n"); - return -EINVAL; - } - - machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL); - if (!machine_data) { - ret = -ENOMEM; - goto error_alloc; - } - - comp = devm_kzalloc(&pdev->dev, 6 * sizeof(*comp), GFP_KERNEL); - if (!comp) { - ret = -ENOMEM; - goto error_alloc; - } - - machine_data->dai[0].cpus = &comp[0]; - machine_data->dai[0].codecs = &comp[1]; - machine_data->dai[0].platforms = &comp[2]; - - machine_data->dai[0].num_cpus = 1; - machine_data->dai[0].num_codecs = 1; - machine_data->dai[0].num_platforms = 1; - - machine_data->dai[1].cpus = &comp[3]; - machine_data->dai[1].codecs = &comp[4]; - machine_data->dai[1].platforms = &comp[5]; - - machine_data->dai[1].num_cpus = 1; - machine_data->dai[1].num_codecs = 1; - machine_data->dai[1].num_platforms = 1; - - machine_data->dai[0].cpus->dai_name = dev_name(&ssi_pdev->dev); - machine_data->dai[0].ops = &mpc8610_hpcd_ops; - - /* ASoC core can match codec with device node */ - machine_data->dai[0].codecs->of_node = codec_np; - - /* The DAI name from the codec (snd_soc_dai_driver.name) */ - machine_data->dai[0].codecs->dai_name = "cs4270-hifi"; - - /* We register two DAIs per SSI, one for playback and the other for - * capture. Currently, we only support codecs that have one DAI for - * both playback and capture. - */ - memcpy(&machine_data->dai[1], &machine_data->dai[0], - sizeof(struct snd_soc_dai_link)); - - /* Get the device ID */ - iprop = of_get_property(np, "cell-index", NULL); - if (!iprop) { - dev_err(&pdev->dev, "cell-index property not found\n"); - ret = -EINVAL; - goto error; - } - machine_data->ssi_id = be32_to_cpup(iprop); - - /* Get the serial format and clock direction. */ - sprop = of_get_property(np, "fsl,mode", NULL); - if (!sprop) { - dev_err(&pdev->dev, "fsl,mode property not found\n"); - ret = -EINVAL; - goto error; - } - - if (strcasecmp(sprop, "i2s-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - - /* In i2s-slave mode, the codec has its own clock source, so we - * need to get the frequency from the device tree and pass it to - * the codec driver. - */ - iprop = of_get_property(codec_np, "clock-frequency", NULL); - if (!iprop || !*iprop) { - dev_err(&pdev->dev, "codec bus-frequency " - "property is missing or invalid\n"); - ret = -EINVAL; - goto error; - } - machine_data->clk_frequency = be32_to_cpup(iprop); - } else if (strcasecmp(sprop, "i2s-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else if (strcasecmp(sprop, "lj-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - } else if (strcasecmp(sprop, "lj-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else if (strcasecmp(sprop, "rj-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - } else if (strcasecmp(sprop, "rj-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else if (strcasecmp(sprop, "ac97-slave") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBP_CFP; - machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; - } else if (strcasecmp(sprop, "ac97-master") == 0) { - machine_data->dai_format = - SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBC_CFC; - machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; - machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; - } else { - dev_err(&pdev->dev, - "unrecognized fsl,mode property '%s'\n", sprop); - ret = -EINVAL; - goto error; - } - - if (!machine_data->clk_frequency) { - dev_err(&pdev->dev, "unknown clock frequency\n"); - ret = -EINVAL; - goto error; - } - - /* Find the playback DMA channel to use. */ - machine_data->dai[0].platforms->name = machine_data->platform_name[0]; - ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", - &machine_data->dai[0], - &machine_data->dma_channel_id[0], - &machine_data->dma_id[0]); - if (ret) { - dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n"); - goto error; - } - - /* Find the capture DMA channel to use. */ - machine_data->dai[1].platforms->name = machine_data->platform_name[1]; - ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", - &machine_data->dai[1], - &machine_data->dma_channel_id[1], - &machine_data->dma_id[1]); - if (ret) { - dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n"); - goto error; - } - - /* Initialize our DAI data structure. */ - machine_data->dai[0].stream_name = "playback"; - machine_data->dai[1].stream_name = "capture"; - machine_data->dai[0].name = machine_data->dai[0].stream_name; - machine_data->dai[1].name = machine_data->dai[1].stream_name; - - machine_data->card.probe = mpc8610_hpcd_machine_probe; - machine_data->card.remove = mpc8610_hpcd_machine_remove; - machine_data->card.name = pdev->name; /* The platform driver name */ - machine_data->card.owner = THIS_MODULE; - machine_data->card.dev = &pdev->dev; - machine_data->card.num_links = 2; - machine_data->card.dai_link = machine_data->dai; - - /* Register with ASoC */ - ret = snd_soc_register_card(&machine_data->card); - if (ret) { - dev_err(&pdev->dev, "could not register card\n"); - goto error; - } - - of_node_put(codec_np); - - return 0; - -error: - kfree(machine_data); -error_alloc: - of_node_put(codec_np); - return ret; -} - -/** - * mpc8610_hpcd_remove: remove the platform device - * - * This function is called when the platform device is removed. - */ -static void mpc8610_hpcd_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct mpc8610_hpcd_data *machine_data = - container_of(card, struct mpc8610_hpcd_data, card); - - snd_soc_unregister_card(card); - kfree(machine_data); -} - -static struct platform_driver mpc8610_hpcd_driver = { - .probe = mpc8610_hpcd_probe, - .remove_new = mpc8610_hpcd_remove, - .driver = { - /* The name must match 'compatible' property in the device tree, - * in lowercase letters. - */ - .name = "snd-soc-mpc8610hpcd", - }, -}; - -/** - * mpc8610_hpcd_init: machine driver initialization. - * - * This function is called when this module is loaded. - */ -static int __init mpc8610_hpcd_init(void) -{ - struct device_node *guts_np; - struct resource res; - - pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n"); - - /* Get the physical address of the global utilities registers */ - guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); - if (of_address_to_resource(guts_np, 0, &res)) { - pr_err("mpc8610-hpcd: missing/invalid global utilities node\n"); - of_node_put(guts_np); - return -EINVAL; - } - guts_phys = res.start; - of_node_put(guts_np); - - return platform_driver_register(&mpc8610_hpcd_driver); -} - -/** - * mpc8610_hpcd_exit: machine driver exit - * - * This function is called when this driver is unloaded. - */ -static void __exit mpc8610_hpcd_exit(void) -{ - platform_driver_unregister(&mpc8610_hpcd_driver); -} - -module_init(mpc8610_hpcd_init); -module_exit(mpc8610_hpcd_exit); - -MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); -MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi index 8acaa2ddb335..9efd31206c9b 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi @@ -58,12 +58,32 @@ * | |-> codec13 * +-+ * - * [Multi-CPU/Codec] + * [Multi-CPU/Codec-0] * +-+ +-+ * cpu1 <--| |<-@--------->| |-> codec1 * cpu2 <--| | | |-> codec2 * +-+ +-+ * + * [Multi-CPU/Codec-1] + * + * +-+ +-+ + * | |<-@--------->| | + * | | | | + * cpu8 <--| |<----------->| |-> codec14 + * cpu9 <--| |<---+------->| |-> codec15 + * +-+ \------>| |-> codec16 + * +-+ + * + * [Multi-CPU/Codec-2] + * + * +-+ +-+ + * | |<-@--------->| | + * | | | | + * cpu10 <-| |<----------->| |-> codec17 + * cpu11 <-| |<-----+----->| |-> codec18 + * cpu12 <-| |<----/ +-+ + * +-+ + * * [DPCM] * * CPU3/CPU4 are converting rate to 44100 @@ -144,16 +164,39 @@ */ &cpu0 - /* [Semi-Multi] */ + /* + * [Semi-Multi] + * cpu7/codec12/codec13 + */ &sm0 /* - * [Multi-CPU/Codec]: cpu side only + * [Multi-CPU/Codec-0]: cpu side only * cpu1/cpu2/codec1/codec2 */ &mcpu0 /* + * [Multi-CPU/Codec-1]: cpu side only + * cpu8/cpu9/codec14/codec15/codec16 + * + * Because it will reach to the maximum of sound minor number, + * disable it so far. + * If you want to try it, please disable some other one instead. + */ + //&mcpu1 + + /* + * [Multi-CPU/Codec-2]: cpu side only + * cpu10/cpu11/cpu12/codec17/codec18 + * + * Because it will reach to the maximum of sound minor number, + * disable it so far. + * If you want to try it, please disable some other one instead. + */ + //&mcpu2 + + /* * [DPCM]: both FE / BE * cpu3/cpu4/codec3 */ @@ -182,64 +225,259 @@ #address-cells = <1>; #size-cells = <0>; + /* + * [Multi-CPU-0] + * + * +---+ +---+ + * cpu1 <--|A X|<-@------->|x a|-> codec1 + * cpu2 <--|B | | b|-> codec2 + * +---+ +---+ + */ ports@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; - /* [Multi-CPU] */ - mcpu0: port@0 { reg = <0>; mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; - port@1 { reg = <1>; mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; - port@2 { reg = <2>; mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; + mcpu0: port@0 { reg = <0>; mcpu00_ep: endpoint { remote-endpoint = <&mcodec00_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; mcpu01_ep: endpoint { remote-endpoint = <&cpu1_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; mcpu02_ep: endpoint { remote-endpoint = <&cpu2_ep>; };};/* (B) Multi Element */ }; - /* [Multi-Codec] */ + /* + * [Multi-Codec-0] + * + * +---+ +---+ + * cpu1 <--|A X|<-@------->|x a|-> codec1 + * cpu2 <--|B | | b|-> codec2 + * +---+ +---+ + */ ports@1 { reg = <1>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; - port@1 { reg = <1>; mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; - port@2 { reg = <2>; mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; + port@0 { reg = <0>; mcodec00_ep: endpoint { remote-endpoint = <&mcpu00_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mcodec01_ep: endpoint { remote-endpoint = <&codec1_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mcodec02_ep: endpoint { remote-endpoint = <&codec2_ep>; };};/* (b) Multi Element */ }; - /* [DPCM-Multi]::BE */ + /* + * [DPCM-Multi]::BE + * + * FE BE + * **** +---+ + * cpu5 <-@--* *-----@--->|x a|-> codec4 + * cpu6 <-@--* * | b|-> codec5 + * **** +---+ + */ ports@2 { reg = <2>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; }; }; - port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; }; }; - port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; }; }; + port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; };};/* (b) Multi Element */ }; - /* [Codec2Codec-Multi]::CPU */ + /* + * [Codec2Codec-Multi]::CPU + * + * +---+ + * +-@->|X A|-> codec8 + * | | B|-> codec9 + * | +---+ + * | +---+ + * +--->|x a|-> codec10 + * | b|-> codec11 + * +---+ + */ ports@3 { reg = <3>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; }; }; - port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; }; }; - port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; }; }; + port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; };};/* (B) Multi Element */ }; - /* [Codec2Codec-Multi]::Codec */ + /* + * [Codec2Codec-Multi]::Codec + * + * +---+ + * +-@->|X A|-> codec8 + * | | B|-> codec9 + * | +---+ + * | +---+ + * +--->|x a|-> codec10 + * | b|-> codec11 + * +---+ + */ ports@4 { reg = <4>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; }; }; - port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; }; }; - port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; }; }; + port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; };};/* (b) Multi Element */ }; - /* [Semi-Multi] */ + /* + * [Semi-Multi] + * + * +---+ + * cpu7 <-@------->|X A|-> codec12 + * | B|-> codec13 + * +---+ + */ ports@5 { reg = <5>; #address-cells = <1>; #size-cells = <0>; - port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; }; }; - port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; }; }; - port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; }; }; + port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; };};/* (B) Multi Element */ + }; + + /* + * [Multi-CPU-1] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu8 <--|A 1|<--------->|3 a|-> codec14 + * cpu9 <--|B 2|<---+----->|4 b|-> codec15 + * +---+ \---->|5 c|-> codec16 + * +---+ + */ + ports@6 { + reg = <6>; + #address-cells = <1>; + #size-cells = <0>; + mcpu1: port@0 { reg = <0>; mcpu10_ep: endpoint { remote-endpoint = <&mcodec10_ep>; };}; /* (X) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu8_ep>; }; /* (A) Multi Element */ + mcpu11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec11_ep_0>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu9_ep>; }; /* (B) Multi Element */ + mcpu12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec12_ep_0>; }; /* (2) connected Codec */ + mcpu12_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec13_ep_0>; }; /* (2) connected Codec */ + }; + }; + + /* + * [Multi-Codec-1] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu8 <--|A 1|<--------->|3 a|-> codec14 + * cpu9 <--|B 2|<---+----->|4 b|-> codec15 + * +---+ \---->|5 c|-> codec16 + * +---+ + */ + ports@7 { + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mcodec10_ep: endpoint { remote-endpoint = <&mcpu10_ep>; };}; /* (x) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec14_ep>; }; /* (a) Multi Element */ + mcodec11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu11_ep_0>; }; /* (3) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec15_ep>; }; /* (b) Multi Element */ + mcodec12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_0>; }; /* (4) connected CPU */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcodec13_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec16_ep>; }; /* (c) Multi Element */ + mcodec13_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_1>; }; /* (5) connected CPU */ + }; + }; + + /* + * [Multi-CPU-2] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu10 <-|A 1|<--------->|4 a|-> codec17 + * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 + * cpu12 <-|C 3|<----/ +---+ + * +---+ + */ + ports@8 { + reg = <8>; + #address-cells = <1>; + #size-cells = <0>; + mcpu2: port@0 { reg = <0>; mcpu20_ep: endpoint { remote-endpoint = <&mcodec20_ep>; };}; /* (X) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu10_ep>; }; /* (A) Multi Element */ + mcpu21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec21_ep_0>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu11_ep>; }; /* (B) Multi Element */ + mcpu22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_0>; }; /* (2) connected Codec */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcpu23_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu12_ep>; }; /* (C) Multi Element */ + mcpu23_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_1>; }; /* (3) connected Codec */ + }; + }; + + /* + * [Multi-Codec-2] + * + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu10 <-|A 1|<--------->|4 a|-> codec17 + * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 + * cpu12 <-|C 3|<----/ +---+ + * +---+ + */ + ports@9 { + reg = <9>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mcodec20_ep: endpoint { remote-endpoint = <&mcpu20_ep>; };}; /* (x) to pair */ + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec17_ep>; }; /* (a) Multi Element */ + mcodec21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu21_ep_0>; }; /* (4) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec18_ep>; }; /* (b) Multi Element */ + mcodec22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu22_ep_0>; }; /* (5) connected CPU */ + mcodec22_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu23_ep_0>; }; /* (5) connected CPU */ + }; }; }; @@ -252,11 +490,27 @@ #address-cells = <1>; #size-cells = <0>; - /* [DPCM]::FE */ + /* + * [DPCM]::FE + * + * FE BE + * **** + * cpu3 <-@(fe00)--* *--(be0)@--> codec3 + * cpu4 <-@(fe01)--* * (44.1kHz) + * **** + */ fe00: port@0 { reg = <0>; fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; }; fe01: port@1 { reg = <1>; fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; }; - /* [DPCM-Multi]::FE */ + /* + * [DPCM-Multi]::FE + * + * FE BE + * **** +-+ + * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 + * cpu6 <-@(fe11)--* * | |-> codec5 + * **** +-+ + */ fe10: port@2 { reg = <2>; fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; }; fe11: port@3 { reg = <3>; fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; }; }; @@ -266,10 +520,26 @@ #address-cells = <1>; #size-cells = <0>; - /* [DPCM]::BE */ + /* + * [DPCM]::BE + * + * FE BE + * **** + * cpu3 <-@(fe00)--* *--(be0)@--> codec3 + * cpu4 <-@(fe01)--* * (44.1kHz) + * **** + */ be0: port@0 { reg = <0>; be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; }; - /* [DPCM-Multi]::BE */ + /* + * [DPCM-Multi]::BE + * + * FE BE + * **** +-+ + * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 + * cpu6 <-@(fe11)--* * | |-> codec5 + * **** +-+ + */ be1: port@1 { reg = <1>; be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; }; }; }; @@ -277,7 +547,13 @@ codec2codec { #address-cells = <1>; #size-cells = <0>; - /* [Codec2Codec] */ + /* + * [Codec2Codec] + * + * +-@(c2c)-> codec6 + * | + * +--------> codec7 + */ ports@0 { reg = <0>; @@ -289,7 +565,18 @@ port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; }; }; - /* [Codec2Codec-Multi] */ + /* + * [Codec2Codec-Multi] + * + * +-+ + * +-@(c2c_m)-->| |-> codec8 + * | | |-> codec9 + * | +-+ + * | +-+ + * +----------->| |-> codec10 + * | |-> codec11 + * +-+ + */ ports@1 { reg = <1>; @@ -323,9 +610,9 @@ /* [Normal] */ cpu0: port@0 { reg = <0>; cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; - /* [Multi-CPU] */ - port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; }; - port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; }; + /* [Multi-CPU-0] */ + port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu01_ep>; }; }; + port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu02_ep>; }; }; /* [DPCM]::FE */ port@3 { reg = <3>; cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; }; @@ -337,6 +624,14 @@ /* [Semi-Multi] */ sm0: port@7 { reg = <7>; cpu7_ep: endpoint { remote-endpoint = <&smcodec0_ep>; }; }; + + /* [Multi-CPU-1] */ + port@8 { reg = <8>; cpu8_ep: endpoint { remote-endpoint = <&mcpu11_ep>; }; }; + port@9 { reg = <9>; cpu9_ep: endpoint { remote-endpoint = <&mcpu12_ep>; }; }; + /* [Multi-CPU-2] */ + port@a { reg = <10>; cpu10_ep: endpoint { remote-endpoint = <&mcpu21_ep>; }; }; + port@b { reg = <11>; cpu11_ep: endpoint { remote-endpoint = <&mcpu22_ep>; }; }; + port@c { reg = <12>; cpu12_ep: endpoint { remote-endpoint = <&mcpu23_ep>; }; }; }; }; @@ -363,9 +658,9 @@ /* [Normal] */ port@0 { reg = <0>; codec0_ep: endpoint { remote-endpoint = <&cpu0_ep>; }; }; - /* [Multi-Codec] */ - port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; }; - port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; }; + /* [Multi-Codec-0] */ + port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec01_ep>; }; }; + port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec02_ep>; }; }; /* [DPCM]::BE */ port@3 { @@ -395,6 +690,13 @@ port@c { reg = <12>; codec12_ep: endpoint { remote-endpoint = <&smcodec1_ep>; }; }; port@d { reg = <13>; codec13_ep: endpoint { remote-endpoint = <&smcodec2_ep>; }; }; + /* [Multi-Codec-1] */ + port@e { reg = <14>; codec14_ep: endpoint { remote-endpoint = <&mcodec11_ep>; }; }; + port@f { reg = <15>; codec15_ep: endpoint { remote-endpoint = <&mcodec12_ep>; }; }; + port@10 { reg = <16>; codec16_ep: endpoint { remote-endpoint = <&mcodec13_ep>; }; }; + /* [Multi-Codec-2] */ + port@11 { reg = <17>; codec17_ep: endpoint { remote-endpoint = <&mcodec21_ep>; }; }; + port@12 { reg = <18>; codec18_ep: endpoint { remote-endpoint = <&mcodec22_ep>; }; }; }; }; }; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 7146611df730..d9e10308a508 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -83,32 +83,32 @@ Multi-CPU/Codec ************************************ -It has connection part (= X) and list part (= y). -links indicates connection part of CPU side (= A). +It has link connection part (= X,x) and list part (= A,B,a,b). +"links" is connection part of CPU side (= @). - +-+ (A) +-+ - CPU1 --(y) | | <-(X)--(X)-> | | (y)-- Codec1 - CPU2 --(y) | | | | (y)-- Codec2 - +-+ +-+ + +----+ +---+ + CPU1 --|A X| <-@----> |x a|-- Codec1 + CPU2 --|B | | b|-- Codec2 + +----+ +---+ - sound { - compatible = "audio-graph-card2"; + sound { + compatible = "audio-graph-card2"; -(A) links = <&mcpu>; +(@) links = <&mcpu>; - multi { - ports@0 { -(X) (A) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; -(y) port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; -(y) port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; - }; - ports@1 { -(X) port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; -(y) port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; -(y) port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; - }; + multi { + ports@0 { +(@) mcpu: port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; }; // (X) to pair + port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; }; // (A) Multi Element + port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; }; // (B) Multi Element + }; + ports@1 { + port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; }; // (x) to pair + port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; }; // (a) Multi Element + port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; }; // (b) Multi Element }; }; + }; CPU { ports { @@ -328,9 +328,9 @@ static struct device_node *graph_get_next_multi_ep(struct device_node **port) /* * multi { * ports { - * => lnk: port@0 { ... }; - * port@1 { ep { ... = rep0 } }; - * port@2 { ep { ... = rep1 } }; + * => lnk: port@0 { ... }; // to pair + * port@1 { ep { ... = rep0 } }; // Multi Element + * port@2 { ep { ... = rep1 } }; // Multi Element * ... * }; * }; @@ -504,40 +504,203 @@ static int __graph_parse_node(struct simple_util_priv *priv, return 0; } -static int graph_parse_node(struct simple_util_priv *priv, - enum graph_type gtype, - struct device_node *port, - struct link_info *li, int is_cpu) +static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, + int *nm_idx, int cpu_idx, + struct device_node *mcpu_port) { - struct device_node *ep; - int ret = 0; + /* + * +---+ +---+ + * | X|<-@------->|x | + * | | | | + * cpu0 <--|A 1|<--------->|4 a|-> codec0 + * cpu1 <--|B 2|<-----+--->|5 b|-> codec1 + * cpu2 <--|C 3|<----/ +---+ + * +---+ + * + * multi { + * ports { + * port@0 { mcpu_top_ep {... = mcodec_ep; }; }; // (X) to pair + * <mcpu_port> port@1 { mcpu0_ep { ... = cpu0_ep; }; // (A) Multi Element + * mcpu0_ep_0 { ... = mcodec0_ep_0; }; }; // (1) connected Codec + * port@2 { mcpu1_ep { ... = cpu1_ep; }; // (B) Multi Element + * mcpu1_ep_0 { ... = mcodec1_ep_0; }; }; // (2) connected Codec + * port@3 { mcpu2_ep { ... = cpu2_ep; }; // (C) Multi Element + * mcpu2_ep_0 { ... = mcodec1_ep_1; }; }; // (3) connected Codec + * }; + * + * ports { + * port@0 { mcodec_top_ep {... = mcpu_ep; }; }; // (x) to pair + * <mcodec_port>port@1 { mcodec0_ep { ... = codec0_ep; }; // (a) Multi Element + * mcodec0_ep_0 { ... = mcpu0_ep_0; }; }; // (4) connected CPU + * port@2 { mcodec1_ep { ... = codec1_ep; }; // (b) Multi Element + * mcodec1_ep_0 { ... = mcpu1_ep_0; }; // (5) connected CPU + * mcodec1_ep_1 { ... = mcpu2_ep_0; }; }; // (5) connected CPU + * }; + * }; + */ + struct device_node *mcpu_ep = port_to_endpoint(mcpu_port); + struct device_node *mcpu_ep_n = mcpu_ep; + struct device_node *mcpu_port_top = of_get_next_child(of_get_parent(mcpu_port), NULL); + struct device_node *mcpu_ep_top = port_to_endpoint(mcpu_port_top); + struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top); + struct device_node *mcodec_port_top = of_get_parent(mcodec_ep_top); + struct device_node *mcodec_ports = of_get_parent(mcodec_port_top); + int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); + int ret = -EINVAL; - if (graph_lnk_is_multi(port)) { - int idx; + if (cpu_idx > dai_link->num_cpus) + goto mcpu_err; - of_node_get(port); + while (1) { + struct device_node *mcodec_ep_n; + struct device_node *mcodec_port_i; + struct device_node *mcodec_port; + int codec_idx; - for (idx = 0;; idx++) { - ep = graph_get_next_multi_ep(&port); - if (!ep) - break; + if (*nm_idx > nm_max) + break; - ret = __graph_parse_node(priv, gtype, ep, - li, is_cpu, idx); - of_node_put(ep); - if (ret < 0) + mcpu_ep_n = of_get_next_child(mcpu_port, mcpu_ep_n); + if (!mcpu_ep_n) { + ret = 0; + break; + } + + mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n); + mcodec_port = of_get_parent(mcodec_ep_n); + + if (mcodec_ports != of_get_parent(mcodec_port)) + goto mcpu_err; + + codec_idx = 0; + mcodec_port_i = of_get_next_child(mcodec_ports, NULL); + while (1) { + if (codec_idx > dai_link->num_codecs) + goto mcodec_err; + + mcodec_port_i = of_get_next_child(mcodec_ports, mcodec_port_i); + + if (!mcodec_port_i) + goto mcodec_err; + + if (mcodec_port_i == mcodec_port) break; + + codec_idx++; } - } else { - /* Single CPU / Codec */ - ep = port_to_endpoint(port); - ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + + dai_link->ch_maps[*nm_idx].cpu = cpu_idx; + dai_link->ch_maps[*nm_idx].codec = codec_idx; + + (*nm_idx)++; + + of_node_put(mcodec_port_i); +mcodec_err: + of_node_put(mcodec_port); + of_node_put(mcpu_ep_n); + of_node_put(mcodec_ep_n); + } +mcpu_err: + of_node_put(mcpu_ep); + of_node_put(mcpu_port_top); + of_node_put(mcpu_ep_top); + of_node_put(mcodec_ep_top); + of_node_put(mcodec_port_top); + of_node_put(mcodec_ports); + + return ret; +} + +static int graph_parse_node_multi(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct device *dev = simple_priv_to_dev(priv); + struct device_node *ep; + int ret = -ENOMEM; + int nm_idx = 0; + int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); + + /* + * create ch_maps if CPU:Codec = N:M + * DPCM is out of scope + */ + if (gtype != GRAPH_DPCM && !dai_link->ch_maps && + dai_link->num_cpus > 1 && dai_link->num_codecs > 1 && + dai_link->num_cpus != dai_link->num_codecs) { + + dai_link->ch_maps = devm_kcalloc(dev, nm_max, + sizeof(struct snd_soc_dai_link_ch_map), GFP_KERNEL); + if (!dai_link->ch_maps) + goto multi_err; + } + + for (int idx = 0;; idx++) { + /* + * multi { + * ports { + * <port> port@0 { ... }; // to pair + * port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element + * port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element + * }; + * }; + * + * cpu { + * ports { + * <ep> port@0 { cpu1_ep { ... = mcpu1_ep };}; + * }; + * }; + */ + ep = graph_get_next_multi_ep(&port); + if (!ep) + break; + + ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, idx); of_node_put(ep); + if (ret < 0) + goto multi_err; + + /* CPU:Codec = N:M */ + if (is_cpu && dai_link->ch_maps) { + ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port); + if (ret < 0) + goto multi_err; + } } + if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max)) + ret = -EINVAL; + +multi_err: return ret; } +static int graph_parse_node_single(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + struct device_node *ep = port_to_endpoint(port); + int ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + + of_node_put(ep); + + return ret; +} + +static int graph_parse_node(struct simple_util_priv *priv, + enum graph_type gtype, + struct device_node *port, + struct link_info *li, int is_cpu) +{ + if (graph_lnk_is_multi(port)) + return graph_parse_node_multi(priv, gtype, port, li, is_cpu); + else + return graph_parse_node_single(priv, gtype, port, li, is_cpu); +} + static void graph_parse_daifmt(struct device_node *node, unsigned int *daifmt, unsigned int *bit_frame) { @@ -920,17 +1083,33 @@ static int graph_counter(struct device_node *lnk) * * multi { * ports { - * => lnk: port@0 { ... }; - * port@1 { ... }; - * port@2 { ... }; + * => lnk: port@0 { ... }; // to pair + * port@1 { ... }; // Multi Element + * port@2 { ... }; // Multi Element * ... * }; * }; * * ignore first lnk part */ - if (graph_lnk_is_multi(lnk)) - return of_graph_get_endpoint_count(of_get_parent(lnk)) - 1; + if (graph_lnk_is_multi(lnk)) { + struct device_node *ports = of_get_parent(lnk); + struct device_node *port = NULL; + int cnt = 0; + + /* + * CPU/Codec = N:M case has many endpoints. + * We can't use of_graph_get_endpoint_count() here + */ + while(1) { + port = of_get_next_child(ports, port); + if (!port) + break; + cnt++; + } + + return cnt - 1; + } /* * Single CPU / Codec */ diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 6060894954df..c018f84fe025 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -277,16 +277,24 @@ static int avs_da7219_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_da7219_driver_ids[] = { + { + .name = "avs_da7219", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_da7219_driver_ids); + static struct platform_driver avs_da7219_driver = { .probe = avs_da7219_probe, .driver = { .name = "avs_da7219", .pm = &snd_soc_pm_ops, }, + .id_table = avs_da7219_driver_ids, }; module_platform_driver(avs_da7219_driver); MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_da7219"); diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index c270646faf86..ba2bc7f689eb 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -77,15 +77,23 @@ static int avs_dmic_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_dmic_driver_ids[] = { + { + .name = "avs_dmic", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids); + static struct platform_driver avs_dmic_driver = { .probe = avs_dmic_probe, .driver = { .name = "avs_dmic", .pm = &snd_soc_pm_ops, }, + .id_table = avs_dmic_driver_ids, }; module_platform_driver(avs_dmic_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_dmic"); diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index f972ef64d284..1090082e7d5b 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -307,15 +307,23 @@ static int avs_es8336_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_es8336_driver_ids[] = { + { + .name = "avs_es8336", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_es8336_driver_ids); + static struct platform_driver avs_es8336_driver = { .probe = avs_es8336_probe, .driver = { .name = "avs_es8336", .pm = &snd_soc_pm_ops, }, + .id_table = avs_es8336_driver_ids, }; module_platform_driver(avs_es8336_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_es8336"); diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index 8876558f19a1..844a918f9a81 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -218,12 +218,21 @@ static int avs_hdaudio_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_hdaudio_driver_ids[] = { + { + .name = "avs_hdaudio", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids); + static struct platform_driver avs_hdaudio_driver = { .probe = avs_hdaudio_probe, .driver = { .name = "avs_hdaudio", .pm = &snd_soc_pm_ops, }, + .id_table = avs_hdaudio_driver_ids, }; module_platform_driver(avs_hdaudio_driver) @@ -231,4 +240,3 @@ module_platform_driver(avs_hdaudio_driver) MODULE_DESCRIPTION("Intel HD-Audio machine driver"); MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_hdaudio"); diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 3d03e1eed3a9..28f254eb0d03 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -185,15 +185,23 @@ static int avs_i2s_test_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_i2s_test_driver_ids[] = { + { + .name = "avs_i2s_test", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_i2s_test_driver_ids); + static struct platform_driver avs_i2s_test_driver = { .probe = avs_i2s_test_probe, .driver = { .name = "avs_i2s_test", .pm = &snd_soc_pm_ops, }, + .id_table = avs_i2s_test_driver_ids, }; module_platform_driver(avs_i2s_test_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_i2s_test"); diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 6ba7b6564279..a83b95f25129 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -135,15 +135,23 @@ static int avs_max98357a_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_max98357a_driver_ids[] = { + { + .name = "avs_max98357a", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_max98357a_driver_ids); + static struct platform_driver avs_max98357a_driver = { .probe = avs_max98357a_probe, .driver = { .name = "avs_max98357a", .pm = &snd_soc_pm_ops, }, + .id_table = avs_max98357a_driver_ids, }; module_platform_driver(avs_max98357a_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_max98357a"); diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index cc7dfdf72083..3b980a025e6f 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -192,15 +192,23 @@ static int avs_max98373_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_max98373_driver_ids[] = { + { + .name = "avs_max98373", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_max98373_driver_ids); + static struct platform_driver avs_max98373_driver = { .probe = avs_max98373_probe, .driver = { .name = "avs_max98373", .pm = &snd_soc_pm_ops, }, + .id_table = avs_max98373_driver_ids, }; module_platform_driver(avs_max98373_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_max98373"); diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index fb0175f37d61..86dd2b228df3 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -189,15 +189,23 @@ static int avs_max98927_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_max98927_driver_ids[] = { + { + .name = "avs_max98927", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_max98927_driver_ids); + static struct platform_driver avs_max98927_driver = { .probe = avs_max98927_probe, .driver = { .name = "avs_max98927", .pm = &snd_soc_pm_ops, }, + .id_table = avs_max98927_driver_ids, }; module_platform_driver(avs_max98927_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_max98927"); diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index d98b5deb78c9..1c1e2083f474 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -294,15 +294,23 @@ static int avs_nau8825_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_nau8825_driver_ids[] = { + { + .name = "avs_nau8825", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_nau8825_driver_ids); + static struct platform_driver avs_nau8825_driver = { .probe = avs_nau8825_probe, .driver = { .name = "avs_nau8825", .pm = &snd_soc_pm_ops, }, + .id_table = avs_nau8825_driver_ids, }; module_platform_driver(avs_nau8825_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_nau8825"); diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c index 411acaee74f9..a9469b5ecb40 100644 --- a/sound/soc/intel/avs/boards/probe.c +++ b/sound/soc/intel/avs/boards/probe.c @@ -50,15 +50,23 @@ static int avs_probe_mb_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_probe_mb_driver_ids[] = { + { + .name = "avs_probe_mb", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_probe_mb_driver_ids); + static struct platform_driver avs_probe_mb_driver = { .probe = avs_probe_mb_probe, .driver = { .name = "avs_probe_mb", .pm = &snd_soc_pm_ops, }, + .id_table = avs_probe_mb_driver_ids, }; module_platform_driver(avs_probe_mb_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_probe_mb"); diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index 157183b1de24..bfcb8845fd15 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -257,15 +257,23 @@ static int avs_rt274_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt274_driver_ids[] = { + { + .name = "avs_rt274", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt274_driver_ids); + static struct platform_driver avs_rt274_driver = { .probe = avs_rt274_probe, .driver = { .name = "avs_rt274", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt274_driver_ids, }; module_platform_driver(avs_rt274_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt274"); diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 131237471e3e..28d7d86b1cc9 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -228,15 +228,23 @@ static int avs_rt286_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt286_driver_ids[] = { + { + .name = "avs_rt286", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt286_driver_ids); + static struct platform_driver avs_rt286_driver = { .probe = avs_rt286_probe, .driver = { .name = "avs_rt286", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt286_driver_ids, }; module_platform_driver(avs_rt286_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt286"); diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index ea32a7690c8a..80f490b9e118 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -247,15 +247,23 @@ static int avs_rt298_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt298_driver_ids[] = { + { + .name = "avs_rt298", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt298_driver_ids); + static struct platform_driver avs_rt298_driver = { .probe = avs_rt298_probe, .driver = { .name = "avs_rt298", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt298_driver_ids, }; module_platform_driver(avs_rt298_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt298"); diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index ad486a52e5e3..60105f453ae2 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -173,15 +173,23 @@ static int avs_rt5514_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt5514_driver_ids[] = { + { + .name = "avs_rt5514", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5514_driver_ids); + static struct platform_driver avs_rt5514_driver = { .probe = avs_rt5514_probe, .driver = { .name = "avs_rt5514", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt5514_driver_ids, }; module_platform_driver(avs_rt5514_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt5514"); diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 3effd789a45e..b4762c2a7bf2 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -246,15 +246,23 @@ static int avs_rt5663_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt5663_driver_ids[] = { + { + .name = "avs_rt5663", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5663_driver_ids); + static struct platform_driver avs_rt5663_driver = { .probe = avs_rt5663_probe, .driver = { .name = "avs_rt5663", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt5663_driver_ids, }; module_platform_driver(avs_rt5663_driver); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt5663"); diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 84e850c0b085..243f979fda98 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -322,16 +322,24 @@ static int avs_rt5682_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_rt5682_driver_ids[] = { + { + .name = "avs_rt5682", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_rt5682_driver_ids); + static struct platform_driver avs_rt5682_driver = { .probe = avs_rt5682_probe, .driver = { .name = "avs_rt5682", .pm = &snd_soc_pm_ops, }, + .id_table = avs_rt5682_driver_ids, }; module_platform_driver(avs_rt5682_driver) MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_rt5682"); diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index 6bcab9deae5c..4a0e136835ff 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -181,15 +181,23 @@ static int avs_ssm4567_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static const struct platform_device_id avs_ssm4567_driver_ids[] = { + { + .name = "avs_ssm4567", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_ssm4567_driver_ids); + static struct platform_driver avs_ssm4567_driver = { .probe = avs_ssm4567_probe, .driver = { .name = "avs_ssm4567", .pm = &snd_soc_pm_ops, }, + .id_table = avs_ssm4567_driver_ids, }; module_platform_driver(avs_ssm4567_driver) MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:avs_ssm4567"); diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index f6da24f3c466..8cf0b33cc02e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -93,8 +93,12 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, * when codec is runtime suspended. Codec needs clock for jack * detection and button press. */ - snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, - 48000 * 512, SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "failed to set codec sysclk: %d\n", ret); + return ret; + } if (ctx->mclk) clk_disable_unprepare(ctx->mclk); diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index ce2967850c2d..4f2cb8e52971 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -3,6 +3,7 @@ // Copyright(c) 2023 Intel Corporation. All rights reserved. #include <sound/soc.h> +#include "../common/soc-intel-quirks.h" #include "hda_dsp_common.h" #include "sof_board_helpers.h" @@ -86,6 +87,55 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; +int sof_intel_board_set_codec_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec codec_type, int ssp_codec) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: codec %s, ssp %d\n", be_id, + sof_ssp_get_codec_name(codec_type), ssp_codec); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + if (soc_intel_is_byt() || soc_intel_is_cht()) { + /* backward-compatibility for BYT/CHT boards */ + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port", + ssp_codec); + } else { + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", + ssp_codec); + } + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs - caller to handle */ + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; + link->dpcm_playback = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_codec_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + int sof_intel_board_set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, enum sof_dmic_be_type be_type) @@ -198,7 +248,287 @@ int sof_intel_board_set_intel_hdmi_link(struct device *dev, } EXPORT_SYMBOL_NS(sof_intel_board_set_intel_hdmi_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); +int sof_intel_board_set_ssp_amp_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec amp_type, int ssp_amp) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id, + sof_ssp_get_codec_name(amp_type), ssp_amp); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs - caller to handle */ + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; /* feedback stream or firmware-generated echo reference */ + link->dpcm_playback = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_ssp_amp_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + +int sof_intel_board_set_bt_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_bt) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + link->codecs = &snd_soc_dummy_dlc; + link->num_codecs = 1; + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; + link->dpcm_playback = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_bt_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + +int sof_intel_board_set_hdmi_in_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_hdmi) +{ + struct snd_soc_dai_link_component *cpus; + + dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi); + + /* link name */ + link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi); + if (!link->name) + return -ENOMEM; + + /* cpus */ + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi); + if (!cpus->dai_name) + return -ENOMEM; + + link->cpus = cpus; + link->num_cpus = 1; + + /* codecs */ + link->codecs = &snd_soc_dummy_dlc; + link->num_codecs = 1; + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + link->no_pcm = 1; + link->dpcm_capture = 1; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_hdmi_in_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + +static int calculate_num_links(struct sof_card_private *ctx) +{ + int num_links = 0; + + /* headphone codec */ + if (ctx->codec_type != CODEC_NONE) + num_links++; + + /* dmic01 and dmic16k */ + if (ctx->dmic_be_num > 0) + num_links++; + + if (ctx->dmic_be_num > 1) + num_links++; + + /* idisp HDMI */ + num_links += ctx->hdmi_num; + + /* speaker amp */ + if (ctx->amp_type != CODEC_NONE) + num_links++; + + /* BT audio offload */ + if (ctx->bt_offload_present) + num_links++; + + /* HDMI-In */ + num_links += hweight32(ctx->ssp_mask_hdmi_in); + + return num_links; +} + +int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + struct snd_soc_dai_link *links; + int num_links; + int i; + int idx = 0; + int ret; + int ssp_hdmi_in = 0; + + num_links = calculate_num_links(ctx); + + links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), + GFP_KERNEL); + if (!links) + return -ENOMEM; + + /* headphone codec */ + if (ctx->codec_type != CODEC_NONE) { + ret = sof_intel_board_set_codec_link(dev, &links[idx], idx, + ctx->codec_type, + ctx->ssp_codec); + if (ret) { + dev_err(dev, "fail to set codec link, ret %d\n", ret); + return ret; + } + + ctx->codec_link = &links[idx]; + idx++; + } + + /* dmic01 and dmic16k */ + if (ctx->dmic_be_num > 0) { + /* at least we have dmic01 */ + ret = sof_intel_board_set_dmic_link(dev, &links[idx], idx, + SOF_DMIC_01); + if (ret) { + dev_err(dev, "fail to set dmic01 link, ret %d\n", ret); + return ret; + } + + idx++; + } + + if (ctx->dmic_be_num > 1) { + /* set up 2 BE links at most */ + ret = sof_intel_board_set_dmic_link(dev, &links[idx], idx, + SOF_DMIC_16K); + if (ret) { + dev_err(dev, "fail to set dmic16k link, ret %d\n", ret); + return ret; + } + + idx++; + } + + /* idisp HDMI */ + for (i = 1; i <= ctx->hdmi_num; i++) { + ret = sof_intel_board_set_intel_hdmi_link(dev, &links[idx], idx, + i, + ctx->hdmi.idisp_codec); + if (ret) { + dev_err(dev, "fail to set hdmi link, ret %d\n", ret); + return ret; + } + + idx++; + } + + /* speaker amp */ + if (ctx->amp_type != CODEC_NONE) { + ret = sof_intel_board_set_ssp_amp_link(dev, &links[idx], idx, + ctx->amp_type, + ctx->ssp_amp); + if (ret) { + dev_err(dev, "fail to set amp link, ret %d\n", ret); + return ret; + } + + ctx->amp_link = &links[idx]; + idx++; + } + + /* BT audio offload */ + if (ctx->bt_offload_present) { + ret = sof_intel_board_set_bt_link(dev, &links[idx], idx, + ctx->ssp_bt); + if (ret) { + dev_err(dev, "fail to set bt link, ret %d\n", ret); + return ret; + } + + idx++; + } + + /* HDMI-In */ + for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) { + ret = sof_intel_board_set_hdmi_in_link(dev, &links[idx], idx, + ssp_hdmi_in); + if (ret) { + dev_err(dev, "fail to set hdmi-in link, ret %d\n", ret); + return ret; + } + + idx++; + } + + if (idx != num_links) { + dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx, + num_links); + return -EINVAL; + } + + card->dai_link = links; + card->num_links = num_links; + + return 0; +} +EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); + MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index df99f576c1d8..3b36058118ca 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -30,6 +30,13 @@ struct sof_rt5682_private { * @amp_type: type of speaker amplifier * @dmic_be_num: number of Intel PCH DMIC BE link * @hdmi_num: number of Intel HDMI BE link + * @ssp_codec: ssp port number of headphone BE link + * @ssp_amp: ssp port number of speaker BE link + * @ssp_bt: ssp port number of BT offload BE link + * @ssp_mask_hdmi_in: ssp port mask of HDMI-IN BE link + * @bt_offload_present: true to create BT offload BE link + * @codec_link: pointer to headset codec dai link + * @amp_link: pointer to speaker amplifier dai link * @rt5682: private data for rt5682 machine driver */ struct sof_card_private { @@ -42,6 +49,16 @@ struct sof_card_private { int dmic_be_num; int hdmi_num; + int ssp_codec; + int ssp_amp; + int ssp_bt; + unsigned long ssp_mask_hdmi_in; + + bool bt_offload_present; + + struct snd_soc_dai_link *codec_link; + struct snd_soc_dai_link *amp_link; + union { struct sof_rt5682_private rt5682; }; @@ -53,12 +70,26 @@ enum sof_dmic_be_type { }; int sof_intel_board_card_late_probe(struct snd_soc_card *card); +int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx); +int sof_intel_board_set_codec_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec codec_type, int ssp_codec); int sof_intel_board_set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, enum sof_dmic_be_type be_type); int sof_intel_board_set_intel_hdmi_link(struct device *dev, struct snd_soc_dai_link *link, int be_id, int hdmi_id, bool idisp_codec); +int sof_intel_board_set_ssp_amp_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + enum sof_ssp_codec amp_type, int ssp_amp); +int sof_intel_board_set_bt_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_bt); +int sof_intel_board_set_hdmi_in_link(struct device *dev, + struct snd_soc_dai_link *link, int be_id, + int ssp_hdmi); #endif /* __SOF_INTEL_BOARD_HELPERS_H */ diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index 1f760fc4cab2..c2442bf8ced0 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -138,13 +138,6 @@ static const struct snd_soc_ops sof_cs42l42_ops = { .hw_params = sof_cs42l42_hw_params, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static int sof_card_late_probe(struct snd_soc_card *card) { return sof_intel_board_card_late_probe(card); @@ -189,147 +182,11 @@ static struct snd_soc_dai_link_component cs42l42_component[] = { } }; -static int create_spk_amp_dai_links(struct device *dev, - struct snd_soc_dai_link *links, - struct snd_soc_dai_link_component *cpus, - int *id, enum sof_ssp_codec amp_type, - int ssp_amp) -{ - int ret = 0; - - /* speaker amp */ - if (amp_type == CODEC_NONE) - return 0; - - links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", - ssp_amp); - if (!links[*id].name) { - ret = -ENOMEM; - goto devm_err; - } - - links[*id].id = *id; - - switch (amp_type) { - case CODEC_MAX98357A: - max_98357a_dai_link(&links[*id]); - break; - case CODEC_MAX98360A: - max_98360a_dai_link(&links[*id]); - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return -EINVAL; - } - - links[*id].platforms = platform_component; - links[*id].num_platforms = ARRAY_SIZE(platform_component); - links[*id].dpcm_playback = 1; - /* firmware-generated echo reference */ - links[*id].dpcm_capture = 1; - - links[*id].no_pcm = 1; - links[*id].cpus = &cpus[*id]; - links[*id].num_cpus = 1; - - links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", ssp_amp); - if (!links[*id].cpus->dai_name) { - ret = -ENOMEM; - goto devm_err; - } - - (*id)++; - -devm_err: - return ret; -} - -static int create_hp_codec_dai_links(struct device *dev, - struct snd_soc_dai_link *links, - struct snd_soc_dai_link_component *cpus, - int *id, int ssp_codec) -{ - /* codec SSP */ - links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", - ssp_codec); - if (!links[*id].name) - goto devm_err; - - links[*id].id = *id; - links[*id].codecs = cs42l42_component; - links[*id].num_codecs = ARRAY_SIZE(cs42l42_component); - links[*id].platforms = platform_component; - links[*id].num_platforms = ARRAY_SIZE(platform_component); - links[*id].init = sof_cs42l42_init; - links[*id].exit = sof_cs42l42_exit; - links[*id].ops = &sof_cs42l42_ops; - links[*id].dpcm_playback = 1; - links[*id].dpcm_capture = 1; - links[*id].no_pcm = 1; - links[*id].cpus = &cpus[*id]; - links[*id].num_cpus = 1; - - links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[*id].cpus->dai_name) - goto devm_err; - - (*id)++; - - return 0; - -devm_err: - return -ENOMEM; -} - -static int create_bt_offload_dai_links(struct device *dev, - struct snd_soc_dai_link *links, - struct snd_soc_dai_link_component *cpus, - int *id, int ssp_bt) -{ - /* bt offload */ - if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)) - return 0; - - links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", - ssp_bt); - if (!links[*id].name) - goto devm_err; - - links[*id].id = *id; - links[*id].codecs = &snd_soc_dummy_dlc; - links[*id].num_codecs = 1; - links[*id].platforms = platform_component; - links[*id].num_platforms = ARRAY_SIZE(platform_component); - - links[*id].dpcm_playback = 1; - links[*id].dpcm_capture = 1; - links[*id].no_pcm = 1; - links[*id].cpus = &cpus[*id]; - links[*id].num_cpus = 1; - - links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_bt); - if (!links[*id].cpus->dai_name) - goto devm_err; - - (*id)++; - - return 0; - -devm_err: - return -ENOMEM; -} - static struct snd_soc_dai_link * sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int ssp_codec, int ssp_amp, int ssp_bt, int dmic_be_num, int hdmi_num, bool idisp_codec) { - struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int ret; int id = 0; @@ -338,9 +195,7 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, links = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) + if (!links) goto devm_err; link_seq = (sof_cs42l42_quirk & SOF_CS42L42_DAILINK_MASK) >> SOF_CS42L42_DAILINK_SHIFT; @@ -350,20 +205,52 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, switch (link_type) { case LINK_HP: - ret = create_hp_codec_dai_links(dev, links, cpus, &id, ssp_codec); - if (ret < 0) { + ret = sof_intel_board_set_codec_link(dev, &links[id], id, + CODEC_CS42L42, + ssp_codec); + if (ret) { dev_err(dev, "fail to create hp codec dai links, ret %d\n", ret); goto devm_err; } + + /* codec-specific fields */ + links[id].codecs = cs42l42_component; + links[id].num_codecs = ARRAY_SIZE(cs42l42_component); + links[id].init = sof_cs42l42_init; + links[id].exit = sof_cs42l42_exit; + links[id].ops = &sof_cs42l42_ops; + + id++; break; case LINK_SPK: - ret = create_spk_amp_dai_links(dev, links, cpus, &id, - amp_type, ssp_amp); - if (ret < 0) { - dev_err(dev, "fail to create spk amp dai links, ret %d\n", - ret); - goto devm_err; + if (amp_type != CODEC_NONE) { + ret = sof_intel_board_set_ssp_amp_link(dev, + &links[id], + id, + amp_type, + ssp_amp); + if (ret) { + dev_err(dev, "fail to create spk amp dai links, ret %d\n", + ret); + goto devm_err; + } + + /* codec-specific fields */ + switch (amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(&links[id]); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(&links[id]); + break; + default: + dev_err(dev, "invalid amp type %d\n", + amp_type); + goto devm_err; + } + + id++; } break; case LINK_DMIC: @@ -413,11 +300,17 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, } break; case LINK_BT: - ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt); - if (ret < 0) { - dev_err(dev, "fail to create bt offload dai links, ret %d\n", - ret); - goto devm_err; + if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) { + ret = sof_intel_board_set_bt_link(dev, + &links[id], id, + ssp_bt); + if (ret) { + dev_err(dev, "fail to create bt offload dai links, ret %d\n", + ret); + goto devm_err; + } + + id++; } break; case LINK_NONE: @@ -440,7 +333,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_bt, ssp_amp, ssp_codec; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -469,25 +362,29 @@ static int sof_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); - ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> + /* port number of peripherals attached to ssp interface */ + ctx->ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> SOF_CS42L42_SSP_BT_SHIFT; - ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> + ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> SOF_CS42L42_SSP_AMP_SHIFT; - ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; + ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; /* compute number of dai links */ sof_audio_card_cs42l42.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; if (ctx->amp_type != CODEC_NONE) sof_audio_card_cs42l42.num_links++; - if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) + if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; sof_audio_card_cs42l42.num_links++; + } dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ssp_codec, ssp_amp, ssp_bt, - ctx->dmic_be_num, ctx->hdmi_num, + ctx->ssp_codec, ctx->ssp_amp, + ctx->ssp_bt, ctx->dmic_be_num, + ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) return -ENOMEM; diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index 3c00afc32805..cf2974718271 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -61,16 +61,21 @@ static int max_98373_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; + int ret = 0; int j; for_each_rtd_codec_dais(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { /* DEV0 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); - } - if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); + } else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { /* DEV1 tdm slot configuration */ - snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); + } + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; } } return 0; diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index dc2821a012d4..15ea6732ff94 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -138,13 +138,6 @@ static struct snd_soc_ops sof_nau8825_ops = { .hw_params = sof_nau8825_hw_params, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); @@ -207,168 +200,69 @@ static struct snd_soc_dai_link_component nau8825_component[] = { } }; -static struct snd_soc_dai_link * -sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, - int ssp_codec, int ssp_amp, int dmic_be_num, - int hdmi_num, bool idisp_codec) +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) { - struct snd_soc_dai_link_component *cpus; - struct snd_soc_dai_link *links; - int i; - int id = 0; int ret; - links = devm_kcalloc(dev, sof_audio_card_nau8825.num_links, - sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_audio_card_nau8825.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) - goto devm_err; - - /* codec SSP */ - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_codec); - if (!links[id].name) - goto devm_err; - - links[id].id = id; - links[id].codecs = nau8825_component; - links[id].num_codecs = ARRAY_SIZE(nau8825_component); - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].init = sof_nau8825_codec_init; - links[id].exit = sof_nau8825_codec_exit; - links[id].ops = &sof_nau8825_ops; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; - - id++; - - /* dmic */ - if (dmic_be_num > 0) { - /* at least we have dmic01 */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_01); - if (ret) - return NULL; - - id++; - } - - if (dmic_be_num > 1) { - /* set up 2 BE links at most */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_16K); - if (ret) - return NULL; + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; - id++; + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; } - /* HDMI */ - for (i = 1; i <= hdmi_num; i++) { - ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], id, - i, idisp_codec); - if (ret) - return NULL; + /* codec-specific fields for headphone codec */ + ctx->codec_link->codecs = nau8825_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(nau8825_component); + ctx->codec_link->init = sof_nau8825_codec_init; + ctx->codec_link->exit = sof_nau8825_codec_exit; + ctx->codec_link->ops = &sof_nau8825_ops; - id++; - } + if (ctx->amp_type == CODEC_NONE) + return 0; - /* speaker amp */ - if (amp_type != CODEC_NONE) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_amp); - if (!links[id].name) - goto devm_err; - - links[id].id = id; - - switch (amp_type) { - case CODEC_MAX98360A: - max_98360a_dai_link(&links[id]); - break; - case CODEC_MAX98373: - links[id].codecs = max_98373_components; - links[id].num_codecs = ARRAY_SIZE(max_98373_components); - links[id].init = max_98373_spk_codec_init; - links[id].ops = &max_98373_ops; - break; - case CODEC_NAU8318: - nau8318_set_dai_link(&links[id]); - break; - case CODEC_RT1015P: - sof_rt1015p_dai_link(&links[id]); - break; - case CODEC_RT1019P: - sof_rt1019p_dai_link(&links[id]); - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return NULL; - } - - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - /* feedback stream or firmware-generated echo reference */ - links[id].dpcm_capture = 1; - - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; - id++; + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; } - /* BT audio offload */ - if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - int port = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - links[id].id = id; - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - goto devm_err; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - if (!links[id].name) - goto devm_err; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + ctx->amp_link->codecs = max_98373_components; + ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); + ctx->amp_link->init = max_98373_spk_codec_init; + ctx->amp_link->ops = &max_98373_ops; + break; + case CODEC_NAU8318: + nau8318_set_dai_link(ctx->amp_link); + break; + case CODEC_RT1015P: + sof_rt1015p_dai_link(ctx->amp_link); + break; + case CODEC_RT1019P: + sof_rt1019p_dai_link(ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; } - return links; -devm_err: - return NULL; + return 0; } static int sof_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; - struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_amp, ssp_codec; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -393,28 +287,22 @@ static int sof_audio_probe(struct platform_device *pdev) if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> - SOF_NAU8825_SSP_AMP_SHIFT; - - ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; + /* port number of peripherals attached to ssp interface */ + ctx->ssp_bt = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; - /* compute number of dai links */ - sof_audio_card_nau8825.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; + ctx->ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> + SOF_NAU8825_SSP_AMP_SHIFT; - if (ctx->amp_type != CODEC_NONE) - sof_audio_card_nau8825.num_links++; + ctx->ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - sof_audio_card_nau8825.num_links++; + ctx->bt_offload_present = true; - dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ssp_codec, ssp_amp, - ctx->dmic_be_num, ctx->hdmi_num, - ctx->hdmi.idisp_codec); - if (!dai_links) - return -ENOMEM; - - sof_audio_card_nau8825.dai_link = dai_links; + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx); + if (ret) + return ret; /* update codec_conf */ switch (ctx->amp_type) { diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 06ad15af46de..cd50f26d1edb 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -463,13 +463,6 @@ static struct snd_soc_ops sof_rt5682_ops = { .hw_params = sof_rt5682_hw_params, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); @@ -570,69 +563,45 @@ static struct snd_soc_dai_link_component rt5650_components[] = { } }; -static struct snd_soc_dai_link * -sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, - enum sof_ssp_codec amp_type, int ssp_codec, - int ssp_amp, int dmic_be_num, int hdmi_num, - bool idisp_codec, bool is_legacy_cpu) +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) { - struct snd_soc_dai_link_component *cpus; - struct snd_soc_dai_link *links; - int i; - int id = 0; int ret; - int hdmi_id_offset = 0; - - links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, - sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_audio_card_rt5682.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) - goto devm_err; - /* codec SSP */ - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_codec); - if (!links[id].name) - goto devm_err; + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; - links[id].id = id; + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; + } - switch (codec_type) { + /* codec-specific fields for headphone codec */ + switch (ctx->codec_type) { case CODEC_RT5650: - links[id].codecs = &rt5650_components[0]; - links[id].num_codecs = 1; + ctx->codec_link->codecs = &rt5650_components[0]; + ctx->codec_link->num_codecs = 1; break; case CODEC_RT5682: - links[id].codecs = rt5682_component; - links[id].num_codecs = ARRAY_SIZE(rt5682_component); + ctx->codec_link->codecs = rt5682_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682_component); break; case CODEC_RT5682S: - links[id].codecs = rt5682s_component; - links[id].num_codecs = ARRAY_SIZE(rt5682s_component); + ctx->codec_link->codecs = rt5682s_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682s_component); break; default: - dev_err(dev, "invalid codec type %d\n", codec_type); - return NULL; + dev_err(dev, "invalid codec type %d\n", ctx->codec_type); + return -EINVAL; } - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].init = sof_rt5682_codec_init; - links[id].exit = sof_rt5682_codec_exit; - links[id].ops = &sof_rt5682_ops; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - if (is_legacy_cpu) { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; - } else { + ctx->codec_link->init = sof_rt5682_codec_init; + ctx->codec_link->exit = sof_rt5682_codec_exit; + ctx->codec_link->ops = &sof_rt5682_ops; + + if (!ctx->rt5682.is_legacy_cpu) { /* * Currently, On SKL+ platforms MCLK will be turned off in sof * runtime suspended, and it will go into runtime suspended @@ -642,184 +611,66 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec codec_type, * avoid the noise. * It can be removed once we can control MCLK by driver. */ - links[id].ignore_pmdown_time = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[id].cpus->dai_name) - goto devm_err; - } - id++; - - /* dmic */ - if (dmic_be_num > 0) { - /* at least we have dmic01 */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_01); - if (ret) - return NULL; - - id++; - } - - if (dmic_be_num > 1) { - /* set up 2 BE links at most */ - ret = sof_intel_board_set_dmic_link(dev, &links[id], id, - SOF_DMIC_16K); - if (ret) - return NULL; - - id++; + ctx->codec_link->ignore_pmdown_time = 1; } - /* HDMI */ - for (i = 1; i <= hdmi_num; i++) { - ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], id, - i, idisp_codec); - if (ret) - return NULL; - - id++; - } - - /* speaker amp */ - if (amp_type != CODEC_NONE) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_amp); - if (!links[id].name) - goto devm_err; - - links[id].id = id; - - switch (amp_type) { - case CODEC_MAX98357A: - max_98357a_dai_link(&links[id]); - break; - case CODEC_MAX98360A: - max_98360a_dai_link(&links[id]); - break; - case CODEC_MAX98373: - links[id].codecs = max_98373_components; - links[id].num_codecs = ARRAY_SIZE(max_98373_components); - links[id].init = max_98373_spk_codec_init; - links[id].ops = &max_98373_ops; - break; - case CODEC_MAX98390: - max_98390_dai_link(dev, &links[id]); - break; - case CODEC_RT1011: - sof_rt1011_dai_link(&links[id]); - break; - case CODEC_RT1015: - sof_rt1015_dai_link(&links[id]); - break; - case CODEC_RT1015P: - sof_rt1015p_dai_link(&links[id]); - break; - case CODEC_RT1019P: - sof_rt1019p_dai_link(&links[id]); - break; - case CODEC_RT5650: - /* use AIF2 to support speaker pipeline */ - links[id].codecs = &rt5650_components[1]; - links[id].num_codecs = 1; - links[id].init = rt5650_spk_init; - links[id].ops = &sof_rt5682_ops; - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return NULL; - } - - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - /* feedback stream or firmware-generated echo reference */ - links[id].dpcm_capture = 1; - - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - if (is_legacy_cpu) { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; - - } else { - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_amp); - if (!links[id].cpus->dai_name) - goto devm_err; - } - id++; - } + if (ctx->amp_type == CODEC_NONE) + return 0; - /* BT audio offload */ - if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - int port = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - links[id].id = id; - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - goto devm_err; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - if (!links[id].name) - goto devm_err; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; } - /* HDMI-In SSP */ - if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) { - unsigned long hdmi_in_ssp = (sof_rt5682_quirk & - SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; - int port = 0; - - for_each_set_bit(port, &hdmi_in_ssp, 32) { - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - return NULL; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); - if (!links[id].name) - return NULL; - links[id].id = id + hdmi_id_offset; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; - id++; - } + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + ctx->amp_link->codecs = max_98373_components; + ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); + ctx->amp_link->init = max_98373_spk_codec_init; + ctx->amp_link->ops = &max_98373_ops; + break; + case CODEC_MAX98390: + max_98390_dai_link(dev, ctx->amp_link); + break; + case CODEC_RT1011: + sof_rt1011_dai_link(ctx->amp_link); + break; + case CODEC_RT1015: + sof_rt1015_dai_link(ctx->amp_link); + break; + case CODEC_RT1015P: + sof_rt1015p_dai_link(ctx->amp_link); + break; + case CODEC_RT1019P: + sof_rt1019p_dai_link(ctx->amp_link); + break; + case CODEC_RT5650: + /* use AIF2 to support speaker pipeline */ + ctx->amp_link->codecs = &rt5650_components[1]; + ctx->amp_link->num_codecs = 1; + ctx->amp_link->init = rt5650_spk_init; + ctx->amp_link->ops = &sof_rt5682_ops; + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; } - return links; -devm_err: - return NULL; + return 0; } static int sof_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; - struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_amp, ssp_codec; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -885,34 +736,25 @@ static int sof_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); - ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> - SOF_RT5682_SSP_AMP_SHIFT; + /* port number/mask of peripherals attached to ssp interface */ + ctx->ssp_mask_hdmi_in = (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> + SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; - ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; + ctx->ssp_bt = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; - /* compute number of dai links */ - sof_audio_card_rt5682.num_links = 1 + ctx->dmic_be_num + ctx->hdmi_num; + ctx->ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> + SOF_RT5682_SSP_AMP_SHIFT; - if (ctx->amp_type != CODEC_NONE) - sof_audio_card_rt5682.num_links++; + ctx->ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - sof_audio_card_rt5682.num_links++; - - if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) - sof_audio_card_rt5682.num_links += - hweight32((sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT); - - dai_links = sof_card_dai_links_create(&pdev->dev, ctx->codec_type, - ctx->amp_type, ssp_codec, ssp_amp, - ctx->dmic_be_num, ctx->hdmi_num, - ctx->hdmi.idisp_codec, - ctx->rt5682.is_legacy_cpu); - if (!dai_links) - return -ENOMEM; + ctx->bt_offload_present = true; - sof_audio_card_rt5682.dai_link = dai_links; + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx); + if (ret) + return ret; /* update codec_conf */ switch (ctx->amp_type) { @@ -1147,6 +989,15 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(0) | SOF_RT5682_NUM_HDMIDEV(3)), }, + { + .name = "mtl_rt5650", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(2) | + SOF_RT5682_SSP_AMP(0) | + SOF_RT5682_NUM_HDMIDEV(3) | + SOF_BT_OFFLOAD_SSP(1) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 77a9ce401103..e4ea4a732895 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -570,16 +570,14 @@ int sdw_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link_ch_map *ch_maps; int ch = params_channels(params); - struct snd_soc_dai *codec_dai; - struct snd_soc_dai *cpu_dai; unsigned int ch_mask; int num_codecs; int step; int i; - int j; - if (!rtd->dai_link->codec_ch_maps) + if (!rtd->dai_link->ch_maps) return 0; /* Identical data will be sent to all codecs in playback */ @@ -605,13 +603,9 @@ int sdw_hw_params(struct snd_pcm_substream *substream, * link has more than one codec DAIs. Set codec channel mask and * ASoC will set the corresponding channel numbers for each cpu dai. */ - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id != i) - continue; - rtd->dai_link->codec_ch_maps[j].ch_mask = ch_mask << (j * step); - } - } + for_each_link_ch_maps(rtd->dai_link, i, ch_maps) + ch_maps->ch_mask = ch_mask << (i * step); + return 0; } @@ -1380,15 +1374,17 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, return 0; } -static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps, +static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps, int codec_num, int cpu_num) { int step; int i; step = codec_num / cpu_num; - for (i = 0; i < codec_num; i++) - sdw_codec_ch_maps[i].connected_cpu_id = i / step; + for (i = 0; i < codec_num; i++) { + sdw_codec_ch_maps[i].cpu = i / step; + sdw_codec_ch_maps[i].codec = i; + } } static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; @@ -1483,7 +1479,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, *ignore_pch_dmic = true; for_each_pcm_streams(stream) { - struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_maps; + struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps; char *name, *cpu_name; int playback, capture; static const char * const sdw_stream_name[] = { @@ -1560,7 +1556,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, dai_links[*link_index].nonatomic = true; set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); - dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps; + dai_links[*link_index].ch_maps = sdw_codec_ch_maps; ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, playback, group_id, adr_index, dai_index); if (ret < 0) { diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 137ba64254bc..ee2e813bf4c0 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -27,21 +27,10 @@ #define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0)) /* HDMI capture*/ -#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(4) -#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 5 -#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(6, 5)) -#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \ - (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) - -#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7 -#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7)) -#define SOF_HDMI_CAPTURE_1_SSP(quirk) \ - (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK) - -#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10 -#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10)) -#define SOF_HDMI_CAPTURE_2_SSP(quirk) \ - (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK) +#define SOF_HDMI_CAPTURE_SSP_MASK_SHIFT 4 +#define SOF_HDMI_CAPTURE_SSP_MASK_MASK (GENMASK(9, 4)) +#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ + (((quirk) << SOF_HDMI_CAPTURE_SSP_MASK_SHIFT) & SOF_HDMI_CAPTURE_SSP_MASK_MASK) /* HDMI playback */ #define SOF_HDMI_PLAYBACK_PRESENT BIT(13) @@ -82,13 +71,6 @@ static struct snd_soc_card sof_ssp_amp_card = { .late_probe = sof_card_late_probe, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } -}; - /* BE ID defined in sof-tgl-rt1308-hdmi-ssp.m4 */ #define HDMI_IN_BE_ID 0 #define SPK_BE_ID 2 @@ -98,66 +80,53 @@ static struct snd_soc_dai_link_component platform_component[] = { static struct snd_soc_dai_link * sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, - int ssp_codec, int dmic_be_num, int hdmi_num, + int ssp_amp, int dmic_be_num, int hdmi_num, bool idisp_codec) { - struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i; int id = 0; int ret; bool fixed_be = false; int be_id; + unsigned long ssp_mask_hdmi_in; links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL); - cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links, - sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!links || !cpus) + if (!links) return NULL; /* HDMI-In SSP */ - if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) { - int num_of_hdmi_ssp = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> + SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; + + if (ssp_mask_hdmi_in) { + int port = 0; /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ fixed_be = true; - for (i = 1; i <= num_of_hdmi_ssp; i++) { - int port = (i == 1 ? (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >> - SOF_HDMI_CAPTURE_1_SSP_SHIFT : - (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >> - SOF_HDMI_CAPTURE_2_SSP_SHIFT); - - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - return NULL; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port); - if (!links[id].name) + be_id = HDMI_IN_BE_ID; + for_each_set_bit(port, &ssp_mask_hdmi_in, 32) { + ret = sof_intel_board_set_hdmi_in_link(dev, &links[id], + be_id, port); + if (ret) return NULL; - links[id].id = fixed_be ? (HDMI_IN_BE_ID + i - 1) : id; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + id++; + be_id++; } } /* codec SSP */ if (amp_type != CODEC_NONE) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); - if (!links[id].name) + be_id = fixed_be ? SPK_BE_ID : id; + ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], be_id, + amp_type, ssp_amp); + if (ret) return NULL; - links[id].id = fixed_be ? SPK_BE_ID : id; - + /* codec-specific fields */ switch (amp_type) { case CODEC_CS35L41: cs35l41_set_dai_link(&links[id]); @@ -170,18 +139,6 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, return NULL; } - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - /* feedback from amplifier or firmware-generated echo reference */ - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].cpus = &cpus[id]; - links[id].num_cpus = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_codec); - if (!links[id].cpus->dai_name) - return NULL; - id++; } @@ -224,29 +181,14 @@ sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT; - links[id].id = id; - links[id].cpus = &cpus[id]; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", port); - if (!links[id].cpus->dai_name) - goto devm_err; - links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - if (!links[id].name) - goto devm_err; - links[id].codecs = &snd_soc_dummy_dlc; - links[id].num_codecs = 1; - links[id].platforms = platform_component; - links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; - links[id].no_pcm = 1; - links[id].num_cpus = 1; + ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); + if (ret) + return NULL; + id++; } return links; -devm_err: - return NULL; } static int sof_ssp_amp_probe(struct platform_device *pdev) @@ -254,7 +196,7 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; - int ret, ssp_codec; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -270,7 +212,14 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) else ctx->dmic_be_num = 0; - ssp_codec = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; + /* port number/mask of peripherals attached to ssp interface */ + ctx->ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> + SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; + + ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + + ctx->ssp_amp = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; /* set number of dai links */ sof_ssp_amp_card.num_links = ctx->dmic_be_num; @@ -278,9 +227,8 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) if (ctx->amp_type != CODEC_NONE) sof_ssp_amp_card.num_links++; - if (sof_ssp_amp_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) - sof_ssp_amp_card.num_links += (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; + if (ctx->ssp_mask_hdmi_in) + sof_ssp_amp_card.num_links += hweight32(ctx->ssp_mask_hdmi_in); if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { ctx->hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >> @@ -297,11 +245,13 @@ static int sof_ssp_amp_probe(struct platform_device *pdev) ctx->hdmi_num = 0; } - if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) + if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; sof_ssp_amp_card.num_links++; + } dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ssp_codec, ctx->dmic_be_num, + ctx->ssp_amp, ctx->dmic_be_num, ctx->hdmi_num, ctx->hdmi.idisp_codec); if (!dai_links) @@ -343,10 +293,8 @@ static const struct platform_device_id board_ids[] = { { .name = "tgl_rt1308_hdmi_ssp", .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) | - SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(1) | - SOF_HDMI_CAPTURE_2_SSP(5) | - SOF_SSP_HDMI_CAPTURE_PRESENT), + SOF_HDMI_CAPTURE_SSP_MASK(0x22)), + /* SSP 1 and SSP 5 are used for HDMI IN */ }, { .name = "adl_cs35l41", @@ -358,28 +306,22 @@ static const struct platform_device_id board_ids[] = { }, { .name = "adl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(0) | - SOF_HDMI_CAPTURE_2_SSP(2) | - SOF_SSP_HDMI_CAPTURE_PRESENT | + .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "rpl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(0) | - SOF_HDMI_CAPTURE_2_SSP(2) | - SOF_SSP_HDMI_CAPTURE_PRESENT | + .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "mtl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) | - SOF_HDMI_CAPTURE_1_SSP(0) | - SOF_HDMI_CAPTURE_2_SSP(2) | - SOF_SSP_HDMI_CAPTURE_PRESENT | + .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, diff --git a/sound/soc/intel/boards/sof_ssp_common.c b/sound/soc/intel/boards/sof_ssp_common.c index 41a258e45a61..96072790e9c0 100644 --- a/sound/soc/intel/boards/sof_ssp_common.c +++ b/sound/soc/intel/boards/sof_ssp_common.c @@ -96,6 +96,27 @@ enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev) } EXPORT_SYMBOL_NS(sof_ssp_detect_amp_type, SND_SOC_INTEL_SOF_SSP_COMMON); +const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(codecs); i++) { + if (codecs[i].codec_type != codec_type) + continue; + + return codecs[i].name; + } + for (i = 0; i < ARRAY_SIZE(amps); i++) { + if (amps[i].codec_type != codec_type) + continue; + + return amps[i].name; + } + + return NULL; +} +EXPORT_SYMBOL_NS(sof_ssp_get_codec_name, SND_SOC_INTEL_SOF_SSP_COMMON); + MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_ssp_common.h b/sound/soc/intel/boards/sof_ssp_common.h index e3fd6fb1db1c..6d827103479b 100644 --- a/sound/soc/intel/boards/sof_ssp_common.h +++ b/sound/soc/intel/boards/sof_ssp_common.h @@ -67,5 +67,6 @@ enum sof_ssp_codec { enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev); enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev); +const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type); #endif /* __SOF_SSP_COMMON_H */ diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 5a90ebdbf799..f2c17cee1a5d 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -40,6 +40,11 @@ static const struct snd_soc_acpi_codecs mtl_lt6911_hdmi = { .codecs = {"INTC10B0"} }; +static const struct snd_soc_acpi_codecs mtl_rt5650_amp = { + .num_codecs = 1, + .codecs = {"10EC5650"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { { .comp_ids = &mtl_rt5682_rt5682s_hp, @@ -77,6 +82,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .id = "10EC5650", + .drv_name = "mtl_rt5650", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &mtl_rt5650_amp, + .sof_tplg_filename = "sof-mtl-rt5650.tplg", + }, /* place amp-only boards in the end of table */ { .id = "INTC10B0", diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 2ef47aa2c778..84601ba43b7d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1379,7 +1379,9 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev io->chan = dma_request_channel(mask, shdma_chan_filter, (void *)io->dma_id); #else - io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx"); + io->chan = dma_request_chan(dev, is_play ? "tx" : "rx"); + if (IS_ERR(io->chan)) + io->chan = NULL; #endif if (io->chan) { struct dma_slave_config cfg = {}; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b2bd45e87bc3..4ca3319a8e19 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1015,6 +1015,94 @@ component_dai_empty: return -EINVAL; } +#define MAX_DEFAULT_CH_MAP_SIZE 7 +static struct snd_soc_dai_link_ch_map default_ch_map_sync[MAX_DEFAULT_CH_MAP_SIZE] = { + { .cpu = 0, .codec = 0 }, + { .cpu = 1, .codec = 1 }, + { .cpu = 2, .codec = 2 }, + { .cpu = 3, .codec = 3 }, + { .cpu = 4, .codec = 4 }, + { .cpu = 5, .codec = 5 }, + { .cpu = 6, .codec = 6 }, +}; +static struct snd_soc_dai_link_ch_map default_ch_map_1cpu[MAX_DEFAULT_CH_MAP_SIZE] = { + { .cpu = 0, .codec = 0 }, + { .cpu = 0, .codec = 1 }, + { .cpu = 0, .codec = 2 }, + { .cpu = 0, .codec = 3 }, + { .cpu = 0, .codec = 4 }, + { .cpu = 0, .codec = 5 }, + { .cpu = 0, .codec = 6 }, +}; +static struct snd_soc_dai_link_ch_map default_ch_map_1codec[MAX_DEFAULT_CH_MAP_SIZE] = { + { .cpu = 0, .codec = 0 }, + { .cpu = 1, .codec = 0 }, + { .cpu = 2, .codec = 0 }, + { .cpu = 3, .codec = 0 }, + { .cpu = 4, .codec = 0 }, + { .cpu = 5, .codec = 0 }, + { .cpu = 6, .codec = 0 }, +}; +static int snd_soc_compensate_channel_connection_map(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_dai_link_ch_map *ch_maps; + int i; + + /* + * dai_link->ch_maps indicates how CPU/Codec are connected. + * It will be a map seen from a larger number of DAI. + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + + /* it should have ch_maps if connection was N:M */ + if (dai_link->num_cpus > 1 && dai_link->num_codecs > 1 && + dai_link->num_cpus != dai_link->num_codecs && !dai_link->ch_maps) { + dev_err(card->dev, "need to have ch_maps when N:M connction (%s)", + dai_link->name); + return -EINVAL; + } + + /* do nothing if it has own maps */ + if (dai_link->ch_maps) + goto sanity_check; + + /* check default map size */ + if (dai_link->num_cpus > MAX_DEFAULT_CH_MAP_SIZE || + dai_link->num_codecs > MAX_DEFAULT_CH_MAP_SIZE) { + dev_err(card->dev, "soc-core.c needs update default_connection_maps"); + return -EINVAL; + } + + /* Compensate missing map for ... */ + if (dai_link->num_cpus == dai_link->num_codecs) + dai_link->ch_maps = default_ch_map_sync; /* for 1:1 or N:N */ + else if (dai_link->num_cpus < dai_link->num_codecs) + dai_link->ch_maps = default_ch_map_1cpu; /* for 1:N */ + else + dai_link->ch_maps = default_ch_map_1codec; /* for N:1 */ + +sanity_check: + dev_dbg(card->dev, "dai_link %s\n", dai_link->stream_name); + for_each_link_ch_maps(dai_link, i, ch_maps) { + if ((ch_maps->cpu >= dai_link->num_cpus) || + (ch_maps->codec >= dai_link->num_codecs)) { + dev_err(card->dev, + "unexpected dai_link->ch_maps[%d] index (cpu(%d/%d) codec(%d/%d))", + i, + ch_maps->cpu, dai_link->num_cpus, + ch_maps->codec, dai_link->num_codecs); + return -EINVAL; + } + + dev_dbg(card->dev, " [%d] cpu%d <-> codec%d\n", + i, ch_maps->cpu, ch_maps->codec); + } + + return 0; +} + /** * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card * @card: The ASoC card to which the pcm_runtime has @@ -1121,8 +1209,13 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card, int num_dai_link) { for (int i = 0; i < num_dai_link; i++) { - int ret = snd_soc_add_pcm_runtime(card, dai_link + i); + int ret; + + ret = snd_soc_compensate_channel_connection_map(card, dai_link + i); + if (ret < 0) + return ret; + ret = snd_soc_add_pcm_runtime(card, dai_link + i); if (ret < 0) return ret; } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3844f777c87b..bffeea80277f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -320,7 +320,8 @@ EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); /* create a new dapm widget */ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( - const struct snd_soc_dapm_widget *_widget) + const struct snd_soc_dapm_widget *_widget, + const char *prefix) { struct snd_soc_dapm_widget *w; @@ -328,13 +329,19 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( if (!w) return NULL; - /* - * w->name is duplicated in caller, but w->sname isn't. - * Duplicate it here if defined - */ + if (prefix) + w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, _widget->name); + else + w->name = kstrdup_const(_widget->name, GFP_KERNEL); + if (!w->name) { + kfree(w); + return NULL; + } + if (_widget->sname) { w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); if (!w->sname) { + kfree_const(w->name); kfree(w); return NULL; } @@ -3629,20 +3636,12 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, { enum snd_soc_dapm_direction dir; struct snd_soc_dapm_widget *w; - const char *prefix; int ret = -ENOMEM; - if ((w = dapm_cnew_widget(widget)) == NULL) + w = dapm_cnew_widget(widget, soc_dapm_prefix(dapm)); + if (!w) goto cnew_failed; - prefix = soc_dapm_prefix(dapm); - if (prefix) - w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); - else - w->name = kstrdup_const(widget->name, GFP_KERNEL); - if (!w->name) - goto name_failed; - switch (w->id) { case snd_soc_dapm_regulator_supply: w->regulator = devm_regulator_get(dapm->dev, widget->name); @@ -3767,7 +3766,6 @@ request_failed: dev_err_probe(dapm->dev, ret, "ASoC: Failed to request %s\n", w->name); kfree_const(w->name); -name_failed: kfree_const(w->sname); kfree(w); cnew_failed: @@ -4438,11 +4436,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *cpu_dai; struct snd_soc_dai *codec_dai; - int i; /* for each BE DAI link... */ for_each_card_rtds(card, rtd) { + struct snd_soc_dai_link_ch_map *ch_maps; + int i; + /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. @@ -4450,39 +4451,15 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) if (rtd->dai_link->dynamic) continue; - if (rtd->dai_link->num_cpus == 1) { - for_each_rtd_codec_dais(rtd, i, codec_dai) - dapm_connect_dai_pair(card, rtd, codec_dai, - snd_soc_rtd_to_cpu(rtd, 0)); - } else if (rtd->dai_link->num_codecs == rtd->dai_link->num_cpus) { - for_each_rtd_codec_dais(rtd, i, codec_dai) - dapm_connect_dai_pair(card, rtd, codec_dai, - snd_soc_rtd_to_cpu(rtd, i)); - } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) { - int cpu_id; - - if (!rtd->dai_link->codec_ch_maps) { - dev_err(card->dev, "%s: no codec channel mapping table provided\n", - __func__); - continue; - } + /* + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + for_each_rtd_ch_maps(rtd, i, ch_maps) { + cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); - for_each_rtd_codec_dais(rtd, i, codec_dai) { - cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id; - if (cpu_id >= rtd->dai_link->num_cpus) { - dev_err(card->dev, - "%s: dai_link %s cpu_id %d too large, num_cpus is %d\n", - __func__, rtd->dai_link->name, cpu_id, - rtd->dai_link->num_cpus); - continue; - } - dapm_connect_dai_pair(card, rtd, codec_dai, - snd_soc_rtd_to_cpu(rtd, cpu_id)); - } - } else { - dev_err(card->dev, - "%s: codec number %d < cpu number %d is not supported\n", - __func__, rtd->dai_link->num_codecs, rtd->dai_link->num_cpus); + dapm_connect_dai_pair(card, rtd, codec_dai, cpu_dai); } } } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 323e4d7b6adf..c20573aeb756 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1050,6 +1050,7 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, } for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + struct snd_soc_dai_link_ch_map *ch_maps; unsigned int ch_mask = 0; int j; @@ -1063,22 +1064,20 @@ static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, /* copy params for each cpu */ tmp_params = *params; - if (!rtd->dai_link->codec_ch_maps) - goto hw_params; /* * construct cpu channel mask by combining ch_mask of each * codec which maps to the cpu. + * see + * soc.h :: [dai_link->ch_maps Image sample] */ - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (rtd->dai_link->codec_ch_maps[j].connected_cpu_id == i) - ch_mask |= rtd->dai_link->codec_ch_maps[j].ch_mask; - } + for_each_rtd_ch_maps(rtd, j, ch_maps) + if (ch_maps->cpu == i) + ch_mask |= ch_maps->ch_mask; /* fixup cpu channel number */ if (ch_mask) soc_pcm_codec_params_fixup(&tmp_params, ch_mask); -hw_params: ret = snd_soc_dai_hw_params(cpu_dai, substream, &tmp_params); if (ret < 0) goto out; @@ -2826,35 +2825,20 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, } } } else { + struct snd_soc_dai_link_ch_map *ch_maps; struct snd_soc_dai *codec_dai; /* Adapt stream for codec2codec links */ int cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); int cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK); - for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (dai_link->num_cpus == 1) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - } else if (dai_link->num_cpus == dai_link->num_codecs) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, i); - } else if (rtd->dai_link->num_codecs > rtd->dai_link->num_cpus) { - int cpu_id; - - if (!rtd->dai_link->codec_ch_maps) { - dev_err(rtd->card->dev, "%s: no codec channel mapping table provided\n", - __func__); - return -EINVAL; - } - - cpu_id = rtd->dai_link->codec_ch_maps[i].connected_cpu_id; - cpu_dai = snd_soc_rtd_to_cpu(rtd, cpu_id); - } else { - dev_err(rtd->card->dev, - "%s codec number %d < cpu number %d is not supported\n", - __func__, rtd->dai_link->num_codecs, - rtd->dai_link->num_cpus); - return -EINVAL; - } + /* + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + for_each_rtd_ch_maps(rtd, i, ch_maps) { + cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && snd_soc_dai_stream_valid(cpu_dai, cpu_playback)) diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 2680f061ba42..f088fd1a672b 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -313,6 +313,13 @@ static struct snd_soc_dai_driver imx8m_dai[] = { .channels_max = 32, }, }, +{ + .name = "micfil", + .capture = { + .channels_min = 1, + .channels_max = 8, + }, +}, }; static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 46fb2d1425e9..1805cf754beb 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -510,9 +510,8 @@ cleanup: return chip_info->init_core_mask; /* disable DSP */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, - SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, 0); + hda_dsp_ctrl_ppcap_enable(sdev, false); + return ret; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 744c0dd5766d..fe4ae349dad5 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1350,8 +1350,7 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) if (!sdev->dspless_mode_selected) { /* disable DSP IRQ */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_PIE, 0); + hda_dsp_ctrl_ppcap_int_enable(sdev, false); } /* disable CIE and GIE interrupts */ @@ -1366,8 +1365,7 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) chip->power_down_dsp(sdev); /* disable DSP */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, 0); + hda_dsp_ctrl_ppcap_enable(sdev, false); skip_disable_dsp: free_irq(sdev->ipc_irq, sdev); diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 254dbbeac1d0..3ef9e5c37028 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -440,7 +440,8 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; unsigned int status; - u32 ipc_hdr; + u32 ipc_hdr, flags; + char *dump_msg; int ret; /* step 1: purge FW request */ @@ -493,8 +494,18 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) return 0; err: - snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0); + flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL; + + /* after max boot attempts make sure that the dump is printed */ + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + flags &= ~SOF_DBG_DUMP_OPTIONAL; + + dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d", + hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS); + snd_sof_dsp_dbg_dump(sdev, dump_msg, flags); mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); + + kfree(dump_msg); return ret; } diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 2d0addcbc819..330f04bcd75d 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -384,6 +384,17 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dev_dbg(component->dev, "AMD_DMIC channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_IMX_MICFIL: + rate->min = private->dai_config->micfil.pdm_rate; + rate->max = private->dai_config->micfil.pdm_rate; + channels->min = private->dai_config->micfil.pdm_ch; + channels->max = private->dai_config->micfil.pdm_ch; + + dev_dbg(component->dev, + "MICFIL PDM rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, "MICFIL PDM channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; default: dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type); break; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index ba4ef290b634..7a4932c152a9 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -286,6 +286,16 @@ static const struct sof_topology_token acpi2s_tokens[] = { offsetof(struct sof_ipc_dai_acp_params, tdm_mode)}, }; +/* MICFIL PDM */ +static const struct sof_topology_token micfil_pdm_tokens[] = { + {SOF_TKN_IMX_MICFIL_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_micfil_params, pdm_rate)}, + {SOF_TKN_IMX_MICFIL_CH, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_micfil_params, pdm_ch)}, +}; + /* Core tokens */ static const struct sof_topology_token core_tokens[] = { {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -322,6 +332,8 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)}, [SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)}, [SOF_ACPI2S_TOKENS] = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)}, + [SOF_MICFIL_TOKENS] = {"MICFIL PDM tokens", + micfil_pdm_tokens, ARRAY_SIZE(micfil_pdm_tokens)}, }; /** @@ -1136,6 +1148,37 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_da return 0; } +static int sof_link_micfil_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + config->hdr.size = size; + + /* parse the required set of MICFIL PDM tokens based on num_hw_cfgs */ + ret = sof_update_ipc_object(scomp, &config->micfil, SOF_MICFIL_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + dev_info(scomp->dev, "MICFIL PDM config dai_index %d channel %d rate %d\n", + config->dai_index, config->micfil.pdm_ch, config->micfil.pdm_rate); + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { @@ -1559,6 +1602,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) case SOF_DAI_IMX_ESAI: ret = sof_link_esai_load(scomp, slink, config, dai); break; + case SOF_DAI_IMX_MICFIL: + ret = sof_link_micfil_load(scomp, slink, config, dai); + break; case SOF_DAI_AMD_BT: ret = sof_link_acp_bt_load(scomp, slink, config, dai); break; diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 938efaceb81c..3d2a35f27a87 100644 --- a/sound/soc/sof/ipc4-control.c +++ b/sound/soc/sof/ipc4-control.c @@ -240,6 +240,50 @@ sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev, return ret; } +static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol) +{ + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; + struct snd_soc_component *scomp = scontrol->scomp; + struct sof_ipc4_control_msg_payload *data; + struct sof_ipc4_msg *msg = &cdata->msg; + size_t data_size; + unsigned int i; + int ret; + + if (!scontrol->comp_data_dirty) + return; + + if (!pm_runtime_active(scomp->dev)) + return; + + data_size = struct_size(data, chanv, scontrol->num_channels); + data = kmalloc(data_size, GFP_KERNEL); + if (!data) + return; + + data->id = cdata->index; + data->num_elems = scontrol->num_channels; + msg->data_ptr = data; + msg->data_size = data_size; + + scontrol->comp_data_dirty = false; + ret = sof_ipc4_set_get_kcontrol_data(scontrol, false, true); + msg->data_ptr = NULL; + msg->data_size = 0; + if (!ret) { + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = data->chanv[i].channel; + cdata->chanv[i].value = data->chanv[i].value; + } + } else { + dev_err(scomp->dev, "Failed to read control data for %s\n", + scontrol->name); + scontrol->comp_data_dirty = true; + } + + kfree(data); +} + static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, struct snd_ctl_elem_value *ucontrol) { @@ -290,6 +334,8 @@ static int sof_ipc4_switch_get(struct snd_sof_control *scontrol, struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; unsigned int i; + sof_ipc4_refresh_generic_control(scontrol); + /* read back each channel */ for (i = 0; i < scontrol->num_channels; i++) ucontrol->value.integer.value[i] = cdata->chanv[i].value; @@ -347,6 +393,8 @@ static int sof_ipc4_enum_get(struct snd_sof_control *scontrol, struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; unsigned int i; + sof_ipc4_refresh_generic_control(scontrol); + /* read back each channel */ for (i = 0; i < scontrol->num_channels; i++) ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; @@ -601,6 +649,136 @@ sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false); } +#define PARAM_ID_FROM_EXTENSION(_ext) (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) \ + >> SOF_IPC4_MOD_EXT_MSG_PARAM_ID_SHIFT) + +static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message) +{ + struct sof_ipc4_msg *ipc4_msg = ipc_message; + struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr; + struct sof_ipc4_control_msg_payload *msg_data; + struct sof_ipc4_control_data *cdata; + struct snd_soc_dapm_widget *widget; + struct snd_sof_control *scontrol; + struct snd_sof_widget *swidget; + struct snd_kcontrol *kc = NULL; + bool scontrol_found = false; + u32 event_param_id; + int i, type; + + if (ndata->event_data_size < sizeof(*msg_data)) { + dev_err(sdev->dev, + "%s: Invalid event data size for module %u.%u: %u\n", + __func__, ndata->module_id, ndata->instance_id, + ndata->event_data_size); + return; + } + + event_param_id = ndata->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK; + switch (event_param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + type = SND_SOC_TPLG_TYPE_MIXER; + break; + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + type = SND_SOC_TPLG_TYPE_ENUM; + break; + default: + dev_err(sdev->dev, + "%s: Invalid control type for module %u.%u: %u\n", + __func__, ndata->module_id, ndata->instance_id, + event_param_id); + return; + } + + /* Find the swidget based on ndata->module_id and ndata->instance_id */ + swidget = sof_ipc4_find_swidget_by_ids(sdev, ndata->module_id, + ndata->instance_id); + if (!swidget) { + dev_err(sdev->dev, "%s: Failed to find widget for module %u.%u\n", + __func__, ndata->module_id, ndata->instance_id); + return; + } + + /* Find the scontrol which is the source of the notification */ + msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data; + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id) { + u32 local_param_id; + + cdata = scontrol->ipc_control_data; + /* + * The scontrol's param_id is stored in the IPC message + * template's extension + */ + local_param_id = PARAM_ID_FROM_EXTENSION(cdata->msg.extension); + if (local_param_id == event_param_id && + msg_data->id == cdata->index) { + scontrol_found = true; + break; + } + } + } + + if (!scontrol_found) { + dev_err(sdev->dev, + "%s: Failed to find control on widget %s: %u:%u\n", + __func__, swidget->widget->name, ndata->event_id & 0xffff, + msg_data->id); + return; + } + + if (msg_data->num_elems) { + /* + * The message includes the updated value/data, update the + * control's local cache using the received notification + */ + for (i = 0; i < msg_data->num_elems; i++) { + u32 channel = msg_data->chanv[i].channel; + + if (channel >= scontrol->num_channels) { + dev_warn(sdev->dev, + "Invalid channel index for %s: %u\n", + scontrol->name, i); + + /* + * Mark the scontrol as dirty to force a refresh + * on next read + */ + scontrol->comp_data_dirty = true; + break; + } + + cdata->chanv[channel].value = msg_data->chanv[i].value; + } + } else { + /* + * Mark the scontrol as dirty because the value/data is changed + * in firmware, forcing a refresh on next read access + */ + scontrol->comp_data_dirty = true; + } + + /* + * Look up the ALSA kcontrol of the scontrol to be able to send a + * notification to user space + */ + widget = swidget->widget; + for (i = 0; i < widget->num_kcontrols; i++) { + /* skip non matching types or non matching indexes within type */ + if (widget->dobj.widget.kcontrol_type[i] == type && + widget->kcontrol_news[i].index == cdata->index) { + kc = widget->kcontrols[i]; + break; + } + } + + if (!kc) + return; + + snd_ctl_notify_one(swidget->scomp->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, kc, 0); +} + /* set up all controls for the widget */ static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { @@ -674,6 +852,7 @@ const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = { .bytes_ext_put = sof_ipc4_bytes_ext_put, .bytes_ext_get = sof_ipc4_bytes_ext_get, .bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get, + .update = sof_ipc4_control_update, .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup, .set_up_volume_table = sof_ipc4_set_up_volume_table, }; diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 9e69b7c29117..fea93b693f4d 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -115,6 +115,9 @@ int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev); struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, const guid_t *uuid); +struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev, + u32 module_id, int instance_id); + struct sof_ipc4_base_module_cfg; void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev, struct sof_ipc4_fw_module *fw_module, diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index b24a64377f68..8ab9c42069ee 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -167,6 +167,26 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, }; +struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev, + u32 module_id, int instance_id) +{ + struct snd_sof_widget *swidget; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + struct sof_ipc4_fw_module *fw_module = swidget->module_info; + + /* Only active module instances have valid instance_id */ + if (!swidget->use_count) + continue; + + if (fw_module && fw_module->man4_module_entry.id == module_id && + swidget->instance_id == instance_id) + return swidget; + } + + return NULL; +} + static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt, int num_formats) { diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 8441f4ae4065..a9d9800d2fcc 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -78,6 +78,9 @@ static const struct sof_ipc4_fw_status { {165, "Reserved (ADSP_IPC_PIPELINE_ALREADY_EXISTS removed)"}, }; +typedef void (*ipc4_notification_handler)(struct snd_sof_dev *sdev, + struct sof_ipc4_msg *msg); + static int sof_ipc4_check_reply_status(struct snd_sof_dev *sdev, u32 status) { int i, ret; @@ -610,9 +613,55 @@ static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg return sof_ipc4_init_msg_memory(sdev); } +static void sof_ipc4_module_notification_handler(struct snd_sof_dev *sdev, + struct sof_ipc4_msg *ipc4_msg) +{ + struct sof_ipc4_notify_module_data *data = ipc4_msg->data_ptr; + + /* + * If the notification includes additional, module specific data, then + * we need to re-allocate the buffer and re-read the whole payload, + * including the event_data + */ + if (data->event_data_size) { + void *new; + int ret; + + ipc4_msg->data_size += data->event_data_size; + + new = krealloc(ipc4_msg->data_ptr, ipc4_msg->data_size, GFP_KERNEL); + if (!new) { + ipc4_msg->data_size -= data->event_data_size; + return; + } + + /* re-read the whole payload */ + ipc4_msg->data_ptr = new; + ret = snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, + ipc4_msg->data_size); + if (ret < 0) { + dev_err(sdev->dev, + "Failed to read the full module notification: %d\n", + ret); + return; + } + data = ipc4_msg->data_ptr; + } + + /* Handle ALSA kcontrol notification */ + if ((data->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_MASK) == + SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL) { + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + + if (tplg_ops->control->update) + tplg_ops->control->update(sdev, ipc4_msg); + } +} + static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) { struct sof_ipc4_msg *ipc4_msg = sdev->ipc->msg.rx_data; + ipc4_notification_handler handler_func = NULL; size_t data_size = 0; int err; @@ -648,6 +697,10 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) case SOF_IPC4_NOTIFY_EXCEPTION_CAUGHT: snd_sof_dsp_panic(sdev, 0, true); break; + case SOF_IPC4_NOTIFY_MODULE_NOTIFICATION: + data_size = sizeof(struct sof_ipc4_notify_module_data); + handler_func = sof_ipc4_module_notification_handler; + break; default: dev_dbg(sdev->dev, "Unhandled DSP message: %#x|%#x\n", ipc4_msg->primary, ipc4_msg->extension); @@ -663,6 +716,10 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, ipc4_msg->data_size); } + /* Handle notifications with payload */ + if (handler_func) + handler_func(sdev, ipc4_msg); + sof_ipc4_log_header(sdev->dev, "ipc rx done ", ipc4_msg, true); if (data_size) { diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h index d41e904e6614..35527567962e 100644 --- a/sound/soc/sof/mediatek/adsp_helper.h +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -15,17 +15,13 @@ struct mtk_adsp_chip_info { phys_addr_t pa_sram; phys_addr_t pa_dram; /* adsp dram physical base */ - phys_addr_t pa_shared_dram; /* adsp dram physical base */ phys_addr_t pa_cfgreg; u32 sramsize; u32 dramsize; u32 cfgregsize; - u32 shared_size; void __iomem *va_sram; /* corresponding to pa_sram */ void __iomem *va_dram; /* corresponding to pa_dram */ void __iomem *va_cfgreg; - void __iomem *shared_sram; /* part of va_sram */ - void __iomem *shared_dram; /* part of va_dram */ phys_addr_t adsp_bootup_addr; int dram_offset; /*dram offset between system and dsp view*/ diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index b69fa788b16f..0d2d7d697de0 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -96,29 +96,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) struct mtk_adsp_chip_info *adsp = data; int ret; - mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!mem_region) { - dev_err(dev, "no dma memory-region phandle\n"); - return -ENODEV; - } - - ret = of_address_to_resource(mem_region, 0, &res); - of_node_put(mem_region); - if (ret) { - dev_err(dev, "of_address_to_resource dma failed\n"); - return ret; - } - - dev_dbg(dev, "DMA %pR\n", &res); - - adsp->pa_shared_dram = (phys_addr_t)res.start; - adsp->shared_size = resource_size(&res); - if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { - dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", - (u32)adsp->pa_shared_dram); - return -EINVAL; - } - ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -248,26 +225,6 @@ static int adsp_memory_remap_init(struct snd_sof_dev *sdev, struct mtk_adsp_chip return 0; } -static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) -{ - struct device *dev = &pdev->dev; - struct mtk_adsp_chip_info *adsp = data; - - /* remap shared-dram base to be non-cachable */ - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - adsp->shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "failed to ioremap base %pa size %#x\n", - adsp->shared_dram, adsp->shared_size); - return -ENOMEM; - } - - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); - - return 0; -} - static int mt8186_run(struct snd_sof_dev *sdev) { u32 adsp_bootup_addr; @@ -324,12 +281,6 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev) priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM]; - ret = adsp_shared_base_ioremap(pdev, priv->adsp); - if (ret) { - dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n"); - return ret; - } - sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg; sdev->bar[DSP_SECREG_BAR] = priv->adsp->va_secreg; sdev->bar[DSP_BUSREG_BAR] = priv->adsp->va_busreg; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index cac0a085f60a..8ee7ee246344 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -96,29 +96,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) struct mtk_adsp_chip_info *adsp = data; int ret; - mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!mem_region) { - dev_err(dev, "no dma memory-region phandle\n"); - return -ENODEV; - } - - ret = of_address_to_resource(mem_region, 0, &res); - of_node_put(mem_region); - if (ret) { - dev_err(dev, "of_address_to_resource dma failed\n"); - return ret; - } - - dev_dbg(dev, "DMA %pR\n", &res); - - adsp->pa_shared_dram = (phys_addr_t)res.start; - adsp->shared_size = resource_size(&res); - if (adsp->pa_shared_dram & DRAM_REMAP_MASK) { - dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n", - (u32)adsp->pa_shared_dram); - return -EINVAL; - } - ret = of_reserved_mem_device_init(dev); if (ret) { dev_err(dev, "of_reserved_mem_device_init failed\n"); @@ -238,26 +215,6 @@ static int adsp_memory_remap_init(struct device *dev, struct mtk_adsp_chip_info return 0; } -static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data) -{ - struct device *dev = &pdev->dev; - struct mtk_adsp_chip_info *adsp = data; - - /* remap shared-dram base to be non-cachable */ - adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, - adsp->shared_size); - if (!adsp->shared_dram) { - dev_err(dev, "failed to ioremap base %pa size %#x\n", - adsp->shared_dram, adsp->shared_size); - return -ENOMEM; - } - - dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", - adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size); - - return 0; -} - static int mt8195_run(struct snd_sof_dev *sdev) { u32 adsp_bootup_addr; @@ -338,12 +295,6 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) } priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM]; - ret = adsp_shared_base_ioremap(pdev, priv->adsp); - if (ret) { - dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n"); - goto err_adsp_sram_power_off; - } - sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg; sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 5d5eeb1a1a6f..99c940b22538 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -275,6 +275,7 @@ enum sof_tokens { SOF_GAIN_TOKENS, SOF_ACPDMIC_TOKENS, SOF_ACPI2S_TOKENS, + SOF_MICFIL_TOKENS, /* this should be the last */ SOF_TOKEN_COUNT, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a3a3af252259..9f717366cddc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -296,6 +296,7 @@ static const struct sof_dai_types sof_dais[] = { {"AFE", SOF_DAI_MEDIATEK_AFE}, {"ACPSP_VIRTUAL", SOF_DAI_AMD_SP_VIRTUAL}, {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL}, + {"MICFIL", SOF_DAI_IMX_MICFIL}, }; @@ -1960,6 +1961,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ token_id = SOF_ACPI2S_TOKENS; num_tuples += token_list[SOF_ACPI2S_TOKENS].count; break; + case SOF_DAI_IMX_MICFIL: + token_id = SOF_MICFIL_TOKENS; + num_tuples += token_list[SOF_MICFIL_TOKENS].count; + break; default: break; } diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 2c21a86421e6..ba824f14a39c 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -461,10 +461,6 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, return 0; } -static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = { - .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, -}; - static int sti_uniperiph_probe(struct platform_device *pdev) { struct sti_uniperiph_data *priv; @@ -493,8 +489,7 @@ static int sti_uniperiph_probe(struct platform_device *pdev) if (ret < 0) return ret; - return devm_snd_dmaengine_pcm_register(&pdev->dev, - &dmaengine_pcm_config, 0); + return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); } static struct platform_driver sti_uniperiph_driver = { diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 142e8d4eefd5..42acb56543db 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -98,8 +98,8 @@ int tegra_pcm_open(struct snd_soc_component *component, return ret; } - chan = dma_request_slave_channel(cpu_dai->dev, dmap->chan_name); - if (!chan) { + chan = dma_request_chan(cpu_dai->dev, dmap->chan_name); + if (IS_ERR(chan)) { dev_err(cpu_dai->dev, "dmaengine request slave channel failed! (%s)\n", dmap->chan_name); |