ASoC: fsl_spdif: add support for enabling raw capture mode
authorViorel Suman <viorel.suman@nxp.com>
Mon, 26 Apr 2021 08:24:04 +0000 (16:24 +0800)
committerMark Brown <broonie@kernel.org>
Mon, 10 May 2021 12:05:31 +0000 (13:05 +0100)
Since i.MX8MM SPDIF interface is able to capture raw data.
Add support in SPDIF driver for this functionality.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Link: https://lore.kernel.org/r/1619425444-8666-1-git-send-email-shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_spdif.h

index c631de3..2a76714 100644 (file)
@@ -49,6 +49,7 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
  * @imx: for imx platform
  * @shared_root_clock: flag of sharing a clock source with others;
  *                     so the driver shouldn't set root clock rate
+ * @raw_capture_mode: if raw capture mode support
  * @interrupts: interrupt number
  * @tx_burst: tx maxburst size
  * @rx_burst: rx maxburst size
@@ -57,6 +58,7 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
 struct fsl_spdif_soc_data {
        bool imx;
        bool shared_root_clock;
+       bool raw_capture_mode;
        u32 interrupts;
        u32 tx_burst;
        u32 rx_burst;
@@ -136,6 +138,7 @@ struct fsl_spdif_priv {
 static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
        .imx = false,
        .shared_root_clock = false,
+       .raw_capture_mode = false,
        .interrupts = 1,
        .tx_burst = FSL_SPDIF_TXFIFO_WML,
        .rx_burst = FSL_SPDIF_RXFIFO_WML,
@@ -145,6 +148,7 @@ static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
 static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
        .imx = true,
        .shared_root_clock = false,
+       .raw_capture_mode = false,
        .interrupts = 1,
        .tx_burst = FSL_SPDIF_TXFIFO_WML,
        .rx_burst = FSL_SPDIF_RXFIFO_WML,
@@ -154,6 +158,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
 static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
        .imx = true,
        .shared_root_clock = true,
+       .raw_capture_mode = false,
        .interrupts = 1,
        .tx_burst = FSL_SPDIF_TXFIFO_WML,
        .rx_burst = FSL_SPDIF_RXFIFO_WML,
@@ -164,12 +169,23 @@ static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
 static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
        .imx = true,
        .shared_root_clock = true,
+       .raw_capture_mode = false,
        .interrupts = 2,
        .tx_burst = 2,          /* Applied for EDMA */
        .rx_burst = 2,          /* Applied for EDMA */
        .tx_formats = SNDRV_PCM_FMTBIT_S24_LE,  /* Applied for EDMA */
 };
 
+static struct fsl_spdif_soc_data fsl_spdif_imx8mm = {
+       .imx = true,
+       .shared_root_clock = false,
+       .raw_capture_mode = true,
+       .interrupts = 1,
+       .tx_burst = FSL_SPDIF_TXFIFO_WML,
+       .rx_burst = FSL_SPDIF_RXFIFO_WML,
+       .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
+};
+
 /* Check if clk is a root clock that does not share clock source with others */
 static inline bool fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv *spdif, int clk)
 {
@@ -846,6 +862,39 @@ static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static int fsl_spdif_rx_rcm_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 val;
+
+       regmap_read(regmap, REG_SPDIF_SCR, &val);
+       val = (val & SCR_RAW_CAPTURE_MODE) ? 1 : 0;
+       ucontrol->value.integer.value[0] = val;
+
+       return 0;
+}
+
+static int fsl_spdif_rx_rcm_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 val = (ucontrol->value.integer.value[0] ? SCR_RAW_CAPTURE_MODE : 0);
+
+       if (val)
+               cpu_dai->driver->capture.formats |= SNDRV_PCM_FMTBIT_S32_LE;
+       else
+               cpu_dai->driver->capture.formats &= ~SNDRV_PCM_FMTBIT_S32_LE;
+
+       regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_RAW_CAPTURE_MODE, val);
+
+       return 0;
+}
+
 /* DPLL lock information */
 static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_info *uinfo)
@@ -1029,6 +1078,19 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
        },
 };
 
+static struct snd_kcontrol_new fsl_spdif_ctrls_rcm[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "IEC958 Raw Capture Mode",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_WRITE |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = snd_ctl_boolean_mono_info,
+               .get = fsl_spdif_rx_rcm_get,
+               .put = fsl_spdif_rx_rcm_put,
+       },
+};
+
 static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
 {
        struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
@@ -1038,6 +1100,10 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
 
        snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
 
+       if (spdif_private->soc->raw_capture_mode)
+               snd_soc_add_dai_controls(dai, fsl_spdif_ctrls_rcm,
+                                        ARRAY_SIZE(fsl_spdif_ctrls_rcm));
+
        /*Clear the val bit for Tx*/
        regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR,
                           SCR_VAL_MASK, SCR_VAL_CLEAR);
@@ -1476,6 +1542,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = {
        { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
        { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, },
        { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
+       { .compatible = "fsl,imx8mm-spdif", .data = &fsl_spdif_imx8mm, },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
index d5f1dfd..bff8290 100644 (file)
@@ -63,6 +63,7 @@
 #define SCR_TXFIFO_FSEL_IF4            (0x1 << SCR_TXFIFO_FSEL_OFFSET)
 #define SCR_TXFIFO_FSEL_IF8            (0x2 << SCR_TXFIFO_FSEL_OFFSET)
 #define SCR_TXFIFO_FSEL_IF12           (0x3 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_RAW_CAPTURE_MODE           BIT(14)
 #define SCR_LOW_POWER                  (1 << 13)
 #define SCR_SOFT_RESET                 (1 << 12)
 #define SCR_TXFIFO_CTRL_OFFSET         10