diff options
Diffstat (limited to 'sound')
33 files changed, 1191 insertions, 347 deletions
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 9775bda2a4ca..a4ade6bb5beb 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -32,6 +32,7 @@ struct i2s_stream_instance { u16 channels; u32 xfer_resolution; struct page *pg; + u64 bytescount; void __iomem *acp3x_base; }; @@ -317,6 +318,24 @@ static int acp3x_dma_open(struct snd_pcm_substream *substream) return 0; } +static u64 acp_get_byte_count(struct i2s_stream_instance *rtd, int direction) +{ + u64 byte_count; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + byte_count = rv_readl(rtd->acp3x_base + + mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH); + byte_count |= rv_readl(rtd->acp3x_base + + mmACP_BT_TX_LINEARPOSITIONCNTR_LOW); + } else { + byte_count = rv_readl(rtd->acp3x_base + + mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH); + byte_count |= rv_readl(rtd->acp3x_base + + mmACP_BT_RX_LINEARPOSITIONCNTR_LOW); + } + return byte_count; +} + static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -350,18 +369,17 @@ static int acp3x_dma_hw_params(struct snd_pcm_substream *substream, static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream) { u32 pos = 0; - struct i2s_stream_instance *rtd = substream->runtime->private_data; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - pos = rv_readl(rtd->acp3x_base + - mmACP_BT_TX_LINKPOSITIONCNTR); - else - pos = rv_readl(rtd->acp3x_base + - mmACP_BT_RX_LINKPOSITIONCNTR); - - if (pos >= MAX_BUFFER) - pos = 0; - + u32 buffersize = 0; + u64 bytescount = 0; + struct i2s_stream_instance *rtd = + substream->runtime->private_data; + + buffersize = frames_to_bytes(substream->runtime, + substream->runtime->buffer_size); + bytescount = acp_get_byte_count(rtd, substream->stream); + if (bytescount > rtd->bytescount) + bytescount -= rtd->bytescount; + pos = do_div(bytescount, buffersize); return bytes_to_frames(substream->runtime, pos); } @@ -521,6 +539,7 @@ static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + rtd->bytescount = acp_get_byte_count(rtd, substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { rv_writel(period_bytes, rtd->acp3x_base + mmACP_BT_TX_INTR_WATERMARK_SIZE); diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index ebb9e0cf8364..3e8dbf63adbe 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <sound/pcm_params.h> @@ -45,6 +46,7 @@ struct cs42xx8_priv { bool slave_mode; unsigned long sysclk; u32 tx_channels; + struct gpio_desc *gpiod_reset; }; /* -127.5dB to 0dB with step of 0.5dB */ @@ -467,6 +469,13 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) return -EINVAL; } + cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(cs42xx8->gpiod_reset)) + return PTR_ERR(cs42xx8->gpiod_reset); + + gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0); + cs42xx8->clk = devm_clk_get(dev, "mclk"); if (IS_ERR(cs42xx8->clk)) { dev_err(dev, "failed to get the clock: %ld\n", @@ -547,6 +556,8 @@ static int cs42xx8_runtime_resume(struct device *dev) return ret; } + gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0); + ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies); if (ret) { @@ -585,6 +596,8 @@ static int cs42xx8_runtime_suspend(struct device *dev) regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies); + gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1); + clk_disable_unprepare(cs42xx8->clk); return 0; diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 39caf19abb0b..6a0cc8d7e141 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -278,13 +278,10 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; - struct snd_soc_dai_driver *daidrv; - struct hdmi_codec_daifmt daifmt[2]; - struct mutex current_stream_lock; - struct snd_pcm_substream *current_stream; uint8_t eld[MAX_ELD_BYTES]; struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; + struct mutex lock; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -392,44 +389,22 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } -static int hdmi_codec_new_stream(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - int ret = 0; - - mutex_lock(&hcp->current_stream_lock); - if (!hcp->current_stream) { - hcp->current_stream = substream; - } else if (hcp->current_stream != substream) { - dev_err(dai->dev, "Only one simultaneous stream supported!\n"); - ret = -EINVAL; - } - mutex_unlock(&hcp->current_stream_lock); - - return ret; -} - static int hdmi_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); int ret = 0; - dev_dbg(dai->dev, "%s()\n", __func__); - - ret = hdmi_codec_new_stream(substream, dai); - if (ret) - return ret; + ret = mutex_trylock(&hcp->lock); + if (!ret) { + dev_err(dai->dev, "Only one simultaneous stream supported!\n"); + return -EINVAL; + } if (hcp->hcd.ops->audio_startup) { ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); - if (ret) { - mutex_lock(&hcp->current_stream_lock); - hcp->current_stream = NULL; - mutex_unlock(&hcp->current_stream_lock); - return ret; - } + if (ret) + goto err; } if (hcp->hcd.ops->get_eld) { @@ -439,17 +414,18 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (!ret) { ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); - if (ret) { - mutex_lock(&hcp->current_stream_lock); - hcp->current_stream = NULL; - mutex_unlock(&hcp->current_stream_lock); - return ret; - } + if (ret) + goto err; } /* Select chmap supported */ hdmi_codec_eld_chmap(hcp); } return 0; + +err: + /* Release the exclusive lock on error */ + mutex_unlock(&hcp->lock); + return ret; } static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, @@ -457,16 +433,10 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - dev_dbg(dai->dev, "%s()\n", __func__); - - WARN_ON(hcp->current_stream != substream); - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); - mutex_lock(&hcp->current_stream_lock); - hcp->current_stream = NULL; - mutex_unlock(&hcp->current_stream_lock); + mutex_unlock(&hcp->lock); } static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, @@ -474,6 +444,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; struct hdmi_codec_params hp = { .iec = { .status = { 0 }, @@ -518,30 +489,27 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, hp.channels = params_channels(params); return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, - &hcp->daifmt[dai->id], &hp); + cf, &hp); } -static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, - unsigned int fmt) +static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) { - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - struct hdmi_codec_daifmt cf = { 0 }; + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; - dev_dbg(dai->dev, "%s()\n", __func__); - - if (dai->id == DAI_ID_SPDIF) - return 0; + /* Reset daifmt */ + memset(cf, 0, sizeof(*cf)); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - cf.bit_clk_master = 1; - cf.frame_clk_master = 1; + cf->bit_clk_master = 1; + cf->frame_clk_master = 1; break; case SND_SOC_DAIFMT_CBS_CFM: - cf.frame_clk_master = 1; + cf->frame_clk_master = 1; break; case SND_SOC_DAIFMT_CBM_CFS: - cf.bit_clk_master = 1; + cf->bit_clk_master = 1; break; case SND_SOC_DAIFMT_CBS_CFS: break; @@ -553,43 +521,41 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_NB_IF: - cf.frame_clk_inv = 1; + cf->frame_clk_inv = 1; break; case SND_SOC_DAIFMT_IB_NF: - cf.bit_clk_inv = 1; + cf->bit_clk_inv = 1; break; case SND_SOC_DAIFMT_IB_IF: - cf.frame_clk_inv = 1; - cf.bit_clk_inv = 1; + cf->frame_clk_inv = 1; + cf->bit_clk_inv = 1; break; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - cf.fmt = HDMI_I2S; + cf->fmt = HDMI_I2S; break; case SND_SOC_DAIFMT_DSP_A: - cf.fmt = HDMI_DSP_A; + cf->fmt = HDMI_DSP_A; break; case SND_SOC_DAIFMT_DSP_B: - cf.fmt = HDMI_DSP_B; + cf->fmt = HDMI_DSP_B; break; case SND_SOC_DAIFMT_RIGHT_J: - cf.fmt = HDMI_RIGHT_J; + cf->fmt = HDMI_RIGHT_J; break; case SND_SOC_DAIFMT_LEFT_J: - cf.fmt = HDMI_LEFT_J; + cf->fmt = HDMI_LEFT_J; break; case SND_SOC_DAIFMT_AC97: - cf.fmt = HDMI_AC97; + cf->fmt = HDMI_AC97; break; default: dev_err(dai->dev, "Invalid DAI interface format\n"); return -EINVAL; } - hcp->daifmt[dai->id] = cf; - return 0; } @@ -597,8 +563,6 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - dev_dbg(dai->dev, "%s()\n", __func__); - if (hcp->hcd.ops->digital_mute) return hcp->hcd.ops->digital_mute(dai->dev->parent, hcp->hcd.data, mute); @@ -606,14 +570,20 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) return 0; } -static const struct snd_soc_dai_ops hdmi_dai_ops = { +static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { .startup = hdmi_codec_startup, .shutdown = hdmi_codec_shutdown, .hw_params = hdmi_codec_hw_params, - .set_fmt = hdmi_codec_set_fmt, + .set_fmt = hdmi_codec_i2s_set_fmt, .digital_mute = hdmi_codec_digital_mute, }; +static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .digital_mute = hdmi_codec_digital_mute, +}; #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ @@ -656,8 +626,6 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, }; int ret; - dev_dbg(dai->dev, "%s()\n", __func__); - ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, NULL, drv->playback.channels_max, 0, &hcp->chmap_info); @@ -683,20 +651,52 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, static int hdmi_dai_probe(struct snd_soc_dai *dai) { struct snd_soc_dapm_context *dapm; + struct hdmi_codec_daifmt *daifmt; struct snd_soc_dapm_route route = { .sink = "TX", .source = dai->driver->playback.stream_name, }; + int ret; dapm = snd_soc_component_get_dapm(dai->component); + ret = snd_soc_dapm_add_routes(dapm, &route, 1); + if (ret) + return ret; + + daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL); + if (!daifmt) + return -ENOMEM; + + dai->playback_dma_data = daifmt; + return 0; +} + +static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) +{ + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + int ret; + + ret = hdmi_dai_probe(dai); + if (ret) + return ret; + + cf = dai->playback_dma_data; + cf->fmt = HDMI_SPDIF; + + return 0; +} - return snd_soc_dapm_add_routes(dapm, &route, 1); +static int hdmi_codec_dai_remove(struct snd_soc_dai *dai) +{ + kfree(dai->playback_dma_data); + return 0; } static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, .probe = hdmi_dai_probe, + .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -705,14 +705,15 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .formats = I2S_FORMATS, .sig_bits = 24, }, - .ops = &hdmi_dai_ops, + .ops = &hdmi_codec_i2s_dai_ops, .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, - .probe = hdmi_dai_probe, + .probe = hdmi_dai_spdif_probe, + .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -720,7 +721,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .rates = HDMI_RATES, .formats = SPDIF_FORMATS, }, - .ops = &hdmi_dai_ops, + .ops = &hdmi_codec_spdif_dai_ops, .pcm_new = hdmi_codec_pcm_new, }; @@ -749,13 +750,12 @@ static const struct snd_soc_component_driver hdmi_driver = { static int hdmi_codec_probe(struct platform_device *pdev) { struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; + struct snd_soc_dai_driver *daidrv; struct device *dev = &pdev->dev; struct hdmi_codec_priv *hcp; int dai_count, i = 0; int ret; - dev_dbg(dev, "%s()\n", __func__); - if (!hcd) { dev_err(dev, "%s: No platform data\n", __func__); return -EINVAL; @@ -773,29 +773,25 @@ static int hdmi_codec_probe(struct platform_device *pdev) return -ENOMEM; hcp->hcd = *hcd; - mutex_init(&hcp->current_stream_lock); + mutex_init(&hcp->lock); - hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv), - GFP_KERNEL); - if (!hcp->daidrv) + daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); + if (!daidrv) return -ENOMEM; if (hcd->i2s) { - hcp->daidrv[i] = hdmi_i2s_dai; - hcp->daidrv[i].playback.channels_max = - hcd->max_i2s_channels; + daidrv[i] = hdmi_i2s_dai; + daidrv[i].playback.channels_max = hcd->max_i2s_channels; i++; } - if (hcd->spdif) { - hcp->daidrv[i] = hdmi_spdif_dai; - hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF; - } + if (hcd->spdif) + daidrv[i] = hdmi_spdif_dai; dev_set_drvdata(dev, hcp); - ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv, - dai_count); + ret = devm_snd_soc_register_component(dev, &hdmi_driver, daidrv, + dai_count); if (ret) { dev_err(dev, "%s: snd_soc_register_component() failed (%d)\n", __func__, ret); diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index d037a3e4d323..80080a6415b3 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -59,21 +59,7 @@ static const struct snd_soc_dapm_route max98357a_dapm_routes[] = { {"Speaker", NULL, "HiFi Playback"}, }; -static int max98357a_component_probe(struct snd_soc_component *component) -{ - struct gpio_desc *sdmode; - - sdmode = devm_gpiod_get_optional(component->dev, "sdmode", GPIOD_OUT_LOW); - if (IS_ERR(sdmode)) - return PTR_ERR(sdmode); - - snd_soc_component_set_drvdata(component, sdmode); - - return 0; -} - static const struct snd_soc_component_driver max98357a_component_driver = { - .probe = max98357a_component_probe, .dapm_widgets = max98357a_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), .dapm_routes = max98357a_dapm_routes, @@ -112,16 +98,20 @@ static struct snd_soc_dai_driver max98357a_dai_driver = { static int max98357a_platform_probe(struct platform_device *pdev) { + struct gpio_desc *sdmode; + + sdmode = devm_gpiod_get_optional(&pdev->dev, + "sdmode", GPIOD_OUT_LOW); + if (IS_ERR(sdmode)) + return PTR_ERR(sdmode); + + dev_set_drvdata(&pdev->dev, sdmode); + return devm_snd_soc_register_component(&pdev->dev, &max98357a_component_driver, &max98357a_dai_driver, 1); } -static int max98357a_platform_remove(struct platform_device *pdev) -{ - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id max98357a_device_id[] = { { .compatible = "maxim,max98357a" }, @@ -145,7 +135,6 @@ static struct platform_driver max98357a_platform_driver = { .acpi_match_table = ACPI_PTR(max98357a_acpi_match), }, .probe = max98357a_platform_probe, - .remove = max98357a_platform_remove, }; module_platform_driver(max98357a_platform_driver); diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 84b6bd8b50e1..871ccb37318d 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -29,6 +29,8 @@ #include "rt5677-spi.h" +#define DRV_NAME "rt5677spi" + #define RT5677_SPI_BURST_LEN 240 #define RT5677_SPI_HEADER 5 #define RT5677_SPI_FREQ 6000000 @@ -232,7 +234,7 @@ MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id); static struct spi_driver rt5677_spi_driver = { .driver = { - .name = "rt5677", + .name = DRV_NAME, .acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id), }, .probe = rt5677_spi_probe, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 6fc70e441458..c49b5c218666 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -832,13 +832,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 127, 0, dac_vol_tlv), /* IN1/IN2 Control */ SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv), @@ -4650,7 +4650,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) } static const struct gpio_chip rt5677_template_chip = { - .label = "rt5677", + .label = RT5677_DRV_NAME, .owner = THIS_MODULE, .direction_output = rt5677_gpio_direction_out, .set = rt5677_gpio_set, @@ -4958,6 +4958,7 @@ static struct snd_soc_dai_driver rt5677_dai[] = { }; static const struct snd_soc_component_driver soc_component_dev_rt5677 = { + .name = RT5677_DRV_NAME, .probe = rt5677_probe, .remove = rt5677_remove, .suspend = rt5677_suspend, @@ -5079,7 +5080,7 @@ static struct regmap_irq rt5677_irqs[] = { }; static struct regmap_irq_chip rt5677_irq_chip = { - .name = "rt5677", + .name = RT5677_DRV_NAME, .irqs = rt5677_irqs, .num_irqs = ARRAY_SIZE(rt5677_irqs), @@ -5267,7 +5268,7 @@ static int rt5677_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5677_i2c_driver = { .driver = { - .name = "rt5677", + .name = RT5677_DRV_NAME, .of_match_table = rt5677_of_match, .acpi_match_table = ACPI_PTR(rt5677_acpi_match), }, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 183d92b03045..11a2ffceec3b 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1674,6 +1674,8 @@ #define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin" #define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin" +#define RT5677_DRV_NAME "rt5677" + /* System Clock Source */ enum { RT5677_SCLK_S_MCLK, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 516d17cb2182..599e4ed3850b 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -324,6 +324,9 @@ static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0); */ static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1); +/* Output volumes. From 0 to 9 dB in 1 dB steps */ +static const DECLARE_TLV_DB_SCALE(out_tlv, 0, 100, 0); + static const struct snd_kcontrol_new aic3x_snd_controls[] = { /* Output */ SOC_DOUBLE_R_TLV("PCM Playback Volume", @@ -386,11 +389,17 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), - /* Output pin mute controls */ + /* Output pin controls */ + SOC_DOUBLE_R_TLV("Line Playback Volume", LLOPM_CTRL, RLOPM_CTRL, 4, + 9, 0, out_tlv), SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, 0x01, 0), + SOC_DOUBLE_R_TLV("HP Playback Volume", HPLOUT_CTRL, HPROUT_CTRL, 4, + 9, 0, out_tlv), SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, 0x01, 0), + SOC_DOUBLE_R_TLV("HPCOM Playback Volume", HPLCOM_CTRL, HPRCOM_CTRL, + 4, 9, 0, out_tlv), SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, 0x01, 0), @@ -472,6 +481,9 @@ static const struct snd_kcontrol_new aic3x_mono_controls[] = { 0, 118, 1, output_stage_tlv), SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), + SOC_SINGLE_TLV("Mono Playback Volume", MONOLOPM_CTRL, 4, 9, 0, + out_tlv), + }; /* diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 0b937924d2e4..71793d3dc75c 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -26,24 +26,6 @@ #define pair_dbg(fmt, ...) \ dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) -/* Sample rates are aligned with that defined in pcm.h file */ -static const u8 process_option[][12][2] = { - /* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ - {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ - {{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ - {{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ - {{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ - {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ - {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ -}; - /* Corresponding to process_option */ static int supported_input_rate[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, @@ -80,6 +62,52 @@ static unsigned char output_clk_map_imx53[] = { static unsigned char *clk_map[2]; /** + * Select the pre-processing and post-processing options + * Make sure to exclude following unsupported cases before + * calling this function: + * 1) inrate > 8.125 * outrate + * 2) inrate > 16.125 * outrate + * + * inrate: input sample rate + * outrate: output sample rate + * pre_proc: return value for pre-processing option + * post_proc: return value for post-processing option + */ +static void fsl_asrc_sel_proc(int inrate, int outrate, + int *pre_proc, int *post_proc) +{ + bool post_proc_cond2; + bool post_proc_cond0; + + /* select pre_proc between [0, 2] */ + if (inrate * 8 > 33 * outrate) + *pre_proc = 2; + else if (inrate * 8 > 15 * outrate) { + if (inrate > 152000) + *pre_proc = 2; + else + *pre_proc = 1; + } else if (inrate < 76000) + *pre_proc = 0; + else if (inrate > 152000) + *pre_proc = 2; + else + *pre_proc = 1; + + /* Condition for selection of post-processing */ + post_proc_cond2 = (inrate * 15 > outrate * 16 && outrate < 56000) || + (inrate > 56000 && outrate < 56000); + post_proc_cond0 = inrate * 23 < outrate * 8; + + if (post_proc_cond2) + *post_proc = 2; + else if (post_proc_cond0) + *post_proc = 0; + else + *post_proc = 1; +} + +/** * Request ASRC pair * * It assigns pair by the order of A->C->B because allocation of pair B, @@ -239,6 +267,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) u32 inrate, outrate, indiv, outdiv; u32 clk_index[2], div[2]; int in, out, channels; + int pre_proc, post_proc; struct clk *clk; bool ideal; @@ -377,11 +406,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), ASRCTR_IDR(index) | ASRCTR_USR(index)); + fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc); + /* Apply configurations for pre- and post-processing */ regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), - ASRCFG_PREMOD(index, process_option[in][out][0]) | - ASRCFG_POSTMOD(index, process_option[in][out][1])); + ASRCFG_PREMOD(index, pre_proc) | + ASRCFG_POSTMOD(index, post_proc)); return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); } diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index bad0dfed6b68..10d2210c91ef 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/pm_runtime.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> @@ -466,30 +467,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); - int ret; - - /* - * Some platforms might use the same bit to gate all three or two of - * clocks, so keep all clocks open/close at the same time for safety - */ - ret = clk_prepare_enable(esai_priv->coreclk); - if (ret) - return ret; - if (!IS_ERR(esai_priv->spbaclk)) { - ret = clk_prepare_enable(esai_priv->spbaclk); - if (ret) - goto err_spbaclk; - } - if (!IS_ERR(esai_priv->extalclk)) { - ret = clk_prepare_enable(esai_priv->extalclk); - if (ret) - goto err_extalck; - } - if (!IS_ERR(esai_priv->fsysclk)) { - ret = clk_prepare_enable(esai_priv->fsysclk); - if (ret) - goto err_fsysclk; - } if (!dai->active) { /* Set synchronous mode */ @@ -506,16 +483,6 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, return 0; -err_fsysclk: - if (!IS_ERR(esai_priv->extalclk)) - clk_disable_unprepare(esai_priv->extalclk); -err_extalck: - if (!IS_ERR(esai_priv->spbaclk)) - clk_disable_unprepare(esai_priv->spbaclk); -err_spbaclk: - clk_disable_unprepare(esai_priv->coreclk); - - return ret; } static int fsl_esai_hw_params(struct snd_pcm_substream *substream, @@ -576,20 +543,6 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, return 0; } -static void fsl_esai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); - - if (!IS_ERR(esai_priv->fsysclk)) - clk_disable_unprepare(esai_priv->fsysclk); - if (!IS_ERR(esai_priv->extalclk)) - clk_disable_unprepare(esai_priv->extalclk); - if (!IS_ERR(esai_priv->spbaclk)) - clk_disable_unprepare(esai_priv->spbaclk); - clk_disable_unprepare(esai_priv->coreclk); -} - static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -658,7 +611,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, static const struct snd_soc_dai_ops fsl_esai_dai_ops = { .startup = fsl_esai_startup, - .shutdown = fsl_esai_shutdown, .trigger = fsl_esai_trigger, .hw_params = fsl_esai_hw_params, .set_sysclk = fsl_esai_set_dai_sysclk, @@ -947,6 +899,10 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } + pm_runtime_enable(&pdev->dev); + + regcache_cache_only(esai_priv->regmap, true); + ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE); if (ret) dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret); @@ -954,6 +910,13 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } +static int fsl_esai_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + static const struct of_device_id fsl_esai_dt_ids[] = { { .compatible = "fsl,imx35-esai", }, { .compatible = "fsl,vf610-esai", }, @@ -961,22 +924,35 @@ static const struct of_device_id fsl_esai_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids); -#ifdef CONFIG_PM_SLEEP -static int fsl_esai_suspend(struct device *dev) -{ - struct fsl_esai *esai = dev_get_drvdata(dev); - - regcache_cache_only(esai->regmap, true); - regcache_mark_dirty(esai->regmap); - - return 0; -} - -static int fsl_esai_resume(struct device *dev) +#ifdef CONFIG_PM +static int fsl_esai_runtime_resume(struct device *dev) { struct fsl_esai *esai = dev_get_drvdata(dev); int ret; + /* + * Some platforms might use the same bit to gate all three or two of + * clocks, so keep all clocks open/close at the same time for safety + */ + ret = clk_prepare_enable(esai->coreclk); + if (ret) + return ret; + if (!IS_ERR(esai->spbaclk)) { + ret = clk_prepare_enable(esai->spbaclk); + if (ret) + goto err_spbaclk; + } + if (!IS_ERR(esai->extalclk)) { + ret = clk_prepare_enable(esai->extalclk); + if (ret) + goto err_extalclk; + } + if (!IS_ERR(esai->fsysclk)) { + ret = clk_prepare_enable(esai->fsysclk); + if (ret) + goto err_fsysclk; + } + regcache_cache_only(esai->regmap, false); /* FIFO reset for safety */ @@ -987,22 +963,59 @@ static int fsl_esai_resume(struct device *dev) ret = regcache_sync(esai->regmap); if (ret) - return ret; + goto err_regcache_sync; /* FIFO reset done */ regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0); regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0); return 0; + +err_regcache_sync: + if (!IS_ERR(esai->fsysclk)) + clk_disable_unprepare(esai->fsysclk); +err_fsysclk: + if (!IS_ERR(esai->extalclk)) + clk_disable_unprepare(esai->extalclk); +err_extalclk: + if (!IS_ERR(esai->spbaclk)) + clk_disable_unprepare(esai->spbaclk); +err_spbaclk: + clk_disable_unprepare(esai->coreclk); + + return ret; +} + +static int fsl_esai_runtime_suspend(struct device *dev) +{ + struct fsl_esai *esai = dev_get_drvdata(dev); + + regcache_cache_only(esai->regmap, true); + regcache_mark_dirty(esai->regmap); + + if (!IS_ERR(esai->fsysclk)) + clk_disable_unprepare(esai->fsysclk); + if (!IS_ERR(esai->extalclk)) + clk_disable_unprepare(esai->extalclk); + if (!IS_ERR(esai->spbaclk)) + clk_disable_unprepare(esai->spbaclk); + clk_disable_unprepare(esai->coreclk); + + return 0; } -#endif /* CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ static const struct dev_pm_ops fsl_esai_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(fsl_esai_suspend, fsl_esai_resume) + SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend, + fsl_esai_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver fsl_esai_driver = { .probe = fsl_esai_probe, + .remove = fsl_esai_remove, .driver = { .name = "fsl-esai-dai", .pm = &fsl_esai_pm_ops, diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 8593269156bd..d58cc3ae90d8 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -596,15 +596,8 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - struct device *dev = &sai->pdev->dev; int ret; - ret = clk_prepare_enable(sai->bus_clk); - if (ret) { - dev_err(dev, "failed to enable bus clock: %d\n", ret); - return ret; - } - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, FSL_SAI_CR3_TRCE); @@ -621,8 +614,6 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0); - - clk_disable_unprepare(sai->bus_clk); } static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { @@ -935,6 +926,14 @@ static int fsl_sai_runtime_suspend(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev); + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); + + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); + + clk_disable_unprepare(sai->bus_clk); + regcache_cache_only(sai->regmap, true); regcache_mark_dirty(sai->regmap); @@ -944,6 +943,25 @@ static int fsl_sai_runtime_suspend(struct device *dev) static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(sai->bus_clk); + if (ret) { + dev_err(dev, "failed to enable bus clock: %d\n", ret); + return ret; + } + + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) { + ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]); + if (ret) + goto disable_bus_clk; + } + + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) { + ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]); + if (ret) + goto disable_tx_clk; + } regcache_cache_only(sai->regmap, false); regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); @@ -951,7 +969,23 @@ static int fsl_sai_runtime_resume(struct device *dev) usleep_range(1000, 2000); regmap_write(sai->regmap, FSL_SAI_TCSR, 0); regmap_write(sai->regmap, FSL_SAI_RCSR, 0); - return regcache_sync(sai->regmap); + + ret = regcache_sync(sai->regmap); + if (ret) + goto disable_rx_clk; + + return 0; + +disable_rx_clk: + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]); +disable_tx_clk: + if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) + clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]); +disable_bus_clk: + clk_disable_unprepare(sai->bus_clk); + + return ret; } #endif /* CONFIG_PM */ diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index fc1396adde71..b089ed3bf77f 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -165,6 +165,22 @@ config SND_SOC_INTEL_CFL If you have a Intel CoffeeLake platform with the DSP enabled in the BIOS then enable this option by saying Y or m. +config SND_SOC_INTEL_CML_H + tristate "CometLake-H Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel CometLake-H platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_CML_LP + tristate "CometLake-LP Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel CometLake-LP platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + config SND_SOC_INTEL_SKYLAKE_FAMILY tristate select SND_SOC_INTEL_SKYLAKE_COMMON diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index f72a7bf028d7..1efe7fdad2cb 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -219,8 +219,60 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, return 0; } +static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int j, ret; + + for (j = 0; j < rtd->num_codecs; j++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + const char *name = codec_dai->component->name; + struct snd_soc_component *component = codec_dai->component; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char pin_name[20]; + + if (strcmp(name, MAX98927_DEV0_NAME) && + strcmp(name, MAX98927_DEV1_NAME) && + strcmp(name, MAX98373_DEV0_NAME) && + strcmp(name, MAX98373_DEV1_NAME)) + continue; + + snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", + codec_dai->component->name_prefix); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = snd_soc_dapm_enable_pin(dapm, pin_name); + if (ret) { + dev_err(rtd->dev, "failed to enable %s: %d\n", + pin_name, ret); + return ret; + } + snd_soc_dapm_sync(dapm); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = snd_soc_dapm_disable_pin(dapm, pin_name); + if (ret) { + dev_err(rtd->dev, "failed to disable %s: %d\n", + pin_name, ret); + return ret; + } + snd_soc_dapm_sync(dapm); + break; + } + } + + return 0; +} + static struct snd_soc_ops kabylake_ssp0_ops = { .hw_params = kabylake_ssp0_hw_params, + .trigger = kabylake_ssp0_trigger, }; static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, @@ -950,6 +1002,7 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) { struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); struct kbl_hdmi_pcm *pcm; + struct snd_soc_dapm_context *dapm = &card->dapm; struct snd_soc_component *component = NULL; int err, i = 0; char jack_name[NAME_SIZE]; @@ -976,9 +1029,25 @@ static int kabylake_card_late_probe(struct snd_soc_card *card) if (!component) return -EINVAL; - return hdac_hdmi_jack_port_init(component, &card->dapm); - return 0; + err = hdac_hdmi_jack_port_init(component, &card->dapm); + + if (err < 0) + return err; + + err = snd_soc_dapm_disable_pin(dapm, "Left Spk"); + if (err) { + dev_err(card->dev, "failed to disable Left Spk: %d\n", err); + return err; + } + + err = snd_soc_dapm_disable_pin(dapm, "Right Spk"); + if (err) { + dev_err(card->dev, "failed to disable Right Spk: %d\n", err); + return err; + } + + return snd_soc_dapm_sync(dapm); } /* kabylake audio machine driver for SPT + DA7219 */ diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 4bf70b4429f0..df01dc952521 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -255,6 +255,22 @@ static const struct skl_dsp_ops dsp_ops[] = { .init_fw = cnl_sst_init_fw, .cleanup = cnl_sst_dsp_cleanup }, + { + .id = 0x02c8, + .num_cores = 4, + .loader_ops = bxt_get_loader_ops, + .init = cnl_sst_dsp_init, + .init_fw = cnl_sst_init_fw, + .cleanup = cnl_sst_dsp_cleanup + }, + { + .id = 0x06c8, + .num_cores = 4, + .loader_ops = bxt_get_loader_ops, + .init = cnl_sst_dsp_init, + .init_fw = cnl_sst_init_fw, + .cleanup = cnl_sst_dsp_cleanup + }, }; const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 4ed5b7e17d44..f864f7b3df3a 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -1167,6 +1167,16 @@ static const struct pci_device_id skl_ids[] = { { PCI_DEVICE(0x8086, 0xa348), .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, #endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) + /* CML-LP */ + { PCI_DEVICE(0x8086, 0x02c8), + .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) + /* CML-H */ + { PCI_DEVICE(0x8086, 0x06c8), + .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, +#endif { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index fded11d14cde..19048c3dc324 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -241,6 +241,7 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; int hd_audio = 0; + int hd_align = 1; /* set hd mode */ switch (substream->runtime->format) { @@ -249,9 +250,11 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, break; case SNDRV_PCM_FORMAT_S32_LE: hd_audio = 1; + hd_align = 1; break; case SNDRV_PCM_FORMAT_S24_LE: hd_audio = 1; + hd_align = 0; break; default: dev_err(afe->dev, "%s() error: unsupported format %d\n", @@ -262,6 +265,10 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, 1, hd_audio, memif->data->hd_shift); + mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg, + memif->data->hd_align_mshift, + hd_align ? memif->data->hd_align_mshift : 0); + return 0; } EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare); diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h index bd8d5e0c6843..60cb609a9790 100644 --- a/sound/soc/mediatek/common/mtk-base-afe.h +++ b/sound/soc/mediatek/common/mtk-base-afe.h @@ -24,7 +24,9 @@ struct mtk_base_memif_data { int enable_reg; int enable_shift; int hd_reg; + int hd_align_reg; int hd_shift; + int hd_align_mshift; int msb_reg; int msb_shift; int agent_disable_reg; diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 1bc0fafe5e29..ab2bce1d9b3d 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -437,7 +437,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = DL1_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = DL1_HD_SFT, + .hd_align_mshift = DL1_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -456,7 +458,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = DL2_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = DL2_HD_SFT, + .hd_align_mshift = DL2_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -475,7 +479,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = DL3_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = DL3_HD_SFT, + .hd_align_mshift = DL3_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -494,7 +500,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = VUL2_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = VUL2_HD_SFT, + .hd_align_mshift = VUL2_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -513,7 +521,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = AWB_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = AWB_HD_SFT, + .hd_align_mshift = AWB_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -532,7 +542,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = AWB2_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = AWB2_HD_SFT, + .hd_align_mshift = AWB2_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -551,7 +563,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = VUL12_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = VUL12_HD_SFT, + .hd_align_mshift = VUL12_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -570,7 +584,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = AFE_DAC_CON0, .enable_shift = MOD_DAI_ON_SFT, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = MOD_DAI_HD_SFT, + .hd_align_mshift = MOD_DAI_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, @@ -589,7 +605,9 @@ static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { .enable_reg = -1, /* control in tdm for sync start */ .enable_shift = -1, .hd_reg = AFE_MEMIF_HD_MODE, + .hd_align_reg = AFE_MEMIF_HDALIGN, .hd_shift = HDMI_HD_SFT, + .hd_align_mshift = HDMI_HD_ALIGN_MASK_SFT, .agent_disable_reg = -1, .agent_disable_shift = -1, .msb_reg = -1, diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig index 8779fe23671d..4e5b4d4f3531 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -56,6 +56,7 @@ config SND_MESON_AXG_SOUND_CARD imply SND_MESON_AXG_SPDIFOUT imply SND_MESON_AXG_SPDIFIN imply SND_MESON_AXG_PDM + imply SND_MESON_G12A_TOHDMITX if DRM_MESON_DW_HDMI help Select Y or M to add support for the AXG SoC sound card @@ -82,4 +83,11 @@ config SND_MESON_AXG_PDM help Select Y or M to add support for PDM input embedded in the Amlogic AXG SoC family + +config SND_MESON_G12A_TOHDMITX + tristate "Amlogic G12A To HDMI TX Control Support" + imply SND_SOC_HDMI_CODEC + help + Select Y or M to add support for HDMI audio on the g12a SoC + family endmenu diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index b45dfb9e2f88..1a8b1470ed84 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -11,6 +11,7 @@ snd-soc-meson-axg-sound-card-objs := axg-card.o snd-soc-meson-axg-spdifin-objs := axg-spdifin.o snd-soc-meson-axg-spdifout-objs := axg-spdifout.o snd-soc-meson-axg-pdm-objs := axg-pdm.o +snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o @@ -23,3 +24,4 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o +obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index aa54d2c612c9..db0a7fc18928 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -29,6 +29,18 @@ struct axg_dai_link_tdm_data { struct axg_dai_link_tdm_mask *codec_masks; }; +/* + * Base params for the codec to codec links + * Those will be over-written by the CPU side of the link + */ +static const struct snd_soc_pcm_stream codec_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 5525, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 8, +}; + #define PREFIX "amlogic," static int axg_card_reallocate_links(struct axg_card *priv, @@ -80,10 +92,11 @@ static int axg_card_parse_dai(struct snd_soc_card *card, static int axg_card_set_link_name(struct snd_soc_card *card, struct snd_soc_dai_link *link, + struct device_node *node, const char *prefix) { char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s", - prefix, link->cpu_of_node->full_name); + prefix, node->full_name); if (!name) return -ENOMEM; @@ -474,7 +487,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, codec++; } - ret = axg_card_set_link_name(card, link, "be"); + ret = axg_card_set_link_name(card, link, node, "be"); if (ret) dev_err(card->dev, "error setting %pOFn link name\n", np); @@ -483,6 +496,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, static int axg_card_set_fe_link(struct snd_soc_card *card, struct snd_soc_dai_link *link, + struct device_node *node, bool is_playback) { link->dynamic = 1; @@ -497,7 +511,7 @@ static int axg_card_set_fe_link(struct snd_soc_card *card, else link->dpcm_capture = 1; - return axg_card_set_link_name(card, link, "fe"); + return axg_card_set_link_name(card, link, node, "fe"); } static int axg_card_cpu_is_capture_fe(struct device_node *np) @@ -515,6 +529,11 @@ static int axg_card_cpu_is_tdm_iface(struct device_node *np) return of_device_is_compatible(np, PREFIX "axg-tdm-iface"); } +static int axg_card_cpu_is_codec(struct device_node *np) +{ + return of_device_is_compatible(np, PREFIX "g12a-tohdmitx"); +} + static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, int *index) { @@ -527,9 +546,9 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, return ret; if (axg_card_cpu_is_playback_fe(dai_link->cpu_of_node)) - ret = axg_card_set_fe_link(card, dai_link, true); + ret = axg_card_set_fe_link(card, dai_link, np, true); else if (axg_card_cpu_is_capture_fe(dai_link->cpu_of_node)) - ret = axg_card_set_fe_link(card, dai_link, false); + ret = axg_card_set_fe_link(card, dai_link, np, false); else ret = axg_card_set_be_link(card, dai_link, np); @@ -538,6 +557,8 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, if (axg_card_cpu_is_tdm_iface(dai_link->cpu_of_node)) ret = axg_card_parse_tdm(card, np, index); + else if (axg_card_cpu_is_codec(dai_link->cpu_of_node)) + dai_link->params = &codec_params; return ret; } diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c new file mode 100644 index 000000000000..707ccb192e4c --- /dev/null +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2019 BayLibre, SAS. +// Author: Jerome Brunet <jbrunet@baylibre.com> + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <sound/pcm_params.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> + +#include <dt-bindings/sound/meson-g12a-tohdmitx.h> + +#define G12A_TOHDMITX_DRV_NAME "g12a-tohdmitx" + +#define TOHDMITX_CTRL0 0x0 +#define CTRL0_ENABLE_SHIFT 31 +#define CTRL0_I2S_DAT_SEL GENMASK(13, 12) +#define CTRL0_I2S_LRCLK_SEL GENMASK(9, 8) +#define CTRL0_I2S_BLK_CAP_INV BIT(7) +#define CTRL0_I2S_BCLK_O_INV BIT(6) +#define CTRL0_I2S_BCLK_SEL GENMASK(5, 4) +#define CTRL0_SPDIF_CLK_CAP_INV BIT(3) +#define CTRL0_SPDIF_CLK_O_INV BIT(2) +#define CTRL0_SPDIF_SEL BIT(1) +#define CTRL0_SPDIF_CLK_SEL BIT(0) + +struct g12a_tohdmitx_input { + struct snd_pcm_hw_params params; + unsigned int fmt; +}; + +static struct snd_soc_dapm_widget * +g12a_tohdmitx_get_input(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_widget *in; + + snd_soc_dapm_widget_for_each_source_path(w, p) { + if (!p->connect) + continue; + + /* Check that we still are in the same component */ + if (snd_soc_dapm_to_component(w->dapm) != + snd_soc_dapm_to_component(p->source->dapm)) + continue; + + if (p->source->id == snd_soc_dapm_dai_in) + return p->source; + + in = g12a_tohdmitx_get_input(p->source); + if (in) + return in; + } + + return NULL; +} + +static struct g12a_tohdmitx_input * +g12a_tohdmitx_get_input_data(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_widget *in = + g12a_tohdmitx_get_input(w); + struct snd_soc_dai *dai; + + if (WARN_ON(!in)) + return NULL; + + dai = in->priv; + + return dai->playback_dma_data; +} + +static const char * const g12a_tohdmitx_i2s_mux_texts[] = { + "I2S A", "I2S B", "I2S C", +}; + +static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_i2s_mux_enum, + g12a_tohdmitx_i2s_mux_texts); + +static int g12a_tohdmitx_get_input_val(struct snd_soc_component *component, + unsigned int mask) +{ + unsigned int val; + + snd_soc_component_read(component, TOHDMITX_CTRL0, &val); + return (val & mask) >> __ffs(mask); +} + +static int g12a_tohdmitx_i2s_mux_get_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + + ucontrol->value.enumerated.item[0] = + g12a_tohdmitx_get_input_val(component, CTRL0_I2S_DAT_SEL); + + return 0; +} + +static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int mux = ucontrol->value.enumerated.item[0]; + unsigned int val = g12a_tohdmitx_get_input_val(component, + CTRL0_I2S_DAT_SEL); + + /* Force disconnect of the mux while updating */ + if (val != mux) + snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); + + snd_soc_component_update_bits(component, TOHDMITX_CTRL0, + CTRL0_I2S_DAT_SEL | + CTRL0_I2S_LRCLK_SEL | + CTRL0_I2S_BCLK_SEL, + FIELD_PREP(CTRL0_I2S_DAT_SEL, mux) | + FIELD_PREP(CTRL0_I2S_LRCLK_SEL, mux) | + FIELD_PREP(CTRL0_I2S_BCLK_SEL, mux)); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + + return 0; +} + +static const struct snd_kcontrol_new g12a_tohdmitx_i2s_mux = + SOC_DAPM_ENUM_EXT("I2S Source", g12a_tohdmitx_i2s_mux_enum, + g12a_tohdmitx_i2s_mux_get_enum, + g12a_tohdmitx_i2s_mux_put_enum); + +static const char * const g12a_tohdmitx_spdif_mux_texts[] = { + "SPDIF A", "SPDIF B", +}; + +static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_spdif_mux_enum, + g12a_tohdmitx_spdif_mux_texts); + +static int g12a_tohdmitx_spdif_mux_get_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + + ucontrol->value.enumerated.item[0] = + g12a_tohdmitx_get_input_val(component, CTRL0_SPDIF_SEL); + + return 0; +} + +static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int mux = ucontrol->value.enumerated.item[0]; + unsigned int val = g12a_tohdmitx_get_input_val(component, + CTRL0_SPDIF_SEL); + + /* Force disconnect of the mux while updating */ + if (val != mux) + snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); + + snd_soc_component_update_bits(component, TOHDMITX_CTRL0, + CTRL0_SPDIF_SEL | + CTRL0_SPDIF_CLK_SEL, + FIELD_PREP(CTRL0_SPDIF_SEL, mux) | + FIELD_PREP(CTRL0_SPDIF_CLK_SEL, mux)); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + + return 0; +} + +static const struct snd_kcontrol_new g12a_tohdmitx_spdif_mux = + SOC_DAPM_ENUM_EXT("SPDIF Source", g12a_tohdmitx_spdif_mux_enum, + g12a_tohdmitx_spdif_mux_get_enum, + g12a_tohdmitx_spdif_mux_put_enum); + +static const struct snd_kcontrol_new g12a_tohdmitx_out_enable = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOHDMITX_CTRL0, + CTRL0_ENABLE_SHIFT, 1, 0); + +static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { + SND_SOC_DAPM_MUX("I2S SRC", SND_SOC_NOPM, 0, 0, + &g12a_tohdmitx_i2s_mux), + SND_SOC_DAPM_SWITCH("I2S OUT EN", SND_SOC_NOPM, 0, 0, + &g12a_tohdmitx_out_enable), + SND_SOC_DAPM_MUX("SPDIF SRC", SND_SOC_NOPM, 0, 0, + &g12a_tohdmitx_spdif_mux), + SND_SOC_DAPM_SWITCH("SPDIF OUT EN", SND_SOC_NOPM, 0, 0, + &g12a_tohdmitx_out_enable), +}; + +static int g12a_tohdmitx_input_probe(struct snd_soc_dai *dai) +{ + struct g12a_tohdmitx_input *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + dai->playback_dma_data = data; + return 0; +} + +static int g12a_tohdmitx_input_remove(struct snd_soc_dai *dai) +{ + kfree(dai->playback_dma_data); + return 0; +} + +static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct g12a_tohdmitx_input *data = dai->playback_dma_data; + + /* Save the stream params for the downstream link */ + memcpy(&data->params, params, sizeof(*params)); + + return 0; +} + +static int g12a_tohdmitx_output_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct g12a_tohdmitx_input *in_data = + g12a_tohdmitx_get_input_data(dai->capture_widget); + + if (!in_data) + return -ENODEV; + + memcpy(params, &in_data->params, sizeof(*params)); + + return 0; +} + +static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct g12a_tohdmitx_input *data = dai->playback_dma_data; + + /* Save the source stream format for the downstream link */ + data->fmt = fmt; + return 0; +} + +static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct g12a_tohdmitx_input *in_data = + g12a_tohdmitx_get_input_data(dai->capture_widget); + + if (!in_data) + return -ENODEV; + + if (!in_data->fmt) + return 0; + + return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt); +} + +static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { + .hw_params = g12a_tohdmitx_input_hw_params, + .set_fmt = g12a_tohdmitx_input_set_fmt, +}; + +static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { + .hw_params = g12a_tohdmitx_output_hw_params, + .startup = g12a_tohdmitx_output_startup, +}; + +#define TOHDMITX_SPDIF_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) + +#define TOHDMITX_I2S_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define TOHDMITX_STREAM(xname, xsuffix, xfmt, xchmax) \ +{ \ + .stream_name = xname " " xsuffix, \ + .channels_min = 1, \ + .channels_max = (xchmax), \ + .rate_min = 8000, \ + .rate_max = 192000, \ + .formats = (xfmt), \ +} + +#define TOHDMITX_IN(xname, xid, xfmt, xchmax) { \ + .name = xname, \ + .id = (xid), \ + .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \ + .ops = &g12a_tohdmitx_input_ops, \ + .probe = g12a_tohdmitx_input_probe, \ + .remove = g12a_tohdmitx_input_remove, \ +} + +#define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \ + .name = xname, \ + .id = (xid), \ + .capture = TOHDMITX_STREAM(xname, "Capture", xfmt, xchmax), \ + .ops = &g12a_tohdmitx_output_ops, \ +} + +static struct snd_soc_dai_driver g12a_tohdmitx_dai_drv[] = { + TOHDMITX_IN("I2S IN A", TOHDMITX_I2S_IN_A, + TOHDMITX_I2S_FORMATS, 8), + TOHDMITX_IN("I2S IN B", TOHDMITX_I2S_IN_B, + TOHDMITX_I2S_FORMATS, 8), + TOHDMITX_IN("I2S IN C", TOHDMITX_I2S_IN_C, + TOHDMITX_I2S_FORMATS, 8), + TOHDMITX_OUT("I2S OUT", TOHDMITX_I2S_OUT, + TOHDMITX_I2S_FORMATS, 8), + TOHDMITX_IN("SPDIF IN A", TOHDMITX_SPDIF_IN_A, + TOHDMITX_SPDIF_FORMATS, 2), + TOHDMITX_IN("SPDIF IN B", TOHDMITX_SPDIF_IN_B, + TOHDMITX_SPDIF_FORMATS, 2), + TOHDMITX_OUT("SPDIF OUT", TOHDMITX_SPDIF_OUT, + TOHDMITX_SPDIF_FORMATS, 2), +}; + +static int g12a_tohdmi_component_probe(struct snd_soc_component *c) +{ + /* Initialize the static clock parameters */ + return snd_soc_component_write(c, TOHDMITX_CTRL0, + CTRL0_I2S_BLK_CAP_INV | CTRL0_SPDIF_CLK_CAP_INV); +} + +static const struct snd_soc_dapm_route g12a_tohdmitx_routes[] = { + { "I2S SRC", "I2S A", "I2S IN A Playback" }, + { "I2S SRC", "I2S B", "I2S IN B Playback" }, + { "I2S SRC", "I2S C", "I2S IN C Playback" }, + { "I2S OUT EN", "Switch", "I2S SRC" }, + { "I2S OUT Capture", NULL, "I2S OUT EN" }, + { "SPDIF SRC", "SPDIF A", "SPDIF IN A Playback" }, + { "SPDIF SRC", "SPDIF B", "SPDIF IN B Playback" }, + { "SPDIF OUT EN", "Switch", "SPDIF SRC" }, + { "SPDIF OUT Capture", NULL, "SPDIF OUT EN" }, +}; + +static const struct snd_soc_component_driver g12a_tohdmitx_component_drv = { + .probe = g12a_tohdmi_component_probe, + .dapm_widgets = g12a_tohdmitx_widgets, + .num_dapm_widgets = ARRAY_SIZE(g12a_tohdmitx_widgets), + .dapm_routes = g12a_tohdmitx_routes, + .num_dapm_routes = ARRAY_SIZE(g12a_tohdmitx_routes), + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct regmap_config g12a_tohdmitx_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static const struct of_device_id g12a_tohdmitx_of_match[] = { + { .compatible = "amlogic,g12a-tohdmitx", }, + {} +}; +MODULE_DEVICE_TABLE(of, g12a_tohdmitx_of_match); + +static int g12a_tohdmitx_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *regs; + struct regmap *map; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + map = devm_regmap_init_mmio(dev, regs, &g12a_tohdmitx_regmap_cfg); + if (IS_ERR(map)) { + dev_err(dev, "failed to init regmap: %ld\n", + PTR_ERR(map)); + return PTR_ERR(map); + } + + return devm_snd_soc_register_component(dev, + &g12a_tohdmitx_component_drv, g12a_tohdmitx_dai_drv, + ARRAY_SIZE(g12a_tohdmitx_dai_drv)); +} + +static struct platform_driver g12a_tohdmitx_pdrv = { + .driver = { + .name = G12A_TOHDMITX_DRV_NAME, + .of_match_table = g12a_tohdmitx_of_match, + }, + .probe = g12a_tohdmitx_probe, +}; +module_platform_driver(g12a_tohdmitx_pdrv); + +MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); +MODULE_DESCRIPTION("Amlogic G12a To HDMI Tx Control Codec Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 4fb29f0e561e..444ce0602f76 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -4,6 +4,8 @@ // // Copyright (c) 2013-15, Intel Corporation. +#include <linux/export.h> +#include <linux/module.h> #include <sound/soc-acpi.h> struct snd_soc_acpi_mach * diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2403bec2fccf..e83edbe27041 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -687,6 +687,8 @@ int snd_soc_resume(struct device *dev) struct snd_soc_card *card = dev_get_drvdata(dev); bool bus_control = false; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + int i; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) @@ -694,14 +696,12 @@ int snd_soc_resume(struct device *dev) /* activate pins from sleep state */ for_each_card_rtds(card, rtd) { - struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int j; if (cpu_dai->active) pinctrl_pm_select_default_state(cpu_dai->dev); - for_each_rtd_codec_dai(rtd, j, codec_dai) { + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->active) pinctrl_pm_select_default_state(codec_dai->dev); } @@ -738,6 +738,18 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); static const struct snd_soc_dai_ops null_dai_ops = { }; +static struct device_node +*soc_component_to_node(struct snd_soc_component *component) +{ + struct device_node *of_node; + + of_node = component->dev->of_node; + if (!of_node && component->dev->parent) + of_node = component->dev->parent->of_node; + + return of_node; +} + static struct snd_soc_component *soc_find_component( const struct device_node *of_node, const char *name) { @@ -748,9 +760,7 @@ static struct snd_soc_component *soc_find_component( for_each_component(component) { if (of_node) { - component_of_node = component->dev->of_node; - if (!component_of_node && component->dev->parent) - component_of_node = component->dev->parent->of_node; + component_of_node = soc_component_to_node(component); if (component_of_node == of_node) return component; @@ -768,9 +778,7 @@ static int snd_soc_is_matching_component( { struct device_node *component_of_node; - component_of_node = component->dev->of_node; - if (!component_of_node && component->dev->parent) - component_of_node = component->dev->parent->of_node; + component_of_node = soc_component_to_node(component); if (dlc->of_node && component_of_node != dlc->of_node) return 0; @@ -878,7 +886,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; - struct snd_soc_dai **codec_dais; int i; if (dai_link->ignore) @@ -907,24 +914,22 @@ static int soc_bind_dai_link(struct snd_soc_card *card, } snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component); - rtd->num_codecs = dai_link->num_codecs; - /* Find CODEC from registered CODECs */ - codec_dais = rtd->codec_dais; + rtd->num_codecs = dai_link->num_codecs; for_each_link_codecs(dai_link, i, codecs) { - codec_dais[i] = snd_soc_find_dai(codecs); - if (!codec_dais[i]) { + rtd->codec_dais[i] = snd_soc_find_dai(codecs); + if (!rtd->codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs->dai_name); goto _err_defer; } - snd_soc_rtdcom_add(rtd, codec_dais[i]->component); + snd_soc_rtdcom_add(rtd, rtd->codec_dais[i]->component); } /* Single codec links expect codec and codec_dai in runtime data */ - rtd->codec_dai = codec_dais[0]; + rtd->codec_dai = rtd->codec_dais[0]; - /* find one from the set of registered platforms */ + /* Find PLATFORM from registered PLATFORMs */ for_each_component(component) { if (!snd_soc_is_matching_component(dai_link->platforms, component)) @@ -1320,13 +1325,10 @@ EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); static void soc_set_of_name_prefix(struct snd_soc_component *component) { - struct device_node *component_of_node = component->dev->of_node; + struct device_node *component_of_node = soc_component_to_node(component); const char *str; int ret; - if (!component_of_node && component->dev->parent) - component_of_node = component->dev->parent->of_node; - ret = of_property_read_string(component_of_node, "sound-name-prefix", &str); if (!ret) @@ -1340,10 +1342,7 @@ static void soc_set_name_prefix(struct snd_soc_card *card, for (i = 0; i < card->num_configs && card->codec_conf; i++) { struct snd_soc_codec_conf *map = &card->codec_conf[i]; - struct device_node *component_of_node = component->dev->of_node; - - if (!component_of_node && component->dev->parent) - component_of_node = component->dev->parent->of_node; + struct device_node *component_of_node = soc_component_to_node(component); if (map->of_node && component_of_node != map->of_node) continue; @@ -3752,7 +3751,7 @@ EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); int snd_soc_get_dai_id(struct device_node *ep) { - struct snd_soc_component *pos; + struct snd_soc_component *component; struct device_node *node; int ret; @@ -3766,20 +3765,10 @@ int snd_soc_get_dai_id(struct device_node *ep) */ ret = -ENOTSUPP; mutex_lock(&client_mutex); - for_each_component(pos) { - struct device_node *component_of_node = pos->dev->of_node; - - if (!component_of_node && pos->dev->parent) - component_of_node = pos->dev->parent->of_node; - - if (component_of_node != node) - continue; - - if (pos->driver->of_xlate_dai_id) - ret = pos->driver->of_xlate_dai_id(pos, ep); - - break; - } + component = soc_find_component(node, NULL); + if (component && + component->driver->of_xlate_dai_id) + ret = component->driver->of_xlate_dai_id(component, ep); mutex_unlock(&client_mutex); of_node_put(node); @@ -3797,9 +3786,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, mutex_lock(&client_mutex); for_each_component(pos) { - component_of_node = pos->dev->of_node; - if (!component_of_node && pos->dev->parent) - component_of_node = pos->dev->parent->of_node; + component_of_node = soc_component_to_node(pos); if (component_of_node != args->np) continue; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 81a7a12196ff..a4d6c068b545 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2245,7 +2245,7 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, dapm_kcontrol_for_each_path(path, kcontrol) { found = 1; /* we now need to match the string in the enum to the path */ - if (!(strcmp(path->name, e->texts[mux]))) + if (e && !(strcmp(path->name, e->texts[mux]))) connect = true; else connect = false; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0a4f60c7a188..74c7d38af2c6 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -446,6 +446,42 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) hw->rate_max = min_not_zero(hw->rate_max, rate_max); } +static int soc_pcm_components_open(struct snd_pcm_substream *substream, + struct snd_soc_component **last) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + int ret = 0; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + *last = component; + + if (!component->driver->ops || + !component->driver->ops->open) + continue; + + if (component->driver->module_get_upon_open && + !try_module_get(component->dev->driver->owner)) { + dev_err(component->dev, + "ASoC: can't get module %s\n", + component->name); + return -ENODEV; + } + + ret = component->driver->ops->open(substream); + if (ret < 0) { + dev_err(component->dev, + "ASoC: can't open component %s: %d\n", + component->name, ret); + return ret; + } + } + *last = NULL; + return 0; +} + static int soc_pcm_components_close(struct snd_pcm_substream *substream, struct snd_soc_component *last) { @@ -510,28 +546,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->open) - continue; - - if (component->driver->module_get_upon_open && - !try_module_get(component->dev->driver->owner)) { - ret = -ENODEV; - goto module_err; - } - - ret = component->driver->ops->open(substream); - if (ret < 0) { - dev_err(component->dev, - "ASoC: can't open component %s: %d\n", - component->name, ret); - goto component_err; - } - } - component = NULL; + ret = soc_pcm_components_open(substream, &component); + if (ret < 0) + goto component_err; for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->startup) { @@ -638,7 +655,7 @@ codec_dai_err: component_err: soc_pcm_components_close(substream, component); -module_err: + if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); out: @@ -990,6 +1007,14 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto interface_err; + /* store the parameters for each DAIs */ + cpu_dai->rate = params_rate(params); + cpu_dai->channels = params_channels(params); + cpu_dai->sample_bits = + snd_pcm_format_physical_width(params_format(params)); + + snd_soc_dapm_update_dai(substream, params, cpu_dai); + for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -1007,14 +1032,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } component = NULL; - /* store the parameters for each DAIs */ - cpu_dai->rate = params_rate(params); - cpu_dai->channels = params_channels(params); - cpu_dai->sample_bits = - snd_pcm_format_physical_width(params_format(params)); - - snd_soc_dapm_update_dai(substream, params, cpu_dai); - ret = soc_pcm_params_symmetry(substream, params); if (ret) goto component_err; @@ -1027,6 +1044,7 @@ component_err: if (cpu_dai->driver->ops->hw_free) cpu_dai->driver->ops->hw_free(substream, cpu_dai); + cpu_dai->rate = 0; interface_err: i = rtd->num_codecs; diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 603e0db4f012..17e10d65fc0c 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -24,6 +24,8 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT select SND_SOC_SOF_COFFEELAKE if SND_SOC_SOF_COFFEELAKE_SUPPORT select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT + select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT + select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -179,6 +181,36 @@ config SND_SOC_SOF_ICELAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_COMETLAKE_LP + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_COMETLAKE_LP_SUPPORT + bool "SOF support for CometLake-LP" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Cometlake-LP processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_COMETLAKE_H + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_COMETLAKE_H_SUPPORT + bool "SOF support for CometLake-H" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Cometlake-H processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 08a1a3d3c08d..c059d1170bab 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -266,3 +266,22 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(cnl_chip_info); + +const struct sof_intel_dsp_desc icl_chip_info = { + /* Icelake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1) | + HDA_DSP_CORE_MASK(2) | + HDA_DSP_CORE_MASK(3), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(icl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 92d45c43b4b1..455046612b94 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -348,6 +348,7 @@ /* SSP Count of the Platform */ #define APL_SSP_COUNT 6 #define CNL_SSP_COUNT 3 +#define ICL_SSP_COUNT 6 /* SSP Registers */ #define SSP_SSC1_OFFSET 0x4 @@ -579,5 +580,6 @@ extern const struct snd_sof_dsp_ops sof_skl_ops; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc skl_chip_info; +extern const struct sof_intel_dsp_desc icl_chip_info; #endif diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 649968841dad..4f536c0de0a5 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -416,7 +416,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; int ret; - int err; /* nothing to do for BE */ if (rtd->dai_link->no_pcm) @@ -434,14 +433,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) caps = &spcm->pcm.caps[substream->stream]; - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err(sdev->dev, "error: pcm open failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* set any runtime constraints based on topology */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, @@ -485,17 +476,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) spcm->stream[substream->stream].substream = substream; ret = snd_sof_pcm_platform_open(sdev, substream); - if (ret < 0) { - dev_err(sdev->dev, "error: pcm open failed %d\n", - ret); - - pm_runtime_mark_last_busy(sdev->dev); - - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err(sdev->dev, "error: pcm close failed to idle %d\n", - err); - } + if (ret < 0) + dev_err(sdev->dev, "error: pcm open failed %d\n", ret); return ret; } @@ -530,13 +512,6 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) */ } - pm_runtime_mark_last_busy(sdev->dev); - - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err(sdev->dev, "error: pcm close failed to idle %d\n", - err); - return 0; } diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index b778dffb2d25..e2b19782f01a 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -129,6 +129,26 @@ static const struct sof_dev_desc cfl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) || \ + IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) + +static const struct sof_dev_desc cml_desc = { + .machines = snd_soc_acpi_intel_cnl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) static const struct sof_dev_desc icl_desc = { .machines = snd_soc_acpi_intel_icl_machines, @@ -137,7 +157,7 @@ static const struct sof_dev_desc icl_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, - .chip_info = &cnl_chip_info, + .chip_info = &icl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .nocodec_fw_filename = "sof-icl.ri", @@ -354,6 +374,14 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x34C8), .driver_data = (unsigned long)&icl_desc}, #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) + { PCI_DEVICE(0x8086, 0x02c8), + .driver_data = (unsigned long)&cml_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) + { PCI_DEVICE(0x8086, 0x06c8), + .driver_data = (unsigned long)&cml_desc}, +#endif { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 8ee697ff1f86..8846f49b2951 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -16,6 +16,7 @@ * details. */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/module.h> @@ -37,6 +38,10 @@ #define STM32_I2S_TXDR_REG 0X20 #define STM32_I2S_RXDR_REG 0x30 #define STM32_I2S_CGFR_REG 0X50 +#define STM32_I2S_HWCFGR_REG 0x3F0 +#define STM32_I2S_VERR_REG 0x3F4 +#define STM32_I2S_IPIDR_REG 0x3F8 +#define STM32_I2S_SIDR_REG 0x3FC /* Bit definition for SPI2S_CR1 register */ #define I2S_CR1_SPE BIT(0) @@ -143,6 +148,23 @@ #define I2S_CGFR_ODD BIT(I2S_CGFR_ODD_SHIFT) #define I2S_CGFR_MCKOE BIT(25) +/* Registers below apply to I2S version 1.1 and more */ + +/* Bit definition for SPI_HWCFGR register */ +#define I2S_HWCFGR_I2S_SUPPORT_MASK GENMASK(15, 12) + +/* Bit definition for SPI_VERR register */ +#define I2S_VERR_MIN_MASK GENMASK(3, 0) +#define I2S_VERR_MAJ_MASK GENMASK(7, 4) + +/* Bit definition for SPI_IPIDR register */ +#define I2S_IPIDR_ID_MASK GENMASK(31, 0) + +/* Bit definition for SPI_SIDR register */ +#define I2S_SIDR_ID_MASK GENMASK(31, 0) + +#define I2S_IPIDR_NUMBER 0x00130022 + enum i2s_master_mode { I2S_MS_NOT_SET, I2S_MS_MASTER, @@ -280,6 +302,10 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) case STM32_I2S_SR_REG: case STM32_I2S_RXDR_REG: case STM32_I2S_CGFR_REG: + case STM32_I2S_HWCFGR_REG: + case STM32_I2S_VERR_REG: + case STM32_I2S_IPIDR_REG: + case STM32_I2S_SIDR_REG: return true; default: return false; @@ -711,10 +737,11 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = STM32_I2S_CGFR_REG, + .max_register = STM32_I2S_SIDR_REG, .readable_reg = stm32_i2s_readable_reg, .volatile_reg = stm32_i2s_volatile_reg, .writeable_reg = stm32_i2s_writeable_reg, + .num_reg_defaults_raw = STM32_I2S_SIDR_REG / sizeof(u32) + 1, .fast_io = true, .cache_type = REGCACHE_FLAT, }; @@ -865,6 +892,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, static int stm32_i2s_probe(struct platform_device *pdev) { struct stm32_i2s_data *i2s; + u32 val; int ret; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); @@ -903,8 +931,34 @@ static int stm32_i2s_probe(struct platform_device *pdev) return ret; /* Set SPI/I2S in i2s mode */ - return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, - I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); + if (ret) + return ret; + + ret = regmap_read(i2s->regmap, STM32_I2S_IPIDR_REG, &val); + if (ret) + return ret; + + if (val == I2S_IPIDR_NUMBER) { + ret = regmap_read(i2s->regmap, STM32_I2S_HWCFGR_REG, &val); + if (ret) + return ret; + + if (!FIELD_GET(I2S_HWCFGR_I2S_SUPPORT_MASK, val)) { + dev_err(&pdev->dev, + "Device does not support i2s mode\n"); + return -EPERM; + } + + ret = regmap_read(i2s->regmap, STM32_I2S_VERR_REG, &val); + + dev_dbg(&pdev->dev, "I2S version: %lu.%lu registered\n", + FIELD_GET(I2S_VERR_MAJ_MASK, val), + FIELD_GET(I2S_VERR_MIN_MASK, val)); + } + + return ret; } MODULE_DEVICE_TABLE(of, stm32_i2s_ids); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 3d64200edbb5..4a3fad4a711f 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -16,6 +16,7 @@ * details. */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> @@ -36,6 +37,9 @@ #define STM32_SPDIFRX_DR 0x10 #define STM32_SPDIFRX_CSR 0x14 #define STM32_SPDIFRX_DIR 0x18 +#define STM32_SPDIFRX_VERR 0x3F4 +#define STM32_SPDIFRX_IDR 0x3F8 +#define STM32_SPDIFRX_SIDR 0x3FC /* Bit definition for SPDIF_CR register */ #define SPDIFRX_CR_SPDIFEN_SHIFT 0 @@ -169,6 +173,18 @@ #define SPDIFRX_SPDIFEN_SYNC 0x1 #define SPDIFRX_SPDIFEN_ENABLE 0x3 +/* Bit definition for SPDIFRX_VERR register */ +#define SPDIFRX_VERR_MIN_MASK GENMASK(3, 0) +#define SPDIFRX_VERR_MAJ_MASK GENMASK(7, 4) + +/* Bit definition for SPDIFRX_IDR register */ +#define SPDIFRX_IDR_ID_MASK GENMASK(31, 0) + +/* Bit definition for SPDIFRX_SIDR register */ +#define SPDIFRX_SIDR_SID_MASK GENMASK(31, 0) + +#define SPDIFRX_IPIDR_NUMBER 0x00130041 + #define SPDIFRX_IN1 0x1 #define SPDIFRX_IN2 0x2 #define SPDIFRX_IN3 0x3 @@ -607,6 +623,9 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) case STM32_SPDIFRX_DR: case STM32_SPDIFRX_CSR: case STM32_SPDIFRX_DIR: + case STM32_SPDIFRX_VERR: + case STM32_SPDIFRX_IDR: + case STM32_SPDIFRX_SIDR: return true; default: return false; @@ -642,10 +661,11 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = STM32_SPDIFRX_DIR, + .max_register = STM32_SPDIFRX_SIDR, .readable_reg = stm32_spdifrx_readable_reg, .volatile_reg = stm32_spdifrx_volatile_reg, .writeable_reg = stm32_spdifrx_writeable_reg, + .num_reg_defaults_raw = STM32_SPDIFRX_SIDR / sizeof(u32) + 1, .fast_io = true, .cache_type = REGCACHE_FLAT, }; @@ -912,6 +932,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) struct stm32_spdifrx_data *spdifrx; struct reset_control *rst; const struct snd_dmaengine_pcm_config *pcm_config = NULL; + u32 ver, idr; int ret; spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); @@ -968,7 +989,19 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) goto error; } - return 0; + ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr); + if (ret) + goto error; + + if (idr == SPDIFRX_IPIDR_NUMBER) { + ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver); + + dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n", + FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver), + FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver)); + } + + return ret; error: if (!IS_ERR(spdifrx->ctrl_chan)) |