Commit c7b92395 authored by Ricard Wanderlof's avatar Ricard Wanderlof Committed by Mark Brown

ASoC: adau1761: Add ADAU1761-as-ADAU1361 compatibility mode

During probe, determine if the chip is in fact an ADAU1761
even though an ADAU1361 is specified, and perform additional
operations to enable the ADAU1761 to behave as an ADAU1361,
i.e. disregarding the DSP and setting up routing and PM
transparently.

This enables either chip to be mounted when an ADAU1361 is specified.
Signed-off-by: default avatarRicard Wanderlof <ricardw@axis.com>
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2204281841290.5574@lnxricardw1.se.axis.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent c8220e87
......@@ -556,8 +556,6 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
{ "Left DAC", NULL, "Interpolator Resync Clock" },
{ "Right DAC", NULL, "Interpolator Resync Clock" },
{ "DSP", NULL, "Digital Clock 0" },
{ "Slew Clock", NULL, "Digital Clock 0" },
{ "Right Playback Mixer", NULL, "Slew Clock" },
{ "Left Playback Mixer", NULL, "Slew Clock" },
......@@ -569,6 +567,56 @@ static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
{ "Digital Clock 1", NULL, "SYSCLK" },
};
static const struct snd_soc_dapm_route adau1761_dapm_dsp_routes[] = {
{ "DSP", NULL, "Digital Clock 0" },
};
static int adau1761_compatibility_probe(struct device *dev)
{
struct adau *adau = dev_get_drvdata(dev);
struct regmap *regmap = adau->regmap;
int val, ret = 0;
/* Only consider compatibility mode when ADAU1361 was specified. */
if (adau->type != ADAU1361)
return 0;
regcache_cache_bypass(regmap, true);
/*
* This will enable the core clock and bypass the PLL,
* so that we can access the registers for probing purposes
* (without having to set up the PLL).
*/
regmap_write(regmap, ADAU17X1_CLOCK_CONTROL,
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
/*
* ADAU17X1_SERIAL_SAMPLING_RATE doesn't exist in non-DSP chips;
* reading it results in zero at all times, and write is a no-op.
* Use this register to probe for ADAU1761.
*/
regmap_write(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, 1);
ret = regmap_read(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, &val);
if (ret)
goto exit;
if (val != 1)
goto exit;
regmap_write(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, 0);
ret = regmap_read(regmap, ADAU17X1_SERIAL_SAMPLING_RATE, &val);
if (ret)
goto exit;
if (val != 0)
goto exit;
adau->type = ADAU1761_AS_1361;
exit:
/* Disable core clock after probing. */
regmap_write(regmap, ADAU17X1_CLOCK_CONTROL, 0);
regcache_cache_bypass(regmap, false);
return ret;
}
static int adau1761_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
......@@ -823,7 +871,11 @@ static int adau1761_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
if (adau->type == ADAU1761) {
/*
* If we've got an ADAU1761, or an ADAU1761 operating as an
* ADAU1361, we need these non-DSP related DAPM widgets and routes.
*/
if (adau->type == ADAU1761 || adau->type == ADAU1761_AS_1361) {
ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets,
ARRAY_SIZE(adau1761_dapm_widgets));
if (ret)
......@@ -834,7 +886,29 @@ static int adau1761_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
}
/*
* These routes are DSP related and only used when we have a
* bona fide ADAU1761.
*/
if (adau->type == ADAU1761) {
ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_dsp_routes,
ARRAY_SIZE(adau1761_dapm_dsp_routes));
if (ret)
return ret;
}
/*
* In the ADAU1761, by default, the AIF is routed to the DSP, whereas
* for the ADAU1361, the AIF is permanently routed to the ADC and DAC.
* Thus, if we have an ADAU1761 masquerading as an ADAU1361,
* we need to explicitly route the AIF to the ADC and DAC.
* For the ADAU1761, this is normally done by set_tdm_slot, but this
* function is not necessarily called during stream setup, so set up
* the compatible AIF routings here from the start.
*/
if (adau->type == ADAU1761_AS_1361) {
regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE, 0x01);
regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x01);
}
ret = adau17x1_add_routes(component);
if (ret < 0)
return ret;
......@@ -919,6 +993,10 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
if (ret)
return ret;
ret = adau1761_compatibility_probe(dev);
if (ret)
return ret;
/* Enable cache only mode as we could miss writes before bias level
* reaches standby and the core clock is enabled */
regcache_cache_only(regmap, true);
......
......@@ -334,6 +334,17 @@ static bool adau17x1_has_dsp(struct adau *adau)
}
}
/* Chip has a DSP but we're pretending it doesn't. */
static bool adau17x1_has_disused_dsp(struct adau *adau)
{
switch (adau->type) {
case ADAU1761_AS_1361:
return true;
default:
return false;
}
}
static bool adau17x1_has_safeload(struct adau *adau)
{
switch (adau->type) {
......@@ -516,10 +527,11 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
ADAU17X1_CONVERTER0_CONVSR_MASK, div);
if (adau17x1_has_dsp(adau)) {
if (adau17x1_has_dsp(adau) || adau17x1_has_disused_dsp(adau))
regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div);
if (adau17x1_has_dsp(adau))
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
}
if (adau->sigmadsp) {
ret = adau17x1_setup_firmware(component, params_rate(params));
......@@ -663,7 +675,7 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
switch (slot_width * slots) {
case 32:
if (adau->type == ADAU1761)
if (adau->type == ADAU1761 || adau->type == ADAU1761_AS_1361)
return -EINVAL;
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32;
......@@ -738,7 +750,7 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1);
if (!adau17x1_has_dsp(adau))
if (!adau17x1_has_dsp(adau) && !adau17x1_has_disused_dsp(adau))
return 0;
if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) {
......
......@@ -10,6 +10,7 @@
enum adau17x1_type {
ADAU1361,
ADAU1761,
ADAU1761_AS_1361,
ADAU1381,
ADAU1781,
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment