Merge remote-tracking branches 'asoc/topic/sta529', 'asoc/topic/sti-sas', 'asoc/topic/stm32', 'asoc/topic/sun4i' and 'asoc/topic/sun8i' into asoc-next
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index b1acc1a..f301cdf 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -45,6 +45,12 @@
This property sets SAI sub-block as slave of another SAI sub-block.
Must contain the phandle and index of the sai sub-block providing
the synchronization.
+ - st,iec60958: support S/PDIF IEC6958 protocol for playback
+ IEC60958 protocol is not available for capture.
+ By default, custom protocol is assumed, meaning that protocol is
+ configured according to protocol defined in related DAI link node,
+ such as i2s, left justified, right justified, dsp and pdm protocols.
+ Note: ac97 protocol is not supported by SAI driver
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 6607343..2881a0f 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -151,28 +151,28 @@ static const struct snd_kcontrol_new sta529_snd_controls[] = {
SOC_ENUM("PWM Select", pwm_src),
};
-static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
+static int sta529_set_bias_level(struct snd_soc_component *component, enum
snd_soc_bias_level level)
{
- struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
+ struct sta529 *sta529 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
- snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK,
+ snd_soc_component_update_bits(component, STA529_FFXCFG0, POWER_CNTLMSAK,
POWER_UP);
- snd_soc_update_bits(codec, STA529_MISC, FFX_CLK_MSK,
+ snd_soc_component_update_bits(component, STA529_MISC, FFX_CLK_MSK,
FFX_CLK_ENB);
break;
case SND_SOC_BIAS_STANDBY:
- if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
+ if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
regcache_sync(sta529->regmap);
- snd_soc_update_bits(codec, STA529_FFXCFG0,
+ snd_soc_component_update_bits(component, STA529_FFXCFG0,
POWER_CNTLMSAK, POWER_STDBY);
/* Making FFX output to zero */
- snd_soc_update_bits(codec, STA529_FFXCFG0, FFX_MASK,
+ snd_soc_component_update_bits(component, STA529_FFXCFG0, FFX_MASK,
FFX_OFF);
- snd_soc_update_bits(codec, STA529_MISC, FFX_CLK_MSK,
+ snd_soc_component_update_bits(component, STA529_MISC, FFX_CLK_MSK,
FFX_CLK_DIS);
break;
case SND_SOC_BIAS_OFF:
@@ -187,7 +187,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
+ struct snd_soc_component *component = dai->component;
int pdata, play_freq_val, record_freq_val;
int bclk_to_fs_ratio;
@@ -205,7 +205,7 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
bclk_to_fs_ratio = 2;
break;
default:
- dev_err(codec->dev, "Unsupported format\n");
+ dev_err(component->dev, "Unsupported format\n");
return -EINVAL;
}
@@ -228,23 +228,23 @@ static int sta529_hw_params(struct snd_pcm_substream *substream,
record_freq_val = 0;
break;
default:
- dev_err(codec->dev, "Unsupported rate\n");
+ dev_err(component->dev, "Unsupported rate\n");
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- snd_soc_update_bits(codec, STA529_S2PCFG1, PDATA_LEN_MSK,
+ snd_soc_component_update_bits(component, STA529_S2PCFG1, PDATA_LEN_MSK,
pdata << 6);
- snd_soc_update_bits(codec, STA529_S2PCFG1, BCLK_TO_FS_MSK,
+ snd_soc_component_update_bits(component, STA529_S2PCFG1, BCLK_TO_FS_MSK,
bclk_to_fs_ratio << 4);
- snd_soc_update_bits(codec, STA529_MISC, PLAY_FREQ_RANGE_MSK,
+ snd_soc_component_update_bits(component, STA529_MISC, PLAY_FREQ_RANGE_MSK,
play_freq_val << 4);
} else {
- snd_soc_update_bits(codec, STA529_P2SCFG1, PDATA_LEN_MSK,
+ snd_soc_component_update_bits(component, STA529_P2SCFG1, PDATA_LEN_MSK,
pdata << 6);
- snd_soc_update_bits(codec, STA529_P2SCFG1, BCLK_TO_FS_MSK,
+ snd_soc_component_update_bits(component, STA529_P2SCFG1, BCLK_TO_FS_MSK,
bclk_to_fs_ratio << 4);
- snd_soc_update_bits(codec, STA529_MISC, CAP_FREQ_RANGE_MSK,
+ snd_soc_component_update_bits(component, STA529_MISC, CAP_FREQ_RANGE_MSK,
record_freq_val << 2);
}
@@ -258,14 +258,14 @@ static int sta529_mute(struct snd_soc_dai *dai, int mute)
if (mute)
val |= CODEC_MUTE_VAL;
- snd_soc_update_bits(dai->codec, STA529_FFXCFG0, AUDIO_MUTE_MSK, val);
+ snd_soc_component_update_bits(dai->component, STA529_FFXCFG0, AUDIO_MUTE_MSK, val);
return 0;
}
static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_component *component = codec_dai->component;
u8 mode = 0;
/* interface format */
@@ -283,7 +283,7 @@ static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
return -EINVAL;
}
- snd_soc_update_bits(codec, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
+ snd_soc_component_update_bits(component, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
return 0;
}
@@ -313,14 +313,15 @@ static struct snd_soc_dai_driver sta529_dai = {
.ops = &sta529_dai_ops,
};
-static const struct snd_soc_codec_driver sta529_codec_driver = {
- .set_bias_level = sta529_set_bias_level,
- .suspend_bias_off = true,
-
- .component_driver = {
- .controls = sta529_snd_controls,
- .num_controls = ARRAY_SIZE(sta529_snd_controls),
- },
+static const struct snd_soc_component_driver sta529_component_driver = {
+ .set_bias_level = sta529_set_bias_level,
+ .controls = sta529_snd_controls,
+ .num_controls = ARRAY_SIZE(sta529_snd_controls),
+ .suspend_bias_off = 1,
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
};
static const struct regmap_config sta529_regmap = {
@@ -354,21 +355,14 @@ static int sta529_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, sta529);
- ret = snd_soc_register_codec(&i2c->dev,
- &sta529_codec_driver, &sta529_dai, 1);
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &sta529_component_driver, &sta529_dai, 1);
if (ret != 0)
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
return ret;
}
-static int sta529_i2c_remove(struct i2c_client *client)
-{
- snd_soc_unregister_codec(&client->dev);
-
- return 0;
-}
-
static const struct i2c_device_id sta529_i2c_id[] = {
{ "sta529", 0 },
{ }
@@ -387,7 +381,6 @@ static struct i2c_driver sta529_i2c_driver = {
.of_match_table = sta529_of_match,
},
.probe = sta529_i2c_probe,
- .remove = sta529_i2c_remove,
.id_table = sta529_i2c_id,
};
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 62c6187..7316c80 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -106,7 +106,7 @@ static int sti_sas_write_reg(void *context, unsigned int reg,
return status;
}
-static int sti_sas_init_sas_registers(struct snd_soc_codec *codec,
+static int sti_sas_init_sas_registers(struct snd_soc_component *component,
struct sti_sas_data *data)
{
int ret;
@@ -116,35 +116,35 @@ static int sti_sas_init_sas_registers(struct snd_soc_codec *codec,
*/
/* Initialise bi-phase formatter to disabled */
- ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_ENABLE_MASK, 0);
if (!ret)
/* Initialise bi-phase formatter idle value to 0 */
- ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_IDLE_MASK, 0);
if (ret < 0) {
- dev_err(codec->dev, "Failed to update SPDIF registers\n");
+ dev_err(component->dev, "Failed to update SPDIF registers\n");
return ret;
}
/* Init DAC configuration */
/* init configuration */
- ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_STANDBY_MASK,
STIH407_DAC_STANDBY_MASK);
if (!ret)
- ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_STANDBY_ANA_MASK,
STIH407_DAC_STANDBY_ANA_MASK);
if (!ret)
- ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_SOFTMUTE_MASK,
STIH407_DAC_SOFTMUTE_MASK);
if (ret < 0) {
- dev_err(codec->dev, "Failed to update DAC registers\n");
+ dev_err(component->dev, "Failed to update DAC registers\n");
return ret;
}
@@ -158,7 +158,7 @@ static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
/* Sanity check only */
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
- dev_err(dai->codec->dev,
+ dev_err(dai->component->dev,
"%s: ERROR: Unsupporter master mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
@@ -183,14 +183,14 @@ static const struct snd_soc_dapm_route stih407_sas_route[] = {
static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
{
- struct snd_soc_codec *codec = dai->codec;
+ struct snd_soc_component *component = dai->component;
if (mute) {
- return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_SOFTMUTE_MASK,
STIH407_DAC_SOFTMUTE_MASK);
} else {
- return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
+ return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
STIH407_DAC_SOFTMUTE_MASK,
0);
}
@@ -203,7 +203,7 @@ static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
- dev_err(dai->codec->dev,
+ dev_err(dai->component->dev,
"%s: ERROR: Unsupporter master mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
@@ -221,19 +221,19 @@ static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
+ struct snd_soc_component *component = dai->component;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_ENABLE_MASK,
SPDIF_BIPHASE_ENABLE_MASK);
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
+ return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
SPDIF_BIPHASE_ENABLE_MASK,
0);
default:
@@ -260,8 +260,8 @@ static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = dai->codec;
- struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+ struct snd_soc_component *component = dai->component;
+ struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
if (dir == SND_SOC_CLOCK_OUT)
return 0;
@@ -285,20 +285,20 @@ static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
static int sti_sas_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
- struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+ struct snd_soc_component *component = dai->component;
+ struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
struct snd_pcm_runtime *runtime = substream->runtime;
switch (dai->id) {
case STI_SAS_DAI_SPDIF_OUT:
if ((drvdata->spdif.mclk / runtime->rate) != 128) {
- dev_err(codec->dev, "unexpected mclk-fs ratio\n");
+ dev_err(component->dev, "unexpected mclk-fs ratio\n");
return -EINVAL;
}
break;
case STI_SAS_DAI_ANALOG_OUT:
if ((drvdata->dac.mclk / runtime->rate) != 256) {
- dev_err(codec->dev, "unexpected mclk-fs ratio\n");
+ dev_err(component->dev, "unexpected mclk-fs ratio\n");
return -EINVAL;
}
break;
@@ -375,29 +375,33 @@ static struct snd_soc_dai_driver sti_sas_dai[] = {
};
#ifdef CONFIG_PM_SLEEP
-static int sti_sas_resume(struct snd_soc_codec *codec)
+static int sti_sas_resume(struct snd_soc_component *component)
{
- struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+ struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
- return sti_sas_init_sas_registers(codec, drvdata);
+ return sti_sas_init_sas_registers(component, drvdata);
}
#else
#define sti_sas_resume NULL
#endif
-static int sti_sas_codec_probe(struct snd_soc_codec *codec)
+static int sti_sas_component_probe(struct snd_soc_component *component)
{
- struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
+ struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
int ret;
- ret = sti_sas_init_sas_registers(codec, drvdata);
+ ret = sti_sas_init_sas_registers(component, drvdata);
return ret;
}
-static struct snd_soc_codec_driver sti_sas_driver = {
- .probe = sti_sas_codec_probe,
- .resume = sti_sas_resume,
+static struct snd_soc_component_driver sti_sas_driver = {
+ .probe = sti_sas_component_probe,
+ .resume = sti_sas_resume,
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
};
static const struct of_device_id sti_sas_dev_match[] = {
@@ -452,34 +456,26 @@ static int sti_sas_driver_probe(struct platform_device *pdev)
sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
/* Set dapms*/
- sti_sas_driver.component_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
- sti_sas_driver.component_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
+ sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
+ sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
- sti_sas_driver.component_driver.dapm_routes = drvdata->dev_data->dapm_routes;
- sti_sas_driver.component_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
+ sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
+ sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
/* Store context */
dev_set_drvdata(&pdev->dev, drvdata);
- return snd_soc_register_codec(&pdev->dev, &sti_sas_driver,
+ return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
sti_sas_dai,
ARRAY_SIZE(sti_sas_dai));
}
-static int sti_sas_driver_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_codec(&pdev->dev);
-
- return 0;
-}
-
static struct platform_driver sti_sas_platform_driver = {
.driver = {
.name = "sti-sas-codec",
.of_match_table = sti_sas_dev_match,
},
.probe = sti_sas_driver_probe,
- .remove = sti_sas_driver_remove,
};
module_platform_driver(sti_sas_platform_driver);
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d743b7d..f226542 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -30,10 +30,12 @@
static const struct stm32_sai_conf stm32_sai_conf_f4 = {
.version = SAI_STM32F4,
+ .has_spdif = false,
};
static const struct stm32_sai_conf stm32_sai_conf_h7 = {
.version = SAI_STM32H7,
+ .has_spdif = true,
};
static const struct of_device_id stm32_sai_ids[] = {
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index bb062e7..f254221 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -248,9 +248,11 @@ enum stm32_sai_version {
/**
* struct stm32_sai_conf - SAI configuration
* @version: SAI version
+ * @has_spdif: SAI S/PDIF support flag
*/
struct stm32_sai_conf {
int version;
+ bool has_spdif;
};
/**
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 08583b9..cfeb219 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -23,6 +23,7 @@
#include <linux/of_platform.h>
#include <linux/regmap.h>
+#include <sound/asoundef.h>
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
@@ -30,6 +31,7 @@
#include "stm32_sai.h"
#define SAI_FREE_PROTOCOL 0x0
+#define SAI_SPDIF_PROTOCOL 0x1
#define SAI_SLOT_SIZE_AUTO 0x0
#define SAI_SLOT_SIZE_16 0x1
@@ -59,8 +61,13 @@
#define SAI_SYNC_INTERNAL 0x1
#define SAI_SYNC_EXTERNAL 0x2
+#define STM_SAI_PROTOCOL_IS_SPDIF(ip) ((ip)->spdif)
+#define STM_SAI_HAS_SPDIF(x) ((x)->pdata->conf->has_spdif)
#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+#define SAI_IEC60958_BLOCK_FRAMES 192
+#define SAI_IEC60958_STATUS_BYTES 24
+
/**
* struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
* @pdev: device data pointer
@@ -78,6 +85,7 @@
* @id: SAI sub block id corresponding to sub-block A or B
* @dir: SAI block direction (playback or capture). set at init
* @master: SAI block mode flag. (true=master, false=slave) set at init
+ * @spdif: SAI S/PDIF iec60958 mode flag. set at init
* @fmt: SAI block format. relevant only for custom protocols. set at init
* @sync: SAI block synchronization mode. (none, internal or external)
* @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
@@ -87,6 +95,8 @@
* @slot_width: rx or tx slot width in bits
* @slot_mask: rx or tx active slots mask. set at init or at runtime
* @data_size: PCM data width. corresponds to PCM substream width.
+ * @spdif_frm_cnt: S/PDIF playback frame counter
+ * @spdif_status_bits: S/PDIF status bits
*/
struct stm32_sai_sub_data {
struct platform_device *pdev;
@@ -104,6 +114,7 @@ struct stm32_sai_sub_data {
unsigned int id;
int dir;
bool master;
+ bool spdif;
int fmt;
int sync;
int synco;
@@ -113,6 +124,8 @@ struct stm32_sai_sub_data {
int slot_width;
int slot_mask;
int data_size;
+ unsigned int spdif_frm_cnt;
+ unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES];
};
enum stm32_sai_fifo_th {
@@ -171,6 +184,10 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
}
}
+static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = {
+ 0, 0, 0, IEC958_AES3_CON_FS_48000,
+};
+
static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
.reg_bits = 32,
.reg_stride = 4,
@@ -277,6 +294,11 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int slotr, slotr_mask, slot_size;
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ dev_warn(cpu_dai->dev, "Slot setting relevant only for TDM\n");
+ return 0;
+ }
+
dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n",
tx_mask, rx_mask, slots, slot_width);
@@ -326,8 +348,17 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
- cr1_mask = SAI_XCR1_PRTCFG_MASK;
- cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+ /* Do not generate master by default */
+ cr1 = SAI_XCR1_NODIV;
+ cr1_mask = SAI_XCR1_NODIV;
+
+ cr1_mask |= SAI_XCR1_PRTCFG_MASK;
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ cr1 |= SAI_XCR1_PRTCFG_SET(SAI_SPDIF_PROTOCOL);
+ goto conf_update;
+ }
+
+ cr1 |= SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
/* SCK active high for all protocols */
@@ -409,10 +440,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
cr1_mask |= SAI_XCR1_SLAVE;
- /* do not generate master by default */
- cr1 |= SAI_XCR1_NODIV;
- cr1_mask |= SAI_XCR1_NODIV;
-
+conf_update:
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
if (ret < 0) {
dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
@@ -478,6 +506,12 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
SAI_XCR2_FFLUSH |
SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
+ /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ sai->spdif_frm_cnt = 0;
+ return 0;
+ }
+
/* Mode, data format and channel config */
cr1_mask = SAI_XCR1_DS_MASK;
switch (params_format(params)) {
@@ -592,13 +626,14 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
int cr1, mask, div = 0;
int sai_clk_rate, mclk_ratio, den, ret;
int version = sai->pdata->conf->version;
+ unsigned int rate = params_rate(params);
if (!sai->mclk_rate) {
dev_err(cpu_dai->dev, "Mclk rate is null\n");
return -EINVAL;
}
- if (!(params_rate(params) % 11025))
+ if (!(rate % 11025))
clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k);
else
clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
@@ -623,24 +658,28 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
* MCKDIV = sai_ck / (frl x ws) (NOMCK=1)
* Note: NOMCK/NODIV correspond to same bit.
*/
- if (sai->mclk_rate) {
- mclk_ratio = sai->mclk_rate / params_rate(params);
- if (mclk_ratio != 256) {
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ div = DIV_ROUND_CLOSEST(sai_clk_rate,
+ (params_rate(params) * 128));
+ } else {
+ if (sai->mclk_rate) {
+ mclk_ratio = sai->mclk_rate / rate;
if (mclk_ratio == 512) {
mask = SAI_XCR1_OSR;
cr1 = SAI_XCR1_OSR;
- } else {
+ } else if (mclk_ratio != 256) {
dev_err(cpu_dai->dev,
"Wrong mclk ratio %d\n",
mclk_ratio);
return -EINVAL;
}
+ div = DIV_ROUND_CLOSEST(sai_clk_rate,
+ sai->mclk_rate);
+ } else {
+ /* mclk-fs not set, master clock not active */
+ den = sai->fs_length * params_rate(params);
+ div = DIV_ROUND_CLOSEST(sai_clk_rate, den);
}
- div = DIV_ROUND_CLOSEST(sai_clk_rate, sai->mclk_rate);
- } else {
- /* mclk-fs not set, master clock not active. NOMCK=1 */
- den = sai->fs_length * params_rate(params);
- div = DIV_ROUND_CLOSEST(sai_clk_rate, den);
}
}
@@ -670,10 +709,12 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream,
sai->data_size = params_width(params);
- ret = stm32_sai_set_slots(cpu_dai);
- if (ret < 0)
- return ret;
- stm32_sai_set_frame(cpu_dai);
+ if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ ret = stm32_sai_set_slots(cpu_dai);
+ if (ret < 0)
+ return ret;
+ stm32_sai_set_frame(cpu_dai);
+ }
ret = stm32_sai_set_config(cpu_dai, substream, params);
if (ret)
@@ -723,6 +764,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
(unsigned int)~SAI_XCR1_DMAEN);
if (ret < 0)
dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
+ sai->spdif_frm_cnt = 0;
break;
default:
return -EINVAL;
@@ -776,6 +820,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
sai->synco, sai->synci);
}
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
+ memcpy(sai->spdif_status_bits, default_status_bits,
+ sizeof(default_status_bits));
+
cr1_mask |= SAI_XCR1_SYNCEN_MASK;
cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
@@ -792,6 +840,42 @@ static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
.shutdown = stm32_sai_shutdown,
};
+static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream,
+ int channel, unsigned long hwoff,
+ void *buf, unsigned long bytes)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+ int *ptr = (int *)(runtime->dma_area + hwoff +
+ channel * (runtime->dma_bytes / runtime->channels));
+ ssize_t cnt = bytes_to_samples(runtime, bytes);
+ unsigned int frm_cnt = sai->spdif_frm_cnt;
+ unsigned int byte;
+ unsigned int mask;
+
+ do {
+ *ptr = ((*ptr >> 8) & 0x00ffffff);
+
+ /* Set channel status bit */
+ byte = frm_cnt >> 3;
+ mask = 1 << (frm_cnt - (byte << 3));
+ if (sai->spdif_status_bits[byte] & mask)
+ *ptr |= 0x04000000;
+ ptr++;
+
+ if (!(cnt % 2))
+ frm_cnt++;
+
+ if (frm_cnt == SAI_IEC60958_BLOCK_FRAMES)
+ frm_cnt = 0;
+ } while (--cnt);
+ sai->spdif_frm_cnt = frm_cnt;
+
+ return 0;
+}
+
static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
.buffer_bytes_max = 8 * PAGE_SIZE,
@@ -842,8 +926,14 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai[] = {
};
static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
- .pcm_hardware = &stm32_sai_pcm_hw,
- .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .pcm_hardware = &stm32_sai_pcm_hw,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+};
+
+static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config_spdif = {
+ .pcm_hardware = &stm32_sai_pcm_hw,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .process = stm32_sai_pcm_process_spdif,
};
static const struct snd_soc_component_driver stm32_component = {
@@ -900,6 +990,18 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
return -EINVAL;
}
+ /* Get spdif iec60958 property */
+ sai->spdif = false;
+ if (of_get_property(np, "st,iec60958", NULL)) {
+ if (!STM_SAI_HAS_SPDIF(sai) ||
+ sai->dir == SNDRV_PCM_STREAM_CAPTURE) {
+ dev_err(&pdev->dev, "S/PDIF IEC60958 not supported\n");
+ return -EINVAL;
+ }
+ sai->spdif = true;
+ sai->master = true;
+ }
+
/* Get synchronization property */
args.np = NULL;
ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
@@ -999,6 +1101,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
{
struct stm32_sai_sub_data *sai;
const struct of_device_id *of_id;
+ const struct snd_dmaengine_pcm_config *conf = &stm32_sai_pcm_config;
int ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
@@ -1039,8 +1142,10 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
- &stm32_sai_pcm_config, 0);
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
+ conf = &stm32_sai_pcm_config_spdif;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
if (ret) {
dev_err(&pdev->dev, "Could not register pcm dma\n");
return ret;
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index b9bdefc..373df4f 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -819,7 +819,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = {
static struct snd_soc_dai_driver stm32_spdifrx_dai[] = {
{
- .name = "spdifrx-capture-cpu-dai",
.probe = stm32_spdifrx_dai_probe,
.capture = {
.stream_name = "CPU-Capture",
@@ -858,8 +857,8 @@ static const struct of_device_id stm32_spdifrx_ids[] = {
{}
};
-static int stm_spdifrx_parse_of(struct platform_device *pdev,
- struct stm32_spdifrx_data *spdifrx)
+static int stm32_spdifrx_parse_of(struct platform_device *pdev,
+ struct stm32_spdifrx_data *spdifrx)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id;
@@ -914,7 +913,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, spdifrx);
- ret = stm_spdifrx_parse_of(pdev, spdifrx);
+ ret = stm32_spdifrx_parse_of(pdev, spdifrx);
if (ret)
return ret;
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 8862816..9a3cb77 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -792,15 +792,17 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
{ "Mic1", NULL, "VMIC" },
};
-static const struct snd_soc_codec_driver sun4i_codec_codec = {
- .component_driver = {
- .controls = sun4i_codec_controls,
- .num_controls = ARRAY_SIZE(sun4i_codec_controls),
- .dapm_widgets = sun4i_codec_codec_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
- .dapm_routes = sun4i_codec_codec_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
- },
+static const struct snd_soc_component_driver sun4i_codec_codec = {
+ .controls = sun4i_codec_controls,
+ .num_controls = ARRAY_SIZE(sun4i_codec_controls),
+ .dapm_widgets = sun4i_codec_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets),
+ .dapm_routes = sun4i_codec_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
};
/*** sun6i Codec ***/
@@ -1098,15 +1100,17 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Right ADC", NULL, "Right ADC Mixer" },
};
-static const struct snd_soc_codec_driver sun6i_codec_codec = {
- .component_driver = {
- .controls = sun6i_codec_codec_widgets,
- .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
- .dapm_widgets = sun6i_codec_codec_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
- .dapm_routes = sun6i_codec_codec_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
- },
+static const struct snd_soc_component_driver sun6i_codec_codec = {
+ .controls = sun6i_codec_codec_widgets,
+ .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
+ .dapm_widgets = sun6i_codec_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
+ .dapm_routes = sun6i_codec_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
};
/* sun8i A23 codec */
@@ -1126,13 +1130,15 @@ static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
};
-static const struct snd_soc_codec_driver sun8i_a23_codec_codec = {
- .component_driver = {
- .controls = sun8i_a23_codec_codec_controls,
- .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
- .dapm_widgets = sun8i_a23_codec_codec_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
- },
+static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
+ .controls = sun8i_a23_codec_codec_controls,
+ .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
+ .dapm_widgets = sun8i_a23_codec_codec_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
};
static const struct snd_soc_component_driver sun4i_codec_component = {
@@ -1450,7 +1456,7 @@ static const struct regmap_config sun8i_v3s_codec_regmap_config = {
struct sun4i_codec_quirks {
const struct regmap_config *regmap_config;
- const struct snd_soc_codec_driver *codec;
+ const struct snd_soc_component_driver *codec;
struct snd_soc_card * (*create_card)(struct device *dev);
struct reg_field reg_adc_fifoc; /* used for regmap_field */
unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
@@ -1657,7 +1663,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
scodec->capture_dma_data.maxburst = 8;
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
+ ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
&sun4i_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our codec\n");
@@ -1669,20 +1675,20 @@ static int sun4i_codec_probe(struct platform_device *pdev)
&dummy_cpu_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our DAI\n");
- goto err_unregister_codec;
+ goto err_assert_reset;
}
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret) {
dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
- goto err_unregister_codec;
+ goto err_assert_reset;
}
card = quirks->create_card(&pdev->dev);
if (IS_ERR(card)) {
ret = PTR_ERR(card);
dev_err(&pdev->dev, "Failed to create our card\n");
- goto err_unregister_codec;
+ goto err_assert_reset;
}
snd_soc_card_set_drvdata(card, scodec);
@@ -1690,13 +1696,11 @@ static int sun4i_codec_probe(struct platform_device *pdev)
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "Failed to register our card\n");
- goto err_unregister_codec;
+ goto err_assert_reset;
}
return 0;
-err_unregister_codec:
- snd_soc_unregister_codec(&pdev->dev);
err_assert_reset:
if (scodec->rst)
reset_control_assert(scodec->rst);
@@ -1711,7 +1715,6 @@ static int sun4i_codec_remove(struct platform_device *pdev)
struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
snd_soc_unregister_card(card);
- snd_soc_unregister_codec(&pdev->dev);
if (scodec->rst)
reset_control_assert(scodec->rst);
clk_disable_unprepare(scodec->clk_apb);
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 7a15df9..fb37dd9 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -184,7 +184,7 @@ static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
+ struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
u32 value;
/* clock masters */
@@ -304,7 +304,7 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
+ struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
int sample_rate;
u8 bclk_div;
@@ -500,13 +500,15 @@ static struct snd_soc_dai_driver sun8i_codec_dai = {
.ops = &sun8i_codec_dai_ops,
};
-static const struct snd_soc_codec_driver sun8i_soc_codec = {
- .component_driver = {
- .dapm_widgets = sun8i_codec_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
- .dapm_routes = sun8i_codec_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
- },
+static const struct snd_soc_component_driver sun8i_soc_component = {
+ .dapm_widgets = sun8i_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
+ .dapm_routes = sun8i_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
};
static const struct regmap_config sun8i_codec_regmap_config = {
@@ -566,7 +568,7 @@ static int sun8i_codec_probe(struct platform_device *pdev)
goto err_pm_disable;
}
- ret = snd_soc_register_codec(&pdev->dev, &sun8i_soc_codec,
+ ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
&sun8i_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register codec\n");
@@ -594,7 +596,6 @@ static int sun8i_codec_remove(struct platform_device *pdev)
if (!pm_runtime_status_suspended(&pdev->dev))
sun8i_codec_runtime_suspend(&pdev->dev);
- snd_soc_unregister_codec(&pdev->dev);
clk_disable_unprepare(scodec->clk_module);
clk_disable_unprepare(scodec->clk_bus);