ASoC: sh: fsi: modify selection method of I2S/PCM/SPDIF format
[deliverable/linux.git] / sound / soc / sh / fsi.c
index 4c2404b1b8625455358347b65ba15f9414956b1a..0c9997e2d8c05d7407b63cff18b3786ad28b28fa 100644 (file)
 #include <sound/soc.h>
 #include <sound/sh_fsi.h>
 
-#define DO_FMT         0x0000
-#define DOFF_CTL       0x0004
-#define DOFF_ST                0x0008
-#define DI_FMT         0x000C
-#define DIFF_CTL       0x0010
-#define DIFF_ST                0x0014
-#define CKG1           0x0018
-#define CKG2           0x001C
-#define DIDT           0x0020
-#define DODT           0x0024
-#define MUTE_ST                0x0028
-#define OUT_SEL                0x0030
-#define REG_END                OUT_SEL
-
+/* PortA/PortB register */
+#define REG_DO_FMT     0x0000
+#define REG_DOFF_CTL   0x0004
+#define REG_DOFF_ST    0x0008
+#define REG_DI_FMT     0x000C
+#define REG_DIFF_CTL   0x0010
+#define REG_DIFF_ST    0x0014
+#define REG_CKG1       0x0018
+#define REG_CKG2       0x001C
+#define REG_DIDT       0x0020
+#define REG_DODT       0x0024
+#define REG_MUTE_ST    0x0028
+#define REG_OUT_SEL    0x0030
+
+/* master register */
+#define MST_CLK_RST    0x0210
+#define MST_SOFT_RST   0x0214
+#define MST_FIFO_SZ    0x0218
+
+/* core register (depend on FSI version) */
 #define A_MST_CTLR     0x0180
 #define B_MST_CTLR     0x01A0
 #define CPU_INT_ST     0x01F4
 #define INT_ST         0x0200
 #define IEMSK          0x0204
 #define IMSK           0x0208
-#define MUTE           0x020C
-#define CLK_RST                0x0210
-#define SOFT_RST       0x0214
-#define FIFO_SZ                0x0218
-#define MREG_START     A_MST_CTLR
-#define MREG_END       FIFO_SZ
 
 /* DO_FMT */
 /* DI_FMT */
+#define CR_BWS_24      (0x0 << 20) /* FSI2 */
+#define CR_BWS_16      (0x1 << 20) /* FSI2 */
+#define CR_BWS_20      (0x2 << 20) /* FSI2 */
+
+#define CR_DTMD_PCM            (0x0 << 8) /* FSI2 */
+#define CR_DTMD_SPDIF_PCM      (0x1 << 8) /* FSI2 */
+#define CR_DTMD_SPDIF_STREAM   (0x2 << 8) /* FSI2 */
+
 #define CR_MONO                (0x0 << 4)
 #define CR_MONO_D      (0x1 << 4)
 #define CR_PCM         (0x2 << 4)
 #define CR_I2S         (0x3 << 4)
 #define CR_TDM         (0x4 << 4)
 #define CR_TDM_D       (0x5 << 4)
-#define CR_SPDIF       0x00100120
 
 /* DOFF_CTL */
 /* DIFF_CTL */
@@ -71,6 +78,8 @@
 /* CKG1 */
 #define ACKMD_MASK     0x00007000
 #define BPFMD_MASK     0x00000700
+#define DIMD           (1 << 4)
+#define DOMD           (1 << 0)
 
 /* A/B MST_CTLR */
 #define BP     (1 << 4)        /* Fix the signal of Biphase output */
 #define IR             (1 <<  4) /* Interrupt Reset */
 #define FSISR          (1 <<  0) /* Software Reset */
 
+/* OUT_SEL (FSI2) */
+#define DMMD           (1 << 4) /* SPDIF output timing 0: Biphase only */
+                                /*                     1: Biphase and serial */
+
 /* FIFO_SZ */
 #define FIFO_SZ_MASK   0x7
 
 
 #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
+typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int enable);
+
 /*
  * FSI driver use below type name for variable
  *
@@ -117,24 +132,25 @@ struct fsi_stream {
        struct snd_pcm_substream *substream;
 
        int fifo_max_num;
-       int chan_num;
 
        int buff_offset;
        int buff_len;
        int period_len;
        int period_num;
+
+       int uerr_num;
+       int oerr_num;
 };
 
 struct fsi_priv {
        void __iomem *base;
        struct fsi_master *master;
 
+       int chan_num;
        struct fsi_stream playback;
        struct fsi_stream capture;
 
        long rate;
-
-       u32 mst_ctrl;
 };
 
 struct fsi_core {
@@ -143,6 +159,8 @@ struct fsi_core {
        u32 int_st;
        u32 iemsk;
        u32 imsk;
+       u32 a_mclk;
+       u32 b_mclk;
 };
 
 struct fsi_master {
@@ -182,62 +200,22 @@ static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
        __fsi_reg_write(reg, val);
 }
 
-static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
-{
-       if (reg > REG_END) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
-
-       __fsi_reg_write((u32)(fsi->base + reg), data);
-}
-
-static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
-{
-       if (reg > REG_END) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return 0;
-       }
-
-       return __fsi_reg_read((u32)(fsi->base + reg));
-}
-
-static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
-{
-       if (reg > REG_END) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
+#define fsi_reg_write(p, r, d)\
+       __fsi_reg_write((u32)(p->base + REG_##r), d)
 
-       __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
-}
+#define fsi_reg_read(p, r)\
+       __fsi_reg_read((u32)(p->base + REG_##r))
 
-static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
-{
-       unsigned long flags;
+#define fsi_reg_mask_set(p, r, m, d)\
+       __fsi_reg_mask_set((u32)(p->base + REG_##r), m, d)
 
-       if ((reg < MREG_START) ||
-           (reg > MREG_END)) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
-
-       spin_lock_irqsave(&master->lock, flags);
-       __fsi_reg_write((u32)(master->base + reg), data);
-       spin_unlock_irqrestore(&master->lock, flags);
-}
-
-static u32 fsi_master_read(struct fsi_master *master, u32 reg)
+#define fsi_master_read(p, r) _fsi_master_read(p, MST_##r)
+#define fsi_core_read(p, r)   _fsi_master_read(p, p->core->r)
+static u32 _fsi_master_read(struct fsi_master *master, u32 reg)
 {
        u32 ret;
        unsigned long flags;
 
-       if ((reg < MREG_START) ||
-           (reg > MREG_END)) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return 0;
-       }
-
        spin_lock_irqsave(&master->lock, flags);
        ret = __fsi_reg_read((u32)(master->base + reg));
        spin_unlock_irqrestore(&master->lock, flags);
@@ -245,17 +223,13 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg)
        return ret;
 }
 
-static void fsi_master_mask_set(struct fsi_master *master,
+#define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d)
+#define fsi_core_mask_set(p, r, m, d)  _fsi_master_mask_set(p, p->core->r, m, d)
+static void _fsi_master_mask_set(struct fsi_master *master,
                               u32 reg, u32 mask, u32 data)
 {
        unsigned long flags;
 
-       if ((reg < MREG_START) ||
-           (reg > MREG_END)) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
-
        spin_lock_irqsave(&master->lock, flags);
        __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
        spin_unlock_irqrestore(&master->lock, flags);
@@ -282,9 +256,8 @@ static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
        return  rtd->cpu_dai;
 }
 
-static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
+static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai)
 {
-       struct snd_soc_dai *dai = fsi_get_dai(substream);
        struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
 
        if (dai->id == 0)
@@ -293,11 +266,27 @@ static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
                return &master->fsib;
 }
 
+static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
+{
+       return fsi_get_priv_frm_dai(fsi_get_dai(substream));
+}
+
+static set_rate_func fsi_get_info_set_rate(struct fsi_master *master)
+{
+       if (!master->info)
+               return NULL;
+
+       return master->info->set_rate;
+}
+
 static u32 fsi_get_info_flags(struct fsi_priv *fsi)
 {
        int is_porta = fsi_is_port_a(fsi);
        struct fsi_master *master = fsi_get_master(fsi);
 
+       if (!master->info)
+               return 0;
+
        return is_porta ? master->info->porta_flags :
                master->info->portb_flags;
 }
@@ -318,21 +307,6 @@ static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi,
        return is_play ? &fsi->playback : &fsi->capture;
 }
 
-static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
-{
-       u32 mode;
-       u32 flags = fsi_get_info_flags(fsi);
-
-       mode = is_play ? SH_FSI_OUT_SLAVE_MODE : SH_FSI_IN_SLAVE_MODE;
-
-       /* return
-        * 1 : master mode
-        * 0 : slave mode
-        */
-
-       return (mode & flags) != mode;
-}
-
 static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
 {
        int is_porta = fsi_is_port_a(fsi);
@@ -359,29 +333,42 @@ static void fsi_stream_push(struct fsi_priv *fsi,
        io->buff_offset = 0;
        io->period_len  = period_len;
        io->period_num  = 0;
+       io->oerr_num    = -1; /* ignore 1st err */
+       io->uerr_num    = -1; /* ignore 1st err */
 }
 
 static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
 {
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+
+
+       if (io->oerr_num > 0)
+               dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
+
+       if (io->uerr_num > 0)
+               dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
 
        io->substream   = NULL;
        io->buff_len    = 0;
        io->buff_offset = 0;
        io->period_len  = 0;
        io->period_num  = 0;
+       io->oerr_num    = 0;
+       io->uerr_num    = 0;
 }
 
 static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
 {
        u32 status;
-       u32 reg = is_play ? DOFF_ST : DIFF_ST;
-       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        int data_num;
 
-       status = fsi_reg_read(fsi, reg);
+       status = is_play ?
+               fsi_reg_read(fsi, DOFF_ST) :
+               fsi_reg_read(fsi, DIFF_ST);
+
        data_num = 0x1ff & (status >> 8);
-       data_num *= io->chan_num;
+       data_num *= fsi->chan_num;
 
        return data_num;
 }
@@ -403,7 +390,28 @@ static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
        struct snd_pcm_substream *substream = io->substream;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       return frames_to_bytes(runtime, 1) / io->chan_num;
+       return frames_to_bytes(runtime, 1) / fsi->chan_num;
+}
+
+static void fsi_count_fifo_err(struct fsi_priv *fsi)
+{
+       u32 ostatus = fsi_reg_read(fsi, DOFF_ST);
+       u32 istatus = fsi_reg_read(fsi, DIFF_ST);
+
+       if (ostatus & ERR_OVER)
+               fsi->playback.oerr_num++;
+
+       if (ostatus & ERR_UNDER)
+               fsi->playback.uerr_num++;
+
+       if (istatus & ERR_OVER)
+               fsi->capture.oerr_num++;
+
+       if (istatus & ERR_UNDER)
+               fsi->capture.uerr_num++;
+
+       fsi_reg_write(fsi, DOFF_ST, 0);
+       fsi_reg_write(fsi, DIFF_ST, 0);
 }
 
 /*
@@ -473,8 +481,8 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
        u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
        struct fsi_master *master = fsi_get_master(fsi);
 
-       fsi_master_mask_set(master, master->core->imsk,  data, data);
-       fsi_master_mask_set(master, master->core->iemsk, data, data);
+       fsi_core_mask_set(master, imsk,  data, data);
+       fsi_core_mask_set(master, iemsk, data, data);
 }
 
 static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
@@ -482,18 +490,13 @@ static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
        u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
        struct fsi_master *master = fsi_get_master(fsi);
 
-       fsi_master_mask_set(master, master->core->imsk,  data, 0);
-       fsi_master_mask_set(master, master->core->iemsk, data, 0);
+       fsi_core_mask_set(master, imsk,  data, 0);
+       fsi_core_mask_set(master, iemsk, data, 0);
 }
 
 static u32 fsi_irq_get_status(struct fsi_master *master)
 {
-       return fsi_master_read(master, master->core->int_st);
-}
-
-static void fsi_irq_clear_all_status(struct fsi_master *master)
-{
-       fsi_master_write(master, master->core->int_st, 0);
+       return fsi_core_read(master, int_st);
 }
 
 static void fsi_irq_clear_status(struct fsi_priv *fsi)
@@ -505,7 +508,7 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
        data |= AB_IO(1, fsi_get_port_shift(fsi, 1));
 
        /* clear interrupt factor */
