ASoC: max9867: Calculate LRCLK divider
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> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
29f58ff067
commit
715ee1916b
@ -126,76 +126,98 @@ 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) {
|
||||
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:
|
||||
case 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:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
|
||||
MAX9867_IFC1B_BCLK_MASK, value);
|
||||
} else {
|
||||
/*
|
||||
* digital pll locks on to any externally supplied LRCLK signal
|
||||
* and also enable rapid lock mode.
|
||||
@ -204,46 +226,6 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
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;
|
||||
case 8:
|
||||
bclk_value = MAX9867_IFC1B_PCLK_8;
|
||||
break;
|
||||
case 16:
|
||||
bclk_value = MAX9867_IFC1B_PCLK_16;
|
||||
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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -285,8 +267,16 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
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,
|
||||
.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,
|
||||
|
@ -27,10 +27,8 @@
|
||||
#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_NI_LOW_MASK 0xFE
|
||||
#define MAX9867_PLL (1<<7)
|
||||
#define MAX9867_AUDIOCLKLOW 0x07
|
||||
#define MAX9867_RAPID_LOCK 0x01
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user