static int cs42l51_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; struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); int ret; unsigned int i; unsigned int rate; unsigned int ratio; struct cs42l51_ratios *ratios = NULL; int nr_ratios = 0; int intf_ctl, power_ctl, fmt; switch (cs42l51->func) { case MODE_MASTER: return -EINVAL; case MODE_SLAVE: ratios = slave_ratios; nr_ratios = ARRAY_SIZE(slave_ratios); break; case MODE_SLAVE_AUTO: ratios = slave_auto_ratios; nr_ratios = ARRAY_SIZE(slave_auto_ratios); break; } rate = params_rate(params); ratio = cs42l51->mclk / rate; for (i = 0; i < nr_ratios; i++) { if (ratios[i].ratio == ratio) break; } if (i == nr_ratios) { dev_err(codec->dev, "could not find matching ratio\n"); return -EINVAL; } intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL); power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL); intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S | CS42L51_INTF_CTL_DAC_FORMAT(7)); power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3) | CS42L51_MIC_POWER_CTL_MCLK_DIV2); switch (cs42l51->func) { case MODE_MASTER: intf_ctl |= CS42L51_INTF_CTL_MASTER; power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); break; case MODE_SLAVE: power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); break; case MODE_SLAVE_AUTO: power_ctl |= CS42L51_MIC_POWER_CTL_AUTO; break; } switch (cs42l51->audio_mode) { case SND_SOC_DAIFMT_I2S: intf_ctl |= CS42L51_INTF_CTL_ADC_I2S; intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S); break; case SND_SOC_DAIFMT_LEFT_J: intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24); break; case SND_SOC_DAIFMT_RIGHT_J: switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_BE: fmt = CS42L51_DAC_DIF_RJ16; break; case SNDRV_PCM_FORMAT_S18_3LE: case SNDRV_PCM_FORMAT_S18_3BE: fmt = CS42L51_DAC_DIF_RJ18; break; case SNDRV_PCM_FORMAT_S20_3LE: case SNDRV_PCM_FORMAT_S20_3BE: fmt = CS42L51_DAC_DIF_RJ20; break; case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_BE: fmt = CS42L51_DAC_DIF_RJ24; break; default: dev_err(codec->dev, "unknown format\n"); return -EINVAL; } intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt); break; default: dev_err(codec->dev, "unknown format\n"); return -EINVAL; } if (ratios[i].mclk) power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2; ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl); if (ret < 0) return ret; ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl); if (ret < 0) return ret; return 0; }
static int cs42l51_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 cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); int ret; unsigned int i; unsigned int rate; unsigned int ratio; struct cs42l51_ratios *ratios = NULL; int nr_ratios = 0; int intf_ctl, power_ctl, fmt; switch (cs42l51->func) { case MODE_MASTER: return -EINVAL; case MODE_SLAVE: ratios = slave_ratios; nr_ratios = ARRAY_SIZE(slave_ratios); break; case MODE_SLAVE_AUTO: ratios = slave_auto_ratios; nr_ratios = ARRAY_SIZE(slave_auto_ratios); break; } /* Figure out which MCLK/LRCK ratio to use */ rate = params_rate(params); /* Sampling rate, in Hz */ ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */ for (i = 0; i < nr_ratios; i++) { if (ratios[i].ratio == ratio) break; } if (i == nr_ratios) { /* We did not find a matching ratio */ dev_err(codec->dev, "could not find matching ratio\n"); return -EINVAL; } intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL); power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL); intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S | CS42L51_INTF_CTL_DAC_FORMAT(7)); power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3) | CS42L51_MIC_POWER_CTL_MCLK_DIV2); switch (cs42l51->func) { case MODE_MASTER: intf_ctl |= CS42L51_INTF_CTL_MASTER; power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); break; case MODE_SLAVE: power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); break; case MODE_SLAVE_AUTO: power_ctl |= CS42L51_MIC_POWER_CTL_AUTO; break; } switch (cs42l51->audio_mode) { case SND_SOC_DAIFMT_I2S: intf_ctl |= CS42L51_INTF_CTL_ADC_I2S; intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S); break; case SND_SOC_DAIFMT_LEFT_J: intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24); break; case SND_SOC_DAIFMT_RIGHT_J: switch (params_width(params)) { case 16: fmt = CS42L51_DAC_DIF_RJ16; break; case 18: fmt = CS42L51_DAC_DIF_RJ18; break; case 20: fmt = CS42L51_DAC_DIF_RJ20; break; case 24: fmt = CS42L51_DAC_DIF_RJ24; break; default: dev_err(codec->dev, "unknown format\n"); return -EINVAL; } intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt); break; default: dev_err(codec->dev, "unknown format\n"); return -EINVAL; } if (ratios[i].mclk) power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2; ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl); if (ret < 0) return ret; ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl); if (ret < 0) return ret; return 0; }