Commit 25317997 authored by Mark Brown's avatar Mark Brown

Merge branch 'asoc-5.4' into asoc-5.5

parents 3a9e204d 2bdf194e
...@@ -901,7 +901,7 @@ static void max98373_slot_config(struct i2c_client *i2c, ...@@ -901,7 +901,7 @@ static void max98373_slot_config(struct i2c_client *i2c,
max98373->i_slot = value & 0xF; max98373->i_slot = value & 0xF;
else else
max98373->i_slot = 1; max98373->i_slot = 1;
if (dev->of_node) {
max98373->reset_gpio = of_get_named_gpio(dev->of_node, max98373->reset_gpio = of_get_named_gpio(dev->of_node,
"maxim,reset-gpio", 0); "maxim,reset-gpio", 0);
if (!gpio_is_valid(max98373->reset_gpio)) { if (!gpio_is_valid(max98373->reset_gpio)) {
...@@ -912,6 +912,10 @@ static void max98373_slot_config(struct i2c_client *i2c, ...@@ -912,6 +912,10 @@ static void max98373_slot_config(struct i2c_client *i2c,
dev_dbg(dev, "maxim,reset-gpio=%d", dev_dbg(dev, "maxim,reset-gpio=%d",
max98373->reset_gpio); max98373->reset_gpio);
} }
} else {
/* this makes reset_gpio as invalid */
max98373->reset_gpio = -1;
}
if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value)) if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value))
max98373->spkfb_slot = value & 0xF; max98373->spkfb_slot = value & 0xF;
......
...@@ -1770,6 +1770,9 @@ static int rt5651_detect_headset(struct snd_soc_component *component) ...@@ -1770,6 +1770,9 @@ static int rt5651_detect_headset(struct snd_soc_component *component)
static bool rt5651_support_button_press(struct rt5651_priv *rt5651) static bool rt5651_support_button_press(struct rt5651_priv *rt5651)
{ {
if (!rt5651->hp_jack)
return false;
/* Button press support only works with internal jack-detection */ /* Button press support only works with internal jack-detection */
return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) && return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) &&
rt5651->gpiod_hp_det == NULL; rt5651->gpiod_hp_det == NULL;
......
...@@ -995,6 +995,16 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, ...@@ -995,6 +995,16 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
{ {
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
rt5682->hs_jack = hs_jack;
if (!hs_jack) {
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
RT5682_POW_JDH | RT5682_POW_JDL, 0);
return 0;
}
switch (rt5682->pdata.jd_src) { switch (rt5682->pdata.jd_src) {
case RT5682_JD1: case RT5682_JD1:
snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2, snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2,
...@@ -1032,8 +1042,6 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, ...@@ -1032,8 +1042,6 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
break; break;
} }
rt5682->hs_jack = hs_jack;
return 0; return 0;
} }
......
...@@ -533,13 +533,10 @@ static SOC_ENUM_SINGLE_DECL(dac_osr, ...@@ -533,13 +533,10 @@ static SOC_ENUM_SINGLE_DECL(dac_osr,
static SOC_ENUM_SINGLE_DECL(adc_osr, static SOC_ENUM_SINGLE_DECL(adc_osr,
WM8994_OVERSAMPLING, 1, osr_text); WM8994_OVERSAMPLING, 1, osr_text);
static const struct snd_kcontrol_new wm8994_snd_controls[] = { static const struct snd_kcontrol_new wm8994_common_snd_controls[] = {
SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
WM8994_AIF1_ADC1_RIGHT_VOLUME, WM8994_AIF1_ADC1_RIGHT_VOLUME,
1, 119, 0, digital_tlv), 1, 119, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
WM8994_AIF1_ADC2_RIGHT_VOLUME,
1, 119, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME, SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
WM8994_AIF2_ADC_RIGHT_VOLUME, WM8994_AIF2_ADC_RIGHT_VOLUME,
1, 119, 0, digital_tlv), 1, 119, 0, digital_tlv),
...@@ -556,8 +553,6 @@ SOC_ENUM("AIF2DACR Source", aif2dacr_src), ...@@ -556,8 +553,6 @@ SOC_ENUM("AIF2DACR Source", aif2dacr_src),
SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME, SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv), WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME, SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8994_AIF2_DAC_LEFT_VOLUME,
WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv), WM8994_AIF2_DAC_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
...@@ -565,17 +560,12 @@ SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv), ...@@ -565,17 +560,12 @@ SOC_SINGLE_TLV("AIF1 Boost Volume", WM8994_AIF1_CONTROL_2, 10, 3, 0, aif_tlv),
SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv), SOC_SINGLE_TLV("AIF2 Boost Volume", WM8994_AIF2_CONTROL_2, 10, 3, 0, aif_tlv),
SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0), SOC_SINGLE("AIF1DAC1 EQ Switch", WM8994_AIF1_DAC1_EQ_GAINS_1, 0, 1, 0),
SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0), SOC_SINGLE("AIF2 EQ Switch", WM8994_AIF2_EQ_GAINS_1, 0, 1, 0),
WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2), WM8994_DRC_SWITCH("AIF1DAC1 DRC Switch", WM8994_AIF1_DRC1_1, 2),
WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1), WM8994_DRC_SWITCH("AIF1ADC1L DRC Switch", WM8994_AIF1_DRC1_1, 1),
WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0), WM8994_DRC_SWITCH("AIF1ADC1R DRC Switch", WM8994_AIF1_DRC1_1, 0),
WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2), WM8994_DRC_SWITCH("AIF2DAC DRC Switch", WM8994_AIF2_DRC_1, 2),
WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1), WM8994_DRC_SWITCH("AIF2ADCL DRC Switch", WM8994_AIF2_DRC_1, 1),
WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0), WM8994_DRC_SWITCH("AIF2ADCR DRC Switch", WM8994_AIF2_DRC_1, 0),
...@@ -594,9 +584,6 @@ SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0), ...@@ -594,9 +584,6 @@ SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0),
SOC_ENUM("AIF1ADC1 HPF Mode", aif1adc1_hpf), SOC_ENUM("AIF1ADC1 HPF Mode", aif1adc1_hpf),
SOC_DOUBLE("AIF1ADC1 HPF Switch", WM8994_AIF1_ADC1_FILTERS, 12, 11, 1, 0), SOC_DOUBLE("AIF1ADC1 HPF Switch", WM8994_AIF1_ADC1_FILTERS, 12, 11, 1, 0),
SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf), SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf),
SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0), SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0),
...@@ -637,6 +624,24 @@ SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2, ...@@ -637,6 +624,24 @@ SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2,
8, 1, 0), 8, 1, 0),
}; };
/* Controls not available on WM1811 */
static const struct snd_kcontrol_new wm8994_snd_controls[] = {
SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8994_AIF1_ADC2_LEFT_VOLUME,
WM8994_AIF1_ADC2_RIGHT_VOLUME,
1, 119, 0, digital_tlv),
SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
WM8994_AIF1_DAC2_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
SOC_SINGLE("AIF1DAC2 EQ Switch", WM8994_AIF1_DAC2_EQ_GAINS_1, 0, 1, 0),
WM8994_DRC_SWITCH("AIF1DAC2 DRC Switch", WM8994_AIF1_DRC2_1, 2),
WM8994_DRC_SWITCH("AIF1ADC2L DRC Switch", WM8994_AIF1_DRC2_1, 1),
WM8994_DRC_SWITCH("AIF1ADC2R DRC Switch", WM8994_AIF1_DRC2_1, 0),
SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
};
static const struct snd_kcontrol_new wm8994_eq_controls[] = { static const struct snd_kcontrol_new wm8994_eq_controls[] = {
SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0, SOC_SINGLE_TLV("AIF1DAC1 EQ1 Volume", WM8994_AIF1_DAC1_EQ_GAINS_1, 11, 31, 0,
eq_tlv), eq_tlv),
...@@ -4385,13 +4390,15 @@ static int wm8994_component_probe(struct snd_soc_component *component) ...@@ -4385,13 +4390,15 @@ static int wm8994_component_probe(struct snd_soc_component *component)
wm8994_handle_pdata(wm8994); wm8994_handle_pdata(wm8994);
wm_hubs_add_analogue_controls(component); wm_hubs_add_analogue_controls(component);
snd_soc_add_component_controls(component, wm8994_snd_controls, snd_soc_add_component_controls(component, wm8994_common_snd_controls,
ARRAY_SIZE(wm8994_snd_controls)); ARRAY_SIZE(wm8994_common_snd_controls));
snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets, snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
ARRAY_SIZE(wm8994_dapm_widgets)); ARRAY_SIZE(wm8994_dapm_widgets));
switch (control->type) { switch (control->type) {
case WM8994: case WM8994:
snd_soc_add_component_controls(component, wm8994_snd_controls,
ARRAY_SIZE(wm8994_snd_controls));
snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
ARRAY_SIZE(wm8994_specific_dapm_widgets)); ARRAY_SIZE(wm8994_specific_dapm_widgets));
if (control->revision < 4) { if (control->revision < 4) {
...@@ -4411,6 +4418,8 @@ static int wm8994_component_probe(struct snd_soc_component *component) ...@@ -4411,6 +4418,8 @@ static int wm8994_component_probe(struct snd_soc_component *component)
} }
break; break;
case WM8958: case WM8958:
snd_soc_add_component_controls(component, wm8994_snd_controls,
ARRAY_SIZE(wm8994_snd_controls));
snd_soc_add_component_controls(component, wm8958_snd_controls, snd_soc_add_component_controls(component, wm8958_snd_controls,
ARRAY_SIZE(wm8958_snd_controls)); ARRAY_SIZE(wm8958_snd_controls));
snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets, snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
......
...@@ -3697,11 +3697,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) ...@@ -3697,11 +3697,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
u32 xmalg, addr, magic; u32 xmalg, addr, magic;
int i, ret; int i, ret;
alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
if (!alg_region) {
adsp_err(dsp, "No algorithm region found\n");
return -EINVAL;
}
buf = wm_adsp_buffer_alloc(dsp); buf = wm_adsp_buffer_alloc(dsp);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
xmalg = dsp->ops->sys_config_size / sizeof(__be32); xmalg = dsp->ops->sys_config_size / sizeof(__be32);
addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
......
...@@ -308,6 +308,9 @@ static const struct snd_soc_dapm_widget sof_widgets[] = { ...@@ -308,6 +308,9 @@ static const struct snd_soc_dapm_widget sof_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_SPK("Spk", NULL),
};
static const struct snd_soc_dapm_widget dmic_widgets[] = {
SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL),
}; };
...@@ -318,10 +321,6 @@ static const struct snd_soc_dapm_route sof_map[] = { ...@@ -318,10 +321,6 @@ static const struct snd_soc_dapm_route sof_map[] = {
/* other jacks */ /* other jacks */
{ "IN1P", NULL, "Headset Mic" }, { "IN1P", NULL, "Headset Mic" },
/* digital mics */
{"DMic", NULL, "SoC DMIC"},
}; };
static const struct snd_soc_dapm_route speaker_map[] = { static const struct snd_soc_dapm_route speaker_map[] = {
...@@ -329,6 +328,11 @@ static const struct snd_soc_dapm_route speaker_map[] = { ...@@ -329,6 +328,11 @@ static const struct snd_soc_dapm_route speaker_map[] = {
{ "Spk", NULL, "Speaker" }, { "Spk", NULL, "Speaker" },
}; };
static const struct snd_soc_dapm_route dmic_map[] = {
/* digital mics */
{"DMic", NULL, "SoC DMIC"},
};
static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_card *card = rtd->card; struct snd_soc_card *card = rtd->card;
...@@ -342,6 +346,28 @@ static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -342,6 +346,28 @@ static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
} }
static int dmic_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
int ret;
ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
ARRAY_SIZE(dmic_widgets));
if (ret) {
dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
/* Don't need to add routes if widget addition failed */
return ret;
}
ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
ARRAY_SIZE(dmic_map));
if (ret)
dev_err(card->dev, "DMic map addition failed: %d\n", ret);
return ret;
}
/* sof audio machine driver for rt5682 codec */ /* sof audio machine driver for rt5682 codec */
static struct snd_soc_card sof_audio_card_rt5682 = { static struct snd_soc_card sof_audio_card_rt5682 = {
.name = "sof_rt5682", .name = "sof_rt5682",
...@@ -445,6 +471,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, ...@@ -445,6 +471,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].name = "dmic01"; links[id].name = "dmic01";
links[id].cpus = &cpus[id]; links[id].cpus = &cpus[id];
links[id].cpus->dai_name = "DMIC01 Pin"; links[id].cpus->dai_name = "DMIC01 Pin";
links[id].init = dmic_init;
if (dmic_be_num > 1) { if (dmic_be_num > 1) {
/* set up 2 BE links at most */ /* set up 2 BE links at most */
links[id + 1].name = "dmic16k"; links[id + 1].name = "dmic16k";
...@@ -621,8 +648,24 @@ static int sof_audio_probe(struct platform_device *pdev) ...@@ -621,8 +648,24 @@ static int sof_audio_probe(struct platform_device *pdev)
&sof_audio_card_rt5682); &sof_audio_card_rt5682);
} }
static int sof_rt5682_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct snd_soc_component *component = NULL;
for_each_card_components(card, component) {
if (!strcmp(component->name, rt5682_component[0].name)) {
snd_soc_component_set_jack(component, NULL, NULL);
break;
}
}
return 0;
}
static struct platform_driver sof_audio = { static struct platform_driver sof_audio = {
.probe = sof_audio_probe, .probe = sof_audio_probe,
.remove = sof_rt5682_remove,
.driver = { .driver = {
.name = "sof_rt5682", .name = "sof_rt5682",
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// Author: Claude <claude@insginal.co.kr> // Author: Claude <claude@insginal.co.kr>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
...@@ -74,6 +75,17 @@ static struct snd_soc_card arndale_rt5631 = { ...@@ -74,6 +75,17 @@ static struct snd_soc_card arndale_rt5631 = {
.num_links = ARRAY_SIZE(arndale_rt5631_dai), .num_links = ARRAY_SIZE(arndale_rt5631_dai),
}; };
static void arndale_put_of_nodes(struct snd_soc_card *card)
{
struct snd_soc_dai_link *dai_link;
int i;
for_each_card_prelinks(card, i, dai_link) {
of_node_put(dai_link->cpus->of_node);
of_node_put(dai_link->codecs->of_node);
}
}
static int arndale_audio_probe(struct platform_device *pdev) static int arndale_audio_probe(struct platform_device *pdev)
{ {
int n, ret; int n, ret;
...@@ -103,18 +115,31 @@ static int arndale_audio_probe(struct platform_device *pdev) ...@@ -103,18 +115,31 @@ static int arndale_audio_probe(struct platform_device *pdev)
if (!arndale_rt5631_dai[0].codecs->of_node) { if (!arndale_rt5631_dai[0].codecs->of_node) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Property 'samsung,audio-codec' missing or invalid\n"); "Property 'samsung,audio-codec' missing or invalid\n");
return -EINVAL; ret = -EINVAL;
goto err_put_of_nodes;
} }
} }
ret = devm_snd_soc_register_card(card->dev, card); ret = devm_snd_soc_register_card(card->dev, card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
goto err_put_of_nodes;
}
return 0;
if (ret) err_put_of_nodes:
dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); arndale_put_of_nodes(card);
return ret; return ret;
} }
static int arndale_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
arndale_put_of_nodes(card);
return 0;
}
static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = { static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
{ .compatible = "samsung,arndale-rt5631", }, { .compatible = "samsung,arndale-rt5631", },
{ .compatible = "samsung,arndale-alc5631", }, { .compatible = "samsung,arndale-alc5631", },
...@@ -129,6 +154,7 @@ static struct platform_driver arndale_audio_driver = { ...@@ -129,6 +154,7 @@ static struct platform_driver arndale_audio_driver = {
.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
}, },
.probe = arndale_audio_probe, .probe = arndale_audio_probe,
.remove = arndale_audio_remove,
}; };
module_platform_driver(arndale_audio_driver); module_platform_driver(arndale_audio_driver);
......
...@@ -1070,7 +1070,7 @@ static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd) ...@@ -1070,7 +1070,7 @@ static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd)
return ret; return ret;
} }
snd_soc_dai_trigger(cpu_dai, substream, cmd); ret = snd_soc_dai_trigger(cpu_dai, substream, cmd);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1155,7 +1155,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, ...@@ -1155,7 +1155,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
return ret; return ret;
} }
snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd); ret = snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -1582,7 +1582,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, ...@@ -1582,7 +1582,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
/* map user to kernel widget ID */ /* map user to kernel widget ID */
template.id = get_widget_id(le32_to_cpu(w->id)); template.id = get_widget_id(le32_to_cpu(w->id));
if (template.id < 0) if ((int)template.id < 0)
return template.id; return template.id;
/* strings are allocated here, but used and freed by the widget */ /* strings are allocated here, but used and freed by the widget */
......
...@@ -273,6 +273,16 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC ...@@ -273,6 +273,16 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
Say Y if you want to enable HDAudio codecs with SOF. Say Y if you want to enable HDAudio codecs with SOF.
If unsure select "N". If unsure select "N".
config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1
bool "SOF enable DMI Link L1"
help
This option enables DMI L1 for both playback and capture
and disables known workarounds for specific HDaudio platforms.
Only use to look into power optimizations on platforms not
affected by DMI L1 issues. This option is not recommended.
Say Y if you want to enable DMI Link L1
If unsure, select "N".
endif ## SND_SOC_SOF_HDA_COMMON endif ## SND_SOC_SOF_HDA_COMMON
config SND_SOC_SOF_HDA_LINK_BASELINE config SND_SOC_SOF_HDA_LINK_BASELINE
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#define MBOX_SIZE 0x1000 #define MBOX_SIZE 0x1000
#define MBOX_DUMP_SIZE 0x30 #define MBOX_DUMP_SIZE 0x30
#define EXCEPT_OFFSET 0x800 #define EXCEPT_OFFSET 0x800
#define EXCEPT_MAX_HDR_SIZE 0x400
/* DSP peripherals */ /* DSP peripherals */
#define DMAC0_OFFSET 0xFE000 #define DMAC0_OFFSET 0xFE000
...@@ -228,6 +229,11 @@ static void bdw_get_registers(struct snd_sof_dev *sdev, ...@@ -228,6 +229,11 @@ static void bdw_get_registers(struct snd_sof_dev *sdev,
/* note: variable AR register array is not read */ /* note: variable AR register array is not read */
/* then get panic info */ /* then get panic info */
if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
xoops->arch_hdr.totalsize);
return;
}
offset += xoops->arch_hdr.totalsize; offset += xoops->arch_hdr.totalsize;
sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
...@@ -471,6 +477,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) ...@@ -471,6 +477,7 @@ static int bdw_probe(struct snd_sof_dev *sdev)
/* TODO: add offsets */ /* TODO: add offsets */
sdev->mmio_bar = BDW_DSP_BAR; sdev->mmio_bar = BDW_DSP_BAR;
sdev->mailbox_bar = BDW_DSP_BAR; sdev->mailbox_bar = BDW_DSP_BAR;
sdev->dsp_oops_offset = MBOX_OFFSET;
/* PCI base */ /* PCI base */
mmio = platform_get_resource(pdev, IORESOURCE_MEM, mmio = platform_get_resource(pdev, IORESOURCE_MEM,
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define MBOX_OFFSET 0x144000 #define MBOX_OFFSET 0x144000
#define MBOX_SIZE 0x1000 #define MBOX_SIZE 0x1000
#define EXCEPT_OFFSET 0x800 #define EXCEPT_OFFSET 0x800
#define EXCEPT_MAX_HDR_SIZE 0x400
/* DSP peripherals */ /* DSP peripherals */
#define DMAC0_OFFSET 0x098000 #define DMAC0_OFFSET 0x098000
...@@ -126,6 +127,11 @@ static void byt_get_registers(struct snd_sof_dev *sdev, ...@@ -126,6 +127,11 @@ static void byt_get_registers(struct snd_sof_dev *sdev,
/* note: variable AR register array is not read */ /* note: variable AR register array is not read */
/* then get panic info */ /* then get panic info */
if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
xoops->arch_hdr.totalsize);
return;
}
offset += xoops->arch_hdr.totalsize; offset += xoops->arch_hdr.totalsize;
sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
......
...@@ -139,20 +139,16 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) ...@@ -139,20 +139,16 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
*/ */
int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
{ {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_bus *bus = sof_to_bus(sdev);
#endif
u32 val; u32 val;
/* enable/disable audio dsp clock gating */ /* enable/disable audio dsp clock gating */
val = enable ? PCI_CGCTL_ADSPDCGE : 0; val = enable ? PCI_CGCTL_ADSPDCGE : 0;
snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* enable/disable DMI Link L1 support */
/* enable/disable L1 support */ val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0;
val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); HDA_VS_INTEL_EM2_L1SEN, val);
#endif
/* enable/disable audio dsp power gating */ /* enable/disable audio dsp power gating */
val = enable ? 0 : PCI_PGCTL_ADSPPGD; val = enable ? 0 : PCI_PGCTL_ADSPPGD;
......
...@@ -44,6 +44,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, ...@@ -44,6 +44,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
return -ENODEV; return -ENODEV;
} }
hstream = &dsp_stream->hstream; hstream = &dsp_stream->hstream;
hstream->substream = NULL;
/* allocate DMA buffer */ /* allocate DMA buffer */
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
......
...@@ -185,6 +185,17 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) ...@@ -185,6 +185,17 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
direction == SNDRV_PCM_STREAM_PLAYBACK ? direction == SNDRV_PCM_STREAM_PLAYBACK ?
"playback" : "capture"); "playback" : "capture");
/*
* Disable DMI Link L1 entry when capture stream is opened.
* Workaround to address a known issue with host DMA that results
* in xruns during pause/release in capture scenarios.
*/
if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
if (stream && direction == SNDRV_PCM_STREAM_CAPTURE)
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
HDA_VS_INTEL_EM2,
HDA_VS_INTEL_EM2_L1SEN, 0);
return stream; return stream;
} }
...@@ -193,23 +204,43 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) ...@@ -193,23 +204,43 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
struct hdac_stream *s; struct hdac_stream *s;
bool active_capture_stream = false;
bool found = false;
spin_lock_irq(&bus->reg_lock); spin_lock_irq(&bus->reg_lock);
/* find used stream */ /*
* close stream matching the stream tag
* and check if there are any open capture streams.
*/
list_for_each_entry(s, &bus->stream_list, list) { list_for_each_entry(s, &bus->stream_list, list) {
if (s->direction == direction && if (!s->opened)
s->opened && s->stream_tag == stream_tag) { continue;
if (s->direction == direction && s->stream_tag == stream_tag) {
s->opened = false; s->opened = false;
spin_unlock_irq(&bus->reg_lock); found = true;
return 0; } else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) {
active_capture_stream = true;
} }
} }
spin_unlock_irq(&bus->reg_lock); spin_unlock_irq(&bus->reg_lock);
/* Enable DMI L1 entry if there are no capture streams open */
if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
if (!active_capture_stream)
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
HDA_VS_INTEL_EM2,
HDA_VS_INTEL_EM2_L1SEN,
HDA_VS_INTEL_EM2_L1SEN);
if (!found) {
dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag);
return -ENODEV; return -ENODEV;
}
return 0;
} }
int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) #define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) #define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8)
#define EXCEPT_MAX_HDR_SIZE 0x400
/* /*
* Debug * Debug
*/ */
...@@ -131,6 +133,11 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, ...@@ -131,6 +133,11 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
/* note: variable AR register array is not read */ /* note: variable AR register array is not read */
/* then get panic info */ /* then get panic info */
if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
xoops->arch_hdr.totalsize);
return;
}
offset += xoops->arch_hdr.totalsize; offset += xoops->arch_hdr.totalsize;
sof_block_read(sdev, sdev->mmio_bar, offset, sof_block_read(sdev, sdev->mmio_bar, offset,
panic_info, sizeof(*panic_info)); panic_info, sizeof(*panic_info));
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#define SOF_HDA_WAKESTS 0x0E #define SOF_HDA_WAKESTS 0x0E
#define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) #define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1)
#define SOF_HDA_RIRBSTS 0x5d #define SOF_HDA_RIRBSTS 0x5d
#define SOF_HDA_VS_EM2_L1SEN BIT(13)
/* SOF_HDA_GCTL register bist */ /* SOF_HDA_GCTL register bist */
#define SOF_HDA_GCTL_RESET BIT(0) #define SOF_HDA_GCTL_RESET BIT(0)
...@@ -228,6 +227,10 @@ ...@@ -228,6 +227,10 @@
#define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C) #define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C)
#define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10) #define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10)
/* Intel Vendor Specific Registers */
#define HDA_VS_INTEL_EM2 0x1030
#define HDA_VS_INTEL_EM2_L1SEN BIT(13)
/* HIPCI */ /* HIPCI */
#define HDA_DSP_REG_HIPCI_BUSY BIT(31) #define HDA_DSP_REG_HIPCI_BUSY BIT(31)
#define HDA_DSP_REG_HIPCI_MSG_MASK 0x7FFFFFFF #define HDA_DSP_REG_HIPCI_MSG_MASK 0x7FFFFFFF
......
...@@ -546,10 +546,10 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) ...@@ -546,10 +546,10 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
msecs_to_jiffies(sdev->boot_timeout)); msecs_to_jiffies(sdev->boot_timeout));
if (ret == 0) { if (ret == 0) {
dev_err(sdev->dev, "error: firmware boot failure\n"); dev_err(sdev->dev, "error: firmware boot failure\n");
/* after this point FW_READY msg should be ignored */
sdev->boot_complete = true;
snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
SOF_DBG_TEXT | SOF_DBG_PCI); SOF_DBG_TEXT | SOF_DBG_PCI);
/* after this point FW_READY msg should be ignored */
sdev->boot_complete = true;
return -EIO; return -EIO;
} }
......
...@@ -244,7 +244,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) ...@@ -244,7 +244,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
snd_soc_rtdcom_lookup(rtd, DRV_NAME); snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_sof_pcm *spcm; struct snd_sof_pcm *spcm;
int ret; int ret, err = 0;
/* nothing to do for BE */ /* nothing to do for BE */
if (rtd->dai_link->no_pcm) if (rtd->dai_link->no_pcm)
...@@ -254,26 +254,26 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) ...@@ -254,26 +254,26 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
if (!spcm) if (!spcm)
return -EINVAL; return -EINVAL;
if (!spcm->prepared[substream->stream])
return 0;
dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
substream->stream); substream->stream);
if (spcm->prepared[substream->stream]) {
ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
if (ret < 0)
err = ret;
}
snd_pcm_lib_free_pages(substream); snd_pcm_lib_free_pages(substream);
cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
if (ret < 0)
return ret;
ret = snd_sof_pcm_platform_hw_free(sdev, substream); ret = snd_sof_pcm_platform_hw_free(sdev, substream);
if (ret < 0) if (ret < 0) {
dev_err(sdev->dev, "error: platform hw free failed\n"); dev_err(sdev->dev, "error: platform hw free failed\n");
err = ret;
}
return ret; return err;
} }
static int sof_pcm_prepare(struct snd_pcm_substream *substream) static int sof_pcm_prepare(struct snd_pcm_substream *substream)
...@@ -323,6 +323,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -323,6 +323,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct sof_ipc_stream stream; struct sof_ipc_stream stream;
struct sof_ipc_reply reply; struct sof_ipc_reply reply;
bool reset_hw_params = false; bool reset_hw_params = false;
bool ipc_first = false;
int ret; int ret;
/* nothing to do for BE */ /* nothing to do for BE */
...@@ -343,6 +344,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -343,6 +344,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
ipc_first = true;
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
...@@ -363,6 +365,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -363,6 +365,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
ipc_first = true;
reset_hw_params = true; reset_hw_params = true;
break; break;
default: default:
...@@ -370,12 +373,22 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -370,12 +373,22 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return -EINVAL; return -EINVAL;
} }
/*
* DMA and IPC sequence is different for start and stop. Need to send
* STOP IPC before stop DMA
*/
if (!ipc_first)
snd_sof_pcm_platform_trigger(sdev, substream, cmd); snd_sof_pcm_platform_trigger(sdev, substream, cmd);
/* send IPC to the DSP */ /* send IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
sizeof(stream), &reply, sizeof(reply)); sizeof(stream), &reply, sizeof(reply));
/* need to STOP DMA even if STOP IPC failed */
if (ipc_first)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
/* free PCM if reset_hw_params is set and the STOP IPC is successful */
if (!ret && reset_hw_params) if (!ret && reset_hw_params)
ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
......
...@@ -920,7 +920,9 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp, ...@@ -920,7 +920,9 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp,
for (j = 0; j < count; j++) { for (j = 0; j < count; j++) {
/* match token type */ /* match token type */
if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD || if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD ||
tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT)) tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT ||
tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BYTE ||
tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BOOL))
continue; continue;
/* match token id */ /* match token id */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment