ASoC: Fixes for v4.14

I've been quite lax in sending these due to conference season but here's
 a fairly large collection of ASoC updates.  The one thing that's not
 device specific is Takashi's fix for races between delayed work and PCM
 destruction, otherwise everything is specific to an individual device.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAlnx7QsTHGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0H6gB/9Kg6nfaNQDH3ScDO/0KXJevvc9DZUG
 1Mgb6o866WQKVKwHL4/7PeUnwpaAh/Dr5KN7bFS7nImrZlHiJfv64Cmrrca+VMwa
 O9SnAxbzMDN1MXV3uLDlmd5jJ2EETGnSSo31gjyOuFAmvWRYhtvN4QtoLRBQYYJ9
 A32JAKYXKpdjYlIq8sssf1Ey9OcReho3klAc578Yw5qsuHTsB8yJ5SNy0YgmobCm
 rNs+LcY9fBPQxY1nVW5iJ3L8oR9RXlUOdZy1I220i0q6+ku1nynbh64V8m7fFGmp
 KQLIVvH8JGlqaGBidU47C3vwEnUN88y0+98i9dF4Hc26E+Ml3YNyL/z6
 =TVgt
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAloGGn8THGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0BAsB/9tbgkbKpUVsWEQOTXDtz1VARb5+zxJ
 zMRmYGdcfV+au4pmo07NwcxwFDqeLxmsd7dRM+eoPJGbxklD9rr9eL9tZiO1TI0B
 jla9eyKO1aRjCD8dEDsQJEUjDGWWbrpYRvFjlTmYW5cf1vgE9Ta7QtwBN+mK+Ssn
 1PtwfHg5lDffoCMGOgu/5Kah4QhzAIU1mM4Vg77VgsuScZEw5qMYJUncfkdsH6M5
 JiQJpOQR/wNL4/IETodjhFzqhi9vlUvDEfmATNMpHMdHA//erUbphUt2bAjqVauM
 zKTFTSN1vvW1GirJyxz4NiHXQ6upbpZPMDcPsfOzJhHw82OAwx/pp1QT
 =bBtM
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v4.14-rc6' into asoc-linus

ASoC: Fixes for v4.14

I've been quite lax in sending these due to conference season but here's
a fairly large collection of ASoC updates.  The one thing that's not
device specific is Takashi's fix for races between delayed work and PCM
destruction, otherwise everything is specific to an individual device.

# gpg: Signature made Thu 26 Oct 2017 15:11:23 BST
# gpg:                using RSA key ADE668AA675718B59FE29FEA24D68B725D5487D0
# gpg:                issuer "broonie@kernel.org"
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>" [unknown]
# gpg:                 aka "Mark Brown <broonie@debian.org>" [unknown]
# gpg:                 aka "Mark Brown <broonie@kernel.org>" [unknown]
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>" [unknown]
# gpg:                 aka "Mark Brown <broonie@linaro.org>" [unknown]
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 3F25 68AA C269 98F9 E813  A1C5 C3F4 36CA 30F5 D8EB
#      Subkey fingerprint: ADE6 68AA 6757 18B5 9FE2  9FEA 24D6 8B72 5D54 87D0
This commit is contained in:
Mark Brown 2017-11-10 21:30:27 +00:00
commit 16a077e17c
15 changed files with 85 additions and 100 deletions

View File

@ -2115,7 +2115,7 @@ static void max98090_pll_work(struct work_struct *work)
if (!snd_soc_codec_is_active(codec)) if (!snd_soc_codec_is_active(codec))
return; return;
dev_info(codec->dev, "PLL unlocked\n"); dev_info_ratelimited(codec->dev, "PLL unlocked\n");
/* Toggle shutdown OFF then ON */ /* Toggle shutdown OFF then ON */
snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,

View File

@ -104,7 +104,7 @@
#define CDC_A_MICB_1_VAL (0xf141) #define CDC_A_MICB_1_VAL (0xf141)
#define MICB_MIN_VAL 1600 #define MICB_MIN_VAL 1600
#define MICB_STEP_SIZE 50 #define MICB_STEP_SIZE 50
#define MICB_VOLTAGE_REGVAL(v) ((v - MICB_MIN_VAL)/MICB_STEP_SIZE) #define MICB_VOLTAGE_REGVAL(v) (((v - MICB_MIN_VAL)/MICB_STEP_SIZE) << 3)
#define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3) #define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3)
#define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3) #define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3)
#define MICB_1_VAL_MICB_OUT_VAL_V1P80V ((0x4) << 3) #define MICB_1_VAL_MICB_OUT_VAL_V1P80V ((0x4) << 3)
@ -349,8 +349,9 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
| MICB_1_CTL_EXT_PRECHARG_EN_ENABLE); | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
if (wcd->micbias_mv) { if (wcd->micbias_mv) {
snd_soc_write(codec, CDC_A_MICB_1_VAL, snd_soc_update_bits(codec, CDC_A_MICB_1_VAL,
MICB_VOLTAGE_REGVAL(wcd->micbias_mv)); MICB_1_VAL_MICB_OUT_VAL_MASK,
MICB_VOLTAGE_REGVAL(wcd->micbias_mv));
/* /*
* Special headset needs MICBIAS as 2.7V so wait for * Special headset needs MICBIAS as 2.7V so wait for
* 50 msec for the MICBIAS to reach 2.7 volts. * 50 msec for the MICBIAS to reach 2.7 volts.

View File

@ -238,7 +238,7 @@ static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
static const struct soc_enum rx2_mix1_inp_enum[] = { static const struct soc_enum rx2_mix1_inp_enum[] = {
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text), SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text),
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B2_CTL, 0, 6, rx_mix1_text),
}; };
/* RX2 MIX2 */ /* RX2 MIX2 */
@ -249,7 +249,7 @@ static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
static const struct soc_enum rx3_mix1_inp_enum[] = { static const struct soc_enum rx3_mix1_inp_enum[] = {
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text), SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text),
SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B2_CTL, 0, 6, rx_mix1_text),
}; };
/* DEC */ /* DEC */

View File

@ -101,64 +101,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
return 0; return 0;
} }
static int wm8998_in1mux_put(struct snd_kcontrol *kcontrol, static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = wm8998->core.arizona;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mux, inmode;
unsigned int mode_val, src_val;
mux = ucontrol->value.enumerated.item[0];
if (mux > 1)
return -EINVAL;
/* L and R registers have same shift and mask */
inmode = arizona->pdata.inmode[2 * mux];
src_val = mux << ARIZONA_IN1L_SRC_SHIFT;
if (inmode & ARIZONA_INMODE_SE)
src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
switch (arizona->pdata.inmode[0]) {
case ARIZONA_INMODE_DMIC:
if (mux)
mode_val = 0; /* B always analogue */
else
mode_val = 1 << ARIZONA_IN1_MODE_SHIFT;
snd_soc_update_bits(codec, ARIZONA_IN1L_CONTROL,
ARIZONA_IN1_MODE_MASK, mode_val);
/* IN1A is digital so L and R must change together */
/* src_val setting same for both registers */
snd_soc_update_bits(codec,
ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_IN1L_SRC_MASK |
ARIZONA_IN1L_SRC_SE_MASK, src_val);
snd_soc_update_bits(codec,
ARIZONA_ADC_DIGITAL_VOLUME_1R,
ARIZONA_IN1R_SRC_MASK |
ARIZONA_IN1R_SRC_SE_MASK, src_val);
break;
default:
/* both analogue */
snd_soc_update_bits(codec,
e->reg,
ARIZONA_IN1L_SRC_MASK |
ARIZONA_IN1L_SRC_SE_MASK,
src_val);
break;
}
return snd_soc_dapm_mux_update_power(dapm, kcontrol,
ucontrol->value.enumerated.item[0],
e, NULL);
}
static int wm8998_in2mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
@ -166,27 +109,38 @@ static int wm8998_in2mux_put(struct snd_kcontrol *kcontrol,
struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec); struct wm8998_priv *wm8998 = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = wm8998->core.arizona; struct arizona *arizona = wm8998->core.arizona;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int mode_reg, mode_index;
unsigned int mux, inmode, src_val, mode_val; unsigned int mux, inmode, src_val, mode_val;
mux = ucontrol->value.enumerated.item[0]; mux = ucontrol->value.enumerated.item[0];
if (mux > 1) if (mux > 1)
return -EINVAL; return -EINVAL;
inmode = arizona->pdata.inmode[1 + (2 * mux)]; switch (e->reg) {
case ARIZONA_ADC_DIGITAL_VOLUME_2L:
mode_reg = ARIZONA_IN2L_CONTROL;
mode_index = 1 + (2 * mux);
break;
default:
mode_reg = ARIZONA_IN1L_CONTROL;
mode_index = (2 * mux);
break;
}
inmode = arizona->pdata.inmode[mode_index];
if (inmode & ARIZONA_INMODE_DMIC) if (inmode & ARIZONA_INMODE_DMIC)
mode_val = 1 << ARIZONA_IN2_MODE_SHIFT; mode_val = 1 << ARIZONA_IN1_MODE_SHIFT;
else else
mode_val = 0; mode_val = 0;
src_val = mux << ARIZONA_IN2L_SRC_SHIFT; src_val = mux << ARIZONA_IN1L_SRC_SHIFT;
if (inmode & ARIZONA_INMODE_SE) if (inmode & ARIZONA_INMODE_SE)
src_val |= 1 << ARIZONA_IN2L_SRC_SE_SHIFT; src_val |= 1 << ARIZONA_IN1L_SRC_SE_SHIFT;
snd_soc_update_bits(codec, ARIZONA_IN2L_CONTROL, snd_soc_update_bits(codec, mode_reg, ARIZONA_IN1_MODE_MASK, mode_val);
ARIZONA_IN2_MODE_MASK, mode_val);
snd_soc_update_bits(codec, ARIZONA_ADC_DIGITAL_VOLUME_2L, snd_soc_update_bits(codec, e->reg,
ARIZONA_IN2L_SRC_MASK | ARIZONA_IN2L_SRC_SE_MASK, ARIZONA_IN1L_SRC_MASK | ARIZONA_IN1L_SRC_SE_MASK,
src_val); src_val);
return snd_soc_dapm_mux_update_power(dapm, kcontrol, return snd_soc_dapm_mux_update_power(dapm, kcontrol,
@ -216,14 +170,14 @@ static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum,
static const struct snd_kcontrol_new wm8998_in1mux[2] = { static const struct snd_kcontrol_new wm8998_in1mux[2] = {
SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum, SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum,
snd_soc_dapm_get_enum_double, wm8998_in1mux_put), snd_soc_dapm_get_enum_double, wm8998_inmux_put),
SOC_DAPM_ENUM_EXT("IN1R Mux", wm8998_in1muxr_enum, SOC_DAPM_ENUM_EXT("IN1R Mux", wm8998_in1muxr_enum,
snd_soc_dapm_get_enum_double, wm8998_in1mux_put), snd_soc_dapm_get_enum_double, wm8998_inmux_put),
}; };
static const struct snd_kcontrol_new wm8998_in2mux = static const struct snd_kcontrol_new wm8998_in2mux =
SOC_DAPM_ENUM_EXT("IN2 Mux", wm8998_in2mux_enum, SOC_DAPM_ENUM_EXT("IN2 Mux", wm8998_in2mux_enum,
snd_soc_dapm_get_enum_double, wm8998_in2mux_put); snd_soc_dapm_get_enum_double, wm8998_inmux_put);
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);

View File

@ -1982,8 +1982,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
GFP_KERNEL); GFP_KERNEL);
if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list || if (!mcasp->chconstr[SNDRV_PCM_STREAM_PLAYBACK].list ||
!mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) !mcasp->chconstr[SNDRV_PCM_STREAM_CAPTURE].list) {
return -ENOMEM; ret = -ENOMEM;
goto err;
}
ret = davinci_mcasp_set_ch_constraints(mcasp); ret = davinci_mcasp_set_ch_constraints(mcasp);
if (ret) if (ret)

View File

@ -160,7 +160,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
return ret; return ret;
} }
fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS; | SND_SOC_DAIFMT_CBS_CFS;
ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt); ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
@ -173,8 +173,8 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = 48000; rate->min = rate->max = 48000;
channels->min = channels->max = 2; channels->min = channels->max = 2;
/* set SSP2 to 24-bit */ /* set SSP2 to 16-bit */
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
return 0; return 0;
} }

View File

@ -604,6 +604,8 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
codec = pcm->codec_dai->codec; codec = pcm->codec_dai->codec;
snprintf(jack_name, sizeof(jack_name),
"HDMI/DP, pcm=%d Jack", pcm->device);
err = snd_soc_card_jack_new(card, jack_name, err = snd_soc_card_jack_new(card, jack_name,
SND_JACK_AVOUT, &ctx->kabylake_hdmi[i], SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
NULL, 0); NULL, 0);

View File

@ -2382,7 +2382,7 @@ static int skl_tplg_get_token(struct device *dev,
case SKL_TKN_U32_MAX_MCPS: case SKL_TKN_U32_MAX_MCPS:
case SKL_TKN_U32_OBS: case SKL_TKN_U32_OBS:
case SKL_TKN_U32_IBS: case SKL_TKN_U32_IBS:
ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, dir, pin_index); ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
if (ret < 0) if (ret < 0)
return ret; return ret;

View File

@ -692,7 +692,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev)
if (!pm_runtime_status_suspended(&pdev->dev)) if (!pm_runtime_status_suspended(&pdev->dev))
i2s_runtime_suspend(&pdev->dev); i2s_runtime_suspend(&pdev->dev);
clk_disable_unprepare(i2s->mclk);
clk_disable_unprepare(i2s->hclk); clk_disable_unprepare(i2s->hclk);
return 0; return 0;

View File

@ -552,8 +552,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
} }
ret = clk_prepare_enable(i2s->op_clk); ret = clk_prepare_enable(i2s->op_clk);
if (ret) if (ret) {
clk_put(i2s->op_clk);
i2s->op_clk = NULL;
goto err; goto err;
}
i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
/* Over-ride the other's */ /* Over-ride the other's */
@ -1285,6 +1288,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
} }
} }
} }
quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pri_dai->addr = devm_ioremap_resource(&pdev->dev, res); pri_dai->addr = devm_ioremap_resource(&pdev->dev, res);

View File

@ -479,10 +479,10 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
} }
if (req_rate[0] % 48000 == 0) if (req_rate[0] % 48000 == 0)
adg->flags = AUDIO_OUT_48; adg->flags |= AUDIO_OUT_48;
if (of_get_property(np, "clkout-lr-asynchronous", NULL)) if (of_get_property(np, "clkout-lr-asynchronous", NULL))
adg->flags = LRCLK_ASYNC; adg->flags |= LRCLK_ASYNC;
/* /*
* This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC

View File

@ -1112,6 +1112,9 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
i = 0; i = 0;
for_each_child_of_node(node, np) { for_each_child_of_node(node, np) {
if (!of_device_is_available(np))
goto skip;
ssi = rsnd_ssi_get(priv, i); ssi = rsnd_ssi_get(priv, i);
snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
@ -1148,7 +1151,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
of_node_put(np); of_node_put(np);
goto rsnd_ssi_probe_done; goto rsnd_ssi_probe_done;
} }
skip:
i++; i++;
} }

View File

@ -2632,6 +2632,17 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
return ret; return ret;
} }
static void soc_pcm_private_free(struct snd_pcm *pcm)
{
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
struct snd_soc_platform *platform = rtd->platform;
/* need to sync the delayed work before releasing resources */
flush_delayed_work(&rtd->delayed_work);
if (platform->driver->pcm_free)
platform->driver->pcm_free(pcm);
}
/* create a new pcm */ /* create a new pcm */
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{ {
@ -2757,7 +2768,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
} }
} }
pcm->private_free = platform->driver->pcm_free; pcm->private_free = soc_pcm_private_free;
out: out:
dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
(rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,

View File

@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
} }
/* reset */ /* reset */
rst = reset_control_get_exclusive(&pdev->dev, NULL); rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (!IS_ERR(rst)) { if (!IS_ERR(rst)) {
reset_control_assert(rst); reset_control_assert(rst);
udelay(2); udelay(2);

View File

@ -184,7 +184,6 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
static irqreturn_t stm32_sai_isr(int irq, void *devid) static irqreturn_t stm32_sai_isr(int irq, void *devid)
{ {
struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
struct snd_pcm_substream *substream = sai->substream;
struct platform_device *pdev = sai->pdev; struct platform_device *pdev = sai->pdev;
unsigned int sr, imr, flags; unsigned int sr, imr, flags;
snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING; snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
SAI_XCLRFR_MASK); SAI_XCLRFR_MASK);
if (!sai->substream) {
dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
return IRQ_NONE;
}
if (flags & SAI_XIMR_OVRUDRIE) { if (flags & SAI_XIMR_OVRUDRIE) {
dev_err(&pdev->dev, "IRQ %s\n", dev_err(&pdev->dev, "IRQ %s\n",
STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun"); STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
} }
if (status != SNDRV_PCM_STATE_RUNNING) { if (status != SNDRV_PCM_STATE_RUNNING) {
snd_pcm_stream_lock(substream); snd_pcm_stream_lock(sai->substream);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(substream); snd_pcm_stream_unlock(sai->substream);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -442,12 +446,16 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
{ {
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int cr1, cr1_mask, ret; int cr1, cr1_mask, ret;
int fth = STM_SAI_FIFO_TH_HALF;
/* FIFO config */ /*
* DMA bursts increment is set to 4 words.
* SAI fifo threshold is set to half fifo, to keep enough space
* for DMA incoming bursts.
*/
regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX, regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX,
SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth)); SAI_XCR2_FFLUSH |
SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
/* Mode, data format and channel config */ /* Mode, data format and channel config */
cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
@ -481,10 +489,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
return ret; return ret;
} }
/* DMA config */
sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32);
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&sai->dma_params);
return 0; return 0;
} }
@ -727,7 +731,12 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX); sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
sai->dma_params.maxburst = 1; /*
* DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice,
* as it allows bytes, half-word and words transfers. (See DMA fifos
* constraints).
*/
sai->dma_params.maxburst = 4;
/* Buswidth will be set by framework at runtime */ /* Buswidth will be set by framework at runtime */
sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;