-       fsi_master_mask_set(master, master->core->int_st, data, 0);
+       fsi_core_mask_set(master, int_st, data, 0);
 }
 
 /*
@@ -516,17 +519,19 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
 static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
-       u32 val = BP | SE;
+       u32 mask, val;
 
        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);
+       mask = BP | SE;
+       val = enable ? mask : 0;
+
+       fsi_is_port_a(fsi) ?
+               fsi_core_mask_set(master, a_mclk, mask, val) :
+               fsi_core_mask_set(master, b_mclk, mask, val);
 }
 
 /*
@@ -550,7 +555,7 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
 {
        struct fsi_master *master = fsi_get_master(fsi);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       u32 ctrl, shift, i;
+       u32 shift, i;
 
        /* get on-chip RAM capacity */
        shift = fsi_master_read(master, FIFO_SZ);
@@ -578,18 +583,22 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
         * 7 channels:  32 ( 32 x 7 = 224)
         * 8 channels:  32 ( 32 x 8 = 256)
         */
-       for (i = 1; i < io->chan_num; i <<= 1)
+       for (i = 1; i < fsi->chan_num; i <<= 1)
                io->fifo_max_num >>= 1;
        dev_dbg(dai->dev, "%d channel %d store\n",
-               io->chan_num, io->fifo_max_num);
-
-       ctrl = is_play ? DOFF_CTL : DIFF_CTL;
-
-       /* set interrupt generation factor */
-       fsi_reg_write(fsi, ctrl, IRQ_HALF);
+               fsi->chan_num, io->fifo_max_num);
 
