Merge remote-tracking branches 'asoc/topic/dpcm', 'asoc/topic/dwc', 'asoc/topic/fsl', 'asoc/topic/fsl-asrc' and 'asoc/topic/fsl-esai' into asoc-next
This commit is contained in:
Коммит
9764350d71
|
@ -25,6 +25,11 @@ Required properties:
|
|||
"mem" Peripheral access clock to access registers.
|
||||
"ipg" Peripheral clock to driver module.
|
||||
"asrck_<0-f>" Clock sources for input and output clock.
|
||||
"spba" The spba clock is required when ASRC is placed as a
|
||||
bus slave of the Shared Peripheral Bus and when two
|
||||
or more bus masters (CPU, DMA or DSP) try to access
|
||||
it. This property is optional depending on the SoC
|
||||
design.
|
||||
|
||||
- big-endian : If this property is absent, the little endian mode
|
||||
will be in use as default. Otherwise, the big endian
|
||||
|
|
|
@ -27,6 +27,11 @@ Required properties:
|
|||
derive HCK, SCK and FS.
|
||||
"fsys" The system clock derived from ahb clock used to
|
||||
derive HCK, SCK and FS.
|
||||
"spba" The spba clock is required when ESAI is placed as a
|
||||
bus slave of the Shared Peripheral Bus and when two
|
||||
or more bus masters (CPU, DMA or DSP) try to access
|
||||
it. This property is optional depending on the SoC
|
||||
design.
|
||||
|
||||
- fsl,fifo-depth : The number of elements in the transmit and receive
|
||||
FIFOs. This number is the maximum allowed value for
|
||||
|
|
|
@ -45,6 +45,11 @@ struct i2s_platform_data {
|
|||
u32 snd_fmts;
|
||||
u32 snd_rates;
|
||||
|
||||
#define DW_I2S_QUIRK_COMP_REG_OFFSET (1 << 0)
|
||||
unsigned int quirks;
|
||||
unsigned int i2s_reg_comp1;
|
||||
unsigned int i2s_reg_comp2;
|
||||
|
||||
void *play_dma_data;
|
||||
void *capture_dma_data;
|
||||
bool (*filter)(struct dma_chan *chan, void *slave);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <sound/designware_i2s.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -93,7 +94,12 @@ struct dw_i2s_dev {
|
|||
struct clk *clk;
|
||||
int active;
|
||||
unsigned int capability;
|
||||
unsigned int quirks;
|
||||
unsigned int i2s_reg_comp1;
|
||||
unsigned int i2s_reg_comp2;
|
||||
struct device *dev;
|
||||
u32 ccr;
|
||||
u32 xfer_resolution;
|
||||
|
||||
/* data related to DMA transfers b/w i2s and DMAC */
|
||||
union dw_i2s_snd_dma_data play_dma_data;
|
||||
|
@ -213,31 +219,58 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
|
||||
{
|
||||
u32 ch_reg, irq;
|
||||
struct i2s_clk_config_data *config = &dev->config;
|
||||
|
||||
|
||||
i2s_disable_channels(dev, stream);
|
||||
|
||||
for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
i2s_write_reg(dev->i2s_base, TCR(ch_reg),
|
||||
dev->xfer_resolution);
|
||||
i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
|
||||
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
||||
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
|
||||
i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
|
||||
} else {
|
||||
i2s_write_reg(dev->i2s_base, RCR(ch_reg),
|
||||
dev->xfer_resolution);
|
||||
i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
|
||||
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
||||
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
|
||||
i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
struct i2s_clk_config_data *config = &dev->config;
|
||||
u32 ccr, xfer_resolution, ch_reg, irq;
|
||||
int ret;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
config->data_width = 16;
|
||||
ccr = 0x00;
|
||||
xfer_resolution = 0x02;
|
||||
dev->ccr = 0x00;
|
||||
dev->xfer_resolution = 0x02;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
config->data_width = 24;
|
||||
ccr = 0x08;
|
||||
xfer_resolution = 0x04;
|
||||
dev->ccr = 0x08;
|
||||
dev->xfer_resolution = 0x04;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
config->data_width = 32;
|
||||
ccr = 0x10;
|
||||
xfer_resolution = 0x05;
|
||||
dev->ccr = 0x10;
|
||||
dev->xfer_resolution = 0x05;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -258,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
i2s_disable_channels(dev, substream->stream);
|
||||
dw_i2s_config(dev, substream->stream);
|
||||
|
||||
for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
i2s_write_reg(dev->i2s_base, TCR(ch_reg),
|
||||
xfer_resolution);
|
||||
i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
|
||||
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
||||
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
|
||||
i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
|
||||
} else {
|
||||
i2s_write_reg(dev->i2s_base, RCR(ch_reg),
|
||||
xfer_resolution);
|
||||
i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
|
||||
irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
||||
i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
|
||||
i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
|
||||
}
|
||||
}
|
||||
|
||||
i2s_write_reg(dev->i2s_base, CCR, ccr);
|
||||
i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
|
||||
|
||||
config->sample_rate = params_rate(params);
|
||||
|
||||
|
@ -394,6 +409,23 @@ static const struct snd_soc_component_driver dw_i2s_component = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dw_i2s_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (dw_dev->capability & DW_I2S_MASTER)
|
||||
clk_disable(dw_dev->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_i2s_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (dw_dev->capability & DW_I2S_MASTER)
|
||||
clk_enable(dw_dev->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_i2s_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -410,6 +442,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
|
|||
|
||||
if (dev->capability & DW_I2S_MASTER)
|
||||
clk_enable(dev->clk);
|
||||
|
||||
if (dai->playback_active)
|
||||
dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
if (dai->capture_active)
|
||||
dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -459,8 +496,8 @@ static int dw_configure_dai(struct dw_i2s_dev *dev,
|
|||
* Read component parameter registers to extract
|
||||
* the I2S block's configuration.
|
||||
*/
|
||||
u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
|
||||
u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
|
||||
u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
|
||||
u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2);
|
||||
u32 idx;
|
||||
|
||||
if (COMP1_TX_ENABLED(comp1)) {
|
||||
|
@ -503,7 +540,7 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
|
|||
struct resource *res,
|
||||
const struct i2s_platform_data *pdata)
|
||||
{
|
||||
u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
|
||||
u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1);
|
||||
u32 idx = COMP1_APB_DATA_WIDTH(comp1);
|
||||
int ret;
|
||||
|
||||
|
@ -607,6 +644,14 @@ static int dw_i2s_probe(struct platform_device *pdev)
|
|||
if (pdata) {
|
||||
dev->capability = pdata->cap;
|
||||
clk_id = NULL;
|
||||
dev->quirks = pdata->quirks;
|
||||
if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
|
||||
dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
|
||||
dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
|
||||
} else {
|
||||
dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
|
||||
dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
|
||||
}
|
||||
ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
|
||||
} else {
|
||||
clk_id = "i2sclk";
|
||||
|
@ -649,7 +694,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
|
|||
goto err_clk_disable;
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
return 0;
|
||||
|
||||
err_clk_disable:
|
||||
|
@ -665,6 +710,7 @@ static int dw_i2s_remove(struct platform_device *pdev)
|
|||
if (dev->capability & DW_I2S_MASTER)
|
||||
clk_disable_unprepare(dev->clk);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -677,12 +723,17 @@ static const struct of_device_id dw_i2s_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops dwc_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver dw_i2s_driver = {
|
||||
.probe = dw_i2s_probe,
|
||||
.remove = dw_i2s_remove,
|
||||
.driver = {
|
||||
.name = "designware-i2s",
|
||||
.of_match_table = of_match_ptr(dw_i2s_of_match),
|
||||
.pm = &dwc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -107,6 +107,13 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
|||
{"CPU-Capture", NULL, "Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map_ac97[] = {
|
||||
{"AC97 Playback", NULL, "ASRC-Playback"},
|
||||
{"Playback", NULL, "AC97 Playback"},
|
||||
{"ASRC-Capture", NULL, "AC97 Capture"},
|
||||
{"AC97 Capture", NULL, "Capture"},
|
||||
};
|
||||
|
||||
/* Add all possible widgets into here without being redundant */
|
||||
static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line Out Jack", NULL),
|
||||
|
@ -579,7 +586,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
|
|||
priv->card.dev = &pdev->dev;
|
||||
priv->card.name = priv->name;
|
||||
priv->card.dai_link = priv->dai_link;
|
||||
priv->card.dapm_routes = audio_map;
|
||||
priv->card.dapm_routes = fsl_asoc_card_is_ac97(priv) ?
|
||||
audio_map_ac97 : audio_map;
|
||||
priv->card.late_probe = fsl_asoc_card_late_probe;
|
||||
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
|
||||
priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
|
||||
|
|
|
@ -31,21 +31,21 @@
|
|||
dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__)
|
||||
|
||||
/* Sample rates are aligned with that defined in pcm.h file */
|
||||
static const u8 process_option[][8][2] = {
|
||||
/* 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */
|
||||
{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */
|
||||
{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */
|
||||
{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */
|
||||
{{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */
|
||||
{{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */
|
||||
{{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */
|
||||
{{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */
|
||||
{{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */
|
||||
{{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */
|
||||
{{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */
|
||||
{{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */
|
||||
{{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */
|
||||
{{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */
|
||||
static const u8 process_option[][12][2] = {
|
||||
/* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */
|
||||
{{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */
|
||||
{{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */
|
||||
{{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */
|
||||
{{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */
|
||||
{{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */
|
||||
{{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */
|
||||
{{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */
|
||||
{{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */
|
||||
{{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */
|
||||
{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */
|
||||
{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */
|
||||
{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */
|
||||
{{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */
|
||||
};
|
||||
|
||||
/* Corresponding to process_option */
|
||||
|
@ -55,7 +55,7 @@ static int supported_input_rate[] = {
|
|||
};
|
||||
|
||||
static int supported_asrc_rate[] = {
|
||||
32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
|
||||
8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -286,6 +286,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((outrate > 8000 && outrate < 30000) &&
|
||||
(outrate/inrate > 24 || inrate/outrate > 8)) {
|
||||
pair_err("exceed supported ratio range [1/24, 8] for \
|
||||
inrate/outrate: %d/%d\n", inrate, outrate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate input and output clock sources */
|
||||
clk_index[IN] = clk_map[IN][config->inclk];
|
||||
clk_index[OUT] = clk_map[OUT][config->outclk];
|
||||
|
@ -447,7 +454,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai);
|
||||
int width = snd_pcm_format_width(params_format(params));
|
||||
int width = params_width(params);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct fsl_asrc_pair *pair = runtime->private_data;
|
||||
unsigned int channels = params_channels(params);
|
||||
|
@ -859,6 +866,10 @@ static int fsl_asrc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(asrc_priv->ipg_clk);
|
||||
}
|
||||
|
||||
asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba");
|
||||
if (IS_ERR(asrc_priv->spba_clk))
|
||||
dev_warn(&pdev->dev, "failed to get spba clock\n");
|
||||
|
||||
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
|
||||
sprintf(tmp, "asrck_%x", i);
|
||||
asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp);
|
||||
|
@ -939,6 +950,11 @@ static int fsl_asrc_runtime_resume(struct device *dev)
|
|||
ret = clk_prepare_enable(asrc_priv->ipg_clk);
|
||||
if (ret)
|
||||
goto disable_mem_clk;
|
||||
if (!IS_ERR(asrc_priv->spba_clk)) {
|
||||
ret = clk_prepare_enable(asrc_priv->spba_clk);
|
||||
if (ret)
|
||||
goto disable_ipg_clk;
|
||||
}
|
||||
for (i = 0; i < ASRC_CLK_MAX_NUM; i++) {
|
||||
ret = clk_prepare_enable(asrc_priv->asrck_clk[i]);
|
||||
if (ret)
|
||||
|
@ -950,6 +966,9 @@ static int fsl_asrc_runtime_resume(struct device *dev)
|
|||
disable_asrck_clk:
|
||||
for (i--; i >= 0; i--)
|
||||
clk_disable_unprepare(asrc_priv->asrck_clk[i]);
|
||||
if (!IS_ERR(asrc_priv->spba_clk))
|
||||
clk_disable_unprepare(asrc_priv->spba_clk);
|
||||
disable_ipg_clk:
|
||||
clk_disable_unprepare(asrc_priv->ipg_clk);
|
||||
disable_mem_clk:
|
||||
clk_disable_unprepare(asrc_priv->mem_clk);
|
||||
|
@ -963,6 +982,8 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
|
|||
|
||||
for (i = 0; i < ASRC_CLK_MAX_NUM; i++)
|
||||
clk_disable_unprepare(asrc_priv->asrck_clk[i]);
|
||||
if (!IS_ERR(asrc_priv->spba_clk))
|
||||
clk_disable_unprepare(asrc_priv->spba_clk);
|
||||
clk_disable_unprepare(asrc_priv->ipg_clk);
|
||||
clk_disable_unprepare(asrc_priv->mem_clk);
|
||||
|
||||
|
|
|
@ -426,6 +426,7 @@ struct fsl_asrc_pair {
|
|||
* @paddr: physical address to the base address of registers
|
||||
* @mem_clk: clock source to access register
|
||||
* @ipg_clk: clock source to drive peripheral
|
||||
* @spba_clk: SPBA clock (optional, depending on SoC design)
|
||||
* @asrck_clk: clock sources to driver ASRC internal logic
|
||||
* @lock: spin lock for resource protection
|
||||
* @pair: pair pointers
|
||||
|
@ -442,6 +443,7 @@ struct fsl_asrc {
|
|||
unsigned long paddr;
|
||||
struct clk *mem_clk;
|
||||
struct clk *ipg_clk;
|
||||
struct clk *spba_clk;
|
||||
struct clk *asrck_clk[ASRC_CLK_MAX_NUM];
|
||||
spinlock_t lock;
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
* @coreclk: clock source to access register
|
||||
* @extalclk: esai clock source to derive HCK, SCK and FS
|
||||
* @fsysclk: system clock source to derive HCK, SCK and FS
|
||||
* @spbaclk: SPBA clock (optional, depending on SoC design)
|
||||
* @fifo_depth: depth of tx/rx FIFO
|
||||
* @slot_width: width of each DAI slot
|
||||
* @slots: number of slots
|
||||
|
@ -54,6 +55,7 @@ struct fsl_esai {
|
|||
struct clk *coreclk;
|
||||
struct clk *extalclk;
|
||||
struct clk *fsysclk;
|
||||
struct clk *spbaclk;
|
||||
u32 fifo_depth;
|
||||
u32 slot_width;
|
||||
u32 slots;
|
||||
|
@ -469,6 +471,11 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
|
|||
ret = clk_prepare_enable(esai_priv->coreclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!IS_ERR(esai_priv->spbaclk)) {
|
||||
ret = clk_prepare_enable(esai_priv->spbaclk);
|
||||
if (ret)
|
||||
goto err_spbaclk;
|
||||
}
|
||||
if (!IS_ERR(esai_priv->extalclk)) {
|
||||
ret = clk_prepare_enable(esai_priv->extalclk);
|
||||
if (ret)
|
||||
|
@ -499,6 +506,9 @@ err_fsysclk:
|
|||
if (!IS_ERR(esai_priv->extalclk))
|
||||
clk_disable_unprepare(esai_priv->extalclk);
|
||||
err_extalck:
|
||||
if (!IS_ERR(esai_priv->spbaclk))
|
||||
clk_disable_unprepare(esai_priv->spbaclk);
|
||||
err_spbaclk:
|
||||
clk_disable_unprepare(esai_priv->coreclk);
|
||||
|
||||
return ret;
|
||||
|
@ -510,7 +520,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
u32 width = snd_pcm_format_width(params_format(params));
|
||||
u32 width = params_width(params);
|
||||
u32 channels = params_channels(params);
|
||||
u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
|
||||
u32 slot_width = width;
|
||||
|
@ -564,6 +574,8 @@ static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
|
|||
clk_disable_unprepare(esai_priv->fsysclk);
|
||||
if (!IS_ERR(esai_priv->extalclk))
|
||||
clk_disable_unprepare(esai_priv->extalclk);
|
||||
if (!IS_ERR(esai_priv->spbaclk))
|
||||
clk_disable_unprepare(esai_priv->spbaclk);
|
||||
clk_disable_unprepare(esai_priv->coreclk);
|
||||
}
|
||||
|
||||
|
@ -653,21 +665,28 @@ static const struct snd_soc_component_driver fsl_esai_component = {
|
|||
};
|
||||
|
||||
static const struct reg_default fsl_esai_reg_defaults[] = {
|
||||
{0x8, 0x00000000},
|
||||
{0x10, 0x00000000},
|
||||
{0x18, 0x00000000},
|
||||
{0x98, 0x00000000},
|
||||
{0xd0, 0x00000000},
|
||||
{0xd4, 0x00000000},
|
||||
{0xd8, 0x00000000},
|
||||
{0xdc, 0x00000000},
|
||||
{0xe0, 0x00000000},
|
||||
{0xe4, 0x0000ffff},
|
||||
{0xe8, 0x0000ffff},
|
||||
{0xec, 0x0000ffff},
|
||||
{0xf0, 0x0000ffff},
|
||||
{0xf8, 0x00000000},
|
||||
{0xfc, 0x00000000},
|
||||
{REG_ESAI_ETDR, 0x00000000},
|
||||
{REG_ESAI_ECR, 0x00000000},
|
||||
{REG_ESAI_TFCR, 0x00000000},
|
||||
{REG_ESAI_RFCR, 0x00000000},
|
||||
{REG_ESAI_TX0, 0x00000000},
|
||||
{REG_ESAI_TX1, 0x00000000},
|
||||
{REG_ESAI_TX2, 0x00000000},
|
||||
{REG_ESAI_TX3, 0x00000000},
|
||||
{REG_ESAI_TX4, 0x00000000},
|
||||
{REG_ESAI_TX5, 0x00000000},
|
||||
{REG_ESAI_TSR, 0x00000000},
|
||||
{REG_ESAI_SAICR, 0x00000000},
|
||||
{REG_ESAI_TCR, 0x00000000},
|
||||
{REG_ESAI_TCCR, 0x00000000},
|
||||
{REG_ESAI_RCR, 0x00000000},
|
||||
{REG_ESAI_RCCR, 0x00000000},
|
||||
{REG_ESAI_TSMA, 0x0000ffff},
|
||||
{REG_ESAI_TSMB, 0x0000ffff},
|
||||
{REG_ESAI_RSMA, 0x0000ffff},
|
||||
{REG_ESAI_RSMB, 0x0000ffff},
|
||||
{REG_ESAI_PRRC, 0x00000000},
|
||||
{REG_ESAI_PCRC, 0x00000000},
|
||||
};
|
||||
|
||||
static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
|
||||
|
@ -705,17 +724,10 @@ static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
|
|||
static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case REG_ESAI_ETDR:
|
||||
case REG_ESAI_ERDR:
|
||||
case REG_ESAI_ESR:
|
||||
case REG_ESAI_TFSR:
|
||||
case REG_ESAI_RFSR:
|
||||
case REG_ESAI_TX0:
|
||||
case REG_ESAI_TX1:
|
||||
case REG_ESAI_TX2:
|
||||
case REG_ESAI_TX3:
|
||||
case REG_ESAI_TX4:
|
||||
case REG_ESAI_TX5:
|
||||
case REG_ESAI_RX0:
|
||||
case REG_ESAI_RX1:
|
||||
case REG_ESAI_RX2:
|
||||
|
@ -819,6 +831,11 @@ static int fsl_esai_probe(struct platform_device *pdev)
|
|||
dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
|
||||
PTR_ERR(esai_priv->fsysclk));
|
||||
|
||||
esai_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
|
||||
if (IS_ERR(esai_priv->spbaclk))
|
||||
dev_warn(&pdev->dev, "failed to get spba clock: %ld\n",
|
||||
PTR_ERR(esai_priv->spbaclk));
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
|
||||
|
|
|
@ -126,6 +126,17 @@ out:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
|
||||
u32 rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
|
||||
sai->slots = slots;
|
||||
sai->slot_width = slot_width;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
|
||||
int clk_id, unsigned int freq, int fsl_dir)
|
||||
{
|
||||
|
@ -354,13 +365,25 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) {
|
||||
/*
|
||||
* 1) For Asynchronous mode, we must set RCR2 register for capture, and
|
||||
* set TCR2 register for playback.
|
||||
* 2) For Tx sync with Rx clock, we must set RCR2 register for playback
|
||||
* and capture.
|
||||
* 3) For Rx sync with Tx clock, we must set TCR2 register for playback
|
||||
* and capture.
|
||||
* 4) For Tx and Rx are both Synchronous with another SAI, we just
|
||||
* ignore it.
|
||||
*/
|
||||
if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
|
||||
(!tx && !sai->synchronous[RX])) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
|
||||
FSL_SAI_CR2_MSEL_MASK,
|
||||
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
|
||||
FSL_SAI_CR2_DIV_MASK, savediv - 1);
|
||||
} else {
|
||||
} else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
|
||||
(tx && !sai->synchronous[TX])) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
|
||||
FSL_SAI_CR2_MSEL_MASK,
|
||||
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
||||
|
@ -381,13 +404,21 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
unsigned int channels = params_channels(params);
|
||||
u32 word_width = snd_pcm_format_width(params_format(params));
|
||||
u32 word_width = params_width(params);
|
||||
u32 val_cr4 = 0, val_cr5 = 0;
|
||||
u32 slots = (channels == 1) ? 2 : channels;
|
||||
u32 slot_width = word_width;
|
||||
int ret;
|
||||
|
||||
if (sai->slots)
|
||||
slots = sai->slots;
|
||||
|
||||
if (sai->slot_width)
|
||||
slot_width = sai->slot_width;
|
||||
|
||||
if (!sai->is_slave_mode) {
|
||||
ret = fsl_sai_set_bclk(cpu_dai, tx,
|
||||
2 * word_width * params_rate(params));
|
||||
slots * slot_width * params_rate(params));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -399,21 +430,49 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
sai->mclk_streams |= BIT(substream->stream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!sai->is_dsp_mode)
|
||||
val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
|
||||
val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
|
||||
|
||||
val_cr5 |= FSL_SAI_CR5_WNW(word_width);
|
||||
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
|
||||
val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
|
||||
val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
|
||||
|
||||
if (sai->is_lsb_first)
|
||||
val_cr5 |= FSL_SAI_CR5_FBT(0);
|
||||
else
|
||||
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
|
||||
|
||||
val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
|
||||
val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
|
||||
|
||||
/*
|
||||
* For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
|
||||
* generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
|
||||
* RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
|
||||
* error.
|
||||
*/
|
||||
|
||||
if (!sai->is_slave_mode) {
|
||||
if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
||||
val_cr4);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
|
||||
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
|
||||
FSL_SAI_CR5_FBT_MASK, val_cr5);
|
||||
regmap_write(sai->regmap, FSL_SAI_TMR,
|
||||
~0UL - ((1 << channels) - 1));
|
||||
} else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
||||
val_cr4);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
|
||||
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
|
||||
FSL_SAI_CR5_FBT_MASK, val_cr5);
|
||||
regmap_write(sai->regmap, FSL_SAI_RMR,
|
||||
~0UL - ((1 << channels) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
||||
|
@ -569,6 +628,7 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
|
|||
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
|
||||
.set_sysclk = fsl_sai_set_dai_sysclk,
|
||||
.set_fmt = fsl_sai_set_dai_fmt,
|
||||
.set_tdm_slot = fsl_sai_set_dai_tdm_slot,
|
||||
.hw_params = fsl_sai_hw_params,
|
||||
.hw_free = fsl_sai_hw_free,
|
||||
.trigger = fsl_sai_trigger,
|
||||
|
@ -627,6 +687,22 @@ static const struct snd_soc_component_driver fsl_component = {
|
|||
.name = "fsl-sai",
|
||||
};
|
||||
|
||||
static struct reg_default fsl_sai_reg_defaults[] = {
|
||||
{FSL_SAI_TCR1, 0},
|
||||
{FSL_SAI_TCR2, 0},
|
||||
{FSL_SAI_TCR3, 0},
|
||||
{FSL_SAI_TCR4, 0},
|
||||
{FSL_SAI_TCR5, 0},
|
||||
{FSL_SAI_TDR, 0},
|
||||
{FSL_SAI_TMR, 0},
|
||||
{FSL_SAI_RCR1, 0},
|
||||
{FSL_SAI_RCR2, 0},
|
||||
{FSL_SAI_RCR3, 0},
|
||||
{FSL_SAI_RCR4, 0},
|
||||
{FSL_SAI_RCR5, 0},
|
||||
{FSL_SAI_RMR, 0},
|
||||
};
|
||||
|
||||
static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
|
@ -660,13 +736,11 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
|
|||
case FSL_SAI_RCSR:
|
||||
case FSL_SAI_TFR:
|
||||
case FSL_SAI_RFR:
|
||||
case FSL_SAI_TDR:
|
||||
case FSL_SAI_RDR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
|
||||
|
@ -699,6 +773,8 @@ static const struct regmap_config fsl_sai_regmap_config = {
|
|||
.val_bits = 32,
|
||||
|
||||
.max_register = FSL_SAI_RMR,
|
||||
.reg_defaults = fsl_sai_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults),
|
||||
.readable_reg = fsl_sai_readable_reg,
|
||||
.volatile_reg = fsl_sai_volatile_reg,
|
||||
.writeable_reg = fsl_sai_writeable_reg,
|
||||
|
|
|
@ -143,6 +143,9 @@ struct fsl_sai {
|
|||
|
||||
unsigned int mclk_id[2];
|
||||
unsigned int mclk_streams;
|
||||
unsigned int slots;
|
||||
unsigned int slot_width;
|
||||
|
||||
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||
};
|
||||
|
|
|
@ -1006,12 +1006,14 @@ static const struct snd_soc_component_driver fsl_spdif_component = {
|
|||
|
||||
/* FSL SPDIF REGMAP */
|
||||
static const struct reg_default fsl_spdif_reg_defaults[] = {
|
||||
{0x0, 0x00000400},
|
||||
{0x4, 0x00000000},
|
||||
{0xc, 0x00000000},
|
||||
{0x34, 0x00000000},
|
||||
{0x38, 0x00000000},
|
||||
{0x50, 0x00020f00},
|
||||
{REG_SPDIF_SCR, 0x00000400},
|
||||
{REG_SPDIF_SRCD, 0x00000000},
|
||||
{REG_SPDIF_SIE, 0x00000000},
|
||||
{REG_SPDIF_STL, 0x00000000},
|
||||
{REG_SPDIF_STR, 0x00000000},
|
||||
{REG_SPDIF_STCSCH, 0x00000000},
|
||||
{REG_SPDIF_STCSCL, 0x00000000},
|
||||
{REG_SPDIF_STC, 0x00020f00},
|
||||
};
|
||||
|
||||
static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
|
||||
|
@ -1049,8 +1051,6 @@ static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg)
|
|||
case REG_SPDIF_SRCSL:
|
||||
case REG_SPDIF_SRU:
|
||||
case REG_SPDIF_SRQ:
|
||||
case REG_SPDIF_STL:
|
||||
case REG_SPDIF_STR:
|
||||
case REG_SPDIF_SRFM:
|
||||
return true;
|
||||
default:
|
||||
|
|
|
@ -113,17 +113,17 @@ struct fsl_ssi_rxtx_reg_val {
|
|||
};
|
||||
|
||||
static const struct reg_default fsl_ssi_reg_defaults[] = {
|
||||
{0x10, 0x00000000},
|
||||
{0x18, 0x00003003},
|
||||
{0x1c, 0x00000200},
|
||||
{0x20, 0x00000200},
|
||||
{0x24, 0x00040000},
|
||||
{0x28, 0x00040000},
|
||||
{0x38, 0x00000000},
|
||||
{0x48, 0x00000000},
|
||||
{0x4c, 0x00000000},
|
||||
{0x54, 0x00000000},
|
||||
{0x58, 0x00000000},
|
||||
{CCSR_SSI_SCR, 0x00000000},
|
||||
{CCSR_SSI_SIER, 0x00003003},
|
||||
{CCSR_SSI_STCR, 0x00000200},
|
||||
{CCSR_SSI_SRCR, 0x00000200},
|
||||
{CCSR_SSI_STCCR, 0x00040000},
|
||||
{CCSR_SSI_SRCCR, 0x00040000},
|
||||
{CCSR_SSI_SACNT, 0x00000000},
|
||||
{CCSR_SSI_STMSK, 0x00000000},
|
||||
{CCSR_SSI_SRMSK, 0x00000000},
|
||||
{CCSR_SSI_SACCEN, 0x00000000},
|
||||
{CCSR_SSI_SACCDIS, 0x00000000},
|
||||
};
|
||||
|
||||
static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
|
||||
|
@ -767,8 +767,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
|
|||
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct regmap *regs = ssi_private->regs;
|
||||
unsigned int channels = params_channels(hw_params);
|
||||
unsigned int sample_size =
|
||||
snd_pcm_format_width(params_format(hw_params));
|
||||
unsigned int sample_size = params_width(hw_params);
|
||||
u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
|
||||
int ret;
|
||||
u32 scr_val;
|
||||
|
|
|
@ -220,9 +220,9 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
|
|||
ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
|
||||
runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
|
||||
|
||||
pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
|
||||
pr_debug("%s: ret: %d %p %pad 0x%08x\n", __func__, ret,
|
||||
runtime->dma_area,
|
||||
runtime->dma_addr,
|
||||
&runtime->dma_addr,
|
||||
runtime->dma_bytes);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1614,6 +1614,56 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
|
|||
snd_pcm_stream_unlock_irq(substream);
|
||||
}
|
||||
|
||||
static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
|
||||
int stream)
|
||||
{
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
|
||||
struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai;
|
||||
int err;
|
||||
|
||||
/* apply symmetry for FE */
|
||||
if (soc_pcm_has_symmetry(fe_substream))
|
||||
fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
|
||||
|
||||
/* Symmetry only applies if we've got an active stream. */
|
||||
if (fe_cpu_dai->active) {
|
||||
err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* apply symmetry for BE */
|
||||
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
|
||||
struct snd_soc_pcm_runtime *be = dpcm->be;
|
||||
struct snd_pcm_substream *be_substream =
|
||||
snd_soc_dpcm_get_substream(be, stream);
|
||||
struct snd_soc_pcm_runtime *rtd = be_substream->private_data;
|
||||
int i;
|
||||
|
||||
if (soc_pcm_has_symmetry(be_substream))
|
||||
be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
|
||||
|
||||
/* Symmetry only applies if we've got an active stream. */
|
||||
if (rtd->cpu_dai->active) {
|
||||
err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < rtd->num_codecs; i++) {
|
||||
if (rtd->codec_dais[i]->active) {
|
||||
err = soc_pcm_apply_symmetry(be_substream,
|
||||
rtd->codec_dais[i]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
|
||||
|
@ -1642,6 +1692,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
|
|||
dpcm_set_fe_runtime(fe_substream);
|
||||
snd_pcm_limit_hw_rates(runtime);
|
||||
|
||||
ret = dpcm_apply_symmetry(fe_substream, stream);
|
||||
if (ret < 0) {
|
||||
dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n",
|
||||
ret);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
|
||||
return 0;
|
||||
|
||||
|
@ -2113,7 +2170,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
|
|||
continue;
|
||||
|
||||
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
|
||||
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
|
||||
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
|
||||
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
|
||||
continue;
|
||||
|
||||
dev_dbg(be->dev, "ASoC: prepare BE %s\n",
|
||||
|
|
Загрузка…
Ссылка в новой задаче