struct pcm512x_priv { struct regmap *regmap; struct clk *sclk; struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; int fmt; int pll_in; int pll_out; int pll_r; int pll_j; int pll_d; int pll_p; unsignedlong real_pll; unsignedlong overclock_pll; unsignedlong overclock_dac; unsignedlong overclock_dsp; int mute; struct mutex mutex; unsignedint bclk_ratio; int force_pll_on;
};
/* * We can't use the same notifier block for more than one supply and * there's no way I can see to get from a callback to the caller * except container_of().
*/ #define PCM512x_REGULATOR_EVENT(n) \ staticint pcm512x_regulator_event_##n(struct notifier_block *nb, \ unsignedlong event, void *data) \
{ \ struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \
supply_nb[n]); \ if (event & REGULATOR_EVENT_DISABLE) { \
regcache_mark_dirty(pcm512x->regmap); \
regcache_cache_only(pcm512x->regmap, true); \
} \ return 0; \
}
staticbool pcm512x_readable(struct device *dev, unsignedint reg)
{ switch (reg) { case PCM512x_RESET: case PCM512x_POWER: case PCM512x_MUTE: case PCM512x_PLL_EN: case PCM512x_SPI_MISO_FUNCTION: case PCM512x_DSP: case PCM512x_GPIO_EN: case PCM512x_BCLK_LRCLK_CFG: case PCM512x_DSP_GPIO_INPUT: case PCM512x_MASTER_MODE: case PCM512x_PLL_REF: case PCM512x_DAC_REF: case PCM512x_GPIO_DACIN: case PCM512x_GPIO_PLLIN: case PCM512x_SYNCHRONIZE: case PCM512x_PLL_COEFF_0: case PCM512x_PLL_COEFF_1: case PCM512x_PLL_COEFF_2: case PCM512x_PLL_COEFF_3: case PCM512x_PLL_COEFF_4: case PCM512x_DSP_CLKDIV: case PCM512x_DAC_CLKDIV: case PCM512x_NCP_CLKDIV: case PCM512x_OSR_CLKDIV: case PCM512x_MASTER_CLKDIV_1: case PCM512x_MASTER_CLKDIV_2: case PCM512x_FS_SPEED_MODE: case PCM512x_IDAC_1: case PCM512x_IDAC_2: case PCM512x_ERROR_DETECT: case PCM512x_I2S_1: case PCM512x_I2S_2: case PCM512x_DAC_ROUTING: case PCM512x_DSP_PROGRAM: case PCM512x_CLKDET: case PCM512x_AUTO_MUTE: case PCM512x_DIGITAL_VOLUME_1: case PCM512x_DIGITAL_VOLUME_2: case PCM512x_DIGITAL_VOLUME_3: case PCM512x_DIGITAL_MUTE_1: case PCM512x_DIGITAL_MUTE_2: case PCM512x_DIGITAL_MUTE_3: case PCM512x_GPIO_OUTPUT_1: case PCM512x_GPIO_OUTPUT_2: case PCM512x_GPIO_OUTPUT_3: case PCM512x_GPIO_OUTPUT_4: case PCM512x_GPIO_OUTPUT_5: case PCM512x_GPIO_OUTPUT_6: case PCM512x_GPIO_CONTROL_1: case PCM512x_GPIO_CONTROL_2: case PCM512x_OVERFLOW: case PCM512x_RATE_DET_1: case PCM512x_RATE_DET_2: case PCM512x_RATE_DET_3: case PCM512x_RATE_DET_4: case PCM512x_CLOCK_STATUS: case PCM512x_ANALOG_MUTE_DET: case PCM512x_GPIN: case PCM512x_DIGITAL_MUTE_DET: case PCM512x_OUTPUT_AMPLITUDE: case PCM512x_ANALOG_GAIN_CTRL: case PCM512x_UNDERVOLTAGE_PROT: case PCM512x_ANALOG_MUTE_CTRL: case PCM512x_ANALOG_GAIN_BOOST: case PCM512x_VCOM_CTRL_1: case PCM512x_VCOM_CTRL_2: case PCM512x_CRAM_CTRL: case PCM512x_FLEX_A: case PCM512x_FLEX_B: returntrue; default: /* There are 256 raw register addresses */ return reg < 0xff;
}
}
staticbool pcm512x_volatile(struct device *dev, unsignedint reg)
{ switch (reg) { case PCM512x_PLL_EN: case PCM512x_OVERFLOW: case PCM512x_RATE_DET_1: case PCM512x_RATE_DET_2: case PCM512x_RATE_DET_3: case PCM512x_RATE_DET_4: case PCM512x_CLOCK_STATUS: case PCM512x_ANALOG_MUTE_DET: case PCM512x_GPIN: case PCM512x_DIGITAL_MUTE_DET: case PCM512x_CRAM_CTRL: returntrue; default: /* There are 256 raw register addresses */ return reg < 0xff;
}
}
if (changed) {
ret = pcm512x_update_mute(pcm512x); if (ret != 0) {
dev_err(component->dev, "Failed to update digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex); return ret;
}
}
staticunsignedlong pcm512x_ncp_target(struct pcm512x_priv *pcm512x, unsignedlong dac_rate)
{ /* * If the DAC is not actually overclocked, use the good old * NCP target rate...
*/ if (dac_rate <= 6144000) return 1536000; /* * ...but if the DAC is in fact overclocked, bump the NCP target * rate to get the recommended dividers even when overclocking.
*/ return pcm512x_dac_max(pcm512x, 1536000);
}
frame_size = snd_soc_params_to_frame_size(params); if (frame_size < 0) return frame_size;
switch (frame_size) { case 32: /* No hole when the frame size is 32. */ return 0; case 48: case 64: /* There is only one hole in the range of supported * rates, but it moves with the frame size.
*/
memset(ranges, 0, sizeof(ranges));
ranges[0].min = 8000;
ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2;
ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
ranges[1].max = 384000; break; default: return -EINVAL;
}
/* select sck_rate as a multiple of bclk_rate but still with * as many factors of 2 as possible, as that makes it easier * to find a fast DAC rate
*/
pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate); for (; pow2; pow2 >>= 1) {
sck_rate = rounddown(pcm512x_pll_max(pcm512x),
bclk_rate * pow2); if (sck_rate >= 16000000) break;
} if (!pow2) {
dev_err(dev, "Impossible to generate a suitable SCK\n"); return 0;
}
/* pll_rate = pllin_rate * R * J.D / P * 1 <= R <= 16 * 1 <= J <= 63 * 0 <= D <= 9999 * 1 <= P <= 15 * 64 MHz <= pll_rate <= 100 MHz * if D == 0 * 1 MHz <= pllin_rate / P <= 20 MHz * else if D > 0 * 6.667 MHz <= pllin_rate / P <= 20 MHz * 4 <= J <= 11 * R = 1
*/ staticint pcm512x_find_pll_coeff(struct snd_soc_dai *dai, unsignedlong pllin_rate, unsignedlong pll_rate)
{ struct device *dev = dai->dev; struct snd_soc_component *component = dai->component; struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); unsignedlong common; int R, J, D, P; unsignedlong K; /* 10000 * J.D */ unsignedlong num; unsignedlong den;
common = gcd(pll_rate, pllin_rate);
dev_dbg(dev, "pll %lu pllin %lu common %lu\n",
pll_rate, pllin_rate, common);
num = pll_rate / common;
den = pllin_rate / common;
/* pllin_rate / P (or here, den) cannot be greater than 20 MHz */ if (pllin_rate / den > 20000000 && num < 8) {
num *= DIV_ROUND_UP(pllin_rate / den, 20000000);
den *= DIV_ROUND_UP(pllin_rate / den, 20000000);
}
dev_dbg(dev, "num / den = %lu / %lu\n", num, den);
P = den; if (den <= 15 && num <= 16 * 63
&& 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) { /* Try the case with D = 0 */
D = 0; /* factor 'num' into J and R, such that R <= 16 and J <= 63 */ for (R = 16; R; R--) { if (num % R) continue;
J = num / R; if (J == 0 || J > 63) continue;
/* Try to find an exact pll_rate using the D > 0 case */
common = gcd(10000 * num, den);
num = 10000 * num / common;
den /= common;
dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common);
for (P = den; P <= 15; P++) { if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P) continue; if (num * P % den) continue;
K = num * P / den; /* J == 12 is ok if D == 0 */ if (K < 40000 || K > 120000) continue;
J = K / 10000;
D = K % 10000;
dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P);
pcm512x->real_pll = pll_rate; goto done;
}
/* Fall back to an approximate pll_rate */
fallback: /* find smallest possible P */
P = DIV_ROUND_UP(pllin_rate, 20000000); if (!P)
P = 1; elseif (P > 15) {
dev_err(dev, "Need a slower clock as pll-input\n"); return -EINVAL;
} if (pllin_rate / P < 6667000) {
dev_err(dev, "Need a faster clock as pll-input\n"); return -EINVAL;
}
K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate); if (K < 40000)
K = 40000; /* J == 12 is ok if D == 0 */ if (K > 120000)
K = 120000;
J = K / 10000;
D = K % 10000;
dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P);
pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P);
if (bclk_div > 128) {
dev_err(dev, "Failed to find BCLK divider\n"); return -EINVAL;
}
/* the actual rate */
sample_rate = sck_rate / bclk_div / lrclk_div;
osr_rate = 16 * sample_rate;
/* run DSP no faster than 50 MHz */
dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1;
dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate); if (dac_rate) { /* the desired clock rate is "compatible" with the pll input * clock, so use that clock as dac input instead of the pll * output clock since the pll will introduce jitter and thus * noise.
*/
dev_dbg(dev, "using pll input as dac input\n");
ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
PCM512x_SDAC, PCM512x_SDAC_GPIO); if (ret != 0) {
dev_err(component->dev, "Failed to set gpio as dacref: %d\n", ret); return ret;
}
gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN,
PCM512x_GREF, gpio); if (ret != 0) {
dev_err(component->dev, "Failed to set gpio %d as dacin: %d\n",
pcm512x->pll_in, ret); return ret;
}
dacsrc_rate = pllin_rate;
} else { /* run DAC no faster than 6144000 Hz */ unsignedlong dac_mul = pcm512x_dac_max(pcm512x, 6144000)
/ osr_rate; unsignedlong sck_mul = sck_rate / osr_rate;
for (; dac_mul; dac_mul--) { if (!(sck_mul % dac_mul)) break;
} if (!dac_mul) {
dev_err(dev, "Failed to find DAC rate\n"); return -EINVAL;
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
PCM512x_SDAC, PCM512x_SDAC_SCK); if (ret != 0) {
dev_err(component->dev, "Failed to set sck as dacref: %d\n", ret); return ret;
}
dacsrc_rate = sck_rate;
}
osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); if (osr_div > 128) {
dev_err(dev, "Failed to find OSR divider\n"); return -EINVAL;
}
switch (params_width(params)) { case 16:
alen = PCM512x_ALEN_16; break; case 20:
alen = PCM512x_ALEN_20; break; case 24:
alen = PCM512x_ALEN_24; break; case 32:
alen = PCM512x_ALEN_32; break; default:
dev_err(component->dev, "Bad frame size: %d\n",
params_width(params)); return -EINVAL;
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
PCM512x_ALEN, alen); if (ret != 0) {
dev_err(component->dev, "Failed to set frame size: %d\n", ret); return ret;
}
if ((pcm512x->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
SND_SOC_DAIFMT_CBC_CFC) {
ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
PCM512x_DCAS, 0); if (ret != 0) {
dev_err(component->dev, "Failed to enable clock divider autoset: %d\n",
ret); return ret;
} goto skip_pll;
}
if (pcm512x->pll_out) {
ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11); if (ret != 0) {
dev_err(component->dev, "Failed to set FLEX_A: %d\n", ret); return ret;
}
ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff); if (ret != 0) {
dev_err(component->dev, "Failed to set FLEX_B: %d\n", ret); return ret;
}
if (!pcm512x->force_pll_on) {
ret = regmap_update_bits(pcm512x->regmap,
PCM512x_PLL_EN, PCM512x_PLLE, 0);
} else { /* provide minimum PLL config for TAS575x clocking * and leave PLL enabled
*/
ret = regmap_write(pcm512x->regmap,
PCM512x_PLL_COEFF_0, 0x01); if (ret != 0) {
dev_err(component->dev, "Failed to set pll coefficient: %d\n", ret); return ret;
}
ret = regmap_write(pcm512x->regmap,
PCM512x_PLL_COEFF_1, 0x04); if (ret != 0) {
dev_err(component->dev, "Failed to set pll coefficient: %d\n", ret); return ret;
}
ret = regmap_write(pcm512x->regmap,
PCM512x_PLL_EN, 0x01);
dev_dbg(component->dev, "Enabling PLL for TAS575x\n");
}
if (ret != 0) {
dev_err(component->dev, "Failed to set pll mode: %d\n", ret); return ret;
}
}
ret = pcm512x_set_dividers(dai, params); if (ret != 0) return ret;
if (pcm512x->pll_out) {
ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF,
PCM512x_SREF, PCM512x_SREF_GPIO); if (ret != 0) {
dev_err(component->dev, "Failed to set gpio as pllref: %d\n", ret); return ret;
}
gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN,
PCM512x_GREF, gpio); if (ret != 0) {
dev_err(component->dev, "Failed to set gpio %d as pllin: %d\n",
pcm512x->pll_in, ret); return ret;
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
PCM512x_PLLE, PCM512x_PLLE); if (ret != 0) {
dev_err(component->dev, "Failed to enable pll: %d\n", ret); return ret;
}
gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
gpio, gpio); if (ret != 0) {
dev_err(component->dev, "Failed to enable gpio %d: %d\n",
pcm512x->pll_out, ret); return ret;
}
gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x->pll_out - 1;
ret = regmap_update_bits(pcm512x->regmap, gpio,
PCM512x_GxSL, PCM512x_GxSL_PLLCK); if (ret != 0) {
dev_err(component->dev, "Failed to output pll on %d: %d\n",
ret, pcm512x->pll_out); return ret;
}
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
PCM512x_RQSY, PCM512x_RQSY_HALT); if (ret != 0) {
dev_err(component->dev, "Failed to halt clocks: %d\n", ret); return ret;
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
PCM512x_RQSY, PCM512x_RQSY_RESUME); if (ret != 0) {
dev_err(component->dev, "Failed to resume clocks: %d\n", ret); return ret;
}
skip_pll: return 0;
}
staticint pcm512x_set_fmt(struct snd_soc_dai *dai, unsignedint fmt)
{ struct snd_soc_component *component = dai->component; struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); int afmt; int offset = 0; int clock_output; int provider_mode; int ret;
ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
clock_output); if (ret != 0) {
dev_err(component->dev, "Failed to enable clock output: %d\n", ret); return ret;
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
PCM512x_RLRK | PCM512x_RBCK,
provider_mode); if (ret != 0) {
dev_err(component->dev, "Failed to enable provider mode: %d\n", ret); return ret;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S:
afmt = PCM512x_AFMT_I2S; break; case SND_SOC_DAIFMT_RIGHT_J:
afmt = PCM512x_AFMT_RTJ; break; case SND_SOC_DAIFMT_LEFT_J:
afmt = PCM512x_AFMT_LTJ; break; case SND_SOC_DAIFMT_DSP_A:
offset = 1;
fallthrough; case SND_SOC_DAIFMT_DSP_B:
afmt = PCM512x_AFMT_DSP; break; default:
dev_err(component->dev, "unsupported DAI format: 0x%x\n",
pcm512x->fmt); return -EINVAL;
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
PCM512x_AFMT, afmt); if (ret != 0) {
dev_err(component->dev, "Failed to set data format: %d\n", ret); return ret;
}
ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_2,
0xFF, offset); if (ret != 0) {
dev_err(component->dev, "Failed to set data offset: %d\n", ret); return ret;
}
for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++)
pcm512x->supplies[i].supply = pcm512x_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies),
pcm512x->supplies); if (ret != 0) {
dev_err(dev, "Failed to get supplies: %d\n", ret); return ret;
}
for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) {
ret = devm_regulator_register_notifier(
pcm512x->supplies[i].consumer,
&pcm512x->supply_nb[i]); if (ret != 0) {
dev_err(dev, "Failed to register regulator notifier: %d\n",
ret);
}
}
ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies),
pcm512x->supplies); if (ret != 0) {
dev_err(dev, "Failed to enable supplies: %d\n", ret); return ret;
}
/* Reset the device, verifying I/O in the process for I2C */
ret = regmap_write(regmap, PCM512x_RESET,
PCM512x_RSTM | PCM512x_RSTR); if (ret != 0) {
dev_err(dev, "Failed to reset device: %d\n", ret); goto err;
}
ret = regmap_write(regmap, PCM512x_RESET, 0); if (ret != 0) {
dev_err(dev, "Failed to reset device: %d\n", ret); goto err;
}
pcm512x->sclk = devm_clk_get(dev, NULL); if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER; goto err;
} if (!IS_ERR(pcm512x->sclk)) {
ret = clk_prepare_enable(pcm512x->sclk); if (ret != 0) {
dev_err(dev, "Failed to enable SCLK: %d\n", ret); goto err;
}
}
/* Default to standby mode */
ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER,
PCM512x_RQST, PCM512x_RQST); if (ret != 0) {
dev_err(dev, "Failed to request standby: %d\n",
ret); goto err_clk;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.