diff options
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/eukrea-tlv320.c | 8 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_asrc.c | 29 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_asrc_dma.c | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.c | 55 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.h | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_spdif.c | 21 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_utils.c | 2 | ||||
-rw-r--r-- | sound/soc/fsl/imx-pcm.h | 9 | ||||
-rw-r--r-- | sound/soc/fsl/imx-rpmsg.c | 29 |
9 files changed, 130 insertions, 29 deletions
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 8b61582753c8..9af4c4a35eb1 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -86,7 +86,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) int ret; int int_port = 0, ext_port; struct device_node *np = pdev->dev.of_node; - struct device_node *ssi_np = NULL, *codec_np = NULL; + struct device_node *ssi_np = NULL, *codec_np = NULL, *tmp_np = NULL; eukrea_tlv320.dev = &pdev->dev; if (np) { @@ -143,7 +143,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) } if (machine_is_eukrea_cpuimx27() || - of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) { + (tmp_np = of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux"))) { imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, IMX_AUDMUX_V1_PCR_SYN | IMX_AUDMUX_V1_PCR_TFSDIR | @@ -158,10 +158,11 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) IMX_AUDMUX_V1_PCR_SYN | IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) ); + of_node_put(tmp_np); } else if (machine_is_eukrea_cpuimx25sd() || machine_is_eukrea_cpuimx35sd() || machine_is_eukrea_cpuimx51sd() || - of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) { + (tmp_np = of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux"))) { if (!np) ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3; @@ -178,6 +179,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) IMX_AUDMUX_V2_PTCR_SYN, IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) ); + of_node_put(tmp_np); } else { if (np) { /* The eukrea,asoc-tlv320 driver was explicitly diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index aa5edf32d988..936aef5d2767 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -20,6 +20,7 @@ #define IDEAL_RATIO_DECIMAL_DEPTH 26 #define DIVIDER_NUM 64 +#define INIT_RETRY_NUM 50 #define pair_err(fmt, ...) \ dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) @@ -27,6 +28,9 @@ #define pair_dbg(fmt, ...) \ dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) +#define pair_warn(fmt, ...) \ + dev_warn(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) + /* Corresponding to process_option */ static unsigned int supported_asrc_rate[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, @@ -579,7 +583,7 @@ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) { struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; - int reg, retry = 10, i; + int reg, retry = INIT_RETRY_NUM, i; /* Enable the current pair */ regmap_update_bits(asrc->regmap, REG_ASRCTR, @@ -592,6 +596,10 @@ static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) reg &= ASRCFG_INIRQi_MASK(index); } while (!reg && --retry); + /* NOTE: Doesn't treat initialization timeout as an error */ + if (!retry) + pair_warn("initialization isn't finished\n"); + /* Make the input fifo to ASRC STALL level */ regmap_read(asrc->regmap, REG_ASRCNCR, ®); for (i = 0; i < pair->channels * 4; i++) @@ -1257,6 +1265,7 @@ static int fsl_asrc_runtime_resume(struct device *dev) { struct fsl_asrc *asrc = dev_get_drvdata(dev); struct fsl_asrc_priv *asrc_priv = asrc->private; + int reg, retry = INIT_RETRY_NUM; int i, ret; u32 asrctr; @@ -1295,6 +1304,24 @@ static int fsl_asrc_runtime_resume(struct device *dev) regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_ALL_MASK, asrctr); + /* Wait for status of initialization for all enabled pairs */ + do { + udelay(5); + regmap_read(asrc->regmap, REG_ASRCFG, ®); + reg = (reg >> ASRCFG_INIRQi_SHIFT(0)) & 0x7; + } while ((reg != ((asrctr >> ASRCTR_ASRCEi_SHIFT(0)) & 0x7)) && --retry); + + /* + * NOTE: Doesn't treat initialization timeout as an error + * Some of the pairs may success, then still can continue. + */ + if (!retry) { + for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { + if ((asrctr & ASRCTR_ASRCEi_MASK(i)) && !(reg & (1 << i))) + dev_warn(dev, "Pair %c initialization isn't finished\n", 'A' + i); + } + } + return 0; disable_asrck_clk: diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 12ddf2320f2d..3b81a465814a 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -139,7 +139,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct dma_chan *tmp_chan = NULL, *be_chan = NULL; struct snd_soc_component *component_be = NULL; struct fsl_asrc *asrc = pair->asrc; - struct dma_slave_config config_fe, config_be; + struct dma_slave_config config_fe = {}, config_be = {}; struct sdma_peripheral_config audio_config; enum asrc_pair_index index = pair->index; struct device *dev = component->dev; @@ -183,7 +183,6 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, return -EINVAL; } - memset(&config_fe, 0, sizeof(config_fe)); ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, &config_fe); if (ret) { dev_err(dev, "failed to prepare DMA config for Front-End\n"); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index d430eece1d6b..81f89f6767a2 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -114,11 +114,8 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) if (flags & FSL_SAI_CSR_SEF) dev_dbg(dev, "isr: Tx Frame sync error detected\n"); - if (flags & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) dev_dbg(dev, "isr: Transmit underrun detected\n"); - /* FIFO reset for safety */ - xcsr |= FSL_SAI_CSR_FR; - } if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n"); @@ -148,11 +145,8 @@ irq_rx: if (flags & FSL_SAI_CSR_SEF) dev_dbg(dev, "isr: Rx Frame sync error detected\n"); - if (flags & FSL_SAI_CSR_FEF) { + if (flags & FSL_SAI_CSR_FEF) dev_dbg(dev, "isr: Receive overflow detected\n"); - /* FIFO reset for safety */ - xcsr |= FSL_SAI_CSR_FR; - } if (flags & FSL_SAI_CSR_FWF) dev_dbg(dev, "isr: Enabled receive FIFO is full\n"); @@ -533,14 +527,17 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, u32 slot_width = word_width; int adir = tx ? RX : TX; u32 pins, bclk; + u32 watermark; int ret, i; - if (sai->slots) - slots = sai->slots; - if (sai->slot_width) slot_width = sai->slot_width; + if (sai->slots) + slots = sai->slots; + else if (sai->bclk_ratio) + slots = sai->bclk_ratio / slot_width; + pins = DIV_ROUND_UP(channels, slots); /* @@ -625,7 +622,15 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, FSL_SAI_CR5_FBT_MASK, val_cr5); } - if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1) + /* + * Combine mode has limation: + * - Can't used for singel dataline/FIFO case except the FIFO0 + * - Can't used for multi dataline/FIFO case except the enabled FIFOs + * are successive and start from FIFO0 + * + * So for common usage, all multi fifo case disable the combine mode. + */ + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1 || sai->is_multi_fifo_dma) regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FCOMB_MASK, 0); else @@ -636,6 +641,26 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) + dl_cfg[dl_cfg_idx].start_off[tx] * 0x4; + if (sai->is_multi_fifo_dma) { + sai->audio_config[tx].words_per_fifo = min(slots, channels); + if (tx) { + sai->audio_config[tx].n_fifos_dst = pins; + sai->audio_config[tx].stride_fifos_dst = dl_cfg[dl_cfg_idx].next_off[tx]; + } else { + sai->audio_config[tx].n_fifos_src = pins; + sai->audio_config[tx].stride_fifos_src = dl_cfg[dl_cfg_idx].next_off[tx]; + } + dma_params->maxburst = sai->audio_config[tx].words_per_fifo * pins; + dma_params->peripheral_config = &sai->audio_config[tx]; + dma_params->peripheral_size = sizeof(sai->audio_config[tx]); + + watermark = tx ? (sai->soc_data->fifo_depth - dma_params->maxburst) : + (dma_params->maxburst - 1); + regmap_update_bits(sai->regmap, FSL_SAI_xCR1(tx, ofs), + FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), + watermark); + } + /* Find a proper tcre setting */ for (i = 0; i < sai->soc_data->pins; i++) { trce_mask = (1 << (i + 1)) - 1; @@ -1263,6 +1288,7 @@ static int fsl_sai_probe(struct platform_device *pdev) char tmp[8]; int irq, ret, i; int index; + u32 dmas[4]; sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL); if (!sai) @@ -1319,6 +1345,11 @@ static int fsl_sai_probe(struct platform_device *pdev) fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk, &sai->pll11k_clk); + /* Use Multi FIFO mode depending on the support from SDMA script */ + ret = of_property_read_u32_array(np, "dmas", dmas, 4); + if (!sai->soc_data->use_edma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI) + sai->is_multi_fifo_dma = true; + /* read dataline mask for rx and tx*/ ret = fsl_sai_read_dlcfg(sai); if (ret < 0) { diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 17956b5731dc..697f6690068c 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -6,6 +6,7 @@ #ifndef __FSL_SAI_H #define __FSL_SAI_H +#include <linux/dma/imx-dma.h> #include <sound/dmaengine_pcm.h> #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ @@ -281,6 +282,7 @@ struct fsl_sai { bool is_lsb_first; bool is_dsp_mode; bool is_pdm_mode; + bool is_multi_fifo_dma; bool synchronous[2]; struct fsl_sai_dl_cfg *dl_cfg; unsigned int dl_cfg_cnt; @@ -300,6 +302,7 @@ struct fsl_sai { struct pm_qos_request pm_qos_req; struct pinctrl *pinctrl; struct pinctrl_state *pins_state; + struct sdma_peripheral_config audio_config[2]; }; #define TX 1 diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 7fc1c96929bb..275aba8e0c46 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -44,6 +44,8 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; #define DEFAULT_RXCLK_SRC 1 +#define RX_SAMPLE_RATE_KCONTROL "RX Sample Rate" + /** * struct fsl_spdif_soc_data: soc specific data * @@ -98,6 +100,8 @@ struct spdif_mixer_control { * @soc: SPDIF soc data * @fsl_spdif_control: SPDIF control data * @cpu_dai_drv: cpu dai driver + * @snd_card: sound card pointer + * @rxrate_kcontrol: kcontrol for RX Sample Rate * @pdev: platform device pointer * @regmap: regmap handler * @dpll_locked: dpll lock flag @@ -122,6 +126,8 @@ struct fsl_spdif_priv { const struct fsl_spdif_soc_data *soc; struct spdif_mixer_control fsl_spdif_control; struct snd_soc_dai_driver cpu_dai_drv; + struct snd_card *snd_card; + struct snd_kcontrol *rxrate_kcontrol; struct platform_device *pdev; struct regmap *regmap; bool dpll_locked; @@ -226,6 +232,12 @@ static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) locked ? "locked" : "loss lock"); spdif_priv->dpll_locked = locked ? true : false; + + if (spdif_priv->snd_card && spdif_priv->rxrate_kcontrol) { + snd_ctl_notify(spdif_priv->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, + &spdif_priv->rxrate_kcontrol->id); + } } /* Receiver found illegal symbol interrupt handler */ @@ -1197,7 +1209,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { /* DPLL lock info get controller */ { .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "RX Sample Rate", + .name = RX_SAMPLE_RATE_KCONTROL, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .info = fsl_spdif_rxrate_info, @@ -1251,6 +1263,13 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) snd_soc_add_dai_controls(dai, fsl_spdif_ctrls_rcm, ARRAY_SIZE(fsl_spdif_ctrls_rcm)); + spdif_private->snd_card = dai->component->card->snd_card; + spdif_private->rxrate_kcontrol = snd_soc_card_get_kcontrol(dai->component->card, + RX_SAMPLE_RATE_KCONTROL); + if (!spdif_private->rxrate_kcontrol) + dev_err(&spdif_private->pdev->dev, "failed to get %s kcontrol\n", + RX_SAMPLE_RATE_KCONTROL); + /*Clear the val bit for Tx*/ regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR, SCR_VAL_MASK, SCR_VAL_CLEAR); diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index d0fc430f7033..a5ab27c2f711 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -124,7 +124,7 @@ void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk, { struct clk *p, *pll = NULL, *npll = NULL; bool reparent = false; - int ret = 0; + int ret; if (!clk || !pll8k_clk || !pll11k_clk) return; diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 06b25f4b26b6..ac5f57c3cc55 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -18,15 +18,6 @@ #define IMX_DEFAULT_DMABUF_SIZE (64 * 1024) -static inline void -imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, - int dma, enum sdma_peripheral_type peripheral_type) -{ - dma_data->dma_request = dma; - dma_data->priority = DMA_PRIO_HIGH; - dma_data->peripheral_type = peripheral_type; -} - struct imx_pcm_fiq_params { int irq; void __iomem *base; diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index 2e117311e582..4d99f4858a14 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -19,6 +19,7 @@ struct imx_rpmsg { struct snd_soc_dai_link dai; struct snd_soc_card card; + unsigned long sysclk; }; static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = { @@ -28,6 +29,27 @@ static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = { SND_SOC_DAPM_MIC("Main MIC", NULL), }; +static int imx_rpmsg_late_probe(struct snd_soc_card *card) +{ + struct imx_rpmsg *data = snd_soc_card_get_drvdata(card); + struct snd_soc_pcm_runtime *rtd = list_first_entry(&card->rtd_list, + struct snd_soc_pcm_runtime, list); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct device *dev = card->dev; + int ret; + + if (!data->sysclk) + return 0; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, data->sysclk, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set sysclk in %s\n", __func__); + return ret; + } + + return 0; +} + static int imx_rpmsg_probe(struct platform_device *pdev) { struct snd_soc_dai_link_component *dlc; @@ -72,12 +94,18 @@ static int imx_rpmsg_probe(struct platform_device *pdev) data->dai.codecs->dai_name = "snd-soc-dummy-dai"; data->dai.codecs->name = "snd-soc-dummy"; } else { + struct clk *clk; + data->dai.codecs->of_node = args.np; ret = snd_soc_get_dai_name(&args, &data->dai.codecs->dai_name); if (ret) { dev_err(&pdev->dev, "Unable to get codec_dai_name\n"); goto fail; } + + clk = devm_get_clk_from_child(&pdev->dev, args.np, NULL); + if (!IS_ERR(clk)) + data->sysclk = clk_get_rate(clk); } data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev); @@ -103,6 +131,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev) data->card.owner = THIS_MODULE; data->card.dapm_widgets = imx_rpmsg_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_rpmsg_dapm_widgets); + data->card.late_probe = imx_rpmsg_late_probe; /* * Inoder to use common api to get card name and audio routing. * Use parent of_node for this device, revert it after finishing using |