162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2021 Stephan Gerhold 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Register definitions/sequences taken from various tfa98xx kernel drivers: 662306a36Sopenharmony_ci * Copyright (C) 2014-2020 NXP Semiconductors, All Rights Reserved. 762306a36Sopenharmony_ci * Copyright (C) 2013 Sony Mobile Communications Inc. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define TFA989X_STATUSREG 0x00 1862306a36Sopenharmony_ci#define TFA989X_BATTERYVOLTAGE 0x01 1962306a36Sopenharmony_ci#define TFA989X_TEMPERATURE 0x02 2062306a36Sopenharmony_ci#define TFA989X_REVISIONNUMBER 0x03 2162306a36Sopenharmony_ci#define TFA989X_REVISIONNUMBER_REV_MSK GENMASK(7, 0) /* device revision */ 2262306a36Sopenharmony_ci#define TFA989X_I2SREG 0x04 2362306a36Sopenharmony_ci#define TFA989X_I2SREG_RCV 2 /* receiver mode */ 2462306a36Sopenharmony_ci#define TFA989X_I2SREG_CHSA 6 /* amplifier input select */ 2562306a36Sopenharmony_ci#define TFA989X_I2SREG_CHSA_MSK GENMASK(7, 6) 2662306a36Sopenharmony_ci#define TFA989X_I2SREG_I2SSR 12 /* sample rate */ 2762306a36Sopenharmony_ci#define TFA989X_I2SREG_I2SSR_MSK GENMASK(15, 12) 2862306a36Sopenharmony_ci#define TFA989X_BAT_PROT 0x05 2962306a36Sopenharmony_ci#define TFA989X_AUDIO_CTR 0x06 3062306a36Sopenharmony_ci#define TFA989X_DCDCBOOST 0x07 3162306a36Sopenharmony_ci#define TFA989X_SPKR_CALIBRATION 0x08 3262306a36Sopenharmony_ci#define TFA989X_SYS_CTRL 0x09 3362306a36Sopenharmony_ci#define TFA989X_SYS_CTRL_PWDN 0 /* power down */ 3462306a36Sopenharmony_ci#define TFA989X_SYS_CTRL_I2CR 1 /* I2C reset */ 3562306a36Sopenharmony_ci#define TFA989X_SYS_CTRL_CFE 2 /* enable CoolFlux DSP */ 3662306a36Sopenharmony_ci#define TFA989X_SYS_CTRL_AMPE 3 /* enable amplifier */ 3762306a36Sopenharmony_ci#define TFA989X_SYS_CTRL_DCA 4 /* enable boost */ 3862306a36Sopenharmony_ci#define TFA989X_SYS_CTRL_SBSL 5 /* DSP configured */ 3962306a36Sopenharmony_ci#define TFA989X_SYS_CTRL_AMPC 6 /* amplifier enabled by DSP */ 4062306a36Sopenharmony_ci#define TFA989X_I2S_SEL_REG 0x0a 4162306a36Sopenharmony_ci#define TFA989X_I2S_SEL_REG_SPKR_MSK GENMASK(10, 9) /* speaker impedance */ 4262306a36Sopenharmony_ci#define TFA989X_I2S_SEL_REG_DCFG_MSK GENMASK(14, 11) /* DCDC compensation */ 4362306a36Sopenharmony_ci#define TFA989X_HIDE_UNHIDE_KEY 0x40 4462306a36Sopenharmony_ci#define TFA989X_PWM_CONTROL 0x41 4562306a36Sopenharmony_ci#define TFA989X_CURRENTSENSE1 0x46 4662306a36Sopenharmony_ci#define TFA989X_CURRENTSENSE2 0x47 4762306a36Sopenharmony_ci#define TFA989X_CURRENTSENSE3 0x48 4862306a36Sopenharmony_ci#define TFA989X_CURRENTSENSE4 0x49 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define TFA9890_REVISION 0x80 5162306a36Sopenharmony_ci#define TFA9895_REVISION 0x12 5262306a36Sopenharmony_ci#define TFA9897_REVISION 0x97 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct tfa989x_rev { 5562306a36Sopenharmony_ci unsigned int rev; 5662306a36Sopenharmony_ci int (*init)(struct regmap *regmap); 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct tfa989x { 6062306a36Sopenharmony_ci const struct tfa989x_rev *rev; 6162306a36Sopenharmony_ci struct regulator *vddd_supply; 6262306a36Sopenharmony_ci struct gpio_desc *rcv_gpiod; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic bool tfa989x_writeable_reg(struct device *dev, unsigned int reg) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci return reg > TFA989X_REVISIONNUMBER; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic bool tfa989x_volatile_reg(struct device *dev, unsigned int reg) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci return reg < TFA989X_REVISIONNUMBER; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const struct regmap_config tfa989x_regmap = { 7662306a36Sopenharmony_ci .reg_bits = 8, 7762306a36Sopenharmony_ci .val_bits = 16, 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci .writeable_reg = tfa989x_writeable_reg, 8062306a36Sopenharmony_ci .volatile_reg = tfa989x_volatile_reg, 8162306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic const char * const chsa_text[] = { "Left", "Right", /* "DSP" */ }; 8562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(chsa_enum, TFA989X_I2SREG, TFA989X_I2SREG_CHSA, chsa_text); 8662306a36Sopenharmony_cistatic const struct snd_kcontrol_new chsa_mux = SOC_DAPM_ENUM("Amp Input", chsa_enum); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget tfa989x_dapm_widgets[] = { 8962306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT"), 9062306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("POWER", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_PWDN, 1, NULL, 0), 9162306a36Sopenharmony_ci SND_SOC_DAPM_OUT_DRV("AMPE", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_AMPE, 0, NULL, 0), 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci SND_SOC_DAPM_MUX("Amp Input", SND_SOC_NOPM, 0, 0, &chsa_mux), 9462306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), 9562306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0), 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const struct snd_soc_dapm_route tfa989x_dapm_routes[] = { 9962306a36Sopenharmony_ci {"OUT", NULL, "AMPE"}, 10062306a36Sopenharmony_ci {"AMPE", NULL, "POWER"}, 10162306a36Sopenharmony_ci {"AMPE", NULL, "Amp Input"}, 10262306a36Sopenharmony_ci {"Amp Input", "Left", "AIFINL"}, 10362306a36Sopenharmony_ci {"Amp Input", "Right", "AIFINR"}, 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int tfa989x_put_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 10962306a36Sopenharmony_ci struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci gpiod_set_value_cansleep(tfa989x->rcv_gpiod, ucontrol->value.enumerated.item[0]); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return snd_soc_put_enum_double(kcontrol, ucontrol); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic const char * const mode_text[] = { "Speaker", "Receiver" }; 11762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(mode_enum, TFA989X_I2SREG, TFA989X_I2SREG_RCV, mode_text); 11862306a36Sopenharmony_cistatic const struct snd_kcontrol_new tfa989x_mode_controls[] = { 11962306a36Sopenharmony_ci SOC_ENUM_EXT("Mode", mode_enum, snd_soc_get_enum_double, tfa989x_put_mode), 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int tfa989x_probe(struct snd_soc_component *component) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (tfa989x->rev->rev == TFA9897_REVISION) 12762306a36Sopenharmony_ci return snd_soc_add_component_controls(component, tfa989x_mode_controls, 12862306a36Sopenharmony_ci ARRAY_SIZE(tfa989x_mode_controls)); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic const struct snd_soc_component_driver tfa989x_component = { 13462306a36Sopenharmony_ci .probe = tfa989x_probe, 13562306a36Sopenharmony_ci .dapm_widgets = tfa989x_dapm_widgets, 13662306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tfa989x_dapm_widgets), 13762306a36Sopenharmony_ci .dapm_routes = tfa989x_dapm_routes, 13862306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(tfa989x_dapm_routes), 13962306a36Sopenharmony_ci .use_pmdown_time = 1, 14062306a36Sopenharmony_ci .endianness = 1, 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic const unsigned int tfa989x_rates[] = { 14462306a36Sopenharmony_ci 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int tfa989x_find_sample_rate(unsigned int rate) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci int i; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tfa989x_rates); ++i) 15262306a36Sopenharmony_ci if (tfa989x_rates[i] == rate) 15362306a36Sopenharmony_ci return i; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return -EINVAL; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int tfa989x_hw_params(struct snd_pcm_substream *substream, 15962306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 16062306a36Sopenharmony_ci struct snd_soc_dai *dai) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 16362306a36Sopenharmony_ci int sr; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci sr = tfa989x_find_sample_rate(params_rate(params)); 16662306a36Sopenharmony_ci if (sr < 0) 16762306a36Sopenharmony_ci return sr; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return snd_soc_component_update_bits(component, TFA989X_I2SREG, 17062306a36Sopenharmony_ci TFA989X_I2SREG_I2SSR_MSK, 17162306a36Sopenharmony_ci sr << TFA989X_I2SREG_I2SSR); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const struct snd_soc_dai_ops tfa989x_dai_ops = { 17562306a36Sopenharmony_ci .hw_params = tfa989x_hw_params, 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic struct snd_soc_dai_driver tfa989x_dai = { 17962306a36Sopenharmony_ci .name = "tfa989x-hifi", 18062306a36Sopenharmony_ci .playback = { 18162306a36Sopenharmony_ci .stream_name = "HiFi Playback", 18262306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 18362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 18462306a36Sopenharmony_ci .rate_min = 8000, 18562306a36Sopenharmony_ci .rate_max = 48000, 18662306a36Sopenharmony_ci .channels_min = 1, 18762306a36Sopenharmony_ci .channels_max = 2, 18862306a36Sopenharmony_ci }, 18962306a36Sopenharmony_ci .ops = &tfa989x_dai_ops, 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int tfa9890_init(struct regmap *regmap) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int ret; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* temporarily allow access to hidden registers */ 19762306a36Sopenharmony_ci ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* update PLL registers */ 20262306a36Sopenharmony_ci ret = regmap_set_bits(regmap, 0x59, 0x3); 20362306a36Sopenharmony_ci if (ret) 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* hide registers again */ 20762306a36Sopenharmony_ci ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000); 20862306a36Sopenharmony_ci if (ret) 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return regmap_write(regmap, TFA989X_CURRENTSENSE2, 0x7BE1); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic const struct tfa989x_rev tfa9890_rev = { 21562306a36Sopenharmony_ci .rev = TFA9890_REVISION, 21662306a36Sopenharmony_ci .init = tfa9890_init, 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic const struct reg_sequence tfa9895_reg_init[] = { 22062306a36Sopenharmony_ci /* some other registers must be set for optimal amplifier behaviour */ 22162306a36Sopenharmony_ci { TFA989X_BAT_PROT, 0x13ab }, 22262306a36Sopenharmony_ci { TFA989X_AUDIO_CTR, 0x001f }, 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* peak voltage protection is always on, but may be written */ 22562306a36Sopenharmony_ci { TFA989X_SPKR_CALIBRATION, 0x3c4e }, 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* TFA989X_SYSCTRL_DCA = 0 */ 22862306a36Sopenharmony_ci { TFA989X_SYS_CTRL, 0x024d }, 22962306a36Sopenharmony_ci { TFA989X_PWM_CONTROL, 0x0308 }, 23062306a36Sopenharmony_ci { TFA989X_CURRENTSENSE4, 0x0e82 }, 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int tfa9895_init(struct regmap *regmap) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci return regmap_multi_reg_write(regmap, tfa9895_reg_init, 23662306a36Sopenharmony_ci ARRAY_SIZE(tfa9895_reg_init)); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic const struct tfa989x_rev tfa9895_rev = { 24062306a36Sopenharmony_ci .rev = TFA9895_REVISION, 24162306a36Sopenharmony_ci .init = tfa9895_init, 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int tfa9897_init(struct regmap *regmap) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci int ret; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Reduce slewrate by clearing iddqtestbst to avoid booster damage */ 24962306a36Sopenharmony_ci ret = regmap_write(regmap, TFA989X_CURRENTSENSE3, 0x0300); 25062306a36Sopenharmony_ci if (ret) 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Enable clipping */ 25462306a36Sopenharmony_ci ret = regmap_clear_bits(regmap, TFA989X_CURRENTSENSE4, 0x1); 25562306a36Sopenharmony_ci if (ret) 25662306a36Sopenharmony_ci return ret; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Set required TDM configuration */ 25962306a36Sopenharmony_ci return regmap_write(regmap, 0x14, 0x0); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct tfa989x_rev tfa9897_rev = { 26362306a36Sopenharmony_ci .rev = TFA9897_REVISION, 26462306a36Sopenharmony_ci .init = tfa9897_init, 26562306a36Sopenharmony_ci}; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* 26862306a36Sopenharmony_ci * Note: At the moment this driver bypasses the "CoolFlux DSP" built into the 26962306a36Sopenharmony_ci * TFA989X amplifiers. Unfortunately, there seems to be absolutely 27062306a36Sopenharmony_ci * no documentation for it - the public "short datasheets" do not provide 27162306a36Sopenharmony_ci * any information about the DSP or available registers. 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * Usually the TFA989X amplifiers are configured through proprietary userspace 27462306a36Sopenharmony_ci * libraries. There are also some (rather complex) kernel drivers but even those 27562306a36Sopenharmony_ci * rely on obscure firmware blobs for configuration (so-called "containers"). 27662306a36Sopenharmony_ci * They seem to contain different "profiles" with tuned speaker settings, sample 27762306a36Sopenharmony_ci * rates and volume steps (which would be better exposed as separate ALSA mixers). 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Bypassing the DSP disables volume control (and perhaps some speaker 28062306a36Sopenharmony_ci * optimization?), but at least allows using the speaker without obscure 28162306a36Sopenharmony_ci * kernel drivers and firmware. 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * Ideally NXP (or now Goodix) should release proper documentation for these 28462306a36Sopenharmony_ci * amplifiers so that support for the "CoolFlux DSP" can be implemented properly. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_cistatic int tfa989x_dsp_bypass(struct regmap *regmap) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci int ret; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Clear CHSA to bypass DSP and take input from I2S 1 left channel */ 29162306a36Sopenharmony_ci ret = regmap_clear_bits(regmap, TFA989X_I2SREG, TFA989X_I2SREG_CHSA_MSK); 29262306a36Sopenharmony_ci if (ret) 29362306a36Sopenharmony_ci return ret; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Set DCDC compensation to off and speaker impedance to 8 ohm */ 29662306a36Sopenharmony_ci ret = regmap_update_bits(regmap, TFA989X_I2S_SEL_REG, 29762306a36Sopenharmony_ci TFA989X_I2S_SEL_REG_DCFG_MSK | 29862306a36Sopenharmony_ci TFA989X_I2S_SEL_REG_SPKR_MSK, 29962306a36Sopenharmony_ci TFA989X_I2S_SEL_REG_SPKR_MSK); 30062306a36Sopenharmony_ci if (ret) 30162306a36Sopenharmony_ci return ret; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Set DCDC to follower mode and disable CoolFlux DSP */ 30462306a36Sopenharmony_ci return regmap_clear_bits(regmap, TFA989X_SYS_CTRL, 30562306a36Sopenharmony_ci BIT(TFA989X_SYS_CTRL_DCA) | 30662306a36Sopenharmony_ci BIT(TFA989X_SYS_CTRL_CFE) | 30762306a36Sopenharmony_ci BIT(TFA989X_SYS_CTRL_AMPC)); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic void tfa989x_regulator_disable(void *data) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct tfa989x *tfa989x = data; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci regulator_disable(tfa989x->vddd_supply); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int tfa989x_i2c_probe(struct i2c_client *i2c) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct device *dev = &i2c->dev; 32062306a36Sopenharmony_ci const struct tfa989x_rev *rev; 32162306a36Sopenharmony_ci struct tfa989x *tfa989x; 32262306a36Sopenharmony_ci struct regmap *regmap; 32362306a36Sopenharmony_ci unsigned int val; 32462306a36Sopenharmony_ci int ret; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci rev = device_get_match_data(dev); 32762306a36Sopenharmony_ci if (!rev) { 32862306a36Sopenharmony_ci dev_err(dev, "unknown device revision\n"); 32962306a36Sopenharmony_ci return -ENODEV; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci tfa989x = devm_kzalloc(dev, sizeof(*tfa989x), GFP_KERNEL); 33362306a36Sopenharmony_ci if (!tfa989x) 33462306a36Sopenharmony_ci return -ENOMEM; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci tfa989x->rev = rev; 33762306a36Sopenharmony_ci i2c_set_clientdata(i2c, tfa989x); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci tfa989x->vddd_supply = devm_regulator_get(dev, "vddd"); 34062306a36Sopenharmony_ci if (IS_ERR(tfa989x->vddd_supply)) 34162306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(tfa989x->vddd_supply), 34262306a36Sopenharmony_ci "Failed to get vddd regulator\n"); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (tfa989x->rev->rev == TFA9897_REVISION) { 34562306a36Sopenharmony_ci tfa989x->rcv_gpiod = devm_gpiod_get_optional(dev, "rcv", GPIOD_OUT_LOW); 34662306a36Sopenharmony_ci if (IS_ERR(tfa989x->rcv_gpiod)) 34762306a36Sopenharmony_ci return PTR_ERR(tfa989x->rcv_gpiod); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci regmap = devm_regmap_init_i2c(i2c, &tfa989x_regmap); 35162306a36Sopenharmony_ci if (IS_ERR(regmap)) 35262306a36Sopenharmony_ci return PTR_ERR(regmap); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ret = regulator_enable(tfa989x->vddd_supply); 35562306a36Sopenharmony_ci if (ret) { 35662306a36Sopenharmony_ci dev_err(dev, "Failed to enable vddd regulator: %d\n", ret); 35762306a36Sopenharmony_ci return ret; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, tfa989x_regulator_disable, tfa989x); 36162306a36Sopenharmony_ci if (ret) 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* Bypass regcache for reset and init sequence */ 36562306a36Sopenharmony_ci regcache_cache_bypass(regmap, true); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* Dummy read to generate i2c clocks, required on some devices */ 36862306a36Sopenharmony_ci regmap_read(regmap, TFA989X_REVISIONNUMBER, &val); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci ret = regmap_read(regmap, TFA989X_REVISIONNUMBER, &val); 37162306a36Sopenharmony_ci if (ret) { 37262306a36Sopenharmony_ci dev_err(dev, "failed to read revision number: %d\n", ret); 37362306a36Sopenharmony_ci return ret; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci val &= TFA989X_REVISIONNUMBER_REV_MSK; 37762306a36Sopenharmony_ci if (val != rev->rev) { 37862306a36Sopenharmony_ci dev_err(dev, "invalid revision number, expected %#x, got %#x\n", 37962306a36Sopenharmony_ci rev->rev, val); 38062306a36Sopenharmony_ci return -ENODEV; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = regmap_write(regmap, TFA989X_SYS_CTRL, BIT(TFA989X_SYS_CTRL_I2CR)); 38462306a36Sopenharmony_ci if (ret) { 38562306a36Sopenharmony_ci dev_err(dev, "failed to reset I2C registers: %d\n", ret); 38662306a36Sopenharmony_ci return ret; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ret = rev->init(regmap); 39062306a36Sopenharmony_ci if (ret) { 39162306a36Sopenharmony_ci dev_err(dev, "failed to initialize registers: %d\n", ret); 39262306a36Sopenharmony_ci return ret; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci ret = tfa989x_dsp_bypass(regmap); 39662306a36Sopenharmony_ci if (ret) { 39762306a36Sopenharmony_ci dev_err(dev, "failed to enable DSP bypass: %d\n", ret); 39862306a36Sopenharmony_ci return ret; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci regcache_cache_bypass(regmap, false); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return devm_snd_soc_register_component(dev, &tfa989x_component, 40362306a36Sopenharmony_ci &tfa989x_dai, 1); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic const struct of_device_id tfa989x_of_match[] = { 40762306a36Sopenharmony_ci { .compatible = "nxp,tfa9890", .data = &tfa9890_rev }, 40862306a36Sopenharmony_ci { .compatible = "nxp,tfa9895", .data = &tfa9895_rev }, 40962306a36Sopenharmony_ci { .compatible = "nxp,tfa9897", .data = &tfa9897_rev }, 41062306a36Sopenharmony_ci { } 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tfa989x_of_match); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic struct i2c_driver tfa989x_i2c_driver = { 41562306a36Sopenharmony_ci .driver = { 41662306a36Sopenharmony_ci .name = "tfa989x", 41762306a36Sopenharmony_ci .of_match_table = tfa989x_of_match, 41862306a36Sopenharmony_ci }, 41962306a36Sopenharmony_ci .probe = tfa989x_i2c_probe, 42062306a36Sopenharmony_ci}; 42162306a36Sopenharmony_cimodule_i2c_driver(tfa989x_i2c_driver); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC NXP/Goodix TFA989X (TFA1) driver"); 42462306a36Sopenharmony_ciMODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>"); 42562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 426