Drop "Common NI Values Table" and calculate LRCLK divider, then add allowed rate constraints based on master clock frequency.
Signed-off-by: Ladislav Michl ladis@linux-mips.org --- Should we just warn about unexact frequencies for bail out with error?
sound/soc/codecs/max9867.c | 213 ++++++++++++++++++------------------- sound/soc/codecs/max9867.h | 31 ++---- 2 files changed, 113 insertions(+), 131 deletions(-)
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index d7c96aa0d797..ec0667cc4956 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -126,124 +126,106 @@ static const struct snd_soc_dapm_route max9867_audio_map[] = { {"LINE_IN", NULL, "Right Line"}, };
-enum rates { - pcm_rate_8, pcm_rate_16, pcm_rate_24, - pcm_rate_32, pcm_rate_44, - pcm_rate_48, max_pcm_rate, +static const unsigned int max9867_rates_44k1[] = { + 11025, 22050, 44100, };
-static const struct ni_div_rates { - u32 mclk; - u16 ni[max_pcm_rate]; -} ni_div[] = { - {11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} }, - {12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} }, - {12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} }, - {13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} }, - {19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} }, - {24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} }, - {26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} }, - {27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} }, +static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = { + .list = max9867_rates_44k1, + .count = ARRAY_SIZE(max9867_rates_44k1), };
-static inline int get_ni_value(int mclk, int rate) +static const unsigned int max9867_rates_48k[] = { + 8000, 16000, 32000, 48000, +}; + +static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = { + .list = max9867_rates_48k, + .count = ARRAY_SIZE(max9867_rates_48k), +}; + +struct max9867_priv { + struct regmap *regmap; + const struct snd_pcm_hw_constraint_list *constraints; + unsigned int sysclk, pclk; + bool master, dsp_a; +}; + +static int max9867_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { - int i, ret = 0; + struct max9867_priv *max9867 = + snd_soc_component_get_drvdata(dai->component);
- /* find the closest rate index*/ - for (i = 0; i < ARRAY_SIZE(ni_div); i++) { - if (ni_div[i].mclk >= mclk) - break; - } - if (i == ARRAY_SIZE(ni_div)) - return -EINVAL; + if (max9867->constraints) + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, max9867->constraints);
- switch (rate) { - case 8000: - return ni_div[i].ni[pcm_rate_8]; - case 16000: - return ni_div[i].ni[pcm_rate_16]; - case 32000: - return ni_div[i].ni[pcm_rate_32]; - case 44100: - return ni_div[i].ni[pcm_rate_44]; - case 48000: - return ni_div[i].ni[pcm_rate_48]; - default: - pr_err("%s wrong rate %d\n", __func__, rate); - ret = -EINVAL; - } - return ret; + return 0; }
static int max9867_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + int value; + unsigned long int rate, ratio; struct snd_soc_component *component = dai->component; struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); - unsigned int ni_h, ni_l; - int value; + unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params), + max9867->pclk);
- value = get_ni_value(max9867->sysclk, params_rate(params)); - if (value < 0) - return value; - - ni_h = (0xFF00 & value) >> 8; - ni_l = 0x00FF & value; /* set up the ni value */ regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, - MAX9867_NI_HIGH_MASK, ni_h); + MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8); regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, - MAX9867_NI_LOW_MASK, ni_l); - if (!max9867->master) { - /* - * digital pll locks on to any externally supplied LRCLK signal - * and also enable rapid lock mode. - */ - regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, - MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); - regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, - MAX9867_PLL, MAX9867_PLL); - } else { - unsigned long int bclk_rate, pclk_bclk_ratio; - int bclk_value; - - bclk_rate = params_rate(params) * 2 * params_width(params); - pclk_bclk_ratio = max9867->pclk/bclk_rate; - switch (params_width(params)) { - case 8: - case 16: - switch (pclk_bclk_ratio) { - case 2: - bclk_value = MAX9867_IFC1B_PCLK_2; - break; - case 4: - bclk_value = MAX9867_IFC1B_PCLK_4; - break; + MAX9867_NI_LOW_MASK, 0x00FF & ni); + if (max9867->master) { + if (max9867->dsp_a) { + value = MAX9867_IFC1B_48X; + } else { + rate = params_rate(params) * 2 * params_width(params); + ratio = max9867->pclk / rate; + switch (params_width(params)) { case 8: - bclk_value = MAX9867_IFC1B_PCLK_8; - break; case 16: - bclk_value = MAX9867_IFC1B_PCLK_16; + switch (ratio) { + case 2: + value = MAX9867_IFC1B_PCLK_2; + break; + case 4: + value = MAX9867_IFC1B_PCLK_4; + break; + case 8: + value = MAX9867_IFC1B_PCLK_8; + break; + case 16: + value = MAX9867_IFC1B_PCLK_16; + break; + default: + return -EINVAL; + } + break; + case 24: + value = MAX9867_IFC1B_48X; + break; + case 32: + value = MAX9867_IFC1B_64X; break; default: - dev_err(component->dev, - "unsupported sampling rate\n"); return -EINVAL; } - break; - case 24: - bclk_value = MAX9867_IFC1B_24BIT; - break; - case 32: - bclk_value = MAX9867_IFC1B_32BIT; - break; - default: - dev_err(component->dev, "unsupported sampling rate\n"); - return -EINVAL; } regmap_update_bits(max9867->regmap, MAX9867_IFC1B, - MAX9867_IFC1B_BCLK_MASK, bclk_value); + MAX9867_IFC1B_BCLK_MASK, value); + } else { + /* + * digital pll locks on to any externally supplied LRCLK signal + * and also enable rapid lock mode. + */ + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, + MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, + MAX9867_PLL, MAX9867_PLL); } return 0; } @@ -272,21 +254,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, /* Set the prescaler based on the master clock frequency*/ if (freq >= 10000000 && freq <= 20000000) { value |= MAX9867_PSCLK_10_20; - max9867->pclk = freq; + max9867->pclk = freq; } else if (freq >= 20000000 && freq <= 40000000) { value |= MAX9867_PSCLK_20_40; - max9867->pclk = freq/2; + max9867->pclk = freq / 2; } else if (freq >= 40000000 && freq <= 60000000) { value |= MAX9867_PSCLK_40_60; - max9867->pclk = freq/4; + max9867->pclk = freq / 4; } else { dev_err(component->dev, "Invalid clock frequency %uHz (required 10-60MHz)\n", freq); return -EINVAL; } - value = value << MAX9867_PSCLK_SHIFT; + if (freq % 48000 == 0) + max9867->constraints = &max9867_constraints_48k; + else if (freq % 44100 == 0) + max9867->constraints = &max9867_constraints_44k1; + else + dev_warn(component->dev, + "Unable to set exact rate with %uHz clock frequency\n", + freq); max9867->sysclk = freq; + value = value << MAX9867_PSCLK_SHIFT; /* exact integer mode is not supported */ value &= ~MAX9867_FREQ_MASK; regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, @@ -299,16 +289,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_component *component = codec_dai->component; struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); - u8 iface1A = 0, iface1B = 0; + u8 iface1A, iface1B;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - max9867->master = 1; - iface1A |= MAX9867_MASTER; + max9867->master = true; + iface1A = MAX9867_MASTER; + iface1B = MAX9867_IFC1B_48X; break; case SND_SOC_DAIFMT_CBS_CFS: - max9867->master = 0; - iface1A &= ~MAX9867_MASTER; + max9867->master = false; + iface1A = iface1B = 0; break; default: return -EINVAL; @@ -316,9 +307,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: + max9867->dsp_a = false; iface1A |= MAX9867_I2S_DLY; break; case SND_SOC_DAIFMT_DSP_A: + max9867->dsp_a = true; iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ; break; default: @@ -344,20 +337,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A); regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B); + return 0; }
static const struct snd_soc_dai_ops max9867_dai_ops = { - .set_fmt = max9867_dai_set_fmt, .set_sysclk = max9867_set_dai_sysclk, + .set_fmt = max9867_dai_set_fmt, .digital_mute = max9867_mute, - .hw_params = max9867_dai_hw_params, + .startup = max9867_startup, + .hw_params = max9867_dai_hw_params, };
-#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) -#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) - static struct snd_soc_dai_driver max9867_dai[] = { { .name = "max9867-aif1", @@ -365,15 +356,15 @@ static struct snd_soc_dai_driver max9867_dai[] = { .stream_name = "HiFi Playback", .channels_min = 2, .channels_max = 2, - .rates = MAX9867_RATES, - .formats = MAX9867_FORMATS, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "HiFi Capture", .channels_min = 2, .channels_max = 2, - .rates = MAX9867_RATES, - .formats = MAX9867_FORMATS, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &max9867_dai_ops, .symmetric_rates = 1, diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h index d9170850c96e..7f037ab701a5 100644 --- a/sound/soc/codecs/max9867.h +++ b/sound/soc/codecs/max9867.h @@ -26,13 +26,11 @@ #define MAX9867_PSCLK_10_20 0x1 #define MAX9867_PSCLK_20_40 0x2 #define MAX9867_PSCLK_40_60 0x3 -#define MAX9867_AUDIOCLKHIGH 0x06 -#define MAX9867_NI_HIGH_WIDTH 0x7 -#define MAX9867_NI_HIGH_MASK 0x7F -#define MAX9867_NI_LOW_MASK 0x7F -#define MAX9867_NI_LOW_SHIFT 0x1 -#define MAX9867_PLL (1<<7) -#define MAX9867_AUDIOCLKLOW 0x07 +#define MAX9867_AUDIOCLKHIGH 0x06 +#define MAX9867_NI_HIGH_MASK 0x7F +#define MAX9867_NI_LOW_MASK 0xFE +#define MAX9867_PLL (1<<7) +#define MAX9867_AUDIOCLKLOW 0x07 #define MAX9867_RAPID_LOCK 0x01 #define MAX9867_IFC1A 0x08 #define MAX9867_MASTER (1<<7) @@ -43,12 +41,12 @@ #define MAX9867_BCI_MODE (1<<5) #define MAX9867_IFC1B 0x09 #define MAX9867_IFC1B_BCLK_MASK 7 -#define MAX9867_IFC1B_32BIT 0x01 -#define MAX9867_IFC1B_24BIT 0x02 -#define MAX9867_IFC1B_PCLK_2 4 -#define MAX9867_IFC1B_PCLK_4 5 -#define MAX9867_IFC1B_PCLK_8 6 -#define MAX9867_IFC1B_PCLK_16 7 +#define MAX9867_IFC1B_64X 0x01 +#define MAX9867_IFC1B_48X 0x02 +#define MAX9867_IFC1B_PCLK_2 0x04 +#define MAX9867_IFC1B_PCLK_4 0x05 +#define MAX9867_IFC1B_PCLK_8 0x06 +#define MAX9867_IFC1B_PCLK_16 0x07 #define MAX9867_CODECFLTR 0x0a #define MAX9867_DACGAIN 0x0b #define MAX9867_DACLEVEL 0x0c @@ -72,11 +70,4 @@
#define MAX9867_CACHEREGNUM 10
-/* codec private data */ -struct max9867_priv { - struct regmap *regmap; - unsigned int sysclk; - unsigned int pclk; - unsigned int master; -}; #endif