// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2021 Stephan Gerhold * * Register definitions/sequences taken from various tfa98xx kernel drivers: * Copyright (C) 2014-2020 NXP Semiconductors, All Rights Reserved. * Copyright (C) 2013 Sony Mobile Communications Inc.
*/
staticconststruct reg_sequence tfa9895_reg_init[] = { /* some other registers must be set for optimal amplifier behaviour */
{ TFA989X_BAT_PROT, 0x13ab },
{ TFA989X_AUDIO_CTR, 0x001f },
/* peak voltage protection is always on, but may be written */
{ TFA989X_SPKR_CALIBRATION, 0x3c4e },
/* * Note: At the moment this driver bypasses the "CoolFlux DSP" built into the * TFA989X amplifiers. Unfortunately, there seems to be absolutely * no documentation for it - the public "short datasheets" do not provide * any information about the DSP or available registers. * * Usually the TFA989X amplifiers are configured through proprietary userspace * libraries. There are also some (rather complex) kernel drivers but even those * rely on obscure firmware blobs for configuration (so-called "containers"). * They seem to contain different "profiles" with tuned speaker settings, sample * rates and volume steps (which would be better exposed as separate ALSA mixers). * * Bypassing the DSP disables volume control (and perhaps some speaker * optimization?), but at least allows using the speaker without obscure * kernel drivers and firmware. * * Ideally NXP (or now Goodix) should release proper documentation for these * amplifiers so that support for the "CoolFlux DSP" can be implemented properly.
*/ staticint tfa989x_dsp_bypass(struct regmap *regmap)
{ int ret;
/* Clear CHSA to bypass DSP and take input from I2S 1 left channel */
ret = regmap_clear_bits(regmap, TFA989X_I2SREG, TFA989X_I2SREG_CHSA_MSK); if (ret) return ret;
/* Set DCDC compensation to off and speaker impedance to 8 ohm */
ret = regmap_update_bits(regmap, TFA989X_I2S_SEL_REG,
TFA989X_I2S_SEL_REG_DCFG_MSK |
TFA989X_I2S_SEL_REG_SPKR_MSK,
TFA989X_I2S_SEL_REG_SPKR_MSK); if (ret) return ret;
/* Set DCDC to follower mode and disable CoolFlux DSP */ return regmap_clear_bits(regmap, TFA989X_SYS_CTRL,
BIT(TFA989X_SYS_CTRL_DCA) |
BIT(TFA989X_SYS_CTRL_CFE) |
BIT(TFA989X_SYS_CTRL_AMPC));
}
tfa989x->vddd_supply = devm_regulator_get(dev, "vddd"); if (IS_ERR(tfa989x->vddd_supply)) return dev_err_probe(dev, PTR_ERR(tfa989x->vddd_supply), "Failed to get vddd regulator\n");
if (tfa989x->rev->rev == TFA9897_REVISION) {
tfa989x->rcv_gpiod = devm_gpiod_get_optional(dev, "rcv", GPIOD_OUT_LOW); if (IS_ERR(tfa989x->rcv_gpiod)) return PTR_ERR(tfa989x->rcv_gpiod);
}
regmap = devm_regmap_init_i2c(i2c, &tfa989x_regmap); if (IS_ERR(regmap)) return PTR_ERR(regmap);
ret = regulator_enable(tfa989x->vddd_supply); if (ret) {
dev_err(dev, "Failed to enable vddd regulator: %d\n", ret); return ret;
}
ret = devm_add_action_or_reset(dev, tfa989x_regulator_disable, tfa989x); if (ret) return ret;
/* Bypass regcache for reset and init sequence */
regcache_cache_bypass(regmap, true);
/* Dummy read to generate i2c clocks, required on some devices */
regmap_read(regmap, TFA989X_REVISIONNUMBER, &val);
ret = regmap_read(regmap, TFA989X_REVISIONNUMBER, &val); if (ret) {
dev_err(dev, "failed to read revision number: %d\n", ret); return ret;
}
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.