diff options
| -rw-r--r-- | Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 6 | ||||
| -rw-r--r-- | sound/soc/codecs/sta529.c | 69 | ||||
| -rw-r--r-- | sound/soc/codecs/sti-sas.c | 84 | ||||
| -rw-r--r-- | sound/soc/stm/stm32_sai.c | 2 | ||||
| -rw-r--r-- | sound/soc/stm/stm32_sai.h | 2 | ||||
| -rw-r--r-- | sound/soc/stm/stm32_sai_sub.c | 153 | ||||
| -rw-r--r-- | sound/soc/stm/stm32_spdifrx.c | 7 | ||||
| -rw-r--r-- | sound/soc/sunxi/sun4i-codec.c | 71 | ||||
| -rw-r--r-- | sound/soc/sunxi/sun8i-codec.c | 23 | 
9 files changed, 262 insertions, 155 deletions
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index b1acc1a256ba..f301cdf0b7e6 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -45,6 +45,12 @@ SAI subnodes Optional properties:  	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 660734359bf3..2881a0f7bb39 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 62c618765224..7316c80b8179 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 d743b7dd52fb..f22654253c43 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 bb062e70de63..f25422174909 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 08583b958430..cfeb219e1d78 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 b9bdefcd3e10..373df4f24be1 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 886281673972..9a3cb7704810 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 7a15df924316..fb37dd927e33 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);  | 
