Commit e8c768da authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/sta529', 'asoc/topic/sti-sas',...

Merge remote-tracking branches 'asoc/topic/sta529', 'asoc/topic/sti-sas', 'asoc/topic/stm32', 'asoc/topic/sun4i' and 'asoc/topic/sun8i' into asoc-next
......@@ -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/
......
......@@ -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,
};
......
......@@ -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);
......
......@@ -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[] = {
......
......@@ -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;
};
/**
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment