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:
Mark Brown 2015-12-23 00:23:40 +00:00
14 changed files with 357 additions and 107 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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,
},
};

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
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);

View File

@ -126,6 +126,17 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
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,

View File

@ -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;
};

View File

@ -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:

View File

@ -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;

View File

@ -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;
}

View File

@ -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",