summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/atmel/atmel-classd.c7
-rw-r--r--sound/soc/atmel/atmel-pdmic.c7
-rw-r--r--sound/soc/bcm/cygnus-ssp.c7
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c12
-rw-r--r--sound/soc/codecs/twl6040.c4
-rw-r--r--sound/soc/fsl/fsl_asrc.c4
-rw-r--r--sound/soc/fsl/fsl_dsd.h58
-rw-r--r--sound/soc/fsl/fsl_esai.c4
-rw-r--r--sound/soc/fsl/fsl_sai.c939
-rw-r--r--sound/soc/fsl/fsl_sai.h222
-rw-r--r--sound/soc/fsl/fsl_spdif.c4
-rw-r--r--sound/soc/fsl/fsl_ssi.c4
-rw-r--r--sound/soc/fsl/imx-ssi.c4
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c4
-rw-r--r--sound/soc/mediatek/common/mtk-btcvsd.c4
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c4
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c4
-rw-r--r--sound/soc/mxs/mxs-saif.c8
-rw-r--r--sound/soc/qcom/lpass-platform.c5
-rw-r--r--sound/soc/sof/intel/bdw.c5
-rw-r--r--sound/soc/sof/intel/byt.c5
-rw-r--r--sound/soc/sprd/sprd-mcdt.c4
-rw-r--r--sound/soc/sti/sti_uniperif.c4
-rw-r--r--sound/soc/stm/stm32_i2s.c5
-rw-r--r--sound/soc/stm/stm32_sai.c4
-rw-r--r--sound/soc/stm/stm32_spdifrx.c4
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c4
-rw-r--r--sound/soc/uniphier/aio-dma.c4
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c2
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c1
30 files changed, 1027 insertions, 320 deletions
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index e98601eccfa3..0f2c574f27f1 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -571,8 +571,11 @@ static int atmel_classd_probe(struct platform_device *pdev)
dd->pdata = pdata;
dd->irq = platform_get_irq(pdev, 0);
- if (dd->irq < 0)
- return dd->irq;
+ if (dd->irq < 0) {
+ ret = dd->irq;
+ dev_err(dev, "failed to could not get irq: %d\n", ret);
+ return ret;
+ }
dd->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(dd->pclk)) {
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index 04ec6f0af179..e09c28349e0d 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -612,8 +612,11 @@ static int atmel_pdmic_probe(struct platform_device *pdev)
dd->dev = dev;
dd->irq = platform_get_irq(pdev, 0);
- if (dd->irq < 0)
- return dd->irq;
+ if (dd->irq < 0) {
+ ret = dd->irq;
+ dev_err(dev, "failed to get irq: %d\n", ret);
+ return ret;
+ }
dd->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(dd->pclk)) {
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 2f9357d7da96..b7c358b48d8d 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -1342,8 +1342,11 @@ static int cygnus_ssp_probe(struct platform_device *pdev)
}
cygaud->irq_num = platform_get_irq(pdev, 0);
- if (cygaud->irq_num <= 0)
- return cygaud->irq_num;
+ if (cygaud->irq_num <= 0) {
+ dev_err(dev, "platform_get_irq failed\n");
+ err = cygaud->irq_num;
+ return err;
+ }
err = audio_clk_init(pdev, cygaud);
if (err) {
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index e3d311fb510e..aa9a8ac987dc 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -1185,8 +1185,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
}
irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(dev, "failed to get mbhc switch irq\n");
return irq;
+ }
ret = devm_request_threaded_irq(dev, irq, NULL,
pm8916_mbhc_switch_irq_handler,
@@ -1198,8 +1200,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
if (priv->mbhc_btn_enabled) {
irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(dev, "failed to get button press irq\n");
return irq;
+ }
ret = devm_request_threaded_irq(dev, irq, NULL,
mbhc_btn_press_irq_handler,
@@ -1210,8 +1214,10 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
dev_err(dev, "cannot request mbhc button press irq\n");
irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(dev, "failed to get button release irq\n");
return irq;
+ }
ret = devm_request_threaded_irq(dev, irq, NULL,
mbhc_btn_release_irq_handler,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index f34637afee51..472c2fff34a8 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1108,8 +1108,10 @@ static int twl6040_probe(struct snd_soc_component *component)
priv->component = component;
priv->plug_irq = platform_get_irq(pdev, 0);
- if (priv->plug_irq < 0)
+ if (priv->plug_irq < 0) {
+ dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq);
return priv->plug_irq;
+ }
INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 34f4cda6fd0f..0b6f7c09804f 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1069,8 +1069,10 @@ static int fsl_asrc_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
return irq;
+ }
ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0,
dev_name(&pdev->dev), asrc_priv);
diff --git a/sound/soc/fsl/fsl_dsd.h b/sound/soc/fsl/fsl_dsd.h
new file mode 100644
index 000000000000..a45f31422f84
--- /dev/null
+++ b/sound/soc/fsl/fsl_dsd.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __FSL_DSD_H
+#define __FSL_DSD_H
+
+#include <linux/pinctrl/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+static bool fsl_is_dsd(struct snd_pcm_hw_params *params)
+{
+ snd_pcm_format_t format = params_format(params);
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_DSD_U8:
+ case SNDRV_PCM_FORMAT_DSD_U16_LE:
+ case SNDRV_PCM_FORMAT_DSD_U16_BE:
+ case SNDRV_PCM_FORMAT_DSD_U32_LE:
+ case SNDRV_PCM_FORMAT_DSD_U32_BE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline struct pinctrl_state *fsl_get_pins_state(struct pinctrl *pinctrl,
+ struct snd_pcm_hw_params *params, u32 bclk)
+{
+ struct pinctrl_state *state = 0;
+
+ if (fsl_is_dsd(params)) {
+ /* DSD512@44.1kHz, DSD512@48kHz */
+ if (bclk >= 22579200)
+ state = pinctrl_lookup_state(pinctrl, "dsd512");
+
+ /* Get default DSD state */
+ if (IS_ERR_OR_NULL(state))
+ state = pinctrl_lookup_state(pinctrl, "dsd");
+ } else {
+ /* 706k32b2c, 768k32b2c, etc */
+ if (bclk >= 45158400)
+ state = pinctrl_lookup_state(pinctrl, "pcm_b2m");
+ }
+
+ /* Get default state */
+ if (IS_ERR_OR_NULL(state))
+ state = pinctrl_lookup_state(pinctrl, "default");
+
+ return state;
+}
+
+#endif /* __FSL_DSD_H */
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 8ade4c4d0918..3426d324acf9 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -1048,8 +1048,10 @@ static int fsl_esai_probe(struct platform_device *pdev)
PTR_ERR(esai_priv->spbaclk));
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
return irq;
+ }
num_domains = of_count_phandle_with_args(np, "power-domains",
"#power-domain-cells");
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index b517e4bc1b87..b8d7b08b9b0a 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -2,34 +2,103 @@
//
// Freescale ALSA SoC Digital Audio Interface (SAI) driver.
//
-// Copyright 2012-2015 Freescale Semiconductor, Inc.
+// Copyright 2012-2016 Freescale Semiconductor, Inc.
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
-#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/pm_qos.h>
+#include <linux/pm_domain.h>
#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 <linux/pm_runtime.h>
+#include <linux/busfreq-imx.h>
+#include "fsl_dsd.h"
#include "fsl_sai.h"
#include "imx-pcm.h"
#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
FSL_SAI_CSR_FEIE)
+#define FSL_SAI_VERID_0301 0x0301
+
+static struct fsl_sai_soc_data fsl_sai_vf610 = {
+ .imx = false,
+ /*dataline is mask, not index*/
+ .dataline = 0x1,
+ .fifos = 1,
+ .fifo_depth = 32,
+ .flags = 0,
+ .constrain_period_size = false,
+};
+
+static struct fsl_sai_soc_data fsl_sai_imx6sx = {
+ .imx = true,
+ .dataline = 0x1,
+ .fifos = 1,
+ .fifo_depth = 32,
+ .flags = 0,
+ .reg_offset = 0,
+ .constrain_period_size = false,
+};
+
+static struct fsl_sai_soc_data fsl_sai_imx6ul = {
+ .imx = true,
+ .dataline = 0x1,
+ .fifos = 1,
+ .fifo_depth = 32,
+ .flags = 0,
+ .reg_offset = 0,
+ .constrain_period_size = false,
+};
+
+static struct fsl_sai_soc_data fsl_sai_imx7ulp = {
+ .imx = true,
+ .dataline = 0x3,
+ .fifos = 2,
+ .fifo_depth = 16,
+ .flags = SAI_FLAG_PMQOS,
+ .reg_offset = 8,
+ .constrain_period_size = false,
+};
+
+static struct fsl_sai_soc_data fsl_sai_imx8mq = {
+ .imx = true,
+ .dataline = 0xff,
+ .fifos = 8,
+ .fifo_depth = 128,
+ .flags = 0,
+ .reg_offset = 8,
+ .constrain_period_size = false,
+};
+
+static struct fsl_sai_soc_data fsl_sai_imx8qm = {
+ .imx = true,
+ .dataline = 0xf,
+ .fifos = 1,
+ .fifo_depth = 64,
+ .flags = 0,
+ .reg_offset = 0,
+ .constrain_period_size = true,
+};
+
static const unsigned int fsl_sai_rates[] = {
8000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000,
- 88200, 96000, 176400, 192000
+ 88200, 96000, 176400, 192000, 352800,
+ 384000, 705600, 768000, 1411200, 2822400,
};
static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
@@ -40,7 +109,7 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
static irqreturn_t fsl_sai_isr(int irq, void *devid)
{
struct fsl_sai *sai = (struct fsl_sai *)devid;
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
struct device *dev = &sai->pdev->dev;
u32 flags, xcsr, mask;
bool irq_none = true;
@@ -53,7 +122,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
/* Tx IRQ */
- regmap_read(sai->regmap, FSL_SAI_TCSR(ofs), &xcsr);
+ regmap_read(sai->regmap, FSL_SAI_TCSR(offset), &xcsr);
flags = xcsr & mask;
if (flags)
@@ -83,11 +152,11 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
xcsr &= ~FSL_SAI_CSR_xF_MASK;
if (flags)
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), flags | xcsr);
+ regmap_write(sai->regmap, FSL_SAI_TCSR(offset), flags | xcsr);
irq_rx:
/* Rx IRQ */
- regmap_read(sai->regmap, FSL_SAI_RCSR(ofs), &xcsr);
+ regmap_read(sai->regmap, FSL_SAI_RCSR(offset), &xcsr);
flags = xcsr & mask;
if (flags)
@@ -117,7 +186,7 @@ irq_rx:
xcsr &= ~FSL_SAI_CSR_xF_MASK;
if (flags)
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr);
+ regmap_write(sai->regmap, FSL_SAI_RCSR(offset), flags | xcsr);
out:
if (irq_none)
@@ -137,21 +206,11 @@ static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
return 0;
}
-static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai,
- unsigned int ratio)
-{
- struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
-
- sai->bclk_ratio = ratio;
-
- 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)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
u32 val_cr2 = 0;
@@ -172,20 +231,89 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, offset),
FSL_SAI_CR2_MSEL_MASK, val_cr2);
return 0;
}
+static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+ struct clk *p = sai->mclk_clk[clk_id], *pll = 0, *npll = 0;
+ u64 ratio = freq;
+ int ret;
+
+ while (p && sai->pll8k_clk && sai->pll11k_clk) {
+ struct clk *pp = clk_get_parent(p);
+
+ if (clk_is_match(pp, sai->pll8k_clk) ||
+ clk_is_match(pp, sai->pll11k_clk)) {
+ pll = pp;
+ break;
+ }
+ p = pp;
+ }
+
+ if (pll) {
+ npll = (do_div(ratio, 8000) ? sai->pll11k_clk : sai->pll8k_clk);
+ if (!clk_is_match(pll, npll)) {
+ if (sai->mclk_streams == 0) {
+ ret = clk_set_parent(p, npll);
+ if (ret < 0)
+ dev_warn(dai->dev,
+ "failed to set parent %s: %d\n",
+ __clk_get_name(npll), ret);
+ } else {
+ dev_err(dai->dev,
+ "PLL %s is in use by a running stream.\n",
+ __clk_get_name(pll));
+ return -EINVAL;
+ }
+ }
+ }
+
+ ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
+ if (ret < 0)
+ dev_err(dai->dev, "failed to set clock rate (%u): %d\n",
+ freq, ret);
+ return ret;
+}
+
+static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+
+ sai->bitclk_ratio = ratio;
+ return 0;
+}
+
static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
if (dir == SND_SOC_CLOCK_IN)
return 0;
+ if (freq > 0) {
+ if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
+ dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) {
+ dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id);
+ return -EINVAL;
+ }
+
+ ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq);
+ if (ret < 0)
+ return ret;
+ }
+
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_TRANSMITTER);
if (ret) {
@@ -205,13 +333,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
unsigned int fmt, int fsl_dir)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
u32 val_cr2 = 0, val_cr4 = 0;
if (!sai->is_lsb_first)
val_cr4 |= FSL_SAI_CR4_MF;
+ sai->is_dsp_mode = false;
/* DAI mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -250,6 +379,11 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
val_cr2 |= FSL_SAI_CR2_BCP;
sai->is_dsp_mode = true;
break;
+ case SND_SOC_DAIFMT_PDM:
+ val_cr2 |= FSL_SAI_CR2_BCP;
+ val_cr4 &= ~FSL_SAI_CR4_MF;
+ sai->is_dsp_mode = true;
+ break;
case SND_SOC_DAIFMT_RIGHT_J:
/* To be done */
default:
@@ -278,31 +412,31 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
+ sai->slave_mode[tx] = false;
+
/* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
- sai->is_slave_mode = false;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- sai->is_slave_mode = true;
+ sai->slave_mode[tx] = true;
break;
case SND_SOC_DAIFMT_CBS_CFM:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
- sai->is_slave_mode = false;
break;
case SND_SOC_DAIFMT_CBM_CFS:
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
- sai->is_slave_mode = true;
+ sai->slave_mode[tx] = true;
break;
default:
return -EINVAL;
}
- regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, offset),
FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2);
- regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE |
FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4);
@@ -311,14 +445,23 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
+ if (sai->masterflag[FSL_FMT_TRANSMITTER])
+ fmt = (fmt & (~SND_SOC_DAIFMT_MASTER_MASK)) |
+ sai->masterflag[FSL_FMT_TRANSMITTER];
+
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
if (ret) {
dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
return ret;
}
+ if (sai->masterflag[FSL_FMT_RECEIVER])
+ fmt = (fmt & (~SND_SOC_DAIFMT_MASTER_MASK)) |
+ sai->masterflag[FSL_FMT_RECEIVER];
+
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
if (ret)
dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
@@ -326,19 +469,64 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
return ret;
}
+static int fsl_sai_check_ver(struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+ unsigned char offset = sai->soc->reg_offset;
+ unsigned int val;
+
+ if (FSL_SAI_TCSR(offset) == FSL_SAI_VERID)
+ return 0;
+
+ if (sai->verid.loaded)
+ return 0;
+
+ sai->verid.loaded = true;
+ regmap_read(sai->regmap, FSL_SAI_VERID, &val);
+ dev_dbg(cpu_dai->dev, "VERID: 0x%016X\n", val);
+
+ sai->verid.id = (val & FSL_SAI_VER_ID_MASK) >> FSL_SAI_VER_ID_SHIFT;
+ sai->verid.extfifo_en = (val & FSL_SAI_VER_EFIFO_EN);
+ sai->verid.timestamp_en = (val & FSL_SAI_VER_TSTMP_EN);
+
+ regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
+ dev_dbg(cpu_dai->dev, "PARAM: 0x%016X\n", val);
+
+ /* max slots per frame, power of 2 */
+ sai->param.spf = 1 <<
+ ((val & FSL_SAI_PAR_SPF_MASK) >> FSL_SAI_PAR_SPF_SHIFT);
+
+ /* words per fifo, power of 2 */
+ sai->param.wpf = 1 <<
+ ((val & FSL_SAI_PAR_WPF_MASK) >> FSL_SAI_PAR_WPF_SHIFT);
+
+ /* number of datalines implemented */
+ sai->param.dln = val & FSL_SAI_PAR_DLN_MASK;
+
+ dev_dbg(cpu_dai->dev,
+ "Version: 0x%08X, SPF: %u, WPF: %u, DLN: %u\n",
+ sai->verid.id, sai->param.spf, sai->param.wpf, sai->param.dln
+ );
+
+ return 0;
+}
+
static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
unsigned long clk_rate;
- u32 savediv = 0, ratio, savesub = freq;
+ unsigned int reg = 0;
+ u32 ratio, savesub = freq, saveratio = 0, savediv = 0;
u32 id;
int ret = 0;
/* Don't apply to slave mode */
- if (sai->is_slave_mode)
+ if (sai->slave_mode[tx])
return 0;
+ fsl_sai_check_ver(dai);
+
for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
clk_rate = clk_get_rate(sai->mclk_clk[id]);
if (!clk_rate)
@@ -359,22 +547,21 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
"ratio %d for freq %dHz based on clock %ldHz\n",
ratio, freq, clk_rate);
- if (ratio % 2 == 0 && ratio >= 2 && ratio <= 512)
- ratio /= 2;
- else
- continue;
+ if ((ratio % 2 == 0 && ratio >= 2 && ratio <= 512) ||
+ (ratio == 1 && sai->verid.id >= FSL_SAI_VERID_0301)) {
- if (ret < savesub) {
- savediv = ratio;
- sai->mclk_id[tx] = id;
- savesub = ret;
- }
+ if (ret < savesub) {
+ saveratio = ratio;
+ sai->mclk_id[tx] = id;
+ savesub = ret;
+ }
- if (ret == 0)
- break;
+ if (ret == 0)
+ break;
+ }
}
- if (savediv == 0) {
+ if (saveratio == 0) {
dev_err(dai->dev, "failed to derive required %cx rate: %d\n",
tx ? 'T' : 'R', freq);
return -EINVAL;
@@ -390,24 +577,32 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
* 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(ofs),
- FSL_SAI_CR2_MSEL_MASK,
- FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
- regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs),
- FSL_SAI_CR2_DIV_MASK, savediv - 1);
- } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
- (tx && !sai->synchronous[TX])) {
- regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs),
- FSL_SAI_CR2_MSEL_MASK,
- FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
- regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs),
- FSL_SAI_CR2_DIV_MASK, savediv - 1);
+ if ((!tx || sai->synchronous[TX]) && !sai->synchronous[RX])
+ reg = FSL_SAI_RCR2(offset);
+ else if ((tx || sai->synchronous[RX]) && !sai->synchronous[TX])
+ reg = FSL_SAI_TCR2(offset);
+
+ if (reg) {
+ regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK,
+ FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
+
+ savediv = (saveratio == 1 ? 0 : (saveratio >> 1) - 1);
+ regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_DIV_MASK, savediv);
+
+ if (sai->verid.id >= FSL_SAI_VERID_0301) {
+ regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_BYP,
+ (saveratio == 1 ? FSL_SAI_CR2_BYP : 0));
+ }
+ }
+
+ if (sai->verid.id >= FSL_SAI_VERID_0301) {
+ /* SAI is in master mode at this point, so enable MCLK */
+ regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
+ FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
}
- dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n",
- sai->mclk_id[tx], savediv, savesub);
+ dev_dbg(dai->dev, "best fit: clock id=%d, ratio=%d, deviation=%d\n",
+ sai->mclk_id[tx], saveratio, savesub);
return 0;
}
@@ -417,30 +612,65 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int channels = params_channels(params);
u32 word_width = params_width(params);
+ u32 rate = params_rate(params);
u32 val_cr4 = 0, val_cr5 = 0;
u32 slots = (channels == 1) ? 2 : channels;
u32 slot_width = word_width;
- int ret;
+ u32 pins, bclk;
+ int ret, i, trce_mask = 0, dl_cfg_cnt, dl_cfg_idx = 0;
+ struct fsl_sai_dl_cfg *dl_cfg;
if (sai->slots)
slots = sai->slots;
+ pins = DIV_ROUND_UP(channels, slots);
+ sai->is_dsd = fsl_is_dsd(params);
+ if (sai->is_dsd) {
+ pins = channels;
+ dl_cfg = sai->dsd_dl_cfg;
+ dl_cfg_cnt = sai->dsd_dl_cfg_cnt;
+ } else {
+ dl_cfg = sai->pcm_dl_cfg;
+ dl_cfg_cnt = sai->pcm_dl_cfg_cnt;
+ }
+
+ for (i = 0; i < dl_cfg_cnt; i++) {
+ if (dl_cfg[i].pins == pins) {
+ dl_cfg_idx = i;
+ break;
+ }
+ }
+
+ if (dl_cfg_idx >= dl_cfg_cnt) {
+ dev_err(cpu_dai->dev, "fsl,dataline%s invalid or not provided.\n",
+ sai->is_dsd ? ",dsd" : "");
+ return -EINVAL;
+ }
+
if (sai->slot_width)
slot_width = sai->slot_width;
- if (!sai->is_slave_mode) {
- if (sai->bclk_ratio)
- ret = fsl_sai_set_bclk(cpu_dai, tx,
- sai->bclk_ratio *
- params_rate(params));
- else
- ret = fsl_sai_set_bclk(cpu_dai, tx,
- slots * slot_width *
- params_rate(params));
+ bclk = rate*(sai->bitclk_ratio ? sai->bitclk_ratio : slots * slot_width);
+
+ if (!IS_ERR_OR_NULL(sai->pinctrl)) {
+ sai->pins_state = fsl_get_pins_state(sai->pinctrl, params, bclk);
+
+ if (!IS_ERR_OR_NULL(sai->pins_state)) {
+ ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+ if (ret) {
+ dev_err(cpu_dai->dev,
+ "failed to set proper pins state: %d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ if (!sai->slave_mode[tx]) {
+ ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
if (ret)
return ret;
@@ -460,13 +690,18 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
- if (sai->is_lsb_first)
+ if (sai->is_lsb_first || sai->is_dsd)
val_cr5 |= FSL_SAI_CR5_FBT(0);
else
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
+ /* Output Mode - data pins transmit 0 when slots are masked
+ * or channels are disabled
+ */
+ val_cr4 |= FSL_SAI_CR4_CHMOD;
+
/*
* 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),
@@ -474,36 +709,78 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
* error.
*/
- if (!sai->is_slave_mode) {
+ if (!sai->slave_mode[tx]) {
if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
- regmap_update_bits(sai->regmap, FSL_SAI_TCR4(ofs),
- FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR4(offset),
+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
+ FSL_SAI_CR4_CHMOD_MASK,
val_cr4);
- regmap_update_bits(sai->regmap, FSL_SAI_TCR5(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR5(offset),
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(ofs),
- FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR4(offset),
+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
+ FSL_SAI_CR4_CHMOD_MASK,
val_cr4);
- regmap_update_bits(sai->regmap, FSL_SAI_RCR5(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR5(offset),
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, ofs),
- FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+ if (sai->soc->dataline != 0x1) {
+
+ if (dl_cfg[dl_cfg_idx].mask[tx] <= 1 || sai->is_multi_lane)
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+ FSL_SAI_CR4_FCOMB_MASK, 0);
+ else
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+ FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
+
+ if (sai->is_multi_lane) {
+ if (tx) {
+ sai->dma_params_tx.maxburst =
+ FSL_SAI_MAXBURST_TX * pins;
+ sai->dma_params_tx.fifo_num = pins +
+ (dl_cfg[dl_cfg_idx].offset[tx] << 4);
+ } else {
+ sai->dma_params_rx.maxburst =
+ FSL_SAI_MAXBURST_RX * pins;
+ sai->dma_params_rx.fifo_num = pins +
+ (dl_cfg[dl_cfg_idx].offset[tx] << 4);
+ }
+ }
+
+ snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
+ &sai->dma_params_rx);
+ }
+
+ if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & 0xFF) < pins) {
+ dev_err(cpu_dai->dev, "channel not supported\n");
+ return -EINVAL;
+ }
+
+ /*find a proper tcre setting*/
+ for (i = 0; i < 8; i++) {
+ trce_mask = (1 << (i + 1)) - 1;
+ if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins)
+ break;
+ }
+
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+ FSL_SAI_CR3_TRCE_MASK,
+ FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
+
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
+ FSL_SAI_CR4_CHMOD_MASK,
val_cr4);
- regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, offset),
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
FSL_SAI_CR5_FBT_MASK, val_cr5);
- regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
-
+ regmap_write(sai->regmap, FSL_SAI_xMR(tx),
+ ~0UL - ((1 << min(channels, slots)) - 1));
return 0;
}
@@ -511,9 +788,13 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ unsigned char offset = sai->soc->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- if (!sai->is_slave_mode &&
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+ FSL_SAI_CR3_TRCE_MASK, 0);
+
+ if (!sai->slave_mode[tx] &&
sai->mclk_streams & BIT(substream->stream)) {
clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
sai->mclk_streams &= ~BIT(substream->stream);
@@ -527,19 +808,46 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int ofs = sai->soc_data->reg_offset;
-
+ unsigned char offset = sai->soc->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u8 channels = substream->runtime->channels;
+ u32 slots = (channels == 1) ? 2 : channels;
u32 xcsr, count = 100;
+ u32 pins;
+ int i = 0, j = 0, k = 0, dl_cfg_cnt, dl_cfg_idx = 0;
+ struct fsl_sai_dl_cfg *dl_cfg;
+
+ if (sai->slots)
+ slots = sai->slots;
+
+ pins = DIV_ROUND_UP(channels, slots);
+
+ if (sai->is_dsd) {
+ pins = channels;
+ dl_cfg = sai->dsd_dl_cfg;
+ dl_cfg_cnt = sai->dsd_dl_cfg_cnt;
+ } else {
+ dl_cfg = sai->pcm_dl_cfg;
+ dl_cfg_cnt = sai->pcm_dl_cfg_cnt;
+ }
+
+ for (i = 0; i < dl_cfg_cnt; i++) {
+ if (dl_cfg[i].pins == pins) {
+ dl_cfg_idx = i;
+ break;
+ }
+ }
+
+ i = 0;
/*
* Asynchronous mode: Clear SYNC for both Tx and Rx.
* Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
* Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
*/
- regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC,
- sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
- regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC,
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR2(offset), FSL_SAI_CR2_SYNC,
+ sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR2(offset), FSL_SAI_CR2_SYNC,
sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
/*
@@ -550,44 +858,63 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
+
+ while (tx && i < channels) {
+ if (dl_cfg[dl_cfg_idx].mask[tx] & (1 << j)) {
+ regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
+ i++;
+ k++;
+ }
+ j++;
+
+ if (k%pins == 0)
+ j = 0;
+ }
+
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
- regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
- regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+ FSL_SAI_CSR_SE, FSL_SAI_CSR_SE);
+ if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset),
FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+ } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), offset),
+ FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
+ }
- regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
FSL_SAI_CSR_FRDE, 0);
- regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
FSL_SAI_CSR_xIE_MASK, 0);
/* Check if the opposite FRDE is also disabled */
- regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr);
+ regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, offset), &xcsr);
if (!(xcsr & FSL_SAI_CSR_FRDE)) {
/* Disable both directions and reset their FIFOs */
- regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset),
FSL_SAI_CSR_TERE, 0);
- regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset),
FSL_SAI_CSR_TERE, 0);
/* TERE will remain set till the end of current frame */
do {
udelay(10);
- regmap_read(sai->regmap,
- FSL_SAI_xCSR(tx, ofs), &xcsr);
+ regmap_read(sai->regmap, FSL_SAI_xCSR(tx, offset), &xcsr);
} while (--count && xcsr & FSL_SAI_CSR_TERE);
- regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR(offset),
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
- regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR(offset),
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
/*
@@ -597,15 +924,15 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
* This is a hardware bug, and will be fix in the
* next sai version.
*/
- if (!sai->is_slave_mode) {
+ if (!sai->slave_mode[tx]) {
/* Software Reset for both Tx and Rx */
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs),
- FSL_SAI_CSR_SR);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs),
- FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap,
+ FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap,
+ FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
/* Clear SR bit to finish the reset */
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
+ regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
+ regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
}
}
break;
@@ -620,19 +947,16 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int ofs = sai->soc_data->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
int ret;
- regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
- FSL_SAI_CR3_TRCE_MASK,
- FSL_SAI_CR3_TRCE);
+ if (sai->is_stream_opened[tx])
+ return -EBUSY;
+ else
+ sai->is_stream_opened[tx] = true;
- /*
- * EDMA controller needs period size to be a multiple of
- * tx/rx maxburst
- */
- if (sai->soc_data->use_edma)
+ /* EDMA engine needs periods of size multiple of tx/rx maxburst */
+ if (sai->soc->constrain_period_size)
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
tx ? sai->dma_params_tx.maxburst :
@@ -648,15 +972,14 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- unsigned int ofs = sai->soc_data->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
- FSL_SAI_CR3_TRCE_MASK, 0);
+ if (sai->is_stream_opened[tx])
+ sai->is_stream_opened[tx] = false;
}
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
- .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+ .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
.set_sysclk = fsl_sai_set_dai_sysclk,
.set_fmt = fsl_sai_set_dai_fmt,
.set_tdm_slot = fsl_sai_set_dai_tdm_slot,
@@ -670,20 +993,21 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
/* Software Reset for both Tx and Rx */
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap, FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap, FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
/* Clear SR bit to finish the reset */
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
+ regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
+ regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
- regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs),
- FSL_SAI_CR1_RFW_MASK,
- sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX);
- regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs),
- FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_RX - 1);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR1(offset),
+ sai->soc->fifo_depth - 1,
+ sai->soc->fifo_depth - FSL_SAI_MAXBURST_TX);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR1(offset),
+ sai->soc->fifo_depth - 1,
+ FSL_SAI_MAXBURST_RX - 1);
snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
&sai->dma_params_rx);
@@ -693,6 +1017,23 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static int fsl_sai_dai_resume(struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) {
+ ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+ if (ret) {
+ dev_err(cpu_dai->dev,
+ "failed to set proper pins state: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static struct snd_soc_dai_driver fsl_sai_dai = {
.probe = fsl_sai_dai_probe,
.playback = {
@@ -700,7 +1041,7 @@ static struct snd_soc_dai_driver fsl_sai_dai = {
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
- .rate_max = 192000,
+ .rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
},
@@ -709,10 +1050,11 @@ static struct snd_soc_dai_driver fsl_sai_dai = {
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
- .rate_max = 192000,
+ .rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
},
+ .resume = fsl_sai_dai_resume,
.ops = &fsl_sai_pcm_dai_ops,
};
@@ -720,7 +1062,7 @@ static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-sai",
};
-static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
+static struct reg_default fsl_sai_v2_reg_defaults[] = {
{FSL_SAI_TCR1(0), 0},
{FSL_SAI_TCR2(0), 0},
{FSL_SAI_TCR3(0), 0},
@@ -728,22 +1070,16 @@ static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
{FSL_SAI_TCR5(0), 0},
{FSL_SAI_TDR0, 0},
{FSL_SAI_TDR1, 0},
- {FSL_SAI_TDR2, 0},
- {FSL_SAI_TDR3, 0},
- {FSL_SAI_TDR4, 0},
- {FSL_SAI_TDR5, 0},
- {FSL_SAI_TDR6, 0},
- {FSL_SAI_TDR7, 0},
- {FSL_SAI_TMR, 0},
+ {FSL_SAI_TMR, 0},
{FSL_SAI_RCR1(0), 0},
{FSL_SAI_RCR2(0), 0},
{FSL_SAI_RCR3(0), 0},
{FSL_SAI_RCR4(0), 0},
{FSL_SAI_RCR5(0), 0},
- {FSL_SAI_RMR, 0},
+ {FSL_SAI_RMR, 0},
};
-static struct reg_default fsl_sai_reg_defaults_ofs8[] = {
+static struct reg_default fsl_sai_v3_reg_defaults[] = {
{FSL_SAI_TCR1(8), 0},
{FSL_SAI_TCR2(8), 0},
{FSL_SAI_TCR3(8), 0},
@@ -757,24 +1093,26 @@ static struct reg_default fsl_sai_reg_defaults_ofs8[] = {
{FSL_SAI_TDR5, 0},
{FSL_SAI_TDR6, 0},
{FSL_SAI_TDR7, 0},
- {FSL_SAI_TMR, 0},
+ {FSL_SAI_TMR, 0},
{FSL_SAI_RCR1(8), 0},
{FSL_SAI_RCR2(8), 0},
{FSL_SAI_RCR3(8), 0},
{FSL_SAI_RCR4(8), 0},
{FSL_SAI_RCR5(8), 0},
- {FSL_SAI_RMR, 0},
+ {FSL_SAI_RMR, 0},
+ {FSL_SAI_MCTL, 0},
+ {FSL_SAI_MDIV, 0},
};
static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
{
struct fsl_sai *sai = dev_get_drvdata(dev);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
- if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs))
+ if (reg >= FSL_SAI_TCSR(offset) && reg <= FSL_SAI_TCR5(offset))
return true;
- if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs))
+ if (reg >= FSL_SAI_RCSR(offset) && reg <= FSL_SAI_RCR5(offset))
return true;
switch (reg) {
@@ -804,6 +1142,10 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
case FSL_SAI_RFR6:
case FSL_SAI_RFR7:
case FSL_SAI_RMR:
+ case FSL_SAI_MCTL:
+ case FSL_SAI_MDIV:
+ case FSL_SAI_VERID:
+ case FSL_SAI_PARAM:
return true;
default:
return false;
@@ -813,9 +1155,13 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
{
struct fsl_sai *sai = dev_get_drvdata(dev);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
- if (reg == FSL_SAI_TCSR(ofs) || reg == FSL_SAI_RCSR(ofs))
+ if (reg == FSL_SAI_TCSR(offset) || reg == FSL_SAI_RCSR(offset))
+ return true;
+
+ if (sai->soc->reg_offset == 8 && (reg == FSL_SAI_VERID ||
+ reg == FSL_SAI_PARAM))
return true;
switch (reg) {
@@ -852,12 +1198,12 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
{
struct fsl_sai *sai = dev_get_drvdata(dev);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
- if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs))
+ if (reg >= FSL_SAI_TCSR(offset) && reg <= FSL_SAI_TCR5(offset))
return true;
- if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs))
+ if (reg >= FSL_SAI_RCSR(offset) && reg <= FSL_SAI_RCR5(offset))
return true;
switch (reg) {
@@ -871,30 +1217,128 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
case FSL_SAI_TDR7:
case FSL_SAI_TMR:
case FSL_SAI_RMR:
+ case FSL_SAI_MCTL:
+ case FSL_SAI_MDIV:
return true;
default:
return false;
}
}
-static struct regmap_config fsl_sai_regmap_config = {
+static const struct regmap_config fsl_sai_v2_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .fast_io = true,
.max_register = FSL_SAI_RMR,
- .reg_defaults = fsl_sai_reg_defaults_ofs0,
- .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults_ofs0),
+ .reg_defaults = fsl_sai_v2_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_sai_v2_reg_defaults),
+ .readable_reg = fsl_sai_readable_reg,
+ .volatile_reg = fsl_sai_volatile_reg,
+ .writeable_reg = fsl_sai_writeable_reg,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config fsl_sai_v3_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = FSL_SAI_MDIV,
+ .reg_defaults = fsl_sai_v3_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_sai_v3_reg_defaults),
.readable_reg = fsl_sai_readable_reg,
.volatile_reg = fsl_sai_volatile_reg,
.writeable_reg = fsl_sai_writeable_reg,
.cache_type = REGCACHE_FLAT,
};
+static const struct of_device_id fsl_sai_ids[] = {
+ { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610 },
+ { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx },
+ { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6ul },
+ { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp },
+ { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq },
+ { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+
+static unsigned int fsl_sai_calc_dl_off(unsigned int* dl_mask)
+{
+ int fbidx, nbidx, offset;
+
+ fbidx = find_first_bit((const unsigned long *)dl_mask, 8);
+ nbidx = find_next_bit((const unsigned long *)dl_mask, 8, fbidx+1);
+ offset = nbidx - fbidx - 1;
+
+ return (offset < 0 || offset >= 7 ? 0 : offset);
+}
+
+static int fsl_sai_read_dlcfg(struct platform_device *pdev, char *pn,
+ struct fsl_sai_dl_cfg **rcfg, unsigned int soc_dl)
+{
+ int ret, elems, i, index, num_cfg;
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_sai_dl_cfg *cfg;
+ u32 rx, tx, pins;
+
+ *rcfg = NULL;
+
+ elems = of_property_count_u32_elems(np, pn);
+
+ /* consider default value "0 0x1 0x1" if property is missing */
+ if (elems <= 0)
+ elems = 3;
+
+ if (elems % 3) {
+ dev_err(&pdev->dev,
+ "Number of elements in %s must be divisible to 3.\n", pn);
+ return -EINVAL;
+ }
+
+ num_cfg = elems / 3;
+ cfg = devm_kzalloc(&pdev->dev, num_cfg * sizeof(*cfg), GFP_KERNEL);
+ if (cfg == NULL) {
+ dev_err(&pdev->dev, "Cannot allocate memory for %s.\n", pn);
+ return -ENOMEM;
+ }
+
+ for (i = 0, index = 0; i < num_cfg; i++) {
+ ret = of_property_read_u32_index(np, pn, index++, &pins);
+ if (ret)
+ pins = 0;
+
+ ret = of_property_read_u32_index(np, pn, index++, &rx);
+ if (ret)
+ rx = 1;
+
+ ret = of_property_read_u32_index(np, pn, index++, &tx);
+ if (ret)
+ tx = 1;
+
+ if ((rx & ~soc_dl) || (tx & ~soc_dl)) {
+ dev_err(&pdev->dev,
+ "%s: dataline cfg[%d] setting error, mask is 0x%x\n",
+ pn, i, soc_dl);
+ return -EINVAL;
+ }
+
+ cfg[i].pins = pins;
+ cfg[i].mask[0] = rx;
+ cfg[i].offset[0] = fsl_sai_calc_dl_off(&rx);
+ cfg[i].mask[1] = tx;
+ cfg[i].offset[1] = fsl_sai_calc_dl_off(&tx);
+ }
+
+ *rcfg = cfg;
+ return num_cfg;
+}
+
static int fsl_sai_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id;
struct fsl_sai *sai;
struct regmap *gpr;
struct resource *res;
@@ -902,32 +1346,36 @@ static int fsl_sai_probe(struct platform_device *pdev)
char tmp[8];
int irq, ret, i;
int index;
+ struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
+ unsigned long irqflags = 0;
+ int num_domains = 0;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
return -ENOMEM;
sai->pdev = pdev;
- sai->soc_data = of_device_get_match_data(&pdev->dev);
+
+ of_id = of_match_device(fsl_sai_ids, &pdev->dev);
+ if (!of_id || !of_id->data)
+ return -EINVAL;
sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
+ sai->soc = of_id->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
- if (sai->soc_data->reg_offset == 8) {
- fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8;
- fsl_sai_regmap_config.num_reg_defaults =
- ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
- }
+ if (sai->soc->reg_offset == 8)
+ fsl_sai_regmap_config = fsl_sai_v3_regmap_config;
sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
"bus", base, &fsl_sai_regmap_config);
/* Compatible with old DTB cases */
- if (IS_ERR(sai->regmap))
+ if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER)
sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
"sai", base, &fsl_sai_regmap_config);
if (IS_ERR(sai->regmap)) {
@@ -943,22 +1391,86 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->bus_clk = NULL;
}
- sai->mclk_clk[0] = sai->bus_clk;
- for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
+ for (i = 0; i < FSL_SAI_MCLK_MAX; i++) {
sprintf(tmp, "mclk%d", i);
sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
if (IS_ERR(sai->mclk_clk[i])) {
dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
- i + 1, PTR_ERR(sai->mclk_clk[i]));
+ i, PTR_ERR(sai->mclk_clk[i]));
sai->mclk_clk[i] = NULL;
}
}
+ num_domains = of_count_phandle_with_args(np, "power-domains",
+ "#power-domain-cells");
+ for (i = 0; i < num_domains; i++) {
+ struct device *pd_dev;
+ struct device_link *link;
+
+ pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i);
+ if (IS_ERR(pd_dev))
+ return PTR_ERR(pd_dev);
+
+ link = device_link_add(&pdev->dev, pd_dev,
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (IS_ERR(link))
+ return PTR_ERR(link);
+ }
+
+ sai->pll8k_clk = devm_clk_get(&pdev->dev, "pll8k");
+ if (IS_ERR(sai->pll8k_clk))
+ sai->pll8k_clk = NULL;
+
+ sai->pll11k_clk = devm_clk_get(&pdev->dev, "pll11k");
+ if (IS_ERR(sai->pll11k_clk))
+ sai->pll11k_clk = NULL;
+
+ if (of_find_property(np, "fsl,sai-multi-lane", NULL))
+ sai->is_multi_lane = true;
+
+ /*dataline mask for rx and tx*/
+ ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline", &sai->pcm_dl_cfg,
+ sai->soc->dataline);
+ if (ret < 0)
+ return ret;
+
+ sai->pcm_dl_cfg_cnt = ret;
+
+ ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline,dsd", &sai->dsd_dl_cfg,
+ sai->soc->dataline);
+ if (ret < 0)
+ return ret;
+
+ sai->dsd_dl_cfg_cnt = ret;
+
+ if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
+ (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
+ {
+ sai->masterflag[FSL_FMT_TRANSMITTER] = SND_SOC_DAIFMT_CBS_CFS;
+ sai->masterflag[FSL_FMT_RECEIVER] = SND_SOC_DAIFMT_CBM_CFM;
+ } else {
+ if (!of_property_read_u32(np, "fsl,txmasterflag",
+ &sai->masterflag[FSL_FMT_TRANSMITTER]))
+ sai->masterflag[FSL_FMT_TRANSMITTER] <<= 12;
+ if (!of_property_read_u32(np, "fsl,rxmasterflag",
+ &sai->masterflag[FSL_FMT_RECEIVER]))
+ sai->masterflag[FSL_FMT_RECEIVER] <<= 12;
+ }
+
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
return irq;
+ }
+
+ /* SAI shared interrupt */
+ if (of_property_read_bool(np, "fsl,shared-interrupt"))
+ irqflags = IRQF_SHARED;
- ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
+ ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, irqflags, np->name,
+ sai);
if (ret) {
dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
return ret;
@@ -1007,22 +1519,28 @@ static int fsl_sai_probe(struct platform_device *pdev)
MCLK_DIR(index));
}
+ sai->dma_params_rx.chan_name = "rx";
+ sai->dma_params_tx.chan_name = "tx";
sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+ sai->pinctrl = devm_pinctrl_get(&pdev->dev);
+
platform_set_drvdata(pdev, sai);
pm_runtime_enable(&pdev->dev);
+ regcache_cache_only(sai->regmap, true);
+
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
&fsl_sai_dai, 1);
if (ret)
return ret;
- if (sai->soc_data->use_imx_pcm)
- return imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE);
+ if (sai->soc->imx)
+ return imx_pcm_platform_register(&pdev->dev);
else
return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
}
@@ -1034,57 +1552,15 @@ static int fsl_sai_remove(struct platform_device *pdev)
return 0;
}
-static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
- .use_imx_pcm = false,
- .use_edma = false,
- .fifo_depth = 32,
- .reg_offset = 0,
-};
-
-static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
- .use_imx_pcm = true,
- .use_edma = false,
- .fifo_depth = 32,
- .reg_offset = 0,
-};
-
-static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
- .use_imx_pcm = true,
- .use_edma = false,
- .fifo_depth = 16,
- .reg_offset = 8,
-};
-
-static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
- .use_imx_pcm = true,
- .use_edma = false,
- .fifo_depth = 128,
- .reg_offset = 8,
-};
-
-static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
- .use_imx_pcm = true,
- .use_edma = true,
- .fifo_depth = 64,
- .reg_offset = 0,
-};
-
-static const struct of_device_id fsl_sai_ids[] = {
- { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data },
- { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data },
- { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data },
- { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data },
- { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data },
- { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, fsl_sai_ids);
-
#ifdef CONFIG_PM
static int fsl_sai_runtime_suspend(struct device *dev)
{
struct fsl_sai *sai = dev_get_drvdata(dev);
+ regcache_cache_only(sai->regmap, true);
+
+ release_bus_freq(BUS_FREQ_AUDIO);
+
if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
@@ -1093,6 +1569,9 @@ static int fsl_sai_runtime_suspend(struct device *dev)
clk_disable_unprepare(sai->bus_clk);
+ if (sai->soc->flags & SAI_FLAG_PMQOS)
+ pm_qos_remove_request(&sai->pm_qos_req);
+
regcache_cache_only(sai->regmap, true);
regcache_mark_dirty(sai->regmap);
@@ -1102,7 +1581,7 @@ static int fsl_sai_runtime_suspend(struct device *dev)
static int fsl_sai_runtime_resume(struct device *dev)
{
struct fsl_sai *sai = dev_get_drvdata(dev);
- unsigned int ofs = sai->soc_data->reg_offset;
+ unsigned char offset = sai->soc->reg_offset;
int ret;
ret = clk_prepare_enable(sai->bus_clk);
@@ -1123,12 +1602,20 @@ static int fsl_sai_runtime_resume(struct device *dev)
goto disable_tx_clk;
}
+ request_bus_freq(BUS_FREQ_AUDIO);
+
+ if (sai->soc->flags & SAI_FLAG_PMQOS)
+ pm_qos_add_request(&sai->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
regcache_cache_only(sai->regmap, false);
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR);
+ regcache_mark_dirty(sai->regmap);
+
+ regmap_write(sai->regmap, FSL_SAI_TCSR(offset), FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap, FSL_SAI_RCSR(offset), FSL_SAI_CSR_SR);
usleep_range(1000, 2000);
- regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
- regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
+ regmap_write(sai->regmap, FSL_SAI_TCSR(offset), 0);
+ regmap_write(sai->regmap, FSL_SAI_RCSR(offset), 0);
ret = regcache_sync(sai->regmap);
if (ret)
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 76b15deea80c..20cc5745b0cc 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -1,78 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ * Copyright 2012-2016 Freescale Semiconductor, Inc.
*/
#ifndef __FSL_SAI_H
#define __FSL_SAI_H
+#include <linux/pm_qos.h>
#include <sound/dmaengine_pcm.h>
#define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
- SNDRV_PCM_FMTBIT_S32_LE)
+ SNDRV_PCM_FMTBIT_S32_LE |\
+ SNDRV_PCM_FMTBIT_DSD_U8 |\
+ SNDRV_PCM_FMTBIT_DSD_U16_LE |\
+ SNDRV_PCM_FMTBIT_DSD_U32_LE)
/* SAI Register Map Register */
-#define FSL_SAI_TCSR(ofs) (0x00 + ofs) /* SAI Transmit Control */
-#define FSL_SAI_TCR1(ofs) (0x04 + ofs) /* SAI Transmit Configuration 1 */
-#define FSL_SAI_TCR2(ofs) (0x08 + ofs) /* SAI Transmit Configuration 2 */
-#define FSL_SAI_TCR3(ofs) (0x0c + ofs) /* SAI Transmit Configuration 3 */
-#define FSL_SAI_TCR4(ofs) (0x10 + ofs) /* SAI Transmit Configuration 4 */
-#define FSL_SAI_TCR5(ofs) (0x14 + ofs) /* SAI Transmit Configuration 5 */
-#define FSL_SAI_TDR0 0x20 /* SAI Transmit Data 0 */
-#define FSL_SAI_TDR1 0x24 /* SAI Transmit Data 1 */
-#define FSL_SAI_TDR2 0x28 /* SAI Transmit Data 2 */
-#define FSL_SAI_TDR3 0x2C /* SAI Transmit Data 3 */
-#define FSL_SAI_TDR4 0x30 /* SAI Transmit Data 4 */
-#define FSL_SAI_TDR5 0x34 /* SAI Transmit Data 5 */
-#define FSL_SAI_TDR6 0x38 /* SAI Transmit Data 6 */
-#define FSL_SAI_TDR7 0x3C /* SAI Transmit Data 7 */
-#define FSL_SAI_TFR0 0x40 /* SAI Transmit FIFO 0 */
-#define FSL_SAI_TFR1 0x44 /* SAI Transmit FIFO 1 */
-#define FSL_SAI_TFR2 0x48 /* SAI Transmit FIFO 2 */
-#define FSL_SAI_TFR3 0x4C /* SAI Transmit FIFO 3 */
-#define FSL_SAI_TFR4 0x50 /* SAI Transmit FIFO 4 */
-#define FSL_SAI_TFR5 0x54 /* SAI Transmit FIFO 5 */
-#define FSL_SAI_TFR6 0x58 /* SAI Transmit FIFO 6 */
-#define FSL_SAI_TFR7 0x5C /* SAI Transmit FIFO 7 */
+#define FSL_SAI_VERID 0x00 /* SAI Version ID Register */
+#define FSL_SAI_PARAM 0x04 /* SAI Parameter Register */
+#define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
+#define FSL_SAI_TCR1(offset) (0x04 + offset) /* SAI Transmit Configuration 1 */
+#define FSL_SAI_TCR2(offset) (0x08 + offset) /* SAI Transmit Configuration 2 */
+#define FSL_SAI_TCR3(offset) (0x0c + offset) /* SAI Transmit Configuration 3 */
+#define FSL_SAI_TCR4(offset) (0x10 + offset) /* SAI Transmit Configuration 4 */
+#define FSL_SAI_TCR5(offset) (0x14 + offset) /* SAI Transmit Configuration 5 */
+#define FSL_SAI_TDR0 0x20 /* SAI Transmit Data */
+#define FSL_SAI_TDR1 0x24 /* SAI Transmit Data */
+#define FSL_SAI_TDR2 0x28 /* SAI Transmit Data */
+#define FSL_SAI_TDR3 0x2C /* SAI Transmit Data */
+#define FSL_SAI_TDR4 0x30 /* SAI Transmit Data */
+#define FSL_SAI_TDR5 0x34 /* SAI Transmit Data */
+#define FSL_SAI_TDR6 0x38 /* SAI Transmit Data */
+#define FSL_SAI_TDR7 0x3C /* SAI Transmit Data */
+#define FSL_SAI_TFR0 0x40 /* SAI Transmit FIFO */
+#define FSL_SAI_TFR1 0x44 /* SAI Transmit FIFO */
+#define FSL_SAI_TFR2 0x48 /* SAI Transmit FIFO */
+#define FSL_SAI_TFR3 0x4C /* SAI Transmit FIFO */
+#define FSL_SAI_TFR4 0x50 /* SAI Transmit FIFO */
+#define FSL_SAI_TFR5 0x54 /* SAI Transmit FIFO */
+#define FSL_SAI_TFR6 0x58 /* SAI Transmit FIFO */
+#define FSL_SAI_TFR7 0x5C /* SAI Transmit FIFO */
#define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */
-#define FSL_SAI_RCSR(ofs) (0x80 + ofs) /* SAI Receive Control */
-#define FSL_SAI_RCR1(ofs) (0x84 + ofs)/* SAI Receive Configuration 1 */
-#define FSL_SAI_RCR2(ofs) (0x88 + ofs) /* SAI Receive Configuration 2 */
-#define FSL_SAI_RCR3(ofs) (0x8c + ofs) /* SAI Receive Configuration 3 */
-#define FSL_SAI_RCR4(ofs) (0x90 + ofs) /* SAI Receive Configuration 4 */
-#define FSL_SAI_RCR5(ofs) (0x94 + ofs) /* SAI Receive Configuration 5 */
-#define FSL_SAI_RDR0 0xa0 /* SAI Receive Data 0 */
-#define FSL_SAI_RDR1 0xa4 /* SAI Receive Data 1 */
-#define FSL_SAI_RDR2 0xa8 /* SAI Receive Data 2 */
-#define FSL_SAI_RDR3 0xac /* SAI Receive Data 3 */
-#define FSL_SAI_RDR4 0xb0 /* SAI Receive Data 4 */
-#define FSL_SAI_RDR5 0xb4 /* SAI Receive Data 5 */
-#define FSL_SAI_RDR6 0xb8 /* SAI Receive Data 6 */
-#define FSL_SAI_RDR7 0xbc /* SAI Receive Data 7 */
-#define FSL_SAI_RFR0 0xc0 /* SAI Receive FIFO 0 */
-#define FSL_SAI_RFR1 0xc4 /* SAI Receive FIFO 1 */
-#define FSL_SAI_RFR2 0xc8 /* SAI Receive FIFO 2 */
-#define FSL_SAI_RFR3 0xcc /* SAI Receive FIFO 3 */
-#define FSL_SAI_RFR4 0xd0 /* SAI Receive FIFO 4 */
-#define FSL_SAI_RFR5 0xd4 /* SAI Receive FIFO 5 */
-#define FSL_SAI_RFR6 0xd8 /* SAI Receive FIFO 6 */
-#define FSL_SAI_RFR7 0xdc /* SAI Receive FIFO 7 */
+#define FSL_SAI_TTCTL 0x70 /* SAI Transmit Timestamp Control Register */
+#define FSL_SAI_TTCTN 0x74 /* SAI Transmit Timestamp Counter Register */
+#define FSL_SAI_TBCTN 0x78 /* SAI Transmit Bit Counter Register */
+#define FSL_SAI_TTCAP 0x7C /* SAI Transmit Timestamp Capture */
+
+#define FSL_SAI_RCSR(offset) (0x80 + offset) /* SAI Receive Control */
+#define FSL_SAI_RCR1(offset) (0x84 + offset) /* SAI Receive Configuration 1 */
+#define FSL_SAI_RCR2(offset) (0x88 + offset) /* SAI Receive Configuration 2 */
+#define FSL_SAI_RCR3(offset) (0x8c + offset) /* SAI Receive Configuration 3 */
+#define FSL_SAI_RCR4(offset) (0x90 + offset) /* SAI Receive Configuration 4 */
+#define FSL_SAI_RCR5(offset) (0x94 + offset) /* SAI Receive Configuration 5 */
+#define FSL_SAI_RDR0 0xa0 /* SAI Receive Data */
+#define FSL_SAI_RDR1 0xa4 /* SAI Receive Data */
+#define FSL_SAI_RDR2 0xa8 /* SAI Receive Data */
+#define FSL_SAI_RDR3 0xac /* SAI Receive Data */
+#define FSL_SAI_RDR4 0xb0 /* SAI Receive Data */
+#define FSL_SAI_RDR5 0xb4 /* SAI Receive Data */
+#define FSL_SAI_RDR6 0xb8 /* SAI Receive Data */
+#define FSL_SAI_RDR7 0xbc /* SAI Receive Data */
+#define FSL_SAI_RFR0 0xc0 /* SAI Receive FIFO */
+#define FSL_SAI_RFR1 0xc4 /* SAI Receive FIFO */
+#define FSL_SAI_RFR2 0xc8 /* SAI Receive FIFO */
+#define FSL_SAI_RFR3 0xcc /* SAI Receive FIFO */
+#define FSL_SAI_RFR4 0xd0 /* SAI Receive FIFO */
+#define FSL_SAI_RFR5 0xd4 /* SAI Receive FIFO */
+#define FSL_SAI_RFR6 0xd8 /* SAI Receive FIFO */
+#define FSL_SAI_RFR7 0xdc /* SAI Receive FIFO */
#define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */
+#define FSL_SAI_RTCTL 0xf0 /* SAI Receive Timestamp Control Register */
+#define FSL_SAI_RTCTN 0xf4 /* SAI Receive Timestamp Counter Register */
+#define FSL_SAI_RBCTN 0xf8 /* SAI Receive Bit Counter Register */
+#define FSL_SAI_RTCAP 0xfc /* SAI Receive Timestamp Capture */
+
+#define FSL_SAI_MCTL 0x100 /* SAI MCLK Control Register */
+#define FSL_SAI_MDIV 0x104 /* SAI MCLK Divide Register */
-#define FSL_SAI_xCSR(tx, ofs) (tx ? FSL_SAI_TCSR(ofs) : FSL_SAI_RCSR(ofs))
-#define FSL_SAI_xCR1(tx, ofs) (tx ? FSL_SAI_TCR1(ofs) : FSL_SAI_RCR1(ofs))
-#define FSL_SAI_xCR2(tx, ofs) (tx ? FSL_SAI_TCR2(ofs) : FSL_SAI_RCR2(ofs))
-#define FSL_SAI_xCR3(tx, ofs) (tx ? FSL_SAI_TCR3(ofs) : FSL_SAI_RCR3(ofs))
-#define FSL_SAI_xCR4(tx, ofs) (tx ? FSL_SAI_TCR4(ofs) : FSL_SAI_RCR4(ofs))
-#define FSL_SAI_xCR5(tx, ofs) (tx ? FSL_SAI_TCR5(ofs) : FSL_SAI_RCR5(ofs))
-#define FSL_SAI_xDR(tx, ofs) (tx ? FSL_SAI_TDR(ofs) : FSL_SAI_RDR(ofs))
-#define FSL_SAI_xFR(tx, ofs) (tx ? FSL_SAI_TFR(ofs) : FSL_SAI_RFR(ofs))
+#define FSL_SAI_xCSR(tx, off) (tx ? FSL_SAI_TCSR(off) : FSL_SAI_RCSR(off))
+#define FSL_SAI_xCR1(tx, off) (tx ? FSL_SAI_TCR1(off) : FSL_SAI_RCR1(off))
+#define FSL_SAI_xCR2(tx, off) (tx ? FSL_SAI_TCR2(off) : FSL_SAI_RCR2(off))
+#define FSL_SAI_xCR3(tx, off) (tx ? FSL_SAI_TCR3(off) : FSL_SAI_RCR3(off))
+#define FSL_SAI_xCR4(tx, off) (tx ? FSL_SAI_TCR4(off) : FSL_SAI_RCR4(off))
+#define FSL_SAI_xCR5(tx, off) (tx ? FSL_SAI_TCR5(off) : FSL_SAI_RCR5(off))
#define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR)
/* SAI Transmit/Receive Control Register */
#define FSL_SAI_CSR_TERE BIT(31)
+#define FSL_SAI_CSR_SE BIT(30)
#define FSL_SAI_CSR_FR BIT(25)
#define FSL_SAI_CSR_SR BIT(24)
#define FSL_SAI_CSR_xF_SHIFT 16
@@ -106,19 +122,29 @@
#define FSL_SAI_CR2_MSEL(ID) ((ID) << 26)
#define FSL_SAI_CR2_BCP BIT(25)
#define FSL_SAI_CR2_BCD_MSTR BIT(24)
+#define FSL_SAI_CR2_BYP BIT(23) /* BCLK bypass */
#define FSL_SAI_CR2_DIV_MASK 0xff
/* SAI Transmit and Receive Configuration 3 Register */
-#define FSL_SAI_CR3_TRCE BIT(16)
-#define FSL_SAI_CR3_TRCE_MASK GENMASK(23, 16)
+#define FSL_SAI_CR3_TRCE_MASK (0xff << 16)
+#define FSL_SAI_CR3_TRCE(x) (x << 16)
#define FSL_SAI_CR3_WDFL(x) (x)
#define FSL_SAI_CR3_WDFL_MASK 0x1f
/* SAI Transmit and Receive Configuration 4 Register */
+
+#define FSL_SAI_CR4_FCONT BIT(28)
+#define FSL_SAI_CR4_FCOMB_SHIFT BIT(26)
+#define FSL_SAI_CR4_FCOMB_SOFT BIT(27)
+#define FSL_SAI_CR4_FCOMB_MASK (0x3 << 26)
+#define FSL_SAI_CR4_FPACK_8 (0x2 << 24)
+#define FSL_SAI_CR4_FPACK_16 (0x3 << 24)
#define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16)
#define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
#define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8)
#define FSL_SAI_CR4_SYWD_MASK (0x1f << 8)
+#define FSL_SAI_CR4_CHMOD (1 << 5)
+#define FSL_SAI_CR4_CHMOD_MASK (1 << 5)
#define FSL_SAI_CR4_MF BIT(4)
#define FSL_SAI_CR4_FSE BIT(3)
#define FSL_SAI_CR4_FSP BIT(1)
@@ -132,6 +158,33 @@
#define FSL_SAI_CR5_FBT(x) ((x) << 8)
#define FSL_SAI_CR5_FBT_MASK (0x1f << 8)
+/* SAI MCLK Control Register */
+#define FSL_SAI_MCTL_MCLK_EN BIT(30) /* MCLK Enable */
+#define FSL_SAI_MCTL_MSEL_MASK (0x3 << 24)
+#define FSL_SAI_MCTL_MSEL(ID) ((ID) << 24)
+#define FSL_SAI_MCTL_MSEL_BUS 0
+#define FSL_SAI_MCTL_MSEL_MCLK1 BIT(24)
+#define FSL_SAI_MCTL_MSEL_MCLK2 BIT(25)
+#define FSL_SAI_MCTL_MSEL_MCLK3 (BIT(24) | BIT(25))
+#define FSL_SAI_MCTL_DIV_EN BIT(23)
+#define FSL_SAI_MCTL_DIV_MASK 0xFF
+
+/* SAI VERID Register */
+#define FSL_SAI_VER_ID_SHIFT 16
+#define FSL_SAI_VER_ID_MASK (0xFFFF << FSL_SAI_VER_ID_SHIFT)
+#define FSL_SAI_VER_EFIFO_EN BIT(0)
+#define FSL_SAI_VER_TSTMP_EN BIT(1)
+
+/* SAI PARAM Register */
+#define FSL_SAI_PAR_SPF_SHIFT 16
+#define FSL_SAI_PAR_SPF_MASK (0x0F << FSL_SAI_PAR_SPF_SHIFT)
+#define FSL_SAI_PAR_WPF_SHIFT 8
+#define FSL_SAI_PAR_WPF_MASK (0x0F << FSL_SAI_PAR_WPF_SHIFT)
+#define FSL_SAI_PAR_DLN_MASK (0x0F)
+
+/* SAI MCLK Divide Register */
+#define FSL_SAI_MDIV_MASK 0xFFFFF
+
/* SAI type */
#define FSL_SAI_DMA BIT(0)
#define FSL_SAI_USE_AC97 BIT(1)
@@ -155,11 +208,36 @@
#define FSL_SAI_MAXBURST_TX 6
#define FSL_SAI_MAXBURST_RX 6
+#define SAI_FLAG_PMQOS BIT(0)
+
struct fsl_sai_soc_data {
- bool use_imx_pcm;
- bool use_edma;
unsigned int fifo_depth;
- unsigned int reg_offset;
+ unsigned int fifos;
+ unsigned int dataline;
+ unsigned int flags;
+ unsigned char reg_offset;
+ bool imx;
+ /* True for EDMA because it needs period size multiple of maxburst */
+ bool constrain_period_size;
+};
+
+struct fsl_sai_verid {
+ u32 id;
+ bool timestamp_en;
+ bool extfifo_en;
+ bool loaded;
+};
+
+struct fsl_sai_param {
+ u32 spf; /* max slots per frame */
+ u32 wpf; /* words in fifo */
+ u32 dln; /* number of datalines implemented */
+};
+
+struct fsl_sai_dl_cfg {
+ unsigned int pins;
+ unsigned int mask[2];
+ unsigned int offset[2];
};
struct fsl_sai {
@@ -167,21 +245,39 @@ struct fsl_sai {
struct regmap *regmap;
struct clk *bus_clk;
struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
+ struct clk *pll8k_clk;
+ struct clk *pll11k_clk;
- bool is_slave_mode;
+ bool slave_mode[2];
bool is_lsb_first;
bool is_dsp_mode;
+ bool is_multi_lane;
bool synchronous[2];
+ bool is_stream_opened[2];
+ bool is_dsd;
+
+ int pcm_dl_cfg_cnt;
+ int dsd_dl_cfg_cnt;
+ struct fsl_sai_dl_cfg *pcm_dl_cfg;
+ struct fsl_sai_dl_cfg *dsd_dl_cfg;
+
+ unsigned int masterflag[2];
unsigned int mclk_id[2];
unsigned int mclk_streams;
unsigned int slots;
unsigned int slot_width;
- unsigned int bclk_ratio;
+ unsigned int bitclk_ratio;
- const struct fsl_sai_soc_data *soc_data;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
+ const struct fsl_sai_soc_data *soc;
+ struct pm_qos_request pm_qos_req;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_state;
+
+ struct fsl_sai_verid verid;
+ struct fsl_sai_param param;
};
#define TX 1
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 7858a5499ac5..4842e6df9a2d 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -1248,8 +1248,10 @@ static int fsl_spdif_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
return irq;
+ }
ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
dev_name(&pdev->dev), spdif_priv);
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 537dc69256f0..085855f9b08d 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1510,8 +1510,10 @@ static int fsl_ssi_probe(struct platform_device *pdev)
}
ssi->irq = platform_get_irq(pdev, 0);
- if (ssi->irq < 0)
+ if (ssi->irq < 0) {
+ dev_err(dev, "no irq for node %s\n", pdev->name);
return ssi->irq;
+ }
/* Set software limitations for synchronous mode except AC97 */
if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) {
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 42031ba7da31..9038b61317be 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -520,8 +520,10 @@ static int imx_ssi_probe(struct platform_device *pdev)
}
ssi->irq = platform_get_irq(pdev, 0);
- if (ssi->irq < 0)
+ if (ssi->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ: %d\n", ssi->irq);
return ssi->irq;
+ }
ssi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ssi->clk)) {
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 2a4ffe945177..4b1170562751 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -537,8 +537,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
return PTR_ERR(priv->io);
priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq < 0)
+ if (priv->irq < 0) {
+ dev_err(&pdev->dev, "platform_get_irq failed: %d\n", priv->irq);
return priv->irq;
+ }
if (np) {
priv->burst = 128; /* might be 32 or 128 */
diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c
index d00608c73c6e..c7a81c4be068 100644
--- a/sound/soc/mediatek/common/mtk-btcvsd.c
+++ b/sound/soc/mediatek/common/mtk-btcvsd.c
@@ -1335,8 +1335,10 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev)
/* irq */
irq_id = platform_get_irq(pdev, 0);
- if (irq_id <= 0)
+ if (irq_id <= 0) {
+ dev_err(dev, "%pOFn no irq found\n", dev->of_node);
return irq_id < 0 ? irq_id : -ENXIO;
+ }
ret = devm_request_irq(dev, irq_id, mtk_btcvsd_snd_irq_handler,
IRQF_TRIGGER_LOW, "BTCVSD_ISR_Handle",
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 76502ba261c8..0239f840b096 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -1350,8 +1350,10 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev)
return -ENOMEM;
irq_id = platform_get_irq_byname(pdev, "asys");
- if (irq_id < 0)
+ if (irq_id < 0) {
+ dev_err(dev, "unable to get ASYS IRQ\n");
return irq_id;
+ }
ret = devm_request_irq(dev, irq_id, mt2701_asys_isr,
IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 0ee29255e731..90bd2c92cae7 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -1074,8 +1074,10 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
afe->dev = &pdev->dev;
irq_id = platform_get_irq(pdev, 0);
- if (irq_id <= 0)
+ if (irq_id <= 0) {
+ dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node);
return irq_id < 0 ? irq_id : -ENXIO;
+ }
ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler,
0, "Afe_ISR_Handle", (void *)afe);
if (ret) {
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 1e38ce858326..a2c79426513b 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -790,8 +790,12 @@ static int mxs_saif_probe(struct platform_device *pdev)
return PTR_ERR(saif->base);
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ if (irq < 0) {
+ ret = irq;
+ dev_err(&pdev->dev, "failed to get irq resource: %d\n",
+ ret);
+ return ret;
+ }
saif->dev = &pdev->dev;
ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0,
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 4c745baa39f7..cf7a299f4547 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -564,8 +564,11 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
int ret;
drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
- if (drvdata->lpaif_irq < 0)
+ if (drvdata->lpaif_irq < 0) {
+ dev_err(&pdev->dev, "error getting irq handle: %d\n",
+ drvdata->lpaif_irq);
return -ENODEV;
+ }
/* ensure audio hardware is disabled */
ret = regmap_write(drvdata->lpaif_map,
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index 80e2826fb447..663f45cbb03e 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -483,8 +483,11 @@ static int bdw_probe(struct snd_sof_dev *sdev)
/* register our IRQ */
sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
- if (sdev->ipc_irq < 0)
+ if (sdev->ipc_irq < 0) {
+ dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
+ desc->irqindex_host_ipc);
return sdev->ipc_irq;
+ }
dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index a1e514f71739..89df246a0857 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -599,8 +599,11 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev)
irq:
/* register our IRQ */
sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
- if (sdev->ipc_irq < 0)
+ if (sdev->ipc_irq < 0) {
+ dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
+ desc->irqindex_host_ipc);
return sdev->ipc_irq;
+ }
dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c
index f439e5503a3c..7448015a4935 100644
--- a/sound/soc/sprd/sprd-mcdt.c
+++ b/sound/soc/sprd/sprd-mcdt.c
@@ -959,8 +959,10 @@ static int sprd_mcdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mcdt);
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Failed to get MCDT interrupt\n");
return irq;
+ }
ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler,
0, "sprd-mcdt", mcdt);
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c
index ee4a0151e63e..645bcbe91601 100644
--- a/sound/soc/sti/sti_uniperif.c
+++ b/sound/soc/sti/sti_uniperif.c
@@ -426,8 +426,10 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,
UNIPERIF_FIFO_DATA_OFFSET(uni);
uni->irq = platform_get_irq(priv->pdev, 0);
- if (uni->irq < 0)
+ if (uni->irq < 0) {
+ dev_err(dev, "Failed to get IRQ resource\n");
return -ENXIO;
+ }
uni->type = dev_data->type;
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 3e7226a53e53..ba6452dab69b 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -855,8 +855,11 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
/* Get irqs */
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ if (irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
return irq;
+ }
ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT,
dev_name(&pdev->dev), i2s);
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index ef4273361d0d..1ac5103cea78 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -193,8 +193,10 @@ static int stm32_sai_probe(struct platform_device *pdev)
/* init irqs */
sai->irq = platform_get_irq(pdev, 0);
- if (sai->irq < 0)
+ if (sai->irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
return sai->irq;
+ }
/* reset */
rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index cd4b235fce57..ee71b898897b 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -909,8 +909,10 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev,
}
spdifrx->irq = platform_get_irq(pdev, 0);
- if (spdifrx->irq < 0)
+ if (spdifrx->irq < 0) {
+ dev_err(&pdev->dev, "No irq for node %s\n", pdev->name);
return spdifrx->irq;
+ }
return 0;
}
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d0a8d5810c0a..de448c8d060b 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1198,8 +1198,10 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return PTR_ERR(regs);
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
return irq;
+ }
i2s->variant = of_device_get_match_data(&pdev->dev);
if (!i2s->variant) {
diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c
index e8446cc4e8f8..862346d66774 100644
--- a/sound/soc/uniphier/aio-dma.c
+++ b/sound/soc/uniphier/aio-dma.c
@@ -289,8 +289,10 @@ int uniphier_aiodma_soc_register_platform(struct platform_device *pdev)
return PTR_ERR(chip->regmap);
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ dev_err(dev, "Could not get irq.\n");
return irq;
+ }
ret = devm_request_irq(dev, irq, aiodma_irq,
IRQF_SHARED, dev_name(dev), pdev);
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index 48970efe7838..dc8721f4f56b 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -613,6 +613,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev,
"irq_mm2s");
if (aud_drv_data->mm2s_irq < 0) {
+ dev_err(dev, "xlnx audio mm2s irq resource failed\n");
ret = aud_drv_data->mm2s_irq;
goto clk_err;
}
@@ -639,6 +640,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev,
"irq_s2mm");
if (aud_drv_data->s2mm_irq < 0) {
+ dev_err(dev, "xlnx audio s2mm irq resource failed\n");
ret = aud_drv_data->s2mm_irq;
goto clk_err;
}
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index efd374f114a0..9da395d14a8d 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -570,6 +570,7 @@ static int xtfpga_i2s_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
err = irq;
goto err;
}