ASoC: fsi: Add new funtion for SPDIF
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Thu, 29 Jul 2010 07:48:32 +0000 (16:48 +0900)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Thu, 29 Jul 2010 17:28:49 +0000 (10:28 -0700)
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
include/sound/sh_fsi.h
sound/soc/sh/fsi.c

index 6ac71863c70f213f0d639f7dd4d433165c63dd3f..9d51d6f358930c68d7c8264e4e0e047a1b15343b 100644 (file)
@@ -64,6 +64,8 @@
 #define SH_FSI_FMT_I2S         3
 #define SH_FSI_FMT_TDM         4
 #define SH_FSI_FMT_TDM_DELAY   5
+#define SH_FSI_FMT_SPDIF       6
+
 
 #define SH_FSI_IFMT_TDM_CH(x) \
        (SH_FSI_IFMT(TDM)       | SH_FSI_SET_CH_I(x))
index 4b09b3dfcc00cff22e424712f1799bca91a95213..58c6bec642decf3093746f577fd387c0688ad459 100644 (file)
 #define DIDT           0x0020
 #define DODT           0x0024
 #define MUTE_ST                0x0028
-#define REG_END                MUTE_ST
-
+#define OUT_SEL                0x0030
+#define REG_END                OUT_SEL
 
+#define A_MST_CTLR     0x0180
+#define B_MST_CTLR     0x01A0
 #define CPU_INT_ST     0x01F4
 #define CPU_IEMSK      0x01F8
 #define CPU_IMSK       0x01FC
@@ -43,7 +45,7 @@
 #define CLK_RST                0x0210
 #define SOFT_RST       0x0214
 #define FIFO_SZ                0x0218
-#define MREG_START     CPU_INT_ST
+#define MREG_START     A_MST_CTLR
 #define MREG_END       FIFO_SZ
 
 /* DO_FMT */
@@ -54,6 +56,7 @@
 #define CR_I2S         (0x3 << 4)
 #define CR_TDM         (0x4 << 4)
 #define CR_TDM_D       (0x5 << 4)
+#define CR_SPDIF       0x00100120
 
 /* DOFF_CTL */
 /* DIFF_CTL */
 #define ACKMD_MASK     0x00007000
 #define BPFMD_MASK     0x00000700
 
+/* A/B MST_CTLR */
+#define BP     (1 << 4)        /* Fix the signal of Biphase output */
+#define SE     (1 << 0)        /* Fix the master clock */
+
 /* CLK_RST */
 #define B_CLK          0x00000010
 #define A_CLK          0x00000001
@@ -113,6 +120,8 @@ struct fsi_priv {
        int period_len;
        int buffer_len;
        int periods;
+
+       u32 mst_ctrl;
 };
 
 struct fsi_core {
@@ -392,6 +401,29 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
        fsi_master_mask_set(master, master->core->int_st, data, 0);
 }
 
+/************************************************************************
+
+
+               SPDIF master clock function
+
+These functions are used later FSI2
+************************************************************************/
+static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       u32 val = BP | SE;
+
+       if (master->core->ver < 2) {
+               pr_err("fsi: register access err (%s)\n", __func__);
+               return;
+       }
+
+       if (enable)
+               fsi_master_mask_set(master, fsi->mst_ctrl, val, val);
+       else
+               fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
+}
+
 /************************************************************************
 
 
@@ -671,6 +703,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
        u32 flags = fsi_get_info_flags(fsi);
+       struct fsi_master *master = fsi_get_master(fsi);
        u32 fmt;
        u32 reg;
        u32 data;
@@ -732,6 +765,16 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
                        SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
                data = CR_TDM_D | (fsi->chan - 1);
                break;
+       case SH_FSI_FMT_SPDIF:
+               if (master->core->ver < 2) {
+                       dev_err(dai->dev, "This FSI can not use SPDIF\n");
+                       return -EINVAL;
+               }
+               data = CR_SPDIF;
+               fsi->chan = 2;
+               fsi_spdif_clk_ctrl(fsi, 1);
+               fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
+               break;
        default:
                dev_err(dai->dev, "unknown format.\n");
                return -EINVAL;
@@ -1071,14 +1114,21 @@ static int fsi_probe(struct platform_device *pdev)
                goto exit_kfree;
        }
 
+       /* master setting */
        master->irq             = irq;
        master->info            = pdev->dev.platform_data;
+       master->core            = (struct fsi_core *)id_entry->driver_data;
+       spin_lock_init(&master->lock);
+
+       /* FSI A setting */
        master->fsia.base       = master->base;
        master->fsia.master     = master;
+       master->fsia.mst_ctrl   = A_MST_CTLR;
+
+       /* FSI B setting */
        master->fsib.base       = master->base + 0x40;
        master->fsib.master     = master;
-       master->core            = (struct fsi_core *)id_entry->driver_data;
-       spin_lock_init(&master->lock);
+       master->fsib.mst_ctrl   = B_MST_CTLR;
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);