aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/rt5682s.c27
-rw-r--r--sound/soc/codecs/rt5682s.h6
-rw-r--r--sound/soc/soc-pcm.c8
-rw-r--r--sound/soc/sof/pm.c4
-rw-r--r--sound/soc/sof/sof-audio.c12
-rw-r--r--sound/soc/sof/sof-audio.h8
-rw-r--r--sound/soc/sof/topology.c25
7 files changed, 60 insertions, 30 deletions
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 639a50fa95e2..9dd1796f3339 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -790,6 +790,7 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_
snd_soc_component_update_bits(component, RT5682S_HP_CHARGE_PUMP_2,
RT5682S_OSW_L_MASK | RT5682S_OSW_R_MASK,
RT5682S_OSW_L_EN | RT5682S_OSW_R_EN);
+ usleep_range(35000, 40000);
} else {
rt5682s_sar_power_mode(component, SAR_PWR_OFF, 1);
rt5682s_disable_push_button_irq(component);
@@ -829,6 +830,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
while (!rt5682s->component->card->instantiated)
usleep_range(10000, 15000);
+ mutex_lock(&rt5682s->jdet_mutex);
mutex_lock(&rt5682s->calibrate_mutex);
val = snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL)
@@ -896,6 +898,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
cancel_delayed_work_sync(&rt5682s->jd_check_work);
mutex_unlock(&rt5682s->calibrate_mutex);
+ mutex_unlock(&rt5682s->jdet_mutex);
}
static void rt5682s_jd_check_handler(struct work_struct *work)
@@ -1318,34 +1321,41 @@ static int rt5682s_hp_amp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
+ case SND_SOC_DAPM_POST_PMU:
snd_soc_component_update_bits(component, RT5682S_DEPOP_1,
RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN,
RT5682S_OUT_HP_L_EN | RT5682S_OUT_HP_R_EN);
+ usleep_range(15000, 20000);
snd_soc_component_update_bits(component, RT5682S_DEPOP_1,
RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN |
RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN,
RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN |
RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN);
- break;
-
- case SND_SOC_DAPM_POST_PMU:
- usleep_range(30000, 35000);
snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_11, 0x6666);
snd_soc_component_write(component, RT5682S_BIAS_CUR_CTRL_12, 0xa82a);
+
+ mutex_lock(&rt5682s->jdet_mutex);
+
snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2,
RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK |
RT5682S_HPO_SEL_IP_EN_SW, RT5682S_HPO_L_PATH_EN |
RT5682S_HPO_R_PATH_EN | RT5682S_HPO_IP_EN_GATING);
- snd_soc_component_write(component, RT5682S_HP_AMP_DET_CTL_1, 0x3050);
+ usleep_range(5000, 10000);
+ snd_soc_component_update_bits(component, RT5682S_HP_AMP_DET_CTL_1,
+ RT5682S_CP_SW_SIZE_MASK, RT5682S_CP_SW_SIZE_L | RT5682S_CP_SW_SIZE_S);
+
+ mutex_unlock(&rt5682s->jdet_mutex);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_component_update_bits(component, RT5682S_HP_CTRL_2,
RT5682S_HPO_L_PATH_MASK | RT5682S_HPO_R_PATH_MASK |
RT5682S_HPO_SEL_IP_EN_SW, 0);
+ snd_soc_component_update_bits(component, RT5682S_HP_AMP_DET_CTL_1,
+ RT5682S_CP_SW_SIZE_MASK, RT5682S_CP_SW_SIZE_M);
snd_soc_component_update_bits(component, RT5682S_DEPOP_1,
RT5682S_LDO_PUMP_EN | RT5682S_PUMP_EN |
RT5682S_CAPLESS_L_EN | RT5682S_CAPLESS_R_EN, 0);
@@ -1734,7 +1744,7 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = {
/* HPO */
SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5682s_hp_amp_event,
- SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
/* CLK DET */
SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5682S_CLK_DET,
@@ -3061,6 +3071,7 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c,
mutex_init(&rt5682s->calibrate_mutex);
mutex_init(&rt5682s->sar_mutex);
+ mutex_init(&rt5682s->jdet_mutex);
rt5682s_calibrate(rt5682s);
regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2,
@@ -3072,6 +3083,8 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c,
RT5682S_HP_SIG_SRC_MASK, RT5682S_HP_SIG_SRC_1BIT_CTL);
regmap_update_bits(rt5682s->regmap, RT5682S_HP_CHARGE_PUMP_2,
RT5682S_PM_HP_MASK, RT5682S_PM_HP_HV);
+ regmap_update_bits(rt5682s->regmap, RT5682S_HP_AMP_DET_CTL_1,
+ RT5682S_CP_SW_SIZE_MASK, RT5682S_CP_SW_SIZE_M);
/* DMIC data pin */
switch (rt5682s->pdata.dmic1_data_pin) {
diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h
index 59ba4ea3b062..1bf2ef7ce578 100644
--- a/sound/soc/codecs/rt5682s.h
+++ b/sound/soc/codecs/rt5682s.h
@@ -1366,6 +1366,11 @@
#define RT5682S_SAR_SOUR_BTN (0x3f)
#define RT5682S_SAR_SOUR_TYPE (0x0)
+/* Headphone Amp Detection Control 1 (0x3b00) */
+#define RT5682S_CP_SW_SIZE_MASK (0x7 << 4)
+#define RT5682S_CP_SW_SIZE_L (0x4 << 4)
+#define RT5682S_CP_SW_SIZE_M (0x2 << 4)
+#define RT5682S_CP_SW_SIZE_S (0x1 << 4)
#define RT5682S_STEREO_RATES SNDRV_PCM_RATE_8000_192000
#define RT5682S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
@@ -1441,6 +1446,7 @@ struct rt5682s_priv {
struct delayed_work jd_check_work;
struct mutex calibrate_mutex;
struct mutex sar_mutex;
+ struct mutex jdet_mutex;
#ifdef CONFIG_COMMON_CLK
struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS];
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index b5825d8d6caa..0aa0ae9703d1 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1395,7 +1395,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
if (!fe->dpcm[stream].runtime && !fe->fe_compr)
continue;
- if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
+ /*
+ * Filter for systems with 'component_chaining' enabled.
+ * This helps to avoid unnecessary re-configuration of an
+ * already active BE on such systems.
+ */
+ if (fe->card->component_chaining &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
continue;
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
index 77a3496d3dbd..e65f4f4d6df9 100644
--- a/sound/soc/sof/pm.c
+++ b/sound/soc/sof/pm.c
@@ -157,7 +157,7 @@ static int sof_resume(struct device *dev, bool runtime_resume)
}
/* restore pipelines */
- ret = sof_set_up_pipelines(sdev->dev, false);
+ ret = sof_set_up_pipelines(sdev, false);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to restore pipeline after resume %d\n",
@@ -208,7 +208,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
if (target_state == SOF_DSP_PM_D0)
goto suspend;
- sof_tear_down_pipelines(dev, false);
+ sof_tear_down_pipelines(sdev, false);
/* release trace */
snd_sof_release_trace(sdev);
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index 262cb3ad4674..7cbe757c1fe2 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -203,7 +203,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
break;
case snd_soc_dapm_scheduler:
pipeline = swidget->private;
- ret = sof_load_pipeline_ipc(sdev->dev, pipeline, &r);
+ ret = sof_load_pipeline_ipc(sdev, pipeline, &r);
break;
default:
hdr = swidget->private;
@@ -428,7 +428,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in
if (pipe_widget->complete)
continue;
- pipe_widget->complete = snd_sof_complete_pipeline(sdev->dev, pipe_widget);
+ pipe_widget->complete = snd_sof_complete_pipeline(sdev, pipe_widget);
if (pipe_widget->complete < 0) {
ret = pipe_widget->complete;
goto widget_free;
@@ -593,9 +593,8 @@ const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev,
return NULL;
}
-int sof_set_up_pipelines(struct device *dev, bool verify)
+int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify)
{
- struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
int ret;
@@ -654,7 +653,7 @@ int sof_set_up_pipelines(struct device *dev, bool verify)
continue;
swidget->complete =
- snd_sof_complete_pipeline(dev, swidget);
+ snd_sof_complete_pipeline(sdev, swidget);
break;
default:
break;
@@ -668,9 +667,8 @@ int sof_set_up_pipelines(struct device *dev, bool verify)
* This function doesn't free widgets during suspend. It only resets the set up status for all
* routes and use_count for all widgets.
*/
-int sof_tear_down_pipelines(struct device *dev, bool verify)
+int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify)
{
- struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
int ret;
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 149b3dbcddd1..fe2ffe02fdfb 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -181,10 +181,10 @@ void snd_sof_control_notify(struct snd_sof_dev *sdev,
* be freed by snd_soc_unregister_component,
*/
int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file);
-int snd_sof_complete_pipeline(struct device *dev,
+int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget);
-int sof_load_pipeline_ipc(struct device *dev,
+int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r);
int sof_pipeline_core_enable(struct snd_sof_dev *sdev,
@@ -246,8 +246,8 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params);
/* PM */
-int sof_set_up_pipelines(struct device *dev, bool verify);
-int sof_tear_down_pipelines(struct device *dev, bool verify);
+int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify);
+int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify);
int sof_set_hw_params_upon_resume(struct device *dev);
bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev);
bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 534f004f6162..6a0dbd4487c0 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1690,11 +1690,10 @@ err:
/*
* Pipeline Topology
*/
-int sof_load_pipeline_ipc(struct device *dev,
+int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r)
{
- struct snd_sof_dev *sdev = dev_get_drvdata(dev);
int ret = sof_core_enable(sdev, pipeline->core);
if (ret < 0)
@@ -1703,7 +1702,7 @@ int sof_load_pipeline_ipc(struct device *dev,
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), r, sizeof(*r));
if (ret < 0)
- dev_err(dev, "error: load pipeline ipc failure\n");
+ dev_err(sdev->dev, "error: load pipeline ipc failure\n");
return ret;
}
@@ -2514,6 +2513,15 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
/* power down the pipeline schedule core */
pipeline = swidget->private;
+
+ /*
+ * Runtime PM should still function normally if topology loading fails and
+ * it's components are unloaded. Do not power down the primary core so that the
+ * CTX_SAVE IPC can succeed during runtime suspend.
+ */
+ if (pipeline->core == SOF_DSP_PRIMARY_CORE)
+ break;
+
ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core);
if (ret < 0)
dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
@@ -3373,15 +3381,14 @@ err:
return ret;
}
-int snd_sof_complete_pipeline(struct device *dev,
+int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget)
{
- struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct sof_ipc_pipe_ready ready;
struct sof_ipc_reply reply;
int ret;
- dev_dbg(dev, "tplg: complete pipeline %s id %d\n",
+ dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n",
swidget->widget->name, swidget->comp_id);
memset(&ready, 0, sizeof(ready));
@@ -3460,13 +3467,13 @@ static int sof_complete(struct snd_soc_component *scomp)
/* verify topology components loading including dynamic pipelines */
if (sof_core_debug & SOF_DBG_VERIFY_TPLG) {
- ret = sof_set_up_pipelines(scomp->dev, true);
+ ret = sof_set_up_pipelines(sdev, true);
if (ret < 0) {
dev_err(sdev->dev, "error: topology verification failed %d\n", ret);
return ret;
}
- ret = sof_tear_down_pipelines(scomp->dev, true);
+ ret = sof_tear_down_pipelines(sdev, true);
if (ret < 0) {
dev_err(sdev->dev, "error: topology tear down pipelines failed %d\n", ret);
return ret;
@@ -3474,7 +3481,7 @@ static int sof_complete(struct snd_soc_component *scomp)
}
/* set up static pipelines */
- return sof_set_up_pipelines(scomp->dev, false);
+ return sof_set_up_pipelines(sdev, false);
}
/* manifest - optional to inform component of manifest */