-       /* clear FIFO */
-       fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR);
+       /*
+        * set interrupt generation factor
+        * clear FIFO
+        */
+       if (is_play) {
+               fsi_reg_write(fsi,      DOFF_CTL, IRQ_HALF);
+               fsi_reg_mask_set(fsi,   DOFF_CTL, FIFO_CLR, FIFO_CLR);
+       } else {
+               fsi_reg_write(fsi,      DIFF_CTL, IRQ_HALF);
+               fsi_reg_mask_set(fsi,   DIFF_CTL, FIFO_CLR, FIFO_CLR);
+       }
 }
 
 static void fsi_soft_all_reset(struct fsi_master *master)
@@ -604,13 +613,12 @@ static void fsi_soft_all_reset(struct fsi_master *master)
        mdelay(10);
 }
 
-static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
+static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
 {
        struct snd_pcm_runtime *runtime;
        struct snd_pcm_substream *substream = NULL;
        int is_play = fsi_stream_is_play(stream);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       u32 status_reg = is_play ? DOFF_ST : DIFF_ST;
        int data_residue_num;
        int data_num;
        int data_num_max;
@@ -654,7 +662,7 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
                 * data_num_max : number of FSI fifo free space
                 * data_num     : number of ALSA residue data
                 */
-               data_num_max  = io->fifo_max_num * io->chan_num;
+               data_num_max  = io->fifo_max_num * fsi->chan_num;
                data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
 
                data_num = data_residue_num;
@@ -698,35 +706,20 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
        /* update buff_offset */
        io->buff_offset += fsi_num2offset(data_num, ch_width);
 
-       /* check fifo status */
-       if (!startup) {
-               struct snd_soc_dai *dai = fsi_get_dai(substream);
-               u32 status = fsi_reg_read(fsi, status_reg);
-
-               if (status & ERR_OVER)
-                       dev_err(dai->dev, "over run\n");
-               if (status & ERR_UNDER)
-                       dev_err(dai->dev, "under run\n");
-       }
-       fsi_reg_write(fsi, status_reg, 0);
-
-       /* re-enable irq */
-       fsi_irq_enable(fsi, is_play);
-
        if (over_period)
                snd_pcm_period_elapsed(substream);
 
        return 0;
 }
 
