Merge remote-tracking branches 'asoc/topic/es8328', 'asoc/topic/find-dai', 'asoc/topic/fsl', 'asoc/topic/fsl-sai' and 'asoc/topic/fsl-ssi' into asoc-next

This commit is contained in:
Mark Brown 2016-05-13 14:27:01 +01:00
9 changed files with 290 additions and 68 deletions

View File

@ -7,8 +7,8 @@ codec/DSP interfaces.
Required properties:
- compatible : Compatible list, contains "fsl,vf610-sai" or
"fsl,imx6sx-sai".
- compatible : Compatible list, contains "fsl,vf610-sai",
"fsl,imx6sx-sai" or "fsl,imx6ul-sai"
- reg : Offset and length of the register set for the device.
@ -48,6 +48,11 @@ Required properties:
receive data by following their own bit clocks and
frame sync clocks separately.
Optional properties (for mx6ul):
- fsl,sai-mclk-direction-output: This is a boolean property. If present,
indicates that SAI will output the SAI MCLK clock.
Note:
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
default synchronous mode (sync Rx with Tx) will be used, which means both

View File

@ -4661,6 +4661,7 @@ FREESCALE SOC SOUND DRIVERS
M: Timur Tabi <timur@tabi.org>
M: Nicolin Chen <nicoleotsuka@gmail.com>
M: Xiubo Li <Xiubo.Lee@gmail.com>
R: Fabio Estevam <fabio.estevam@nxp.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
L: linuxppc-dev@lists.ozlabs.org
S: Maintained

View File

@ -447,5 +447,11 @@
#define IMX6UL_GPR1_ENET2_CLK_OUTPUT (0x1 << 18)
#define IMX6UL_GPR1_ENET_CLK_DIR (0x3 << 17)
#define IMX6UL_GPR1_ENET_CLK_OUTPUT (0x3 << 17)
#define IMX6UL_GPR1_SAI1_MCLK_DIR (0x1 << 19)
#define IMX6UL_GPR1_SAI2_MCLK_DIR (0x1 << 20)
#define IMX6UL_GPR1_SAI3_MCLK_DIR (0x1 << 21)
#define IMX6UL_GPR1_SAI_MCLK_MASK (0x7 << 19)
#define MCLK_DIR(x) (x == 1 ? IMX6UL_GPR1_SAI1_MCLK_DIR : x == 2 ? \
IMX6UL_GPR1_SAI2_MCLK_DIR : IMX6UL_GPR1_SAI3_MCLK_DIR)
#endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */

View File

@ -1683,6 +1683,9 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card,
int snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv);
struct snd_soc_dai *snd_soc_find_dai(
const struct snd_soc_dai_link_component *dlc);
#include <sound/soc-dai.h>
#ifdef CONFIG_DEBUG_FS

View File

@ -26,18 +26,30 @@
#include <sound/tlv.h>
#include "es8328.h"
#define ES8328_SYSCLK_RATE_1X 11289600
#define ES8328_SYSCLK_RATE_2X 22579200
static const unsigned int rates_12288[] = {
8000, 12000, 16000, 24000, 32000, 48000, 96000,
};
/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */
static struct {
int rate;
u8 ratio;
} mclk_ratios[] = {
{ 8000, 9 },
{11025, 7 },
{22050, 4 },
{44100, 2 },
static const int ratios_12288[] = {
10, 7, 6, 4, 3, 2, 0,
};
static const struct snd_pcm_hw_constraint_list constraints_12288 = {
.count = ARRAY_SIZE(rates_12288),
.list = rates_12288,
};
static const unsigned int rates_11289[] = {
8018, 11025, 22050, 44100, 88200,
};
static const int ratios_11289[] = {
9, 7, 4, 2, 0,
};
static const struct snd_pcm_hw_constraint_list constraints_11289 = {
.count = ARRAY_SIZE(rates_11289),
.list = rates_11289,
};
/* regulator supplies for sgtl5000, VDDD is an optional external supply */
@ -57,16 +69,28 @@ static const char * const supply_names[ES8328_SUPPLY_NUM] = {
"HPVDD",
};
#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \
#define ES8328_RATES (SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_11025)
#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_11025 | \
SNDRV_PCM_RATE_8000)
#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S18_3LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
struct es8328_priv {
struct regmap *regmap;
struct clk *clk;
int playback_fs;
bool deemph;
int mclkdiv2;
const struct snd_pcm_hw_constraint_list *sysclk_constraints;
const int *mclk_ratios;
struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM];
};
@ -439,54 +463,131 @@ static int es8328_mute(struct snd_soc_dai *dai, int mute)
mute ? ES8328_DACCONTROL3_DACMUTE : 0);
}
static int es8328_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
if (es8328->sysclk_constraints)
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
es8328->sysclk_constraints);
return 0;
}
static int es8328_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 es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
int clk_rate;
int i;
int reg;
u8 ratio;
int wl;
int ratio;
if (!es8328->sysclk_constraints) {
dev_err(codec->dev, "No MCLK configured\n");
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg = ES8328_DACCONTROL2;
else
reg = ES8328_ADCCONTROL5;
clk_rate = clk_get_rate(es8328->clk);
for (i = 0; i < es8328->sysclk_constraints->count; i++)
if (es8328->sysclk_constraints->list[i] == params_rate(params))
break;
if ((clk_rate != ES8328_SYSCLK_RATE_1X) &&
(clk_rate != ES8328_SYSCLK_RATE_2X)) {
dev_err(codec->dev,
"%s: clock is running at %d Hz, not %d or %d Hz\n",
__func__, clk_rate,
ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X);
if (i == es8328->sysclk_constraints->count) {
dev_err(codec->dev, "LRCLK %d unsupported with current clock\n",
params_rate(params));
return -EINVAL;
}
/* find master mode MCLK to sampling frequency ratio */
ratio = mclk_ratios[0].rate;
for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++)
if (params_rate(params) <= mclk_ratios[i].rate)
ratio = mclk_ratios[i].ratio;
ratio = es8328->mclk_ratios[i];
snd_soc_update_bits(codec, ES8328_MASTERMODE,
ES8328_MASTERMODE_MCLKDIV2,
es8328->mclkdiv2 ? ES8328_MASTERMODE_MCLKDIV2 : 0);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
es8328->playback_fs = params_rate(params);
es8328_set_deemph(codec);
switch (params_width(params)) {
case 16:
wl = 3;
break;
case 18:
wl = 2;
break;
case 20:
wl = 1;
break;
case 24:
wl = 0;
break;
case 32:
wl = 4;
break;
default:
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
snd_soc_update_bits(codec, ES8328_DACCONTROL1,
ES8328_DACCONTROL1_DACWL_MASK,
wl << ES8328_DACCONTROL1_DACWL_SHIFT);
es8328->playback_fs = params_rate(params);
es8328_set_deemph(codec);
} else
snd_soc_update_bits(codec, ES8328_ADCCONTROL4,
ES8328_ADCCONTROL4_ADCWL_MASK,
wl << ES8328_ADCCONTROL4_ADCWL_SHIFT);
return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio);
}
static int es8328_set_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
int mclkdiv2 = 0;
switch (freq) {
case 0:
es8328->sysclk_constraints = NULL;
es8328->mclk_ratios = NULL;
break;
case 22579200:
mclkdiv2 = 1;
/* fallthru */
case 11289600:
es8328->sysclk_constraints = &constraints_11289;
es8328->mclk_ratios = ratios_11289;
break;
case 24576000:
mclkdiv2 = 1;
/* fallthru */
case 12288000:
es8328->sysclk_constraints = &constraints_12288;
es8328->mclk_ratios = ratios_12288;
break;
default:
return -EINVAL;
}
es8328->mclkdiv2 = mclkdiv2;
return 0;
}
static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
int clk_rate;
u8 mode = ES8328_DACCONTROL1_DACWL_16;
u8 dac_mode = 0;
u8 adc_mode = 0;
/* set master/slave audio interface */
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
@ -495,13 +596,16 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
mode |= ES8328_DACCONTROL1_DACFORMAT_I2S;
dac_mode |= ES8328_DACCONTROL1_DACFORMAT_I2S;
adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_I2S;
break;
case SND_SOC_DAIFMT_RIGHT_J:
mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST;
dac_mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST;
adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_RJUST;
break;
case SND_SOC_DAIFMT_LEFT_J:
mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST;
dac_mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST;
adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_LJUST;
break;
default:
return -EINVAL;
@ -511,18 +615,14 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
return -EINVAL;
snd_soc_write(codec, ES8328_DACCONTROL1, mode);
snd_soc_write(codec, ES8328_ADCCONTROL4, mode);
snd_soc_update_bits(codec, ES8328_DACCONTROL1,
ES8328_DACCONTROL1_DACFORMAT_MASK, dac_mode);
snd_soc_update_bits(codec, ES8328_ADCCONTROL4,
ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode);
/* Master serial port mode, with BCLK generated automatically */
clk_rate = clk_get_rate(es8328->clk);
if (clk_rate == ES8328_SYSCLK_RATE_1X)
snd_soc_write(codec, ES8328_MASTERMODE,
ES8328_MASTERMODE_MSC);
else
snd_soc_write(codec, ES8328_MASTERMODE,
ES8328_MASTERMODE_MCLKDIV2 |
ES8328_MASTERMODE_MSC);
snd_soc_update_bits(codec, ES8328_MASTERMODE,
ES8328_MASTERMODE_MSC, ES8328_MASTERMODE_MSC);
return 0;
}
@ -579,8 +679,10 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
}
static const struct snd_soc_dai_ops es8328_dai_ops = {
.startup = es8328_startup,
.hw_params = es8328_hw_params,
.digital_mute = es8328_mute,
.set_sysclk = es8328_set_sysclk,
.set_fmt = es8328_set_dai_fmt,
};
@ -601,6 +703,7 @@ static struct snd_soc_dai_driver es8328_dai = {
.formats = ES8328_FORMATS,
},
.ops = &es8328_dai_ops,
.symmetric_rates = 1,
};
static int es8328_suspend(struct snd_soc_codec *codec)
@ -708,6 +811,7 @@ const struct regmap_config es8328_regmap_config = {
.val_bits = 8,
.max_register = ES8328_REG_MAX,
.cache_type = REGCACHE_RBTREE,
.use_single_rw = true,
};
EXPORT_SYMBOL_GPL(es8328_regmap_config);

View File

@ -22,7 +22,7 @@ int es8328_probe(struct device *dev, struct regmap *regmap);
#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0)
#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0)
#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0)
#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0)
#define ES8328_CONTROL1_VMIDSEL_MASK (3 << 0)
#define ES8328_CONTROL1_ENREF (1 << 2)
#define ES8328_CONTROL1_SEQEN (1 << 3)
#define ES8328_CONTROL1_SAMEFS (1 << 4)
@ -84,7 +84,20 @@ int es8328_probe(struct device *dev, struct regmap *regmap);
#define ES8328_ADCCONTROL1 0x09
#define ES8328_ADCCONTROL2 0x0a
#define ES8328_ADCCONTROL3 0x0b
#define ES8328_ADCCONTROL4 0x0c
#define ES8328_ADCCONTROL4_ADCFORMAT_MASK (3 << 0)
#define ES8328_ADCCONTROL4_ADCFORMAT_I2S (0 << 0)
#define ES8328_ADCCONTROL4_ADCFORMAT_LJUST (1 << 0)
#define ES8328_ADCCONTROL4_ADCFORMAT_RJUST (2 << 0)
#define ES8328_ADCCONTROL4_ADCFORMAT_PCM (3 << 0)
#define ES8328_ADCCONTROL4_ADCWL_SHIFT 2
#define ES8328_ADCCONTROL4_ADCWL_MASK (7 << 2)
#define ES8328_ADCCONTROL4_ADCLRP_I2S_POL_NORMAL (0 << 5)
#define ES8328_ADCCONTROL4_ADCLRP_I2S_POL_INV (1 << 5)
#define ES8328_ADCCONTROL4_ADCLRP_PCM_MSB_CLK2 (0 << 5)
#define ES8328_ADCCONTROL4_ADCLRP_PCM_MSB_CLK1 (1 << 5)
#define ES8328_ADCCONTROL5 0x0d
#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0)
@ -109,15 +122,13 @@ int es8328_probe(struct device *dev, struct regmap *regmap);
#define ES8328_ADCCONTROL14 0x16
#define ES8328_DACCONTROL1 0x17
#define ES8328_DACCONTROL1_DACFORMAT_MASK (3 << 1)
#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1)
#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1)
#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1)
#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1)
#define ES8328_DACCONTROL1_DACWL_24 (0 << 3)
#define ES8328_DACCONTROL1_DACWL_20 (1 << 3)
#define ES8328_DACCONTROL1_DACWL_18 (2 << 3)
#define ES8328_DACCONTROL1_DACWL_16 (3 << 3)
#define ES8328_DACCONTROL1_DACWL_32 (4 << 3)
#define ES8328_DACCONTROL1_DACWL_SHIFT 3
#define ES8328_DACCONTROL1_DACWL_MASK (7 << 3)
#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6)
#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6)
#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6)

View File

@ -21,6 +21,8 @@
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include "fsl_sai.h"
#include "imx-pcm.h"
@ -786,10 +788,12 @@ static int fsl_sai_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct fsl_sai *sai;
struct regmap *gpr;
struct resource *res;
void __iomem *base;
char tmp[8];
int irq, ret, i;
int index;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
@ -797,7 +801,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->pdev = pdev;
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai") ||
of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai"))
sai->sai_on_imx = true;
sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
@ -877,6 +882,22 @@ static int fsl_sai_probe(struct platform_device *pdev)
fsl_sai_dai.symmetric_samplebits = 0;
}
if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai")) {
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
if (IS_ERR(gpr)) {
dev_err(&pdev->dev, "cannot find iomuxc registers\n");
return PTR_ERR(gpr);
}
index = of_alias_get_id(np, "sai");
if (index < 0)
return index;
regmap_update_bits(gpr, IOMUXC_GPR1, MCLK_DIR(index),
MCLK_DIR(index));
}
sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
@ -898,6 +919,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,vf610-sai", },
{ .compatible = "fsl,imx6sx-sai", },
{ .compatible = "fsl,imx6ul-sai", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_sai_ids);

View File

@ -262,6 +262,7 @@ struct fsl_ssi_private {
struct fsl_ssi_dbg dbg_stats;
const struct fsl_ssi_soc_data *soc;
struct device *dev;
};
/*
@ -400,6 +401,26 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
}
}
/*
* Clear RX or TX FIFO to remove samples from the previous
* stream session which may be still present in the FIFO and
* may introduce bad samples and/or channel slipping.
*
* Note: The SOR is not documented in recent IMX datasheet, but
* is described in IMX51 reference manual at section 56.3.3.15.
*/
static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private,
bool is_rx)
{
if (is_rx) {
regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR,
CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR);
} else {
regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR,
CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR);
}
}
/*
* Calculate the bits that have to be disabled for the current stream that is
* getting disabled. This keeps the bits enabled that are necessary for the
@ -475,9 +496,11 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
* (online configuration)
*/
if (enable) {
regmap_update_bits(regs, CCSR_SSI_SIER, vals->sier, vals->sier);
fsl_ssi_fifo_clear(ssi_private, vals->scr & CCSR_SSI_SCR_RE);
regmap_update_bits(regs, CCSR_SSI_SRCR, vals->srcr, vals->srcr);
regmap_update_bits(regs, CCSR_SSI_STCR, vals->stcr, vals->stcr);
regmap_update_bits(regs, CCSR_SSI_SIER, vals->sier, vals->sier);
} else {
u32 sier;
u32 srcr;
@ -507,9 +530,41 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
config_done:
/* Enabling of subunits is done after configuration */
if (enable)
if (enable) {
if (ssi_private->use_dma && (vals->scr & CCSR_SSI_SCR_TE)) {
/*
* Be sure the Tx FIFO is filled when TE is set.
* Otherwise, there are some chances to start the
* playback with some void samples inserted first,
* generating a channel slip.
*
* First, SSIEN must be set, to let the FIFO be filled.
*
* Notes:
* - Limit this fix to the DMA case until FIQ cases can
* be tested.
* - Limit the length of the busy loop to not lock the
* system too long, even if 1-2 loops are sufficient
* in general.
*/
int i;
int max_loop = 100;
regmap_update_bits(regs, CCSR_SSI_SCR,
CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN);
for (i = 0; i < max_loop; i++) {
u32 sfcsr;
regmap_read(regs, CCSR_SSI_SFCSR, &sfcsr);
if (CCSR_SSI_SFCSR_TFCNT0(sfcsr))
break;
}
if (i == max_loop) {
dev_err(ssi_private->dev,
"Timeout waiting TX FIFO filling\n");
}
}
regmap_update_bits(regs, CCSR_SSI_SCR, vals->scr, vals->scr);
}
}
static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
@ -671,6 +726,15 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
if (IS_ERR(ssi_private->baudclk))
return -EINVAL;
/*
* Hardware limitation: The bclk rate must be
* never greater than 1/5 IPG clock rate
*/
if (freq * 5 > clk_get_rate(ssi_private->clk)) {
dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n");
return -EINVAL;
}
baudclk_is_used = ssi_private->baudclk_streams & ~(BIT(substream->stream));
/* It should be already enough to divide clock by setting pm alone */
@ -687,13 +751,6 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
else
clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
/*
* Hardware limitation: The bclk rate must be
* never greater than 1/5 IPG clock rate
*/
if (clkrate * 5 > clk_get_rate(ssi_private->clk))
continue;
clkrate /= factor;
afreq = clkrate / (i + 1);
@ -1159,14 +1216,14 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = {
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
.channels_max = 2,
.channels_max = 32,
.rates = FSLSSI_I2S_RATES,
.formats = FSLSSI_I2S_FORMATS,
},
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 1,
.channels_max = 2,
.channels_max = 32,
.rates = FSLSSI_I2S_RATES,
.formats = FSLSSI_I2S_FORMATS,
},
@ -1403,6 +1460,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
}
ssi_private->soc = of_id->data;
ssi_private->dev = &pdev->dev;
sprop = of_get_property(np, "fsl,mode", NULL);
if (sprop) {

View File

@ -930,7 +930,18 @@ static struct snd_soc_component *soc_find_component(
return NULL;
}
static struct snd_soc_dai *snd_soc_find_dai(
/**
* snd_soc_find_dai - Find a registered DAI
*
* @dlc: name of the DAI and optional component info to match
*
* This function will search all regsitered components and their DAIs to
* find the DAI of the same name. The component's of_node and name
* should also match if being specified.
*
* Return: pointer of DAI, or NULL if not found.
*/
struct snd_soc_dai *snd_soc_find_dai(
const struct snd_soc_dai_link_component *dlc)
{
struct snd_soc_component *component;
@ -959,6 +970,7 @@ static struct snd_soc_dai *snd_soc_find_dai(
return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_find_dai);
static bool soc_is_dai_link_bound(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link)