static int uda134x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); u8 hw_params; if (substream == uda134x->slave_substream) { pr_debug("%s ignoring hw_params for slave substream\n", __func__); return 0; } hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0); hw_params &= STATUS0_SYSCLK_MASK; hw_params &= STATUS0_DAIFMT_MASK; pr_debug("%s sysclk: %d, rate:%d\n", __func__, uda134x->sysclk, params_rate(params)); /* set SYSCLK / fs ratio */ switch (uda134x->sysclk / params_rate(params)) { case 512: break; case 384: hw_params |= (1<<4); break; case 256: hw_params |= (1<<5); break; default: printk(KERN_ERR "%s unsupported fs\n", __func__); return -EINVAL; } pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__, uda134x->dai_fmt, params_format(params)); /* set DAI format and word length */ switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: break; case SND_SOC_DAIFMT_RIGHT_J: switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: hw_params |= (1<<1); break; case SNDRV_PCM_FORMAT_S18_3LE: hw_params |= (1<<2); break; case SNDRV_PCM_FORMAT_S20_3LE: hw_params |= ((1<<2) | (1<<1)); break; default: printk(KERN_ERR "%s unsupported format (right)\n", __func__); return -EINVAL; } break; case SND_SOC_DAIFMT_LEFT_J: hw_params |= (1<<3); break; default: printk(KERN_ERR "%s unsupported format\n", __func__); return -EINVAL; } uda134x_write(codec, UDA134X_STATUS0, hw_params); return 0; }
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; struct omap_pcm_dma_data *dma_data; int dma, bus_id = mcbsp_data->bus_id; int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; int pkt_size = 0; unsigned long port; unsigned int format, div, framesize, master; dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream]; if (cpu_class_is_omap1()) { dma = omap1_dma_reqs[bus_id][substream->stream]; port = omap1_mcbsp_port[bus_id][substream->stream]; } else if (cpu_is_omap2420()) { dma = omap24xx_dma_reqs[bus_id][substream->stream]; port = omap2420_mcbsp_port[bus_id][substream->stream]; } else if (cpu_is_omap2430()) { dma = omap24xx_dma_reqs[bus_id][substream->stream]; port = omap2430_mcbsp_port[bus_id][substream->stream]; } else if (cpu_is_omap34xx()) { dma = omap24xx_dma_reqs[bus_id][substream->stream]; port = omap34xx_mcbsp_port[bus_id][substream->stream]; } else if (cpu_is_omap44xx()) { dma = omap44xx_dma_reqs[bus_id][substream->stream]; port = omap44xx_mcbsp_port[bus_id][substream->stream]; } else { return -ENODEV; } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: dma_data->data_type = OMAP_DMA_DATA_TYPE_S16; wlen = 16; break; case SNDRV_PCM_FORMAT_S32_LE: dma_data->data_type = OMAP_DMA_DATA_TYPE_S32; wlen = 32; break; default: return -EINVAL; } if (cpu_is_omap34xx()) { dma_data->set_threshold = omap_mcbsp_set_threshold; /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ if (omap_mcbsp_get_dma_op_mode(bus_id) == MCBSP_DMA_MODE_THRESHOLD) { int period_words, max_thrsh; period_words = params_period_bytes(params) / (wlen / 8); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) max_thrsh = omap_mcbsp_get_max_tx_threshold( mcbsp_data->bus_id); else{ max_thrsh = omap_mcbsp_get_max_rx_threshold( mcbsp_data->bus_id); max_thrsh=1; } /* * If the period contains less or equal number of words, * we are using the original threshold mode setup: * McBSP threshold = sDMA frame size = period_size * Otherwise we switch to sDMA packet mode: * McBSP threshold = sDMA packet size * sDMA frame size = period size */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ if (period_words > max_thrsh) { int divider = 0; /* * Look for the biggest threshold value, which * divides the period size evenly. */ divider = period_words / max_thrsh; if (period_words % max_thrsh) divider++; while (period_words % divider && divider < period_words) divider++; if (divider == period_words) return -EINVAL; pkt_size = period_words / divider; sync_mode = OMAP_DMA_SYNC_PACKET; } else { sync_mode = OMAP_DMA_SYNC_FRAME; } } else { printk("DMA Element Sync Mode for recording \n"); sync_mode=OMAP_DMA_SYNC_ELEMENT; } } } dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback"; dma_data->dma_req = dma; dma_data->port_addr = port; dma_data->sync_mode = sync_mode; dma_data->packet_size = pkt_size; snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); if (mcbsp_data->configured) { /* McBSP already configured by another stream */ return 0; } format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; wpf = channels = params_channels(params); if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || format == SND_SOC_DAIFMT_LEFT_J)) { /* Use dual-phase frames */ regs->rcr2 |= RPHASE; regs->xcr2 |= XPHASE; /* Set 1 word per (McBSP) frame for phase1 and phase2 */ wpf--; regs->rcr2 |= RFRLEN2(wpf - 1); regs->xcr2 |= XFRLEN2(wpf - 1); } regs->rcr1 |= RFRLEN1(wpf - 1); regs->xcr1 |= XFRLEN1(wpf - 1); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: /* Set word lengths */ regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); break; case SNDRV_PCM_FORMAT_S32_LE: /* Set word lengths */ regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_32); break; default: /* Unsupported PCM format */ return -EINVAL; } /* In McBSP master modes, FRAME (i.e. sample rate) is generated * by _counting_ BCLKs. Calculate frame size in BCLKs */ master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK; if (master == SND_SOC_DAIFMT_CBS_CFS) { div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1; framesize = (mcbsp_data->in_freq / div) / params_rate(params); if (framesize < wlen * channels) { printk(KERN_ERR "%s: not enough bandwidth for desired rate and " "channels\n", __func__); return -EINVAL; } } else framesize = wlen * channels; /* Set FS period and length in terms of bit clock periods */ switch (format) { case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_LEFT_J: regs->srgr2 |= FPER(framesize - 1); regs->srgr1 |= FWID((framesize >> 1) - 1); break; case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: regs->srgr2 |= FPER(framesize - 1); regs->srgr1 |= FWID(0); break; } omap_mcbsp_config(bus_id, &mcbsp_data->regs); mcbsp_data->wlen = wlen; mcbsp_data->configured = 1; return 0; }
static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F; u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1; u16 companding = snd_soc_read(codec, WM8940_COMPANDINGCTL) & 0xFFDF; int ret; /* LoutR control */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && params_channels(params) == 2) iface |= (1 << 9); switch (params_rate(params)) { case 8000: addcntrl |= (0x5 << 1); break; case 11025: addcntrl |= (0x4 << 1); break; case 16000: addcntrl |= (0x3 << 1); break; case 22050: addcntrl |= (0x2 << 1); break; case 32000: addcntrl |= (0x1 << 1); break; case 44100: case 48000: break; } ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl); if (ret) goto error_ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: companding = companding | (1 << 5); break; case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: iface |= (1 << 5); break; case SNDRV_PCM_FORMAT_S24_LE: iface |= (2 << 5); break; case SNDRV_PCM_FORMAT_S32_LE: iface |= (3 << 5); break; } ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding); if (ret) goto error_ret; ret = snd_soc_write(codec, WM8940_IFACE, iface); error_ret: return ret; }
static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct device *dev = rtd->card->dev; unsigned int fmt; int channels, ret = 0, driver_mode, slots; unsigned int sw_codec, sw_cpu; bool is_playback; dev_dbg(dev, "%s: Enter\n", __func__); dev_dbg(dev, "%s: substream->pcm->name = %s\n" "substream->pcm->id = %s.\n" "substream->name = %s.\n" "substream->number = %d.\n", __func__, substream->pcm->name, substream->pcm->id, substream->name, substream->number); /* Ensure configuration consistency between DAIs */ mutex_lock(&mop500_ab8500_params_lock); if (mop500_ab8500_usage) { if (mop500_ab8500_rate != params_rate(params) || mop500_ab8500_channels != params_channels(params)) { mutex_unlock(&mop500_ab8500_params_lock); return -EBUSY; } } else { mop500_ab8500_rate = params_rate(params); mop500_ab8500_channels = params_channels(params); } __set_bit(cpu_dai->id, &mop500_ab8500_usage); mutex_unlock(&mop500_ab8500_params_lock); channels = params_channels(params); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S32_LE: sw_cpu = 32; break; case SNDRV_PCM_FORMAT_S16_LE: sw_cpu = 16; break; default: return -EINVAL; } /* Setup codec depending on driver-mode */ if (channels == 8) driver_mode = DRIVERMODE_CODEC_ONLY; else driver_mode = DRIVERMODE_NORMAL; dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__, (driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY"); /* Setup format */ if (driver_mode == DRIVERMODE_NORMAL) { fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CONT; } else { fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_GATED; } ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { dev_err(dev, "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n", __func__, ret); return ret; } ret = snd_soc_dai_set_fmt(cpu_dai, fmt); if (ret < 0) { dev_err(dev, "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n", __func__, ret); return ret; } /* Setup TDM-slots */ is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); switch (channels) { case 1: slots = 16; tx_slots = (is_playback) ? TX_SLOT_MONO : 0; rx_slots = (is_playback) ? 0 : RX_SLOT_MONO; break; case 2: slots = 16; tx_slots = (is_playback) ? TX_SLOT_STEREO : 0; rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO; break; case 8: slots = 16; tx_slots = (is_playback) ? TX_SLOT_8CH : 0; rx_slots = (is_playback) ? 0 : RX_SLOT_8CH; break; default: return -EINVAL; } if (driver_mode == DRIVERMODE_NORMAL) sw_codec = sw_cpu; else sw_codec = 20; dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__, tx_slots, rx_slots); ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots, sw_cpu); if (ret) return ret; dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__, tx_slots, rx_slots); ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots, sw_codec); if (ret) return ret; return 0; }
/* * Configure the SSC. */ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { int id = dai->id; struct atmel_ssc_info *ssc_p = &ssc_info[id]; struct atmel_pcm_dma_params *dma_params; int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; int start_event; int ret; /* * Currently, there is only one set of dma params for * each direction. If more are added, this code will * have to be changed to select the proper set. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dir = 0; else dir = 1; dma_params = ssc_p->dma_params[dir]; channels = params_channels(params); /* * Determine sample size in bits and the PDC increment. */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: bits = 8; dma_params->pdc_xfer_size = 1; break; case SNDRV_PCM_FORMAT_S16_LE: bits = 16; dma_params->pdc_xfer_size = 2; break; case SNDRV_PCM_FORMAT_S24_LE: bits = 24; dma_params->pdc_xfer_size = 4; break; case SNDRV_PCM_FORMAT_S32_LE: bits = 32; dma_params->pdc_xfer_size = 4; break; default: printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format"); return -EINVAL; } /* * The SSC only supports up to 16-bit samples in I2S format, due * to the size of the Frame Mode Register FSLEN field. */ if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S && bits > 16) { printk(KERN_WARNING "atmel_ssc_dai: sample size %d " "is too large for I2S\n", bits); return -EINVAL; } /* * Compute SSC register settings. */ switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: /* * I2S format, SSC provides BCLK and LRC clocks. * * The SSC transmit and receive clocks are generated * from the MCK divider, and the BCLK signal * is output on the SSC TK line. */ rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_DIV); rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | SSC_BF(RFMR_FSLEN, (bits - 1)) | SSC_BF(RFMR_DATNB, (channels - 1)) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | SSC_BF(TCMR_CKS, SSC_CKS_DIV); tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | SSC_BF(TFMR_FSLEN, (bits - 1)) | SSC_BF(TFMR_DATNB, (channels - 1)) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATDEF, 0) | SSC_BF(TFMR_DATLEN, (bits - 1)); break; case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: /* * I2S format, CODEC supplies BCLK and LRC clocks. * * The SSC transmit clock is obtained from the BCLK signal on * on the TK line, and the SSC receive clock is * generated from the transmit clock. * * For single channel data, one sample is transferred * on the falling edge of the LRC clock. * For two channel data, one sample is * transferred on both edges of the LRC clock. */ start_event = ((channels == 1) ? SSC_START_FALLING_RF : SSC_START_EDGE_RF); rcmr = SSC_BF(RCMR_PERIOD, 0) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, start_event) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | SSC_BF(RFMR_FSLEN, 0) | SSC_BF(RFMR_DATNB, 0) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); tcmr = SSC_BF(TCMR_PERIOD, 0) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, start_event) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | SSC_BF(TCMR_CKS, SSC_CKS_PIN); tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | SSC_BF(TFMR_FSLEN, 0) | SSC_BF(TFMR_DATNB, 0) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATDEF, 0) | SSC_BF(TFMR_DATLEN, (bits - 1)); break; case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: /* * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. * * The SSC transmit and receive clocks are generated from the * MCK divider, and the BCLK signal is output * on the SSC TK line. */ rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | SSC_BF(RCMR_STTDLY, 1) | SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_DIV); rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | SSC_BF(RFMR_FSLEN, 0) | SSC_BF(RFMR_DATNB, (channels - 1)) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | SSC_BF(TCMR_STTDLY, 1) | SSC_BF(TCMR_START, SSC_START_RISING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_RISING) | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | SSC_BF(TCMR_CKS, SSC_CKS_DIV); tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | SSC_BF(TFMR_FSLEN, 0) | SSC_BF(TFMR_DATNB, (channels - 1)) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATDEF, 0) | SSC_BF(TFMR_DATLEN, (bits - 1)); break; case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: /* * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. * * The SSC transmit clock is obtained from the BCLK signal on * on the TK line, and the SSC receive clock is * generated from the transmit clock. * * Data is transferred on first BCLK after LRC pulse rising * edge.If stereo, the right channel data is contiguous with * the left channel data. */ rcmr = SSC_BF(RCMR_PERIOD, 0) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_PIN); rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | SSC_BF(RFMR_FSLEN, 0) | SSC_BF(RFMR_DATNB, (channels - 1)) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); tcmr = SSC_BF(TCMR_PERIOD, 0) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, SSC_START_RISING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | SSC_BF(TCMR_CKS, SSC_CKS_PIN); tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | SSC_BF(TFMR_FSLEN, 0) | SSC_BF(TFMR_DATNB, (channels - 1)) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATDEF, 0) | SSC_BF(TFMR_DATLEN, (bits - 1)); break; default: printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", ssc_p->daifmt); return -EINVAL; } pr_debug("atmel_ssc_hw_params: " "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); if (!ssc_p->initialized) { /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); clk_enable(ssc_p->ssc->clk); /* Reset the SSC and its PDC registers */ ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0, ssc_p->name, ssc_p); if (ret < 0) { printk(KERN_WARNING "atmel_ssc_dai: request_irq failure\n"); pr_debug("Atmel_ssc_dai: Stoping clock\n"); clk_disable(ssc_p->ssc->clk); return ret; } ssc_p->initialized = 1; } /* set SSC clock mode register */ ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); /* set receive clock mode and format */ ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); /* set transmit clock mode and format */ ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n"); return 0; }
static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; struct snd_dmaengine_dai_dma_data *dma_data; int wlen, channels, wpf; int pkt_size = 0; unsigned int format, div, framesize, master; dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); channels = params_channels(params); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: wlen = 16; break; case SNDRV_PCM_FORMAT_S32_LE: wlen = 32; break; default: return -EINVAL; } if (mcbsp->pdata->buffer_size) { if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { int period_words, max_thrsh; int divider = 0; period_words = params_period_bytes(params) / (wlen / 8); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) max_thrsh = mcbsp->max_tx_thres; else max_thrsh = mcbsp->max_rx_thres; /* * Use sDMA packet mode if McBSP is in threshold mode: * If period words less than the FIFO size the packet * size is set to the number of period words, otherwise * Look for the biggest threshold value which divides * the period size evenly. */ divider = period_words / max_thrsh; if (period_words % max_thrsh) divider++; while (period_words % divider && divider < period_words) divider++; if (divider == period_words) return -EINVAL; pkt_size = period_words / divider; } else if (channels > 1) { /* Use packet mode for non mono streams */ pkt_size = channels; } omap_mcbsp_set_threshold(substream, pkt_size); } dma_data->maxburst = pkt_size; if (mcbsp->configured) { /* McBSP already configured by another stream */ return 0; } regs->rcr2 &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7)); regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7)); regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK; wpf = channels; if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || format == SND_SOC_DAIFMT_LEFT_J)) { /* Use dual-phase frames */ regs->rcr2 |= RPHASE; regs->xcr2 |= XPHASE; /* Set 1 word per (McBSP) frame for phase1 and phase2 */ wpf--; regs->rcr2 |= RFRLEN2(wpf - 1); regs->xcr2 |= XFRLEN2(wpf - 1); } regs->rcr1 |= RFRLEN1(wpf - 1); regs->xcr1 |= XFRLEN1(wpf - 1); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: /* Set word lengths */ regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); break; case SNDRV_PCM_FORMAT_S32_LE: /* Set word lengths */ regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_32); break; default: /* Unsupported PCM format */ return -EINVAL; } /* In McBSP master modes, FRAME (i.e. sample rate) is generated * by _counting_ BCLKs. Calculate frame size in BCLKs */ master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK; if (master == SND_SOC_DAIFMT_CBS_CFS) { div = mcbsp->clk_div ? mcbsp->clk_div : 1; framesize = (mcbsp->in_freq / div) / params_rate(params); if (framesize < wlen * channels) { printk(KERN_ERR "%s: not enough bandwidth for desired rate and " "channels\n", __func__); return -EINVAL; } } else framesize = wlen * channels; /* Set FS period and length in terms of bit clock periods */ regs->srgr2 &= ~FPER(0xfff); regs->srgr1 &= ~FWID(0xff); switch (format) { case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_LEFT_J: regs->srgr2 |= FPER(framesize - 1); regs->srgr1 |= FWID((framesize >> 1) - 1); break; case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: regs->srgr2 |= FPER(framesize - 1); regs->srgr1 |= FWID(0); break; } omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs); mcbsp->wlen = wlen; mcbsp->configured = 1; return 0; }
static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int pll_out = 0; unsigned int wm9713_div = 0; int ret = 0; int rate = params_rate(params); int width = snd_pcm_format_physical_width(params_format(params)); /* Only support ratios that we can generate neatly from the AC97 * based master clock - in particular, this excludes 44.1kHz. * In most applications the voice DAC will be used for telephony * data so multiples of 8kHz will be the common case. */ switch (rate) { case 8000: wm9713_div = 12; break; case 16000: wm9713_div = 6; break; case 48000: wm9713_div = 2; break; default: /* Don't support OSS emulation */ return -EINVAL; } /* Add 1 to the width for the leading clock cycle */ pll_out = rate * (width + 1) * 8; ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); if (ret < 0) return ret; ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); if (ret < 0) return ret; if (clk_pout) ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, WM9713_PCMDIV(wm9713_div)); else ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, WM9713_PCMDIV(wm9713_div)); if (ret < 0) return ret; ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; return 0; }
static int tegra_bt_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; #ifndef CONFIG_ARCH_TEGRA_2x_SOC struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai); #endif struct snd_soc_card *card = rtd->card; struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); int err, srate, mclk, min_mclk, sample_size; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: sample_size = 16; break; default: return -EINVAL; } srate = params_rate(params); switch (srate) { case 11025: case 22050: case 44100: case 88200: mclk = 11289600; break; case 8000: case 16000: case 32000: case 48000: case 64000: case 96000: mclk = 12288000; break; default: return -EINVAL; } min_mclk = 64 * srate; err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % min_mclk)) mclk = machine->util_data.set_mclk; else { dev_err(card->dev, "Can't configure clocks\n"); return err; } } tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); err = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (err < 0) { dev_err(rtd->codec->card->dev, "cpu_dai fmt not set\n"); return err; } #ifndef CONFIG_ARCH_TEGRA_2x_SOC if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) tegra_max98088_set_dam_cif(i2s->dam_ifc, params_rate(params), params_channels(params), sample_size, 0, 0, 0, 0); #endif return 0; }
/** * Set default hardware params */ static int playback_prepare_params(struct gaudio_snd_dev *snd) { struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_hw_params *params; snd_pcm_sframes_t result; /* * SNDRV_PCM_ACCESS_RW_INTERLEAVED, * SNDRV_PCM_FORMAT_S16_LE * CHANNELS: 2 * RATE: 8000 */ snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; snd->format = SNDRV_PCM_FORMAT_S16_LE; snd->channels = 2; snd->rate = 8000; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; _snd_pcm_hw_params_any(params); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, snd->access, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, snd->format, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, snd->channels, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, snd->rate, 0); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (result < 0) pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); if (result < 0) { pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result); kfree(params); return result; } result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) pr_err("Preparing playback failed: %d\n", (int)result); /* Store the hardware parameters */ snd->access = params_access(params); snd->format = params_format(params); snd->channels = params_channels(params); snd->rate = params_rate(params); kfree(params); pr_debug("playback params: access %x, format %x, channels %d, rate %d\n", snd->access, snd->format, snd->channels, snd->rate); return 0; }
static int dw_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); struct i2s_clk_config_data *config = &dev->config; int ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: config->data_width = 16; dev->ccr = 0x00; dev->xfer_resolution = 0x02; break; case SNDRV_PCM_FORMAT_S24_LE: config->data_width = 24; dev->ccr = 0x08; dev->xfer_resolution = 0x04; break; case SNDRV_PCM_FORMAT_S32_LE: config->data_width = 32; dev->ccr = 0x10; dev->xfer_resolution = 0x05; break; default: dev_err(dev->dev, "designware-i2s: unsupported PCM fmt"); return -EINVAL; } config->chan_nr = params_channels(params); switch (config->chan_nr) { case EIGHT_CHANNEL_SUPPORT: case SIX_CHANNEL_SUPPORT: case FOUR_CHANNEL_SUPPORT: case TWO_CHANNEL_SUPPORT: break; default: dev_err(dev->dev, "channel not supported\n"); return -EINVAL; } dw_i2s_config(dev, substream->stream); i2s_write_reg(dev->i2s_base, CCR, dev->ccr); config->sample_rate = params_rate(params); if (dev->capability & DW_I2S_MASTER) { if (dev->i2s_clk_cfg) { ret = dev->i2s_clk_cfg(config); if (ret < 0) { dev_err(dev->dev, "runtime audio clk config fail\n"); return ret; } } else { u32 bitclk = config->sample_rate * config->data_width * 2; ret = clk_set_rate(dev->clk, bitclk); if (ret) { dev_err(dev->dev, "Can't set I2S clock rate: %d\n", ret); return ret; } } } return 0; }
static int tegra_max98088_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); #ifndef CONFIG_ARCH_TEGRA_2x_SOC struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); #endif int srate, mclk, sample_size, i2s_daifmt; int err; struct clk *clk; int rate; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: sample_size = 16; break; default: return -EINVAL; } srate = params_rate(params); switch (srate) { case 8000: case 16000: case 24000: case 32000: case 48000: case 64000: case 96000: mclk = 12288000; break; case 11025: case 22050: case 44100: case 88200: mclk = 11289600; break; default: mclk = 12000000; break; } #if defined(CONFIG_ARCH_TEGRA_2x_SOC) clk = clk_get_sys(NULL, "cdev1"); #else clk = clk_get_sys("extern1", NULL); #endif if (IS_ERR(clk)) { dev_err(card->dev, "Can't retrieve clk cdev1\n"); err = PTR_ERR(clk); return err; } rate = clk_get_rate(clk); printk("extern1 rate=%d\n",rate); #if TEGRA30_I2S_MASTER_PLAYBACK i2s_daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; #else i2s_daifmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM; mclk = rate; #endif err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % mclk)) mclk = machine->util_data.set_mclk; else { dev_err(card->dev, "Can't configure clocks\n"); return err; } } tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); err = snd_soc_dai_set_fmt(codec_dai,i2s_daifmt); if (err < 0) { dev_err(card->dev, "codec_dai fmt not set\n"); return err; } err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "cpu_dai fmt not set\n"); return err; } err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; } #ifndef CONFIG_ARCH_TEGRA_2x_SOC if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) tegra_max98088_set_dam_cif(i2s->dam_ifc, srate, params_channels(params), sample_size, 0, 0, 0, 0); #endif return 0; }
static int arizona_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; int base = dai->driver->base; const int *rates; int i; int bclk, lrclk, wl, frame, sr_val; if (params_rate(params) % 8000) rates = &arizona_44k1_bclk_rates[0]; else rates = &arizona_48k_bclk_rates[0]; for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { if (rates[i] >= snd_soc_params_to_bclk(params) && rates[i] % params_rate(params) == 0) { bclk = i; break; } } if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) { arizona_aif_err(dai, "Unsupported sample rate %dHz\n", params_rate(params)); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++) if (arizona_sr_vals[i] == params_rate(params)) break; if (i == ARRAY_SIZE(arizona_sr_vals)) { arizona_aif_err(dai, "Unsupported sample rate %dHz\n", params_rate(params)); return -EINVAL; } sr_val = i; lrclk = rates[bclk] / params_rate(params); arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", rates[bclk], rates[bclk] / lrclk); wl = snd_pcm_format_width(params_format(params)); frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; /* * We will need to be more flexible than this in future, * currently we use a single sample rate for SYSCLK. */ switch (dai_priv->clk) { case ARIZONA_CLK_SYSCLK: snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, ARIZONA_SAMPLE_RATE_1_MASK, sr_val); snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, ARIZONA_AIF1_RATE_MASK, 0); break; case ARIZONA_CLK_ASYNCCLK: snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, ARIZONA_AIF1_RATE_MASK, 8 << ARIZONA_AIF1_RATE_SHIFT); break; default: arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); return -EINVAL; } snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE, ARIZONA_AIF1TX_BCPF_MASK, lrclk); snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE, ARIZONA_AIF1RX_BCPF_MASK, lrclk); snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1, ARIZONA_AIF1TX_WL_MASK | ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2, ARIZONA_AIF1RX_WL_MASK | ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); return 0; }
static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); unsigned int regval; int bitwidth, ret; bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { dev_err(dai->dev, "%s() invalid bit width given: %d\n", __func__, bitwidth); return bitwidth; } regval = LPAIF_I2SCTL_LOOPBACK_DISABLE | LPAIF_I2SCTL_WSSRC_INTERNAL; switch (bitwidth) { case 16: regval |= LPAIF_I2SCTL_BITWIDTH_16; break; case 24: regval |= LPAIF_I2SCTL_BITWIDTH_24; break; case 32: regval |= LPAIF_I2SCTL_BITWIDTH_32; break; default: dev_err(dai->dev, "%s() invalid bitwidth given: %d\n", __func__, bitwidth); return -EINVAL; } switch (channels) { case 1: regval |= LPAIF_I2SCTL_SPKMODE_SD0; regval |= LPAIF_I2SCTL_SPKMONO_MONO; break; case 2: regval |= LPAIF_I2SCTL_SPKMODE_SD0; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; case 4: regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; case 6: regval |= LPAIF_I2SCTL_SPKMODE_6CH; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; case 8: regval |= LPAIF_I2SCTL_SPKMODE_8CH; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; default: dev_err(dai->dev, "%s() invalid channels given: %u\n", __func__, channels); return -EINVAL; } ret = regmap_write(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), regval); if (ret) { dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); return ret; } ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id], rate * bitwidth * 2); if (ret) { dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n", __func__, rate * bitwidth * 2, ret); return ret; } return 0; }
static int wm8776_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec); int iface_reg, iface; int ratio_shift, master; int i; switch (dai->driver->id) { case WM8776_DAI_DAC: iface_reg = WM8776_DACIFCTRL; master = 0x80; ratio_shift = 4; break; case WM8776_DAI_ADC: iface_reg = WM8776_ADCIFCTRL; master = 0x100; ratio_shift = 0; break; default: return -EINVAL; } /* Set word length */ switch (snd_pcm_format_width(params_format(params))) { case 16: iface = 0; break; case 20: iface = 0x10; break; case 24: iface = 0x20; break; case 32: iface = 0x30; break; default: dev_err(codec->dev, "Unsupported sample size: %i\n", snd_pcm_format_width(params_format(params))); return -EINVAL; } /* Only need to set MCLK/LRCLK ratio if we're master */ if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) { for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) { if (wm8776->sysclk[dai->driver->id] / params_rate(params) == mclk_ratios[i]) break; } if (i == ARRAY_SIZE(mclk_ratios)) { dev_err(codec->dev, "Unable to configure MCLK ratio %d/%d\n", wm8776->sysclk[dai->driver->id], params_rate(params)); return -EINVAL; } dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]); snd_soc_update_bits(codec, WM8776_MSTRCTRL, 0x7 << ratio_shift, i << ratio_shift); } else { dev_dbg(codec->dev, "DAI in slave mode\n"); } snd_soc_update_bits(codec, iface_reg, 0x30, iface); return 0; }
/* Switch the FLL */ ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, MIDAS_DEFAULT_MCLK1, pll_out); if (ret < 0) dev_err(codec_dai->dev, "Unable to start FLL1: %d\n", ret); ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) { dev_err(codec_dai->dev, "Unable to switch to FLL1: %d\n", ret); return ret; } ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK, 0, MOD_OPCLK_PCLK); if (ret < 0) return ret; #else midas_start_fll1(codec_dai); #endif if (ret < 0) return ret; dev_info(codec_dai->dev, "%s --\n", __func__); return 0; } #else /* CONFIG_SND_SAMSUNG_I2S_MASTER */ static int midas_wm1811_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int bfs, psr, rfs, ret; unsigned long rclk; switch (params_format(params)) { case SNDRV_PCM_FORMAT_U24: case SNDRV_PCM_FORMAT_S24: bfs = 48; break; case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE: bfs = 32; break; default: return -EINVAL; } switch (params_rate(params)) { case 16000: case 22050: case 24000: case 32000: case 44100: case 48000: case 88200: case 96000: if (bfs == 48) rfs = 384; else rfs = 256; break; case 64000: rfs = 384; break; case 8000: case 11025: case 12000: if (bfs == 48) rfs = 768; else rfs = 512; break; default: return -EINVAL; } rclk = params_rate(params) * rfs; switch (rclk) { case 4096000: case 5644800: case 6144000: case 8467200: case 9216000: psr = 8; break; case 8192000: case 11289600: case 12288000: case 16934400: case 18432000: psr = 4; break; case 22579200: case 24576000: case 33868800: case 36864000: psr = 2; break; case 67737600: case 73728000: psr = 1; break; default: printk(KERN_INFO "Not yet supported!\n"); return -EINVAL; } set_epll_rate(rclk * psr); ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, rclk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, 0, SND_SOC_CLOCK_OUT); if (ret < 0) return ret; ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs); if (ret < 0) return ret; return 0; }
static int capture_prepare_params(struct gaudio_snd_dev *snd) { struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_params *params; struct snd_pcm_sw_params *swparams; unsigned long period_size; unsigned long buffer_size; snd_pcm_sframes_t result = 0; /* * SNDRV_PCM_ACCESS_RW_INTERLEAVED, * SNDRV_PCM_FORMAT_S16_LE * CHANNELS: 1 * RATE: 8000 */ snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; snd->format = SNDRV_PCM_FORMAT_S16_LE; snd->channels = 1; snd->rate = 8000; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { pr_err("Failed to allocate hw params"); return -ENOMEM; } _snd_pcm_hw_params_any(params); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, snd->access, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, snd->format, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, snd->channels, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, snd->rate, 0); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (result < 0) pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); if (result < 0) { pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result); kfree(params); return result; } result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) pr_err("Preparing capture failed: %d\n", (int)result); /* Store the hardware parameters */ snd->access = params_access(params); snd->format = params_format(params); snd->channels = params_channels(params); snd->rate = params_rate(params); runtime->frame_bits = snd_pcm_format_physical_width(runtime->format); /*Fix the issue:Passing freed pointer "params" as an argument to function "pcm_buffer_size"*/ buffer_size = pcm_buffer_size(params); period_size = pcm_period_size(params); kfree(params); swparams = kzalloc(sizeof(*swparams), GFP_KERNEL); if (!swparams) { pr_err("Failed to allocate sw params"); return -ENOMEM; } swparams->avail_min = period_size/2; swparams->xfer_align = period_size/2; swparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; swparams->period_step = 1; swparams->start_threshold = 1; swparams->stop_threshold = INT_MAX; swparams->silence_size = 0; swparams->silence_threshold = 0; result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, swparams); if (result < 0) pr_err("SNDRV_PCM_IOCTL_SW_PARAMS failed: %d\n", (int)result); kfree(swparams); pr_debug("capture params: access %x, format %x, channels %d, rate %d\n", snd->access, snd->format, snd->channels, snd->rate); return result; }
/* * Configure the SSC */ static int at32_ssc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; int id = rtd->dai->cpu_dai->id; struct at32_ssc_info *ssc_p = &ssc_info[id]; struct at32_pcm_dma_params *dma_params; int channels, bits; u32 tfmr, rfmr, tcmr, rcmr; int start_event; int ret; /* * Currently, there is only one set of dma_params for each direction. * If more are added, this code will have to be changed to select * the proper set */ dma_params = &ssc_dma_params[id][substream->stream]; dma_params->ssc = ssc_p->ssc; dma_params->substream = substream; ssc_p->dma_params[substream->stream] = dma_params; /* * The cpu_dai->dma_data field is only used to communicate the * appropriate DMA parameters to the PCM driver's hw_params() * function. It should not be used for other purposes as it * is common to all substreams. */ rtd->dai->cpu_dai->dma_data = dma_params; channels = params_channels(params); /* * Determine sample size in bits and the PDC increment */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: bits = 8; dma_params->pdc_xfer_size = 1; break; case SNDRV_PCM_FORMAT_S16: bits = 16; dma_params->pdc_xfer_size = 2; break; case SNDRV_PCM_FORMAT_S24: bits = 24; dma_params->pdc_xfer_size = 4; break; case SNDRV_PCM_FORMAT_S32: bits = 32; dma_params->pdc_xfer_size = 4; break; default: pr_warning("at32-ssc: Unsupported PCM format %d", params_format(params)); return -EINVAL; } pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", bits, dma_params->pdc_xfer_size, channels); /* * The SSC only supports up to 16-bit samples in I2S format, due * to the size of the Frame Mode Register FSLEN field. */ if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) if (bits > 16) { pr_warning("at32-ssc: " "sample size %d is too large for I2S\n", bits); return -EINVAL; } /* * Compute the SSC register settings */ switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: /* * I2S format, SSC provides BCLK and LRS clocks. * * The SSC transmit and receive clocks are generated from the * MCK divider, and the BCLK signal is output on the SSC TK line */ pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_DIV)); rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | SSC_BF(RFMR_FSLEN, bits - 1) | SSC_BF(RFMR_DATNB, channels - 1) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | SSC_BF(TCMR_CKS, SSC_CKS_DIV)); tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | SSC_BF(TFMR_FSLEN, bits - 1) | SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); break; case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: /* * I2S format, CODEC supplies BCLK and LRC clock. * * The SSC transmit clock is obtained from the BCLK signal * on the TK line, and the SSC receive clock is generated from * the transmit clock. * * For single channel data, one sample is transferred on the * falling edge of the LRC clock. For two channel data, one * sample is transferred on both edges of the LRC clock. */ pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); start_event = ((channels == 1) ? SSC_START_FALLING_RF : SSC_START_EDGE_RF); rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, start_event) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK)); rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, start_event) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | SSC_BF(TCMR_CKS, SSC_CKS_PIN)); tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); break; case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: /* * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. * * The SSC transmit and receive clocks are generated from the * MCK divider, and the BCLK signal is output on the SSC TK line */ pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | SSC_BF(RCMR_STTDLY, 1) | SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | SSC_BF(RCMR_CKS, SSC_CKS_DIV)); rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | SSC_BF(RFMR_DATNB, channels - 1) | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | SSC_BF(TCMR_STTDLY, 1) | SSC_BF(TCMR_START, SSC_START_RISING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_RISING) | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | SSC_BF(TCMR_CKS, SSC_CKS_DIV)); tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); break; case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: default: pr_warning("at32-ssc: unsupported DAI format 0x%x\n", ssc_p->daifmt); return -EINVAL; break; } pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); if (!ssc_p->initialized) { /* enable peripheral clock */ pr_debug("at32-ssc: Starting clock\n"); clk_enable(ssc_p->ssc->clk); /* Reset the SSC and its PDC registers */ ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, ssc_p->name, ssc_p); if (ret < 0) { pr_warning("at32-ssc: request irq failed (%d)\n", ret); pr_debug("at32-ssc: Stopping clock\n"); clk_disable(ssc_p->ssc->clk); return ret; } ssc_p->initialized = 1; } /* Set SSC clock mode register */ ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); /* set receive clock mode and format */ ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); /* set transmit clock mode and format */ ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); pr_debug("at32-ssc: SSC initialized\n"); return 0; }
static int wm8770_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec; struct wm8770_priv *wm8770; int i; int iface; int shift; int ratio; codec = dai->codec; wm8770 = snd_soc_codec_get_drvdata(codec); iface = 0; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: iface |= 0x10; break; case SNDRV_PCM_FORMAT_S24_LE: iface |= 0x20; break; case SNDRV_PCM_FORMAT_S32_LE: iface |= 0x30; break; } switch (substream->stream) { case SNDRV_PCM_STREAM_PLAYBACK: i = 0; shift = 4; break; case SNDRV_PCM_STREAM_CAPTURE: i = 2; shift = 0; break; default: return -EINVAL; } /* Only need to set MCLK/LRCLK ratio if we're master */ if (snd_soc_read(codec, WM8770_MSTRCTRL) & 0x100) { for (; i < ARRAY_SIZE(mclk_ratios); ++i) { ratio = wm8770->sysclk / params_rate(params); if (ratio == mclk_ratios[i]) break; } if (i == ARRAY_SIZE(mclk_ratios)) { dev_err(codec->dev, "Unable to configure MCLK ratio %d/%d\n", wm8770->sysclk, params_rate(params)); return -EINVAL; } dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]); snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x7 << shift, i << shift); } snd_soc_update_bits(codec, WM8770_IFACECTRL, 0x30, iface); return 0; }
static int smdk_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; unsigned int pll_out; int bfs, rfs, ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8: bfs = 16; break; case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE: bfs = 32; break; default: return -EINVAL; } /* The Fvco for WM8580 PLLs must fall within [90,100]MHz. * This criterion can't be met if we request PLL output * as {8000x256, 64000x256, 11025x256}Hz. * As a wayout, we rather change rfs to a minimum value that * results in (params_rate(params) * rfs), and itself, acceptable * to both - the CODEC and the CPU. */ switch (params_rate(params)) { case 16000: case 22050: case 32000: case 44100: case 48000: case 88200: case 96000: rfs = 256; break; case 64000: rfs = 384; break; case 8000: case 11025: rfs = 512; break; default: return -EINVAL; } pll_out = params_rate(params) * rfs; /* Set the Codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* Set the AP DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* Set WM8580 to drive MCLK from its PLLA */ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, WM8580_CLKSRC_PLLA); if (ret < 0) return ret; ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, SMDK_WM8580_FREQ, pll_out); if (ret < 0) return ret; ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, pll_out, SND_SOC_CLOCK_IN); if (ret < 0) return ret; return 0; }
static int max98373_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct max98373_priv *max98373 = snd_soc_codec_get_drvdata(codec); unsigned int sampling_rate = 0; unsigned int chan_sz = 0; /* pcm mode configuration */ switch (snd_pcm_format_width(params_format(params))) { case 16: chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_16; break; case 24: chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_24; break; case 32: chan_sz = MAX98373_PCM_MODE_CFG_CHANSZ_32; break; default: dev_err(codec->dev, "format unsupported %d\n", params_format(params)); goto err; } max98373->ch_size = snd_pcm_format_width(params_format(params)); regmap_update_bits(max98373->regmap, MAX98373_R2024_PCM_DATA_FMT_CFG, MAX98373_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); dev_dbg(codec->dev, "format supported %d", params_format(params)); /* sampling rate configuration */ switch (params_rate(params)) { case 8000: sampling_rate = MAX98373_PCM_SR_SET1_SR_8000; break; case 11025: sampling_rate = MAX98373_PCM_SR_SET1_SR_11025; break; case 12000: sampling_rate = MAX98373_PCM_SR_SET1_SR_12000; break; case 16000: sampling_rate = MAX98373_PCM_SR_SET1_SR_16000; break; case 22050: sampling_rate = MAX98373_PCM_SR_SET1_SR_22050; break; case 24000: sampling_rate = MAX98373_PCM_SR_SET1_SR_24000; break; case 32000: sampling_rate = MAX98373_PCM_SR_SET1_SR_32000; break; case 44100: sampling_rate = MAX98373_PCM_SR_SET1_SR_44100; break; case 48000: sampling_rate = MAX98373_PCM_SR_SET1_SR_48000; break; default: dev_err(codec->dev, "rate %d not supported\n", params_rate(params)); goto err; } /* set DAI_SR to correct LRCLK frequency */ regmap_update_bits(max98373->regmap, MAX98373_R2027_PCM_SR_SETUP_1, MAX98373_PCM_SR_SET1_SR_MASK, sampling_rate); regmap_update_bits(max98373->regmap, MAX98373_R2028_PCM_SR_SETUP_2, MAX98373_PCM_SR_SET2_SR_MASK, sampling_rate << MAX98373_PCM_SR_SET2_SR_SHIFT); /* set sampling rate of IV */ if (max98373->interleave_mode && sampling_rate > MAX98373_PCM_SR_SET1_SR_16000) regmap_update_bits(max98373->regmap, MAX98373_R2028_PCM_SR_SETUP_2, MAX98373_PCM_SR_SET2_IVADC_SR_MASK, sampling_rate - 3); else regmap_update_bits(max98373->regmap, MAX98373_R2028_PCM_SR_SETUP_2, MAX98373_PCM_SR_SET2_IVADC_SR_MASK, sampling_rate); return max98373_set_clock(codec, params); err: return -EINVAL; }
static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct davinci_vcif_dev *davinci_vcif_dev = dai->private_data; struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc; struct davinci_pcm_dma_params *dma_params = &davinci_vcif_dev->dma_params[substream->stream]; u32 w; /* Restart the codec before setup */ davinci_vcif_stop(substream); davinci_vcif_start(substream); /* General line settings */ writel(DAVINCI_VC_CTRL_MASK, davinci_vc->base + DAVINCI_VC_CTRL); writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTCLR); writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTEN); w = readl(davinci_vc->base + DAVINCI_VC_CTRL); /* Determine xfer data type */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: dma_params->data_type = 0; MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_RD_UNSIGNED | DAVINCI_VC_CTRL_WD_BITS_8 | DAVINCI_VC_CTRL_WD_UNSIGNED, 1); break; case SNDRV_PCM_FORMAT_S8: dma_params->data_type = 1; MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_WD_BITS_8, 1); MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_UNSIGNED | DAVINCI_VC_CTRL_WD_UNSIGNED, 0); break; case SNDRV_PCM_FORMAT_S16_LE: dma_params->data_type = 2; MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | DAVINCI_VC_CTRL_RD_UNSIGNED | DAVINCI_VC_CTRL_WD_BITS_8 | DAVINCI_VC_CTRL_WD_UNSIGNED, 0); break; default: printk(KERN_WARNING "davinci-vcif: unsupported PCM format"); return -EINVAL; } dma_params->acnt = dma_params->data_type; writel(w, davinci_vc->base + DAVINCI_VC_CTRL); return 0; }
static int aml_asoc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; printk(KERN_DEBUG "enter %s stream: %s rate: %d format: %d\n", __func__, (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", params_rate(params), params_format(params)); /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) { printk(KERN_ERR "%s: set codec dai fmt failed!\n", __func__); return ret; } /* set cpu DAI configuration */ if((!strncmp(codec_info.name_bus,"rt5616",strlen("rt5616"))) || !(strncmp(codec_info.name_bus,"aml_pmu3_codec",strlen("aml_pmu3_codec")))){ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM); }else{ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); } if (ret < 0) { printk(KERN_ERR "%s: set cpu dai fmt failed!\n", __func__); return ret; } if(!strncmp(codec_info.name_bus,"dummy_codec",11)){ goto cpu_dai; } #if 1 /* set codec DAI clock */ ret = snd_soc_dai_set_sysclk(codec_dai, 0, params_rate(params) * 256, SND_SOC_CLOCK_IN); if (ret < 0) { printk(KERN_ERR "%s: set codec dai sysclk failed (rate: %d)!\n", __func__, params_rate(params)); return ret; } cpu_dai: /* set cpu DAI clock */ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, params_rate(params) * 256, SND_SOC_CLOCK_OUT); if (ret < 0) { printk(KERN_ERR "%s: set cpu dai sysclk failed (rate: %d)!\n", __func__, params_rate(params)); return ret; } #endif return 0; }
static int tegra_max98095_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = codec->card; struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); struct tegra_asoc_platform_data *pdata = machine->pdata; #ifndef CONFIG_ARCH_TEGRA_2x_SOC struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); #endif unsigned int srate, mclk, sample_size, i2s_daifmt; int err, rate; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: sample_size = 16; break; default: return -EINVAL; } srate = params_rate(params); switch (srate) { case 8000: case 16000: case 24000: case 32000: case 48000: case 64000: case 96000: mclk = 12288000; break; case 11025: case 22050: case 44100: case 88200: mclk = 11289600; break; default: mclk = 12000000; break; } i2s_daifmt = SND_SOC_DAIFMT_NB_NF; i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ? SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM; switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) { case TEGRA_DAIFMT_I2S : i2s_daifmt |= SND_SOC_DAIFMT_I2S; break; case TEGRA_DAIFMT_DSP_A : i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; break; case TEGRA_DAIFMT_DSP_B : i2s_daifmt |= SND_SOC_DAIFMT_DSP_B; break; case TEGRA_DAIFMT_LEFT_J : i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; break; case TEGRA_DAIFMT_RIGHT_J : i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; break; default : dev_err(card->dev, "Can't configure i2s format\n"); return -EINVAL; } err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); if (err < 0) { if (!(machine->util_data.set_mclk % mclk)) mclk = machine->util_data.set_mclk; else { dev_err(card->dev, "Can't configure clocks\n"); return err; } } tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); rate = clk_get_rate(machine->util_data.clk_cdev1); err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "codec_dai fmt not set\n"); return err; } err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); if (err < 0) { dev_err(card->dev, "cpu_dai fmt not set\n"); return err; } err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN); if (err < 0) { dev_err(card->dev, "codec_dai clock not set\n"); return err; } #ifndef CONFIG_ARCH_TEGRA_2x_SOC if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) tegra_max98095_set_dam_cif(i2s->dam_ifc, srate, params_channels(params), sample_size); #endif return 0; }
static int wm8961_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct wm8961_priv *wm8961 = snd_soc_codec_get_drvdata(codec); int i, best, target, fs; u16 reg; fs = params_rate(params); if (!wm8961->sysclk) { dev_err(codec->dev, "MCLK has not been specified\n"); return -EINVAL; } /* Find the closest sample rate for the filters */ best = 0; for (i = 0; i < ARRAY_SIZE(wm8961_srate); i++) { if (abs(wm8961_srate[i].rate - fs) < abs(wm8961_srate[best].rate - fs)) best = i; } reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_3); reg &= ~WM8961_SAMPLE_RATE_MASK; reg |= wm8961_srate[best].val; snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n", wm8961_srate[best].rate, fs); /* Select a CLK_SYS/fs ratio equal to or higher than required */ target = wm8961->sysclk / fs; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && target < 64) { dev_err(codec->dev, "SYSCLK must be at least 64*fs for DAC\n"); return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && target < 256) { dev_err(codec->dev, "SYSCLK must be at least 256*fs for ADC\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(wm8961_clk_sys_ratio); i++) { if (wm8961_clk_sys_ratio[i].ratio >= target) break; } if (i == ARRAY_SIZE(wm8961_clk_sys_ratio)) { dev_err(codec->dev, "Unable to generate CLK_SYS_RATE\n"); return -EINVAL; } dev_dbg(codec->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n", wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs, wm8961->sysclk / fs); reg = snd_soc_read(codec, WM8961_CLOCKING_4); reg &= ~WM8961_CLK_SYS_RATE_MASK; reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT; snd_soc_write(codec, WM8961_CLOCKING_4, reg); reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0); reg &= ~WM8961_WL_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: reg |= 1 << WM8961_WL_SHIFT; break; case SNDRV_PCM_FORMAT_S24_LE: reg |= 2 << WM8961_WL_SHIFT; break; case SNDRV_PCM_FORMAT_S32_LE: reg |= 3 << WM8961_WL_SHIFT; break; default: return -EINVAL; } snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, reg); /* Sloping stop-band filter is recommended for <= 24kHz */ reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2); if (fs <= 24000) reg |= WM8961_DACSLOPE; else reg &= ~WM8961_DACSLOPE; snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); return 0; }
/** * sta32x_hw_params - program the STA32X with the given hardware parameters. * @substream: the audio stream * @params: the hardware parameters to set * @dai: the SOC DAI (ignored) * * This function programs the hardware with the values provided. * Specifically, the sample rate and the data format. */ static int sta32x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); unsigned int rate; int i, mcs = -1, ir = -1; u8 confa, confb; rate = params_rate(params); pr_debug("rate: %u\n", rate); for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) if (interpolation_ratios[i].fs == rate) { ir = interpolation_ratios[i].ir; break; } if (ir < 0) return -EINVAL; for (i = 0; mclk_ratios[ir][i].ratio; i++) if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) { mcs = mclk_ratios[ir][i].mcs; break; } if (mcs < 0) return -EINVAL; confa = snd_soc_read(codec, STA32X_CONFA); confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); confb = snd_soc_read(codec, STA32X_CONFB); confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_BE: case SNDRV_PCM_FORMAT_S24_3LE: case SNDRV_PCM_FORMAT_S24_3BE: pr_debug("24bit\n"); /* fall through */ case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_S32_BE: pr_debug("24bit or 32bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x0; break; case SND_SOC_DAIFMT_LEFT_J: confb |= 0x1; break; case SND_SOC_DAIFMT_RIGHT_J: confb |= 0x2; break; } break; case SNDRV_PCM_FORMAT_S20_3LE: case SNDRV_PCM_FORMAT_S20_3BE: pr_debug("20bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x4; break; case SND_SOC_DAIFMT_LEFT_J: confb |= 0x5; break; case SND_SOC_DAIFMT_RIGHT_J: confb |= 0x6; break; } break; case SNDRV_PCM_FORMAT_S18_3LE: case SNDRV_PCM_FORMAT_S18_3BE: pr_debug("18bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x8; break; case SND_SOC_DAIFMT_LEFT_J: confb |= 0x9; break; case SND_SOC_DAIFMT_RIGHT_J: confb |= 0xa; break; } break; case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_BE: pr_debug("16bit\n"); switch (sta32x->format) { case SND_SOC_DAIFMT_I2S: confb |= 0x0; break; case SND_SOC_DAIFMT_LEFT_J: confb |= 0xd; break; case SND_SOC_DAIFMT_RIGHT_J: confb |= 0xe; break; } break; default: return -EINVAL; } snd_soc_write(codec, STA32X_CONFA, confa); snd_soc_write(codec, STA32X_CONFB, confb); return 0; }
static int aml_asoc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; printk(KERN_DEBUG "enter %s stream: %s rate: %d format: %d\n", __func__, (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture", params_rate(params), params_format(params)); /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) { printk(KERN_ERR "%s: set codec dai fmt failed!\n", __func__); return ret; } /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) { printk(KERN_ERR "%s: set cpu dai fmt failed!\n", __func__); return ret; } /*set codec DAI sysclk divider,now 512fs for MCLK,sysclk divide 2 */ snd_soc_dai_set_clkdiv(codec_dai,WM8960_SYSCLKDIV,WM8960_SYSCLK_DIV_2); /* set cpu DAI clock */ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, params_rate(params) * 512, SND_SOC_CLOCK_OUT); if (ret < 0) { printk(KERN_ERR "%s: set cpu dai sysclk failed (rate: %d)!\n", __func__, params_rate(params)); return ret; } return 0; }
static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct davinci_mcbsp_dev *dev = dai->private_data; struct davinci_pcm_dma_params *dma_params = &dev->dma_params[substream->stream]; struct snd_interval *i = NULL; int mcbsp_word_length; unsigned int rcr, xcr, srgr; u32 spcr; /* general line settings */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } else { spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); srgr = DAVINCI_MCBSP_SRGR_FSGM; srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); rcr = DAVINCI_MCBSP_RCR_RFIG; xcr = DAVINCI_MCBSP_XCR_XFIG; if (dev->mode == MOD_DSP_B) { rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0); } else { rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); } /* Determine xfer data type */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: dma_params->data_type = 1; mcbsp_word_length = DAVINCI_MCBSP_WORD_8; break; case SNDRV_PCM_FORMAT_S16_LE: dma_params->data_type = 2; mcbsp_word_length = DAVINCI_MCBSP_WORD_16; break; case SNDRV_PCM_FORMAT_S32_LE: dma_params->data_type = 4; mcbsp_word_length = DAVINCI_MCBSP_WORD_32; break; default: printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); return -EINVAL; } dma_params->acnt = dma_params->data_type; rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); else davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); return 0; }
/* XXX RFS & SRC_CLK --> Prescalar Value(SRC_CLK / RFS_VAL / fs - 1) XXX */ static int smdk6440_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; int bfs, rfs, psr, ret; /* Choose BFS and RFS values combination that is supported by * both the S5M8751 codec as well as the S5P6440 AP * * S5M8751 codec supports only S16_LE, S18_3LE, S20_3LE & S24_LE. * S5P6440 AP supports only S8, S16_LE & S24_LE. * We implement all for completeness but only S16_LE & S24_LE bit-lengths * are possible for this AP-Codec combination. */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: bfs = 16; rfs = 256; /* Can take any RFS value for AP */ break; case SNDRV_PCM_FORMAT_S16_LE: bfs = 32; rfs = 256; /* Can take any RFS value for AP */ break; case SNDRV_PCM_FORMAT_S18_3LE: case SNDRV_PCM_FORMAT_S20_3LE: case SNDRV_PCM_FORMAT_S24_LE: bfs = 48; rfs = 512; /* See Table 41-1,2 of S5P6440 UserManual */ break; default: return -EINVAL; } /* Select the AP Sysclk */ ret = snd_soc_dai_set_sysclk(cpu_dai, S5P6440_CDCLKSRC_INT, params_rate(params), SND_SOC_CLOCK_OUT); if (ret < 0) return ret; #ifdef USE_CLKAUDIO ret = snd_soc_dai_set_sysclk(cpu_dai, S5P6440_CLKSRC_CLKAUDIO, params_rate(params), SND_SOC_CLOCK_OUT); #else ret = snd_soc_dai_set_sysclk(cpu_dai, S5P6440_CLKSRC_PCLK, 0, SND_SOC_CLOCK_OUT); #endif if (ret < 0) return ret; /* Set the AP DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* Set the AP RFS */ ret = snd_soc_dai_set_clkdiv(cpu_dai, S5P64XX_DIV_MCLK, rfs); if (ret < 0) return ret; /* Set the AP BFS */ ret = snd_soc_dai_set_clkdiv(cpu_dai, S5P64XX_DIV_BCLK, bfs); if (ret < 0) return ret; switch (params_rate(params)) { case 8000: case 11025: case 16000: case 22050: case 32000: case 44100: case 48000: case 64000: case 88200: case 96000: psr = SRC_CLK / rfs / params_rate(params); ret = SRC_CLK / rfs - psr * params_rate(params); if(ret >= params_rate(params)/2) // round off psr += 1; psr -= 1; break; default: return -EINVAL; } //printk("SRC_CLK=%d PSR=%d RFS=%d BFS=%d\n", SRC_CLK, psr, rfs, bfs); /* Set the AP Prescalar */ ret = snd_soc_dai_set_clkdiv(cpu_dai, S5P64XX_DIV_PRESCALER, psr); if (ret < 0) return ret; /* Set the Codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; /* Set the Codec BCLK(no option to set the MCLK) */ ret = snd_soc_dai_set_clkdiv(codec_dai, S5M8751_BCLK, bfs); if (ret < 0) return ret; return 0; }
static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct rk30_i2s_info *i2s = to_info(dai); u32 iismod; u32 dmarc; unsigned long flags; struct hdmi_audio hdmi_audio_cfg; I2S_DBG("Enter %s, %d \n", __func__, __LINE__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dai->playback_dma_data = &i2s->playback_dma_data; else dai->capture_dma_data = &i2s->capture_dma_data; spin_lock_irqsave(&lock, flags); /* Working copies of register */ iismod = readl(&(pheadi2s->I2S_TXCR)); iismod &= (~((1<<5)-1)); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: iismod |= SAMPLE_DATA_8bit; break; case SNDRV_PCM_FORMAT_S16_LE: iismod |= I2S_DATA_WIDTH(15); break; case SNDRV_PCM_FORMAT_S20_3LE: iismod |= I2S_DATA_WIDTH(19); break; case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_3LE: iismod |= I2S_DATA_WIDTH(23); break; case SNDRV_PCM_FORMAT_S32_LE: iismod |= I2S_DATA_WIDTH(31); break; } iismod &= ~CHANNLE_4_EN; switch (params_channels(params)) { case 8: iismod |= CHANNLE_4_EN; break; case 6: iismod |= CHANNEL_3_EN; break; case 4: iismod |= CHANNEL_2_EN; break; case 2: iismod |= CHANNEL_1_EN; break; default: I2S_DBG("%d channels not supported\n", params_channels(params)); return -EINVAL; } //set hdmi codec params if(HW_PARAMS_FLAG_NLPCM == params->flags) hdmi_audio_cfg.type = HDMI_AUDIO_NLPCM; else hdmi_audio_cfg.type = HDMI_AUDIO_LPCM; //printk("i2s: hdmi_audio_cfg.type: %d\n", hdmi_audio_cfg.type); hdmi_audio_cfg.channel = params_channels(params); hdmi_audio_cfg.rate = SR2FS(params_rate(params)); hdmi_audio_cfg.word_length = HDMI_AUDIO_WORD_LENGTH_16bit; hdmi_config_audio(&hdmi_audio_cfg); // writel((16<<24) |(16<<18)|(16<<12)|(16<<6)|16, &(pheadi2s->I2S_FIFOLR)); dmarc = readl(&(pheadi2s->I2S_DMACR)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dmarc = ((dmarc & 0xFFFFFE00) | 16); else dmarc = ((dmarc & 0xFE00FFFF) | 16<<16); writel(dmarc, &(pheadi2s->I2S_DMACR)); I2S_DBG("Enter %s, %d I2S_TXCR=0x%08X\n", __func__, __LINE__, iismod); writel(iismod, &(pheadi2s->I2S_TXCR)); iismod = iismod & 0x00007FFF; writel(iismod, &(pheadi2s->I2S_RXCR)); spin_unlock_irqrestore(&lock, flags); return 0; }
static int hdmi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct hdmi_audio_data *ad = card_drvdata_substream(substream); struct snd_aes_iec958 *iec = &ad->iec; struct snd_cea_861_aud_if *cea = &ad->cea; WARN_ON(ad->current_stream != substream); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: ad->dma_data.maxburst = 16; break; case SNDRV_PCM_FORMAT_S24_LE: ad->dma_data.maxburst = 32; break; default: dev_err(dai->dev, "format not supported!\n"); return -EINVAL; } ad->dss_audio.iec = iec; ad->dss_audio.cea = cea; /* * fill the IEC-60958 channel status word */ /* initialize the word bytes */ memset(iec->status, 0, sizeof(iec->status)); /* specify IEC-60958-3 (commercial use) */ iec->status[0] &= ~IEC958_AES0_PROFESSIONAL; /* specify that the audio is LPCM*/ iec->status[0] &= ~IEC958_AES0_NONAUDIO; iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT; iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE; iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID; iec->status[1] = IEC958_AES1_CON_GENERAL; iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC; iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC; switch (params_rate(params)) { case 32000: iec->status[3] |= IEC958_AES3_CON_FS_32000; break; case 44100: iec->status[3] |= IEC958_AES3_CON_FS_44100; break; case 48000: iec->status[3] |= IEC958_AES3_CON_FS_48000; break; case 88200: iec->status[3] |= IEC958_AES3_CON_FS_88200; break; case 96000: iec->status[3] |= IEC958_AES3_CON_FS_96000; break; case 176400: iec->status[3] |= IEC958_AES3_CON_FS_176400; break; case 192000: iec->status[3] |= IEC958_AES3_CON_FS_192000; break; default: dev_err(dai->dev, "rate not supported!\n"); return -EINVAL; } /* specify the clock accuracy */ iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM; /* * specify the word length. The same word length value can mean * two different lengths. Hence, we need to specify the maximum * word length as well. */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16; iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24; break; case SNDRV_PCM_FORMAT_S24_LE: iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20; iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24; break; default: dev_err(dai->dev, "format not supported!\n"); return -EINVAL; } /* * Fill the CEA-861 audio infoframe (see spec for details) */ cea->db1_ct_cc = (params_channels(params) - 1) & CEA861_AUDIO_INFOFRAME_DB1CC; cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM; cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM; cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM; cea->db3 = 0; /* not used, all zeros */ /* * The OMAP HDMI IP requires to use the 8-channel channel code when * transmitting more than two channels. */ if (params_channels(params) == 2) cea->db4_ca = 0x0; else cea->db4_ca = 0x13; cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED; /* the expression is trivial but makes clear what we are doing */ cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV); return ad->ops->audio_config(ad->dssdev, &ad->dss_audio); }