Merge branch 'topic/fsl-sai' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-fsl
This commit is contained in:
commit
3d8d0bd078
|
@ -126,6 +126,17 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
|
||||||
return IRQ_HANDLED;
|
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,
|
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
|
||||||
int clk_id, unsigned int freq, int fsl_dir)
|
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;
|
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,
|
regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
|
||||||
FSL_SAI_CR2_MSEL_MASK,
|
FSL_SAI_CR2_MSEL_MASK,
|
||||||
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
||||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
|
regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
|
||||||
FSL_SAI_CR2_DIV_MASK, savediv - 1);
|
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,
|
regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
|
||||||
FSL_SAI_CR2_MSEL_MASK,
|
FSL_SAI_CR2_MSEL_MASK,
|
||||||
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
||||||
|
@ -383,11 +406,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||||
unsigned int channels = params_channels(params);
|
unsigned int channels = params_channels(params);
|
||||||
u32 word_width = snd_pcm_format_width(params_format(params));
|
u32 word_width = snd_pcm_format_width(params_format(params));
|
||||||
u32 val_cr4 = 0, val_cr5 = 0;
|
u32 val_cr4 = 0, val_cr5 = 0;
|
||||||
|
u32 slots = (channels == 1) ? 2 : channels;
|
||||||
|
u32 slot_width = word_width;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (sai->slots)
|
||||||
|
slots = sai->slots;
|
||||||
|
|
||||||
|
if (sai->slot_width)
|
||||||
|
slot_width = sai->slot_width;
|
||||||
|
|
||||||
if (!sai->is_slave_mode) {
|
if (!sai->is_slave_mode) {
|
||||||
ret = fsl_sai_set_bclk(cpu_dai, tx,
|
ret = fsl_sai_set_bclk(cpu_dai, tx,
|
||||||
2 * word_width * params_rate(params));
|
slots * slot_width * params_rate(params));
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -399,21 +430,49 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
|
||||||
sai->mclk_streams |= BIT(substream->stream);
|
sai->mclk_streams |= BIT(substream->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sai->is_dsp_mode)
|
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_WNW(slot_width);
|
||||||
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
|
val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
|
||||||
|
|
||||||
if (sai->is_lsb_first)
|
if (sai->is_lsb_first)
|
||||||
val_cr5 |= FSL_SAI_CR5_FBT(0);
|
val_cr5 |= FSL_SAI_CR5_FBT(0);
|
||||||
else
|
else
|
||||||
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
|
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),
|
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
|
||||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
||||||
|
@ -550,6 +609,7 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
|
||||||
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
|
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
|
||||||
.set_sysclk = fsl_sai_set_dai_sysclk,
|
.set_sysclk = fsl_sai_set_dai_sysclk,
|
||||||
.set_fmt = fsl_sai_set_dai_fmt,
|
.set_fmt = fsl_sai_set_dai_fmt,
|
||||||
|
.set_tdm_slot = fsl_sai_set_dai_tdm_slot,
|
||||||
.hw_params = fsl_sai_hw_params,
|
.hw_params = fsl_sai_hw_params,
|
||||||
.hw_free = fsl_sai_hw_free,
|
.hw_free = fsl_sai_hw_free,
|
||||||
.trigger = fsl_sai_trigger,
|
.trigger = fsl_sai_trigger,
|
||||||
|
|
|
@ -143,6 +143,9 @@ struct fsl_sai {
|
||||||
|
|
||||||
unsigned int mclk_id[2];
|
unsigned int mclk_id[2];
|
||||||
unsigned int mclk_streams;
|
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_rx;
|
||||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue