unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai) { struct s3c_i2sv2_info *i2s = to_info(dai); return clk_get_rate(i2s->iis_cclk); }
static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *socdai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *dai = rtd->dai; struct s3c_pcm_info *pcm = to_info(dai->cpu_dai); struct s3c_dma_params *dma_data; void __iomem *regs = pcm->regs; struct clk *clk; int sclk_div, sync_div; unsigned long flags; u32 clkctl; u32 dma_tsfr_size = 0; /* added by LiXueZhong on 2013.09.25 */ unsigned long srcrate; unsigned long rate; dev_dbg(pcm->dev, "Entered %s\n", __func__); switch (params_channels(params)) { case 1: dma_tsfr_size = 2; break; case 2: dma_tsfr_size = 4; break; case 4: break; case 6: break; default: break; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pcm->dma_playback->dma_size = dma_tsfr_size; dma_data = pcm->dma_playback; } else { pcm->dma_capture->dma_size = dma_tsfr_size; dma_data = pcm->dma_capture; } snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data); /* Strictly check for sample size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; default: return -EINVAL; } spin_lock_irqsave(&pcm->lock, flags); /* Get hold of the PCMSOURCE_CLK */ clkctl = readl(regs + S3C_PCM_CLKCTL); if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK) clk = pcm->pclk; else clk = pcm->cclk; /* Set the SCLK divider */ ////////////////////////////////////////// /* modified by LiXueZhong on 2013.09.25 */ srcrate = clk_get_rate(clk); DBG("--- CLK = %u ---\n", srcrate); rate = pcm->sclk_per_fs * params_rate(params) * 2; sclk_div = srcrate / rate; if (srcrate % rate) sclk_div++; --sclk_div; /////////////////////////////////////////// clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK << S3C_PCM_CLKCTL_SCLKDIV_SHIFT); clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK) << S3C_PCM_CLKCTL_SCLKDIV_SHIFT); /* Set the SYNC divider */ sync_div = pcm->sclk_per_fs - 1; clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK << S3C_PCM_CLKCTL_SYNCDIV_SHIFT); clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK) << S3C_PCM_CLKCTL_SYNCDIV_SHIFT); writel(clkctl, regs + S3C_PCM_CLKCTL); spin_unlock_irqrestore(&pcm->lock, flags); /* dev_dbg(pcm->dev, "SOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n", clk_get_rate(clk), pcm->sclk_per_fs, sclk_div, sync_div); */ DBG("--- SOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d ---\n", clk_get_rate(clk), pcm->sclk_per_fs, sclk_div, sync_div); return 0; }
/* * Set S3C2412 I2S DAI format */ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct s3c_i2sv2_info *i2s = to_info(cpu_dai); u32 iismod; pr_debug("Entered %s\n", __func__); iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("hw_params r: IISMOD: %x \n", iismod); #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) #define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK #define IISMOD_SLAVE S3C2412_IISMOD_SLAVE #define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL #endif #if defined(CONFIG_PLAT_S3C64XX) || defined(CONFIG_PLAT_S5PC1XX) \ || defined(CONFIG_PLAT_S5PC11X) || defined(CONFIG_PLAT_S5P64XX) /* From Rev1.1 datasheet, we have two master and two slave modes: * IMS[11:10]: * 00 = master mode, fed from PCLK * 01 = master mode, fed from CLKAUDIO * 10 = slave mode, using PCLK * 11 = slave mode, using I2SCLK */ #define IISMOD_MASTER_MASK (1 << 11) #define IISMOD_SLAVE (1 << 11) #define IISMOD_MASTER (0 << 11) #endif switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: i2s->master = 0; iismod &= ~IISMOD_MASTER_MASK; iismod |= IISMOD_SLAVE; break; case SND_SOC_DAIFMT_CBS_CFS: i2s->master = 1; iismod &= ~IISMOD_MASTER_MASK; iismod |= IISMOD_MASTER; break; default: pr_err("unknwon master/slave format\n"); return -EINVAL; } iismod &= ~S3C2412_IISMOD_SDF_MASK; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: iismod |= S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_MSB; break; case SND_SOC_DAIFMT_LEFT_J: iismod |= S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_LSB; break; case SND_SOC_DAIFMT_I2S: iismod &= ~S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_IIS; break; default: pr_err("Unknown data format\n"); return -EINVAL; } writel(iismod, i2s->regs + S3C2412_IISMOD); pr_debug("hw_params w: IISMOD: %x \n", iismod); return 0; }
/* * Set S3C2412 Clock dividers */ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { struct s3c_i2sv2_info *i2s = to_info(cpu_dai); u32 reg; pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div); switch (div_id) { case S3C_I2SV2_DIV_BCLK: if (div > 3) { /* convert value to bit field */ switch (div) { case 16: div = S3C2412_IISMOD_BCLK_16FS; break; case 32: div = S3C2412_IISMOD_BCLK_32FS; break; case 24: div = S3C2412_IISMOD_BCLK_24FS; break; case 48: div = S3C2412_IISMOD_BCLK_48FS; break; default: return -EINVAL; } } reg = readl(i2s->regs + S3C2412_IISMOD); reg &= ~S3C2412_IISMOD_BCLK_MASK; writel(reg | div, i2s->regs + S3C2412_IISMOD); pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); break; case S3C_I2SV2_DIV_RCLK: if (div > 3) { /* convert value to bit field */ switch (div) { case 256: div = S3C2412_IISMOD_RCLK_256FS; break; case 384: div = S3C2412_IISMOD_RCLK_384FS; break; case 512: div = S3C2412_IISMOD_RCLK_512FS; break; case 768: div = S3C2412_IISMOD_RCLK_768FS; break; default: return -EINVAL; } } reg = readl(i2s->regs + S3C2412_IISMOD); reg &= ~S3C2412_IISMOD_RCLK_MASK; writel(reg | div, i2s->regs + S3C2412_IISMOD); pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); break; case S3C_I2SV2_DIV_PRESCALER: if (div >= 0) { writel((div << 8) | S3C2412_IISPSR_PSREN, i2s->regs + S3C2412_IISPSR); } else { writel(0x0, i2s->regs + S3C2412_IISPSR); } pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR)); break; default: return -EINVAL; } return 0; }
static int spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *socdai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai); void __iomem *regs = spdif->regs; struct s3c_dma_params *dma_data; u32 con, clkcon, cstas; unsigned long flags; int i, ratio; dev_dbg(spdif->dev, "Entered %s\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dma_data = spdif->dma_playback; else { dev_err(spdif->dev, "Capture is not supported\n"); return -EINVAL; } snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data); spin_lock_irqsave(&spdif->lock, flags); con = readl(regs + CON) & CON_MASK; cstas = readl(regs + CSTAS) & CSTAS_MASK; clkcon = readl(regs + CLKCON) & CLKCTL_MASK; con &= ~CON_FIFO_TH_MASK; con |= (0x7 << CON_FIFO_TH_SHIFT); con |= CON_USERDATA_23RDBIT; con |= CON_PCM_DATA; con &= ~CON_PCM_MASK; switch (params_width(params)) { case 16: con |= CON_PCM_16BIT; break; default: dev_err(spdif->dev, "Unsupported data size.\n"); goto err; } ratio = spdif->clk_rate / params_rate(params); for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++) if (ratio == spdif_sysclk_ratios[i]) break; if (i == ARRAY_SIZE(spdif_sysclk_ratios)) { dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n", spdif->clk_rate, params_rate(params)); goto err; } con &= ~CON_MCLKDIV_MASK; switch (ratio) { case 256: con |= CON_MCLKDIV_256FS; break; case 384: con |= CON_MCLKDIV_384FS; break; case 512: con |= CON_MCLKDIV_512FS; break; } cstas &= ~CSTAS_SAMP_FREQ_MASK; switch (params_rate(params)) { case 44100: cstas |= CSTAS_SAMP_FREQ_44; break; case 48000: cstas |= CSTAS_SAMP_FREQ_48; break; case 32000: cstas |= CSTAS_SAMP_FREQ_32; break; case 96000: cstas |= CSTAS_SAMP_FREQ_96; break; default: dev_err(spdif->dev, "Invalid sampling rate %d\n", params_rate(params)); goto err; } cstas &= ~CSTAS_CATEGORY_MASK; cstas |= CSTAS_CATEGORY_CODE_CDP; cstas |= CSTAS_NO_COPYRIGHT; writel(con, regs + CON); writel(cstas, regs + CSTAS); writel(clkcon, regs + CLKCON); spin_unlock_irqrestore(&spdif->lock, flags); return 0; err: spin_unlock_irqrestore(&spdif->lock, flags); return -EINVAL; }
static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai); int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; int ret = 0; struct s3c_dma_params *dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); pr_debug("Entered %s\n", __func__); switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* On start, ensure that the FIFOs are cleared and reset. */ writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH, i2s->regs + S3C2412_IISFIC); /* clear again, just in case */ writel(0x0, i2s->regs + S3C2412_IISFIC); case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (!i2s->master) { ret = s3c2412_snd_lrsync(i2s); if (ret) goto exit_err; } local_irq_save(irqs); if (capture) s3c2412_snd_rxctrl(i2s, 1); else s3c2412_snd_txctrl(i2s, 1); local_irq_restore(irqs); /* * Load the next buffer to DMA to meet the reqirement * of the auto reload mechanism of S3C24XX. * This call won't bother S3C64XX. */ s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: local_irq_save(irqs); if (capture) s3c2412_snd_rxctrl(i2s, 0); else s3c2412_snd_txctrl(i2s, 0); local_irq_restore(irqs); break; default: ret = -EINVAL; break; } exit_err: return ret; }
static int s5p_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct clk *clk; struct s3c_i2sv2_info *i2s = to_info(cpu_dai); u32 iismod = readl(i2s->regs + S3C2412_IISMOD); switch (clk_id) { case S3C64XX_CLKSRC_PCLK: iismod &= ~S3C64XX_IISMOD_IMS_SYSMUX; break; case S3C64XX_CLKSRC_MUX: iismod |= S3C64XX_IISMOD_IMS_SYSMUX; break; case S3C64XX_CLKSRC_CDCLK: switch (dir) { case SND_SOC_CLOCK_IN: iismod |= S3C64XX_IISMOD_CDCLKCON; break; case SND_SOC_CLOCK_OUT: iismod &= ~S3C64XX_IISMOD_CDCLKCON; break; default: return -EINVAL; } break; #ifdef USE_CLKAUDIO /* IIS-IP is Master and derives its clocks from I2SCLKD2 */ case S3C_CLKSRC_CLKAUDIO: if (!i2s->master) return -EINVAL; iismod &= ~S3C_IISMOD_IMSMASK; iismod |= clk_id; clk = clk_get(NULL, "fout_epll"); if (IS_ERR(clk)) { pr_err("failed to get %s\n", "fout_epll"); return -EBUSY; } clk_disable(clk); switch (freq) { case 8000: case 16000: case 32000: case 48000: case 64000: case 96000: clk_set_rate(clk, 49152000); break; case 11025: case 22050: case 44100: case 88200: default: clk_set_rate(clk, 67738000); break; } clk_enable(clk); clk_put(clk); break; #endif /* IIS-IP is Slave and derives its clocks from the Codec Chip */ case S3C64XX_CLKSRC_I2SEXT: iismod &= ~S3C64XX_IISMOD_IMSMASK; iismod |= clk_id; /* Operation clock for I2S logic selected as Audio Bus Clock */ iismod |= S3C64XX_IISMOD_OPPCLK; clk = clk_get(NULL, "fout_epll"); if (IS_ERR(clk)) { pr_err("failed to get %s\n", "fout_epll"); return -EBUSY; } clk_disable(clk); clk_set_rate(clk, 67738000); clk_enable(clk); clk_put(clk); break; case S3C64XX_CDCLKSRC_EXT: iismod |= S3C64XX_IISMOD_CDCLKCON; break; default: return -EINVAL; } writel(iismod, i2s->regs + S3C2412_IISMOD); return 0; }
int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *socdai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *dai = rtd->dai; struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai); u32 dma_tsfr_size = 0; u32 iismod; pr_debug("Entered %s\n", __func__); /* TODO */ switch (params_channels(params)) { case 1: dma_tsfr_size = 2; break; case 2: dma_tsfr_size = 4; break; case 4: break; case 6: break; default: break; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { i2s->dma_playback->dma_size = dma_tsfr_size; dai->cpu_dai->dma_data = i2s->dma_playback; } else { i2s->dma_capture->dma_size = dma_tsfr_size; dai->cpu_dai->dma_data = i2s->dma_capture; } /* Working copies of register */ iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: iismod |= S3C2412_IISMOD_8BIT; break; case SNDRV_PCM_FORMAT_S16_LE: iismod &= ~S3C2412_IISMOD_8BIT; break; } #endif #if defined(CONFIG_PLAT_S3C64XX) || defined(CONFIG_PLAT_S5P) iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); /* Sample size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: /* 8 bit sample, 16fs BCLK */ iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); break; case SNDRV_PCM_FORMAT_S16_LE: /* 16 bit sample, 32fs BCLK */ break; case SNDRV_PCM_FORMAT_S24_LE: /* 24 bit sample, 48fs BCLK */ iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); break; } /* Set the IISMOD[25:24](BLC_P) to same value */ iismod &= ~(S5P_IISMOD_BLCPMASK); iismod |= ((iismod & S3C64XX_IISMOD_BLC_MASK) << 11); #endif writel(iismod, i2s->regs + S3C2412_IISMOD); pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); return 0; }
static int spdif_hw_params(struct snd_pcm_substream * substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct rockchip_spdif_info *spdif = to_info(dai); void __iomem *regs = spdif->regs; unsigned long flags; int cfgr, dmac, intcr, chnsr_byte[5] = {0}; int data_type, err_flag, data_len, data_info; int bs_num, repetition, burst_info; RK_SPDIF_DBG("Entered %s\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dai->playback_dma_data = &spdif->dma_playback; } else { pr_err("spdif:Capture is not supported\n"); return -EINVAL; } spin_lock_irqsave(&spdif->lock, flags); cfgr = readl(regs + CFGR) & CFGR_VALID_DATA_MASK; cfgr &= ~CFGR_VALID_DATA_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: cfgr |= CFGR_VALID_DATA_16bit; break; case SNDRV_PCM_FORMAT_S20_3LE: cfgr |= CFGR_VALID_DATA_20bit; break; case SNDRV_PCM_FORMAT_S24_LE: cfgr |= CFGR_VALID_DATA_24bit; break; default: goto err; } cfgr &= ~CFGR_HALFWORD_TX_MASK; cfgr |= CFGR_HALFWORD_TX_ENABLE; /* set most MCLK:192kHz */ cfgr &= ~CFGR_CLK_RATE_MASK; cfgr |= (1<<16); cfgr &= ~CFGR_JUSTIFIED_MASK; cfgr |= CFGR_JUSTIFIED_RIGHT; cfgr &= ~CFGR_CSE_MASK; cfgr |= CFGR_CSE_DISABLE; cfgr &= ~CFGR_LINEAR_MASK; cfgr |= CFGR_LINEAR_PCM; /* stream type*/ if (!snd_pcm_format_linear(params_format(params))) cfgr |= CFGR_NON_LINEAR_PCM; cfgr &= ~CFGR_PRE_CHANGE_MASK; cfgr |= CFGR_PRE_CHANGE_ENALBLE; writel(cfgr, regs + CFGR); intcr = readl(regs + INTCR) & INTCR_SDBEIE_MASK; intcr |= INTCR_SDBEIE_ENABLE; writel(intcr, regs + INTCR); dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK); dmac |= 0x10; writel(dmac, regs + DMACR); /* * channel byte 0: * Bit 1 * 1 Main data field represents linear PCM samples. * 0 Main data field used for purposes other purposes. */ chnsr_byte[0] = (0x0) | (0x0 << 1) | (0x0 << 2) | (0x0 << 3) | (0x00 << 6); chnsr_byte[1] = (0x0); chnsr_byte[2] = (0x0) | (0x0 << 4) | (0x0 << 6); chnsr_byte[3] = (0x00) | (0x00); chnsr_byte[4] = (0x0 << 4) | (0x01 << 1 | 0x0); /* set stream type */ if (!snd_pcm_format_linear(params_format(params))) { chnsr_byte[0] |= (0x1<<1); chnsr_byte[4] = (0x0<<4)|(0x00<<1|0x0); } writel((chnsr_byte[4] << 16) | (chnsr_byte[4]), regs + SPDIF_CHNSR02_ADDR); writel((chnsr_byte[3] << 24) | (chnsr_byte[2] << 16) | (chnsr_byte[3] << 8) | (chnsr_byte[2]), regs + SPDIF_CHNSR01_ADDR); writel((chnsr_byte[1] << 24) | (chnsr_byte[0] << 16) | (chnsr_byte[1] << 8) | (chnsr_byte[0]), regs + SPDIF_CHNSR00_ADDR); /* set non-linear params */ if (!snd_pcm_format_linear(params_format(params))) { switch (params_format(params)) { case SNDRV_NON_LINEAR_PCM_FORMAT_AC3: /* bit0:6 AC-3:0x01, DTS-I -II -III:11,12,13 */ data_type = burst_info_DATA_TYPE_AC3; /* * repetition:AC-3:1536 * DTS-I -II -III:512,1024,2048 EAC3:6144 */ repetition = 1536; break; case SNDRV_NON_LINEAR_PCM_FORMAT_DTS_I: data_type = BURST_INFO_DATA_TYPE_DTS_I; repetition = 512; break; case SNDRV_NON_LINEAR_PCM_FORMAT_EAC3: data_type = burst_info_DATA_TYPE_EAC3; repetition = 6144; break; default: return -EINVAL; } err_flag = 0x0; data_len = params_period_size(params) * 2 * 16; data_info = 0; bs_num = 0x0; burst_info = (data_len << 16) | (bs_num << 13) | (data_info << 8) | (err_flag << 7) | data_type; writel(burst_info, regs + SPDIF_BURST_INFO); writel(repetition, regs + SPDIF_REPETTION); } spin_unlock_irqrestore(&spdif->lock, flags); return 0; err: spin_unlock_irqrestore(&spdif->lock, flags); return -EINVAL; }