-static int fsi_data_pop(struct fsi_priv *fsi, int startup)
+static int fsi_data_pop(struct fsi_priv *fsi)
 {
-       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE);
+       return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_CAPTURE);
 }
 
-static int fsi_data_push(struct fsi_priv *fsi, int startup)
+static int fsi_data_push(struct fsi_priv *fsi)
 {
-       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK);
+       return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_PLAYBACK);
 }
 
 static irqreturn_t fsi_interrupt(int irq, void *data)
@@ -739,15 +732,19 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
        fsi_master_mask_set(master, SOFT_RST, IR, IR);
 
        if (int_st & AB_IO(1, AO_SHIFT))
-               fsi_data_push(&master->fsia, 0);
+               fsi_data_push(&master->fsia);
        if (int_st & AB_IO(1, BO_SHIFT))
-               fsi_data_push(&master->fsib, 0);
+               fsi_data_push(&master->fsib);
        if (int_st & AB_IO(1, AI_SHIFT))
-               fsi_data_pop(&master->fsia, 0);
+               fsi_data_pop(&master->fsia);
        if (int_st & AB_IO(1, BI_SHIFT))
-               fsi_data_pop(&master->fsib, 0);
+               fsi_data_pop(&master->fsib);
+
+       fsi_count_fifo_err(&master->fsia);
+       fsi_count_fifo_err(&master->fsib);
 
-       fsi_irq_clear_all_status(master);
+       fsi_irq_clear_status(&master->fsia);
+       fsi_irq_clear_status(&master->fsib);
 
        return IRQ_HANDLED;
 }
@@ -760,26 +757,12 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       struct fsi_master *master = fsi_get_master(fsi);
-       struct fsi_stream *io;
        u32 flags = fsi_get_info_flags(fsi);
-       u32 fmt;
-       u32 reg;
        u32 data;
        int is_play = fsi_is_play(substream);
-       int is_master;
-
-       io = fsi_get_stream(fsi, is_play);
 
        pm_runtime_get_sync(dai->dev);
 
-       /* CKG1 */
-       data = is_play ? (1 << 0) : (1 << 4);
-       is_master = fsi_is_master_mode(fsi, is_play);
-       if (is_master)
-               fsi_reg_mask_set(fsi, CKG1, data, data);
-       else
-               fsi_reg_mask_set(fsi, CKG1, data, 0);
 
        /* clock inversion (CKG2) */
        data = 0;
@@ -794,53 +777,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
 
        fsi_reg_write(fsi, CKG2, data);
 
