Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright (C) 2014-2015 Broadcom Corporation
0003 #include <linux/clk.h>
0004 #include <linux/delay.h>
0005 #include <linux/init.h>
0006 #include <linux/io.h>
0007 #include <linux/module.h>
0008 #include <linux/of_device.h>
0009 #include <linux/slab.h>
0010 #include <sound/core.h>
0011 #include <sound/pcm.h>
0012 #include <sound/pcm_params.h>
0013 #include <sound/soc.h>
0014 #include <sound/soc-dai.h>
0015 
0016 #include "cygnus-ssp.h"
0017 
0018 #define DEFAULT_VCO    1354750204
0019 
0020 #define CAPTURE_FCI_ID_BASE 0x180
0021 #define CYGNUS_SSP_TRISTATE_MASK 0x001fff
0022 #define CYGNUS_PLLCLKSEL_MASK 0xf
0023 
0024 /* Used with stream_on field to indicate which streams are active */
0025 #define  PLAYBACK_STREAM_MASK   BIT(0)
0026 #define  CAPTURE_STREAM_MASK    BIT(1)
0027 
0028 #define I2S_STREAM_CFG_MASK      0xff003ff
0029 #define I2S_CAP_STREAM_CFG_MASK  0xf0
0030 #define SPDIF_STREAM_CFG_MASK    0x3ff
0031 #define CH_GRP_STEREO            0x1
0032 
0033 /* Begin register offset defines */
0034 #define AUD_MISC_SEROUT_OE_REG_BASE  0x01c
0035 #define AUD_MISC_SEROUT_SPDIF_OE  12
0036 #define AUD_MISC_SEROUT_MCLK_OE   3
0037 #define AUD_MISC_SEROUT_LRCK_OE   2
0038 #define AUD_MISC_SEROUT_SCLK_OE   1
0039 #define AUD_MISC_SEROUT_SDAT_OE   0
0040 
0041 /* AUD_FMM_BF_CTRL_xxx regs */
0042 #define BF_DST_CFG0_OFFSET  0x100
0043 #define BF_DST_CFG1_OFFSET  0x104
0044 #define BF_DST_CFG2_OFFSET  0x108
0045 
0046 #define BF_DST_CTRL0_OFFSET 0x130
0047 #define BF_DST_CTRL1_OFFSET 0x134
0048 #define BF_DST_CTRL2_OFFSET 0x138
0049 
0050 #define BF_SRC_CFG0_OFFSET  0x148
0051 #define BF_SRC_CFG1_OFFSET  0x14c
0052 #define BF_SRC_CFG2_OFFSET  0x150
0053 #define BF_SRC_CFG3_OFFSET  0x154
0054 
0055 #define BF_SRC_CTRL0_OFFSET 0x1c0
0056 #define BF_SRC_CTRL1_OFFSET 0x1c4
0057 #define BF_SRC_CTRL2_OFFSET 0x1c8
0058 #define BF_SRC_CTRL3_OFFSET 0x1cc
0059 
0060 #define BF_SRC_GRP0_OFFSET  0x1fc
0061 #define BF_SRC_GRP1_OFFSET  0x200
0062 #define BF_SRC_GRP2_OFFSET  0x204
0063 #define BF_SRC_GRP3_OFFSET  0x208
0064 
0065 #define BF_SRC_GRP_EN_OFFSET        0x320
0066 #define BF_SRC_GRP_FLOWON_OFFSET    0x324
0067 #define BF_SRC_GRP_SYNC_DIS_OFFSET  0x328
0068 
0069 /* AUD_FMM_IOP_OUT_I2S_xxx regs */
0070 #define OUT_I2S_0_STREAM_CFG_OFFSET 0xa00
0071 #define OUT_I2S_0_CFG_OFFSET        0xa04
0072 #define OUT_I2S_0_MCLK_CFG_OFFSET   0xa0c
0073 
0074 #define OUT_I2S_1_STREAM_CFG_OFFSET 0xa40
0075 #define OUT_I2S_1_CFG_OFFSET        0xa44
0076 #define OUT_I2S_1_MCLK_CFG_OFFSET   0xa4c
0077 
0078 #define OUT_I2S_2_STREAM_CFG_OFFSET 0xa80
0079 #define OUT_I2S_2_CFG_OFFSET        0xa84
0080 #define OUT_I2S_2_MCLK_CFG_OFFSET   0xa8c
0081 
0082 /* AUD_FMM_IOP_OUT_SPDIF_xxx regs */
0083 #define SPDIF_STREAM_CFG_OFFSET  0xac0
0084 #define SPDIF_CTRL_OFFSET        0xac4
0085 #define SPDIF_FORMAT_CFG_OFFSET  0xad8
0086 #define SPDIF_MCLK_CFG_OFFSET    0xadc
0087 
0088 /* AUD_FMM_IOP_PLL_0_xxx regs */
0089 #define IOP_PLL_0_MACRO_OFFSET    0xb00
0090 #define IOP_PLL_0_MDIV_Ch0_OFFSET 0xb14
0091 #define IOP_PLL_0_MDIV_Ch1_OFFSET 0xb18
0092 #define IOP_PLL_0_MDIV_Ch2_OFFSET 0xb1c
0093 
0094 #define IOP_PLL_0_ACTIVE_MDIV_Ch0_OFFSET 0xb30
0095 #define IOP_PLL_0_ACTIVE_MDIV_Ch1_OFFSET 0xb34
0096 #define IOP_PLL_0_ACTIVE_MDIV_Ch2_OFFSET 0xb38
0097 
0098 /* AUD_FMM_IOP_xxx regs */
0099 #define IOP_PLL_0_CONTROL_OFFSET     0xb04
0100 #define IOP_PLL_0_USER_NDIV_OFFSET   0xb08
0101 #define IOP_PLL_0_ACTIVE_NDIV_OFFSET 0xb20
0102 #define IOP_PLL_0_RESET_OFFSET       0xb5c
0103 
0104 /* AUD_FMM_IOP_IN_I2S_xxx regs */
0105 #define IN_I2S_0_STREAM_CFG_OFFSET 0x00
0106 #define IN_I2S_0_CFG_OFFSET        0x04
0107 #define IN_I2S_1_STREAM_CFG_OFFSET 0x40
0108 #define IN_I2S_1_CFG_OFFSET        0x44
0109 #define IN_I2S_2_STREAM_CFG_OFFSET 0x80
0110 #define IN_I2S_2_CFG_OFFSET        0x84
0111 
0112 /* AUD_FMM_IOP_MISC_xxx regs */
0113 #define IOP_SW_INIT_LOGIC          0x1c0
0114 
0115 /* End register offset defines */
0116 
0117 
0118 /* AUD_FMM_IOP_OUT_I2S_x_MCLK_CFG_0_REG */
0119 #define I2S_OUT_MCLKRATE_SHIFT 16
0120 
0121 /* AUD_FMM_IOP_OUT_I2S_x_MCLK_CFG_REG */
0122 #define I2S_OUT_PLLCLKSEL_SHIFT  0
0123 
0124 /* AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG */
0125 #define I2S_OUT_STREAM_ENA  31
0126 #define I2S_OUT_STREAM_CFG_GROUP_ID  20
0127 #define I2S_OUT_STREAM_CFG_CHANNEL_GROUPING  24
0128 
0129 /* AUD_FMM_IOP_IN_I2S_x_CAP */
0130 #define I2S_IN_STREAM_CFG_CAP_ENA   31
0131 #define I2S_IN_STREAM_CFG_0_GROUP_ID 4
0132 
0133 /* AUD_FMM_IOP_OUT_I2S_x_I2S_CFG_REG */
0134 #define I2S_OUT_CFGX_CLK_ENA         0
0135 #define I2S_OUT_CFGX_DATA_ENABLE     1
0136 #define I2S_OUT_CFGX_DATA_ALIGNMENT  6
0137 #define I2S_OUT_CFGX_BITS_PER_SLOT  13
0138 #define I2S_OUT_CFGX_VALID_SLOT     14
0139 #define I2S_OUT_CFGX_FSYNC_WIDTH    18
0140 #define I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32 26
0141 #define I2S_OUT_CFGX_SLAVE_MODE     30
0142 #define I2S_OUT_CFGX_TDM_MODE       31
0143 
0144 /* AUD_FMM_BF_CTRL_SOURCECH_CFGx_REG */
0145 #define BF_SRC_CFGX_SFIFO_ENA              0
0146 #define BF_SRC_CFGX_BUFFER_PAIR_ENABLE     1
0147 #define BF_SRC_CFGX_SAMPLE_CH_MODE         2
0148 #define BF_SRC_CFGX_SFIFO_SZ_DOUBLE        5
0149 #define BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY  10
0150 #define BF_SRC_CFGX_BIT_RES               20
0151 #define BF_SRC_CFGX_PROCESS_SEQ_ID_VALID  31
0152 
0153 /* AUD_FMM_BF_CTRL_DESTCH_CFGx_REG */
0154 #define BF_DST_CFGX_CAP_ENA              0
0155 #define BF_DST_CFGX_BUFFER_PAIR_ENABLE   1
0156 #define BF_DST_CFGX_DFIFO_SZ_DOUBLE      2
0157 #define BF_DST_CFGX_NOT_PAUSE_WHEN_FULL 11
0158 #define BF_DST_CFGX_FCI_ID              12
0159 #define BF_DST_CFGX_CAP_MODE            24
0160 #define BF_DST_CFGX_PROC_SEQ_ID_VALID   31
0161 
0162 /* AUD_FMM_IOP_OUT_SPDIF_xxx */
0163 #define SPDIF_0_OUT_DITHER_ENA     3
0164 #define SPDIF_0_OUT_STREAM_ENA    31
0165 
0166 /* AUD_FMM_IOP_PLL_0_USER */
0167 #define IOP_PLL_0_USER_NDIV_FRAC   10
0168 
0169 /* AUD_FMM_IOP_PLL_0_ACTIVE */
0170 #define IOP_PLL_0_ACTIVE_NDIV_FRAC 10
0171 
0172 
0173 #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \
0174         .i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \
0175         .i2s_cap_stream_cfg = IN_I2S_ ##num## _STREAM_CFG_OFFSET, \
0176         .i2s_cfg = OUT_I2S_ ##num## _CFG_OFFSET, \
0177         .i2s_cap_cfg = IN_I2S_ ##num## _CFG_OFFSET, \
0178         .i2s_mclk_cfg = OUT_I2S_ ##num## _MCLK_CFG_OFFSET, \
0179         .bf_destch_ctrl = BF_DST_CTRL ##num## _OFFSET, \
0180         .bf_destch_cfg = BF_DST_CFG ##num## _OFFSET, \
0181         .bf_sourcech_ctrl = BF_SRC_CTRL ##num## _OFFSET, \
0182         .bf_sourcech_cfg = BF_SRC_CFG ##num## _OFFSET, \
0183         .bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \
0184 }
0185 
0186 struct pll_macro_entry {
0187     u32 mclk;
0188     u32 pll_ch_num;
0189 };
0190 
0191 /*
0192  * PLL has 3 output channels (1x, 2x, and 4x). Below are
0193  * the common MCLK frequencies used by audio driver
0194  */
0195 static const struct pll_macro_entry pll_predef_mclk[] = {
0196     { 4096000, 0},
0197     { 8192000, 1},
0198     {16384000, 2},
0199 
0200     { 5644800, 0},
0201     {11289600, 1},
0202     {22579200, 2},
0203 
0204     { 6144000, 0},
0205     {12288000, 1},
0206     {24576000, 2},
0207 
0208     {12288000, 0},
0209     {24576000, 1},
0210     {49152000, 2},
0211 
0212     {22579200, 0},
0213     {45158400, 1},
0214     {90316800, 2},
0215 
0216     {24576000, 0},
0217     {49152000, 1},
0218     {98304000, 2},
0219 };
0220 
0221 #define CYGNUS_RATE_MIN     8000
0222 #define CYGNUS_RATE_MAX   384000
0223 
0224 /* List of valid frame sizes for tdm mode */
0225 static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512};
0226 
0227 static const unsigned int cygnus_rates[] = {
0228      8000, 11025,  16000,  22050,  32000,  44100, 48000,
0229     88200, 96000, 176400, 192000, 352800, 384000
0230 };
0231 
0232 static const struct snd_pcm_hw_constraint_list cygnus_rate_constraint = {
0233     .count = ARRAY_SIZE(cygnus_rates),
0234     .list = cygnus_rates,
0235 };
0236 
0237 static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai)
0238 {
0239     struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
0240 
0241     return &cygaud->portinfo[dai->id];
0242 }
0243 
0244 static int audio_ssp_init_portregs(struct cygnus_aio_port *aio)
0245 {
0246     u32 value, fci_id;
0247     int status = 0;
0248 
0249     switch (aio->port_type) {
0250     case PORT_TDM:
0251         value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
0252         value &= ~I2S_STREAM_CFG_MASK;
0253 
0254         /* Set Group ID */
0255         writel(aio->portnum,
0256             aio->cygaud->audio + aio->regs.bf_sourcech_grp);
0257 
0258         /* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */
0259         value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID;
0260         value |= aio->portnum; /* FCI ID is the port num */
0261         value |= CH_GRP_STEREO << I2S_OUT_STREAM_CFG_CHANNEL_GROUPING;
0262         writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
0263 
0264         /* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */
0265         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0266         value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
0267         value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
0268         value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
0269         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0270 
0271         /* Configure the AUD_FMM_IOP_IN_I2S_x_CAP_STREAM_CFG_0 reg */
0272         value = readl(aio->cygaud->i2s_in +
0273             aio->regs.i2s_cap_stream_cfg);
0274         value &= ~I2S_CAP_STREAM_CFG_MASK;
0275         value |= aio->portnum << I2S_IN_STREAM_CFG_0_GROUP_ID;
0276         writel(value, aio->cygaud->i2s_in +
0277             aio->regs.i2s_cap_stream_cfg);
0278 
0279         /* Configure the AUD_FMM_BF_CTRL_DESTCH_CFGX_REG_BASE reg */
0280         fci_id = CAPTURE_FCI_ID_BASE + aio->portnum;
0281 
0282         value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
0283         value |= BIT(BF_DST_CFGX_DFIFO_SZ_DOUBLE);
0284         value &= ~BIT(BF_DST_CFGX_NOT_PAUSE_WHEN_FULL);
0285         value |= (fci_id << BF_DST_CFGX_FCI_ID);
0286         value |= BIT(BF_DST_CFGX_PROC_SEQ_ID_VALID);
0287         writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
0288 
0289         /* Enable the transmit pin for this port */
0290         value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
0291         value &= ~BIT((aio->portnum * 4) + AUD_MISC_SEROUT_SDAT_OE);
0292         writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
0293         break;
0294     case PORT_SPDIF:
0295         writel(aio->portnum, aio->cygaud->audio + BF_SRC_GRP3_OFFSET);
0296 
0297         value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET);
0298         value |= BIT(SPDIF_0_OUT_DITHER_ENA);
0299         writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET);
0300 
0301         /* Enable and set the FCI ID for the SPDIF channel */
0302         value = readl(aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
0303         value &= ~SPDIF_STREAM_CFG_MASK;
0304         value |= aio->portnum; /* FCI ID is the port num */
0305         value |= BIT(SPDIF_0_OUT_STREAM_ENA);
0306         writel(value, aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET);
0307 
0308         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0309         value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY);
0310         value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE);
0311         value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID);
0312         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0313 
0314         /* Enable the spdif output pin */
0315         value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
0316         value &= ~BIT(AUD_MISC_SEROUT_SPDIF_OE);
0317         writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
0318         break;
0319     default:
0320         dev_err(aio->cygaud->dev, "Port not supported\n");
0321         status = -EINVAL;
0322     }
0323 
0324     return status;
0325 }
0326 
0327 static void audio_ssp_in_enable(struct cygnus_aio_port *aio)
0328 {
0329     u32 value;
0330 
0331     value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
0332     value |= BIT(BF_DST_CFGX_CAP_ENA);
0333     writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
0334 
0335     writel(0x1, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
0336 
0337     value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
0338     value |= BIT(I2S_OUT_CFGX_CLK_ENA);
0339     value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
0340     writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
0341 
0342     value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
0343     value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA);
0344     writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
0345 
0346     aio->streams_on |= CAPTURE_STREAM_MASK;
0347 }
0348 
0349 static void audio_ssp_in_disable(struct cygnus_aio_port *aio)
0350 {
0351     u32 value;
0352 
0353     value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
0354     value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA);
0355     writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg);
0356 
0357     aio->streams_on &= ~CAPTURE_STREAM_MASK;
0358 
0359     /* If both playback and capture are off */
0360     if (!aio->streams_on) {
0361         value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
0362         value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
0363         value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
0364         writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
0365     }
0366 
0367     writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl);
0368 
0369     value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg);
0370     value &= ~BIT(BF_DST_CFGX_CAP_ENA);
0371     writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg);
0372 }
0373 
0374 static int audio_ssp_out_enable(struct cygnus_aio_port *aio)
0375 {
0376     u32 value;
0377     int status = 0;
0378 
0379     switch (aio->port_type) {
0380     case PORT_TDM:
0381         value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
0382         value |= BIT(I2S_OUT_STREAM_ENA);
0383         writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
0384 
0385         writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
0386 
0387         value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
0388         value |= BIT(I2S_OUT_CFGX_CLK_ENA);
0389         value |= BIT(I2S_OUT_CFGX_DATA_ENABLE);
0390         writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
0391 
0392         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0393         value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
0394         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0395 
0396         aio->streams_on |= PLAYBACK_STREAM_MASK;
0397         break;
0398     case PORT_SPDIF:
0399         value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
0400         value |= 0x3;
0401         writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
0402 
0403         writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
0404 
0405         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0406         value |= BIT(BF_SRC_CFGX_SFIFO_ENA);
0407         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0408         break;
0409     default:
0410         dev_err(aio->cygaud->dev,
0411             "Port not supported %d\n", aio->portnum);
0412         status = -EINVAL;
0413     }
0414 
0415     return status;
0416 }
0417 
0418 static int audio_ssp_out_disable(struct cygnus_aio_port *aio)
0419 {
0420     u32 value;
0421     int status = 0;
0422 
0423     switch (aio->port_type) {
0424     case PORT_TDM:
0425         aio->streams_on &= ~PLAYBACK_STREAM_MASK;
0426 
0427         /* If both playback and capture are off */
0428         if (!aio->streams_on) {
0429             value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
0430             value &= ~BIT(I2S_OUT_CFGX_CLK_ENA);
0431             value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE);
0432             writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
0433         }
0434 
0435         /* set group_sync_dis = 1 */
0436         value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
0437         value |= BIT(aio->portnum);
0438         writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
0439 
0440         writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
0441 
0442         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0443         value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
0444         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0445 
0446         /* set group_sync_dis = 0 */
0447         value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
0448         value &= ~BIT(aio->portnum);
0449         writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET);
0450 
0451         value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg);
0452         value &= ~BIT(I2S_OUT_STREAM_ENA);
0453         writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg);
0454 
0455         /* IOP SW INIT on OUT_I2S_x */
0456         value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
0457         value |= BIT(aio->portnum);
0458         writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
0459         value &= ~BIT(aio->portnum);
0460         writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC);
0461         break;
0462     case PORT_SPDIF:
0463         value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
0464         value &= ~0x3;
0465         writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET);
0466         writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl);
0467 
0468         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0469         value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA);
0470         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0471         break;
0472     default:
0473         dev_err(aio->cygaud->dev,
0474             "Port not supported %d\n", aio->portnum);
0475         status = -EINVAL;
0476     }
0477 
0478     return status;
0479 }
0480 
0481 static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk,
0482     struct cygnus_aio_port *aio)
0483 {
0484     int i = 0, error;
0485     bool found = false;
0486     const struct pll_macro_entry *p_entry;
0487     struct clk *ch_clk;
0488 
0489     for (i = 0; i < ARRAY_SIZE(pll_predef_mclk); i++) {
0490         p_entry = &pll_predef_mclk[i];
0491         if (p_entry->mclk == mclk) {
0492             found = true;
0493             break;
0494         }
0495     }
0496     if (!found) {
0497         dev_err(cygaud->dev,
0498             "%s No valid mclk freq (%u) found!\n", __func__, mclk);
0499         return -EINVAL;
0500     }
0501 
0502     ch_clk = cygaud->audio_clk[p_entry->pll_ch_num];
0503 
0504     if ((aio->clk_trace.cap_en) && (!aio->clk_trace.cap_clk_en)) {
0505         error = clk_prepare_enable(ch_clk);
0506         if (error) {
0507             dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
0508                 __func__, error);
0509             return error;
0510         }
0511         aio->clk_trace.cap_clk_en = true;
0512     }
0513 
0514     if ((aio->clk_trace.play_en) && (!aio->clk_trace.play_clk_en)) {
0515         error = clk_prepare_enable(ch_clk);
0516         if (error) {
0517             dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n",
0518                 __func__, error);
0519             return error;
0520         }
0521         aio->clk_trace.play_clk_en = true;
0522     }
0523 
0524     error = clk_set_rate(ch_clk, mclk);
0525     if (error) {
0526         dev_err(cygaud->dev, "%s Set MCLK rate failed: %d\n",
0527             __func__, error);
0528         return error;
0529     }
0530 
0531     return p_entry->pll_ch_num;
0532 }
0533 
0534 static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio)
0535 {
0536     u32 value;
0537     u32 mask = 0xf;
0538     u32 sclk;
0539     u32 mclk_rate;
0540     unsigned int bit_rate;
0541     unsigned int ratio;
0542 
0543     bit_rate = aio->bit_per_frame * aio->lrclk;
0544 
0545     /*
0546      * Check if the bit clock can be generated from the given MCLK.
0547      * MCLK must be a perfect multiple of bit clock and must be one of the
0548      * following values... (2,4,6,8,10,12,14)
0549      */
0550     if ((aio->mclk % bit_rate) != 0)
0551         return -EINVAL;
0552 
0553     ratio = aio->mclk / bit_rate;
0554     switch (ratio) {
0555     case 2:
0556     case 4:
0557     case 6:
0558     case 8:
0559     case 10:
0560     case 12:
0561     case 14:
0562         mclk_rate = ratio / 2;
0563         break;
0564 
0565     default:
0566         dev_err(aio->cygaud->dev,
0567             "Invalid combination of MCLK and BCLK\n");
0568         dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n",
0569             aio->lrclk, aio->bit_per_frame, aio->mclk);
0570         return -EINVAL;
0571     }
0572 
0573     /* Set sclk rate */
0574     switch (aio->port_type) {
0575     case PORT_TDM:
0576         sclk = aio->bit_per_frame;
0577         if (sclk == 512)
0578             sclk = 0;
0579 
0580         /* sclks_per_1fs_div = sclk cycles/32 */
0581         sclk /= 32;
0582 
0583         /* Set number of bitclks per frame */
0584         value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
0585         value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32);
0586         value |= sclk << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32;
0587         writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
0588         dev_dbg(aio->cygaud->dev,
0589             "SCLKS_PER_1FS_DIV32 = 0x%x\n", value);
0590         break;
0591     case PORT_SPDIF:
0592         break;
0593     default:
0594         dev_err(aio->cygaud->dev, "Unknown port type\n");
0595         return -EINVAL;
0596     }
0597 
0598     /* Set MCLK_RATE ssp port (spdif and ssp are the same) */
0599     value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
0600     value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT);
0601     value |= (mclk_rate << I2S_OUT_MCLKRATE_SHIFT);
0602     writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
0603 
0604     dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value);
0605     dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n",
0606             aio->bit_per_frame, aio->mclk, aio->lrclk);
0607     return 0;
0608 }
0609 
0610 static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream,
0611                  struct snd_pcm_hw_params *params,
0612                  struct snd_soc_dai *dai)
0613 {
0614     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
0615     int rate, bitres;
0616     u32 value;
0617     u32 mask = 0x1f;
0618     int ret = 0;
0619 
0620     dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum);
0621     dev_dbg(aio->cygaud->dev, "params_channels %d\n",
0622             params_channels(params));
0623     dev_dbg(aio->cygaud->dev, "rate %d\n", params_rate(params));
0624     dev_dbg(aio->cygaud->dev, "format %d\n", params_format(params));
0625 
0626     rate = params_rate(params);
0627 
0628     switch (aio->mode) {
0629     case CYGNUS_SSPMODE_TDM:
0630         if ((rate == 192000) && (params_channels(params) > 4)) {
0631             dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n",
0632                 params_channels(params), rate);
0633             return -EINVAL;
0634         }
0635         break;
0636     case CYGNUS_SSPMODE_I2S:
0637         aio->bit_per_frame = 64; /* I2S must be 64 bit per frame */
0638         break;
0639     default:
0640         dev_err(aio->cygaud->dev,
0641             "%s port running in unknown mode\n", __func__);
0642         return -EINVAL;
0643     }
0644 
0645     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0646         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0647         value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE);
0648         value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE);
0649         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0650 
0651         switch (params_format(params)) {
0652         case SNDRV_PCM_FORMAT_S16_LE:
0653             bitres = 16;
0654             break;
0655 
0656         case SNDRV_PCM_FORMAT_S32_LE:
0657             /* 32 bit mode is coded as 0 */
0658             bitres = 0;
0659             break;
0660 
0661         default:
0662             return -EINVAL;
0663         }
0664 
0665         value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0666         value &= ~(mask << BF_SRC_CFGX_BIT_RES);
0667         value |= (bitres << BF_SRC_CFGX_BIT_RES);
0668         writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg);
0669 
0670     } else {
0671 
0672         switch (params_format(params)) {
0673         case SNDRV_PCM_FORMAT_S16_LE:
0674             value = readl(aio->cygaud->audio +
0675                     aio->regs.bf_destch_cfg);
0676             value |= BIT(BF_DST_CFGX_CAP_MODE);
0677             writel(value, aio->cygaud->audio +
0678                     aio->regs.bf_destch_cfg);
0679             break;
0680 
0681         case SNDRV_PCM_FORMAT_S32_LE:
0682             value = readl(aio->cygaud->audio +
0683                     aio->regs.bf_destch_cfg);
0684             value &= ~BIT(BF_DST_CFGX_CAP_MODE);
0685             writel(value, aio->cygaud->audio +
0686                     aio->regs.bf_destch_cfg);
0687             break;
0688 
0689         default:
0690             return -EINVAL;
0691         }
0692     }
0693 
0694     aio->lrclk = rate;
0695 
0696     if (!aio->is_slave)
0697         ret = cygnus_ssp_set_clocks(aio);
0698 
0699     return ret;
0700 }
0701 
0702 /*
0703  * This function sets the mclk frequency for pll clock
0704  */
0705 static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai,
0706             int clk_id, unsigned int freq, int dir)
0707 {
0708     int sel;
0709     u32 value;
0710     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
0711     struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
0712 
0713     dev_dbg(aio->cygaud->dev,
0714         "%s Enter port = %d\n", __func__, aio->portnum);
0715     sel = pll_configure_mclk(cygaud, freq, aio);
0716     if (sel < 0) {
0717         dev_err(aio->cygaud->dev,
0718             "%s Setting mclk failed.\n", __func__);
0719         return -EINVAL;
0720     }
0721 
0722     aio->mclk = freq;
0723 
0724     dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel);
0725     value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
0726     value &= ~(0xf << I2S_OUT_PLLCLKSEL_SHIFT);
0727     value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT);
0728     writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
0729 
0730     return 0;
0731 }
0732 
0733 static int cygnus_ssp_startup(struct snd_pcm_substream *substream,
0734                    struct snd_soc_dai *dai)
0735 {
0736     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
0737 
0738     snd_soc_dai_set_dma_data(dai, substream, aio);
0739     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0740         aio->clk_trace.play_en = true;
0741     else
0742         aio->clk_trace.cap_en = true;
0743 
0744     substream->runtime->hw.rate_min = CYGNUS_RATE_MIN;
0745     substream->runtime->hw.rate_max = CYGNUS_RATE_MAX;
0746 
0747     snd_pcm_hw_constraint_list(substream->runtime, 0,
0748             SNDRV_PCM_HW_PARAM_RATE, &cygnus_rate_constraint);
0749     return 0;
0750 }
0751 
0752 static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream,
0753                    struct snd_soc_dai *dai)
0754 {
0755     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
0756 
0757     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0758         aio->clk_trace.play_en = false;
0759     else
0760         aio->clk_trace.cap_en = false;
0761 
0762     if (!aio->is_slave) {
0763         u32 val;
0764 
0765         val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
0766         val &= CYGNUS_PLLCLKSEL_MASK;
0767         if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
0768             dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
0769                 val);
0770             return;
0771         }
0772 
0773         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0774             if (aio->clk_trace.play_clk_en) {
0775                 clk_disable_unprepare(aio->cygaud->
0776                         audio_clk[val]);
0777                 aio->clk_trace.play_clk_en = false;
0778             }
0779         } else {
0780             if (aio->clk_trace.cap_clk_en) {
0781                 clk_disable_unprepare(aio->cygaud->
0782                         audio_clk[val]);
0783                 aio->clk_trace.cap_clk_en = false;
0784             }
0785         }
0786     }
0787 }
0788 
0789 /*
0790  * Bit    Update  Notes
0791  * 31     Yes     TDM Mode        (1 = TDM, 0 = i2s)
0792  * 30     Yes     Slave Mode      (1 = Slave, 0 = Master)
0793  * 29:26  No      Sclks per frame
0794  * 25:18  Yes     FS Width
0795  * 17:14  No      Valid Slots
0796  * 13     No      Bits        (1 = 16 bits, 0 = 32 bits)
0797  * 12:08  No     Bits per samp
0798  * 07     Yes     Justifcation    (1 = LSB, 0 = MSB)
0799  * 06     Yes     Alignment       (1 = Delay 1 clk, 0 = no delay
0800  * 05     Yes     SCLK polarity   (1 = Rising, 0 = Falling)
0801  * 04     Yes     LRCLK Polarity  (1 = High for left, 0 = Low for left)
0802  * 03:02  Yes     Reserved - write as zero
0803  * 01     No      Data Enable
0804  * 00     No      CLK Enable
0805  */
0806 #define I2S_OUT_CFG_REG_UPDATE_MASK   0x3C03FF03
0807 
0808 /* Input cfg is same as output, but the FS width is not a valid field */
0809 #define I2S_IN_CFG_REG_UPDATE_MASK  (I2S_OUT_CFG_REG_UPDATE_MASK | 0x03FC0000)
0810 
0811 int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len)
0812 {
0813     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
0814 
0815     if ((len > 0) && (len < 256)) {
0816         aio->fsync_width = len;
0817         return 0;
0818     } else {
0819         return -EINVAL;
0820     }
0821 }
0822 EXPORT_SYMBOL_GPL(cygnus_ssp_set_custom_fsync_width);
0823 
0824 static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
0825 {
0826     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
0827     u32 ssp_curcfg;
0828     u32 ssp_newcfg;
0829     u32 ssp_outcfg;
0830     u32 ssp_incfg;
0831     u32 val;
0832     u32 mask;
0833 
0834     dev_dbg(aio->cygaud->dev, "%s Enter  fmt: %x\n", __func__, fmt);
0835 
0836     if (aio->port_type == PORT_SPDIF)
0837         return -EINVAL;
0838 
0839     ssp_newcfg = 0;
0840 
0841     switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0842     case SND_SOC_DAIFMT_BC_FC:
0843         ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
0844         aio->is_slave = 1;
0845         break;
0846     case SND_SOC_DAIFMT_BP_FP:
0847         ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
0848         aio->is_slave = 0;
0849         break;
0850     default:
0851         return -EINVAL;
0852     }
0853 
0854     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0855     case SND_SOC_DAIFMT_I2S:
0856         ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
0857         ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
0858         aio->mode = CYGNUS_SSPMODE_I2S;
0859         break;
0860 
0861     case SND_SOC_DAIFMT_DSP_A:
0862     case SND_SOC_DAIFMT_DSP_B:
0863         ssp_newcfg |= BIT(I2S_OUT_CFGX_TDM_MODE);
0864 
0865         /* DSP_A = data after FS, DSP_B = data during FS */
0866         if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
0867             ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT);
0868 
0869         if ((aio->fsync_width > 0) && (aio->fsync_width < 256))
0870             ssp_newcfg |=
0871                 (aio->fsync_width << I2S_OUT_CFGX_FSYNC_WIDTH);
0872         else
0873             ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH);
0874 
0875         aio->mode = CYGNUS_SSPMODE_TDM;
0876         break;
0877 
0878     default:
0879         return -EINVAL;
0880     }
0881 
0882     /*
0883      * SSP out cfg.
0884      * Retain bits we do not want to update, then OR in new bits
0885      */
0886     ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
0887     ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg;
0888     writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg);
0889 
0890     /*
0891      * SSP in cfg.
0892      * Retain bits we do not want to update, then OR in new bits
0893      */
0894     ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
0895     ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg;
0896     writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
0897 
0898     val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
0899 
0900     /*
0901      * Configure the word clk and bit clk as output or tristate
0902      * Each port has 4 bits for controlling its pins.
0903      * Shift the mask based upon port number.
0904      */
0905     mask = BIT(AUD_MISC_SEROUT_LRCK_OE)
0906             | BIT(AUD_MISC_SEROUT_SCLK_OE)
0907             | BIT(AUD_MISC_SEROUT_MCLK_OE);
0908     mask = mask << (aio->portnum * 4);
0909     if (aio->is_slave)
0910         /* Set bit for tri-state */
0911         val |= mask;
0912     else
0913         /* Clear bit for drive */
0914         val &= ~mask;
0915 
0916     dev_dbg(aio->cygaud->dev, "%s  Set OE bits 0x%x\n", __func__, val);
0917     writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
0918 
0919     return 0;
0920 }
0921 
0922 static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
0923                    struct snd_soc_dai *dai)
0924 {
0925     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai);
0926     struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai);
0927 
0928     dev_dbg(aio->cygaud->dev,
0929         "%s cmd %d at port = %d\n", __func__, cmd, aio->portnum);
0930 
0931     switch (cmd) {
0932     case SNDRV_PCM_TRIGGER_START:
0933     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0934     case SNDRV_PCM_TRIGGER_RESUME:
0935         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0936             audio_ssp_out_enable(aio);
0937         else
0938             audio_ssp_in_enable(aio);
0939         cygaud->active_ports++;
0940 
0941         break;
0942 
0943     case SNDRV_PCM_TRIGGER_STOP:
0944     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0945     case SNDRV_PCM_TRIGGER_SUSPEND:
0946         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0947             audio_ssp_out_disable(aio);
0948         else
0949             audio_ssp_in_disable(aio);
0950         cygaud->active_ports--;
0951         break;
0952 
0953     default:
0954         return -EINVAL;
0955     }
0956 
0957     return 0;
0958 }
0959 
0960 static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
0961     unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
0962 {
0963     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
0964     u32 value;
0965     int bits_per_slot = 0;     /* default to 32-bits per slot */
0966     int frame_bits;
0967     unsigned int active_slots;
0968     bool found = false;
0969     int i;
0970 
0971     if (tx_mask != rx_mask) {
0972         dev_err(aio->cygaud->dev,
0973             "%s tx_mask must equal rx_mask\n", __func__);
0974         return -EINVAL;
0975     }
0976 
0977     active_slots = hweight32(tx_mask);
0978 
0979     if (active_slots > 16)
0980         return -EINVAL;
0981 
0982     /* Slot value must be even */
0983     if (active_slots % 2)
0984         return -EINVAL;
0985 
0986     /* We encode 16 slots as 0 in the reg */
0987     if (active_slots == 16)
0988         active_slots = 0;
0989 
0990     /* Slot Width is either 16 or 32 */
0991     switch (slot_width) {
0992     case 16:
0993         bits_per_slot = 1;
0994         break;
0995     case 32:
0996         bits_per_slot = 0;
0997         break;
0998     default:
0999         bits_per_slot = 0;
1000         dev_warn(aio->cygaud->dev,
1001             "%s Defaulting Slot Width to 32\n", __func__);
1002     }
1003 
1004     frame_bits = slots * slot_width;
1005 
1006     for (i = 0; i < ARRAY_SIZE(ssp_valid_tdm_framesize); i++) {
1007         if (ssp_valid_tdm_framesize[i] == frame_bits) {
1008             found = true;
1009             break;
1010         }
1011     }
1012 
1013     if (!found) {
1014         dev_err(aio->cygaud->dev,
1015             "%s In TDM mode, frame bits INVALID (%d)\n",
1016             __func__, frame_bits);
1017         return -EINVAL;
1018     }
1019 
1020     aio->bit_per_frame = frame_bits;
1021 
1022     dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n",
1023             __func__, active_slots, frame_bits);
1024 
1025     /* Set capture side of ssp port */
1026     value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
1027     value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
1028     value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
1029     value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
1030     value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
1031     writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg);
1032 
1033     /* Set playback side of ssp port */
1034     value = readl(aio->cygaud->audio + aio->regs.i2s_cfg);
1035     value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT);
1036     value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT);
1037     value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT);
1038     value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT);
1039     writel(value, aio->cygaud->audio + aio->regs.i2s_cfg);
1040 
1041     return 0;
1042 }
1043 
1044 #ifdef CONFIG_PM_SLEEP
1045 static int __cygnus_ssp_suspend(struct snd_soc_dai *cpu_dai)
1046 {
1047     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
1048 
1049     if (!snd_soc_dai_active(cpu_dai))
1050         return 0;
1051 
1052     if (!aio->is_slave) {
1053         u32 val;
1054 
1055         val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg);
1056         val &= CYGNUS_PLLCLKSEL_MASK;
1057         if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) {
1058             dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n",
1059                 val);
1060             return -EINVAL;
1061         }
1062 
1063         if (aio->clk_trace.cap_clk_en)
1064             clk_disable_unprepare(aio->cygaud->audio_clk[val]);
1065         if (aio->clk_trace.play_clk_en)
1066             clk_disable_unprepare(aio->cygaud->audio_clk[val]);
1067 
1068         aio->pll_clk_num = val;
1069     }
1070 
1071     return 0;
1072 }
1073 
1074 static int cygnus_ssp_suspend(struct snd_soc_component *component)
1075 {
1076     struct snd_soc_dai *dai;
1077     int ret = 0;
1078 
1079     for_each_component_dais(component, dai)
1080         ret |= __cygnus_ssp_suspend(dai);
1081 
1082     return ret;
1083 }
1084 
1085 static int __cygnus_ssp_resume(struct snd_soc_dai *cpu_dai)
1086 {
1087     struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai);
1088     int error;
1089 
1090     if (!snd_soc_dai_active(cpu_dai))
1091         return 0;
1092 
1093     if (!aio->is_slave) {
1094         if (aio->clk_trace.cap_clk_en) {
1095             error = clk_prepare_enable(aio->cygaud->
1096                     audio_clk[aio->pll_clk_num]);
1097             if (error) {
1098                 dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
1099                     __func__);
1100                 return -EINVAL;
1101             }
1102         }
1103         if (aio->clk_trace.play_clk_en) {
1104             error = clk_prepare_enable(aio->cygaud->
1105                     audio_clk[aio->pll_clk_num]);
1106             if (error) {
1107                 if (aio->clk_trace.cap_clk_en)
1108                     clk_disable_unprepare(aio->cygaud->
1109                         audio_clk[aio->pll_clk_num]);
1110                 dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n",
1111                     __func__);
1112                 return -EINVAL;
1113             }
1114         }
1115     }
1116 
1117     return 0;
1118 }
1119 
1120 static int cygnus_ssp_resume(struct snd_soc_component *component)
1121 {
1122     struct snd_soc_dai *dai;
1123     int ret = 0;
1124 
1125     for_each_component_dais(component, dai)
1126         ret |= __cygnus_ssp_resume(dai);
1127 
1128     return ret;
1129 }
1130 
1131 #else
1132 #define cygnus_ssp_suspend NULL
1133 #define cygnus_ssp_resume  NULL
1134 #endif
1135 
1136 static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
1137     .startup    = cygnus_ssp_startup,
1138     .shutdown   = cygnus_ssp_shutdown,
1139     .trigger    = cygnus_ssp_trigger,
1140     .hw_params  = cygnus_ssp_hw_params,
1141     .set_fmt    = cygnus_ssp_set_fmt,
1142     .set_sysclk = cygnus_ssp_set_sysclk,
1143     .set_tdm_slot   = cygnus_set_dai_tdm_slot,
1144 };
1145 
1146 static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
1147     .startup    = cygnus_ssp_startup,
1148     .shutdown   = cygnus_ssp_shutdown,
1149     .trigger    = cygnus_ssp_trigger,
1150     .hw_params  = cygnus_ssp_hw_params,
1151     .set_sysclk = cygnus_ssp_set_sysclk,
1152 };
1153 
1154 #define INIT_CPU_DAI(num) { \
1155     .name = "cygnus-ssp" #num, \
1156     .playback = { \
1157         .channels_min = 2, \
1158         .channels_max = 16, \
1159         .rates = SNDRV_PCM_RATE_KNOT, \
1160         .formats = SNDRV_PCM_FMTBIT_S16_LE | \
1161                 SNDRV_PCM_FMTBIT_S32_LE, \
1162     }, \
1163     .capture = { \
1164         .channels_min = 2, \
1165         .channels_max = 16, \
1166         .rates = SNDRV_PCM_RATE_KNOT, \
1167         .formats =  SNDRV_PCM_FMTBIT_S16_LE | \
1168                 SNDRV_PCM_FMTBIT_S32_LE, \
1169     }, \
1170     .ops = &cygnus_ssp_dai_ops, \
1171 }
1172 
1173 static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = {
1174     INIT_CPU_DAI(0),
1175     INIT_CPU_DAI(1),
1176     INIT_CPU_DAI(2),
1177 };
1178 
1179 static const struct snd_soc_dai_driver cygnus_spdif_dai_info = {
1180     .name = "cygnus-spdif",
1181     .playback = {
1182         .channels_min = 2,
1183         .channels_max = 2,
1184         .rates = SNDRV_PCM_RATE_KNOT,
1185         .formats = SNDRV_PCM_FMTBIT_S16_LE |
1186             SNDRV_PCM_FMTBIT_S32_LE,
1187     },
1188     .ops = &cygnus_spdif_dai_ops,
1189 };
1190 
1191 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
1192 
1193 static const struct snd_soc_component_driver cygnus_ssp_component = {
1194     .name           = "cygnus-audio",
1195     .suspend        = cygnus_ssp_suspend,
1196     .resume         = cygnus_ssp_resume,
1197     .legacy_dai_naming  = 1,
1198 };
1199 
1200 /*
1201  * Return < 0 if error
1202  * Return 0 if disabled
1203  * Return 1 if enabled and node is parsed successfully
1204  */
1205 static int parse_ssp_child_node(struct platform_device *pdev,
1206                 struct device_node *dn,
1207                 struct cygnus_audio *cygaud,
1208                 struct snd_soc_dai_driver *p_dai)
1209 {
1210     struct cygnus_aio_port *aio;
1211     struct cygnus_ssp_regs ssp_regs[3];
1212     u32 rawval;
1213     int portnum = -1;
1214     enum cygnus_audio_port_type port_type;
1215 
1216     if (of_property_read_u32(dn, "reg", &rawval)) {
1217         dev_err(&pdev->dev, "Missing reg property\n");
1218         return -EINVAL;
1219     }
1220 
1221     portnum = rawval;
1222     switch (rawval) {
1223     case 0:
1224         ssp_regs[0] = INIT_SSP_REGS(0);
1225         port_type = PORT_TDM;
1226         break;
1227     case 1:
1228         ssp_regs[1] = INIT_SSP_REGS(1);
1229         port_type = PORT_TDM;
1230         break;
1231     case 2:
1232         ssp_regs[2] = INIT_SSP_REGS(2);
1233         port_type = PORT_TDM;
1234         break;
1235     case 3:
1236         port_type = PORT_SPDIF;
1237         break;
1238     default:
1239         dev_err(&pdev->dev, "Bad value for reg %u\n", rawval);
1240         return -EINVAL;
1241     }
1242 
1243     aio = &cygaud->portinfo[portnum];
1244     aio->cygaud = cygaud;
1245     aio->portnum = portnum;
1246     aio->port_type = port_type;
1247     aio->fsync_width = -1;
1248 
1249     switch (port_type) {
1250     case PORT_TDM:
1251         aio->regs = ssp_regs[portnum];
1252         *p_dai = cygnus_ssp_dai_info[portnum];
1253         aio->mode = CYGNUS_SSPMODE_UNKNOWN;
1254         break;
1255 
1256     case PORT_SPDIF:
1257         aio->regs.bf_sourcech_cfg = BF_SRC_CFG3_OFFSET;
1258         aio->regs.bf_sourcech_ctrl = BF_SRC_CTRL3_OFFSET;
1259         aio->regs.i2s_mclk_cfg = SPDIF_MCLK_CFG_OFFSET;
1260         aio->regs.i2s_stream_cfg = SPDIF_STREAM_CFG_OFFSET;
1261         *p_dai = cygnus_spdif_dai_info;
1262 
1263         /* For the purposes of this code SPDIF can be I2S mode */
1264         aio->mode = CYGNUS_SSPMODE_I2S;
1265         break;
1266     default:
1267         dev_err(&pdev->dev, "Bad value for port_type %d\n", port_type);
1268         return -EINVAL;
1269     }
1270 
1271     dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum);
1272     aio->streams_on = 0;
1273     aio->cygaud->dev = &pdev->dev;
1274     aio->clk_trace.play_en = false;
1275     aio->clk_trace.cap_en = false;
1276 
1277     audio_ssp_init_portregs(aio);
1278     return 0;
1279 }
1280 
1281 static int audio_clk_init(struct platform_device *pdev,
1282                         struct cygnus_audio *cygaud)
1283 {
1284     int i;
1285     char clk_name[PROP_LEN_MAX];
1286 
1287     for (i = 0; i < ARRAY_SIZE(cygaud->audio_clk); i++) {
1288         snprintf(clk_name, PROP_LEN_MAX, "ch%d_audio", i);
1289 
1290         cygaud->audio_clk[i] = devm_clk_get(&pdev->dev, clk_name);
1291         if (IS_ERR(cygaud->audio_clk[i]))
1292             return PTR_ERR(cygaud->audio_clk[i]);
1293     }
1294 
1295     return 0;
1296 }
1297 
1298 static int cygnus_ssp_probe(struct platform_device *pdev)
1299 {
1300     struct device *dev = &pdev->dev;
1301     struct device_node *child_node;
1302     struct cygnus_audio *cygaud;
1303     int err;
1304     int node_count;
1305     int active_port_count;
1306 
1307     cygaud = devm_kzalloc(dev, sizeof(struct cygnus_audio), GFP_KERNEL);
1308     if (!cygaud)
1309         return -ENOMEM;
1310 
1311     dev_set_drvdata(dev, cygaud);
1312 
1313     cygaud->audio = devm_platform_ioremap_resource_byname(pdev, "aud");
1314     if (IS_ERR(cygaud->audio))
1315         return PTR_ERR(cygaud->audio);
1316 
1317     cygaud->i2s_in = devm_platform_ioremap_resource_byname(pdev, "i2s_in");
1318     if (IS_ERR(cygaud->i2s_in))
1319         return PTR_ERR(cygaud->i2s_in);
1320 
1321     /* Tri-state all controlable pins until we know that we need them */
1322     writel(CYGNUS_SSP_TRISTATE_MASK,
1323             cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE);
1324 
1325     node_count = of_get_child_count(pdev->dev.of_node);
1326     if ((node_count < 1) || (node_count > CYGNUS_MAX_PORTS)) {
1327         dev_err(dev, "child nodes is %d.  Must be between 1 and %d\n",
1328             node_count, CYGNUS_MAX_PORTS);
1329         return -EINVAL;
1330     }
1331 
1332     active_port_count = 0;
1333 
1334     for_each_available_child_of_node(pdev->dev.of_node, child_node) {
1335         err = parse_ssp_child_node(pdev, child_node, cygaud,
1336                     &cygnus_ssp_dai[active_port_count]);
1337 
1338         /* negative is err, 0 is active and good, 1 is disabled */
1339         if (err < 0) {
1340             of_node_put(child_node);
1341             return err;
1342         }
1343         else if (!err) {
1344             dev_dbg(dev, "Activating DAI: %s\n",
1345                 cygnus_ssp_dai[active_port_count].name);
1346             active_port_count++;
1347         }
1348     }
1349 
1350     cygaud->dev = dev;
1351     cygaud->active_ports = 0;
1352 
1353     dev_dbg(dev, "Registering %d DAIs\n", active_port_count);
1354     err = devm_snd_soc_register_component(dev, &cygnus_ssp_component,
1355                 cygnus_ssp_dai, active_port_count);
1356     if (err) {
1357         dev_err(dev, "snd_soc_register_dai failed\n");
1358         return err;
1359     }
1360 
1361     cygaud->irq_num = platform_get_irq(pdev, 0);
1362     if (cygaud->irq_num <= 0)
1363         return cygaud->irq_num;
1364 
1365     err = audio_clk_init(pdev, cygaud);
1366     if (err) {
1367         dev_err(dev, "audio clock initialization failed\n");
1368         return err;
1369     }
1370 
1371     err = cygnus_soc_platform_register(dev, cygaud);
1372     if (err) {
1373         dev_err(dev, "platform reg error %d\n", err);
1374         return err;
1375     }
1376 
1377     return 0;
1378 }
1379 
1380 static int cygnus_ssp_remove(struct platform_device *pdev)
1381 {
1382     cygnus_soc_platform_unregister(&pdev->dev);
1383 
1384     return 0;
1385 }
1386 
1387 static const struct of_device_id cygnus_ssp_of_match[] = {
1388     { .compatible = "brcm,cygnus-audio" },
1389     {},
1390 };
1391 MODULE_DEVICE_TABLE(of, cygnus_ssp_of_match);
1392 
1393 static struct platform_driver cygnus_ssp_driver = {
1394     .probe      = cygnus_ssp_probe,
1395     .remove     = cygnus_ssp_remove,
1396     .driver     = {
1397         .name   = "cygnus-ssp",
1398         .of_match_table = cygnus_ssp_of_match,
1399     },
1400 };
1401 
1402 module_platform_driver(cygnus_ssp_driver);
1403 
1404 MODULE_ALIAS("platform:cygnus-ssp");
1405 MODULE_LICENSE("GPL v2");
1406 MODULE_AUTHOR("Broadcom");
1407 MODULE_DESCRIPTION("Cygnus ASoC SSP Interface");