-       /* do fmt, di fmt */
-       data = 0;
-       reg = is_play ? DO_FMT : DI_FMT;
-       fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
-       switch (fmt) {
-       case SH_FSI_FMT_MONO:
-               data = CR_MONO;
-               io->chan_num = 1;
-               break;
-       case SH_FSI_FMT_MONO_DELAY:
-               data = CR_MONO_D;
-               io->chan_num = 1;
-               break;
-       case SH_FSI_FMT_PCM:
-               data = CR_PCM;
-               io->chan_num = 2;
-               break;
-       case SH_FSI_FMT_I2S:
-               data = CR_I2S;
-               io->chan_num = 2;
-               break;
-       case SH_FSI_FMT_TDM:
-               io->chan_num = is_play ?
-                       SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
-               data = CR_TDM | (io->chan_num - 1);
-               break;
-       case SH_FSI_FMT_TDM_DELAY:
-               io->chan_num = is_play ?
-                       SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
-               data = CR_TDM_D | (io->chan_num - 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;
-               io->chan_num = 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;
-       }
-       fsi_reg_write(fsi, reg, data);
-
        /* irq clear */
        fsi_irq_disable(fsi, is_play);
        fsi_irq_clear_status(fsi);
@@ -857,12 +793,12 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
        struct fsi_priv *fsi = fsi_get_priv(substream);
        int is_play = fsi_is_play(substream);
        struct fsi_master *master = fsi_get_master(fsi);
-       int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
+       set_rate_func set_rate;
 
        fsi_irq_disable(fsi, is_play);
        fsi_clk_ctrl(fsi, 0);
 
-       set_rate = master->info->set_rate;
+       set_rate = fsi_get_info_set_rate(master);
        if (set_rate && fsi->rate)
                set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
        fsi->rate = 0;
@@ -883,7 +819,8 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                fsi_stream_push(fsi, is_play, substream,
                                frames_to_bytes(runtime, runtime->buffer_size),
                                frames_to_bytes(runtime, runtime->period_size));
-               ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1);
+               ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
+               fsi_irq_enable(fsi, is_play);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                fsi_irq_disable(fsi, is_play);
@@ -894,18 +831,100 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
+static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
+{
+       u32 data = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               data = CR_I2S;
+               fsi->chan_num = 2;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               data = CR_PCM;
+               fsi->chan_num = 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       fsi_reg_write(fsi, DO_FMT, data);
+       fsi_reg_write(fsi, DI_FMT, data);
+
+       return 0;
+}
+
+static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       u32 data = 0;
+
+       if (master->core->ver < 2)
+               return -EINVAL;
+
+       data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
+       fsi->chan_num = 2;
+       fsi_spdif_clk_ctrl(fsi, 1);
+       fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+
+       fsi_reg_write(fsi, DO_FMT, data);
+       fsi_reg_write(fsi, DI_FMT, data);
+
+       return 0;
+}
+
+static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
+       u32 flags = fsi_get_info_flags(fsi);
+       u32 data = 0;
+       int ret;
+
+       pm_runtime_get_sync(dai->dev);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               data = DIMD | DOMD;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               ret = -EINVAL;
+               goto set_fmt_exit;
+       }
+       fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
+
+       /* set format */
+       switch (flags & SH_FSI_FMT_MASK) {
+       case SH_FSI_FMT_DAI:
+               ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+               break;
+       case SH_FSI_FMT_SPDIF:
+               ret = fsi_set_fmt_spdif(fsi);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+set_fmt_exit:
+       pm_runtime_put_sync(dai->dev);
+
+       return ret;
+}
+
 static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params,
                             struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
        struct fsi_master *master = fsi_get_master(fsi);
-       int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
+       set_rate_func set_rate;
        int fsi_ver = master->core->ver;
        long rate = params_rate(params);
        int ret;
 
-       set_rate = master->info->set_rate;
+       set_rate = fsi_get_info_set_rate(master);
        if (!set_rate)
                return 0;
 
@@ -980,6 +999,7 @@ static struct snd_soc_dai_ops fsi_dai_ops = {
        .startup        = fsi_dai_startup,
        .shutdown       = fsi_dai_shutdown,
        .trigger        = fsi_dai_trigger,
+       .set_fmt        = fsi_dai_set_fmt,
        .hw_params      = fsi_dai_hw_params,
 };
 
@@ -1174,12 +1194,10 @@ static int fsi_probe(struct platform_device *pdev)
        /* 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->fsib.mst_ctrl   = B_MST_CTLR;
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
@@ -1266,6 +1284,8 @@ static struct fsi_core fsi2_core = {
        .int_st = CPU_INT_ST,
        .iemsk  = CPU_IEMSK,
        .imsk   = CPU_IMSK,
+       .a_mclk = A_MST_CTLR,
+       .b_mclk = B_MST_CTLR,
 };
 
 static struct platform_device_id fsi_id_table[] = {
This page took 0.063794 seconds and 5 git commands to generate.