cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tfa989x.c (11886B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2021 Stephan Gerhold
      4 *
      5 * Register definitions/sequences taken from various tfa98xx kernel drivers:
      6 * Copyright (C) 2014-2020 NXP Semiconductors, All Rights Reserved.
      7 * Copyright (C) 2013 Sony Mobile Communications Inc.
      8 */
      9
     10#include <linux/gpio/consumer.h>
     11#include <linux/i2c.h>
     12#include <linux/module.h>
     13#include <linux/regmap.h>
     14#include <linux/regulator/consumer.h>
     15#include <sound/soc.h>
     16
     17#define TFA989X_STATUSREG		0x00
     18#define TFA989X_BATTERYVOLTAGE		0x01
     19#define TFA989X_TEMPERATURE		0x02
     20#define TFA989X_REVISIONNUMBER		0x03
     21#define TFA989X_REVISIONNUMBER_REV_MSK	GENMASK(7, 0)	/* device revision */
     22#define TFA989X_I2SREG			0x04
     23#define TFA989X_I2SREG_RCV		2	/* receiver mode */
     24#define TFA989X_I2SREG_CHSA		6	/* amplifier input select */
     25#define TFA989X_I2SREG_CHSA_MSK		GENMASK(7, 6)
     26#define TFA989X_I2SREG_I2SSR		12	/* sample rate */
     27#define TFA989X_I2SREG_I2SSR_MSK	GENMASK(15, 12)
     28#define TFA989X_BAT_PROT		0x05
     29#define TFA989X_AUDIO_CTR		0x06
     30#define TFA989X_DCDCBOOST		0x07
     31#define TFA989X_SPKR_CALIBRATION	0x08
     32#define TFA989X_SYS_CTRL		0x09
     33#define TFA989X_SYS_CTRL_PWDN		0	/* power down */
     34#define TFA989X_SYS_CTRL_I2CR		1	/* I2C reset */
     35#define TFA989X_SYS_CTRL_CFE		2	/* enable CoolFlux DSP */
     36#define TFA989X_SYS_CTRL_AMPE		3	/* enable amplifier */
     37#define TFA989X_SYS_CTRL_DCA		4	/* enable boost */
     38#define TFA989X_SYS_CTRL_SBSL		5	/* DSP configured */
     39#define TFA989X_SYS_CTRL_AMPC		6	/* amplifier enabled by DSP */
     40#define TFA989X_I2S_SEL_REG		0x0a
     41#define TFA989X_I2S_SEL_REG_SPKR_MSK	GENMASK(10, 9)	/* speaker impedance */
     42#define TFA989X_I2S_SEL_REG_DCFG_MSK	GENMASK(14, 11)	/* DCDC compensation */
     43#define TFA989X_PWM_CONTROL		0x41
     44#define TFA989X_CURRENTSENSE1		0x46
     45#define TFA989X_CURRENTSENSE2		0x47
     46#define TFA989X_CURRENTSENSE3		0x48
     47#define TFA989X_CURRENTSENSE4		0x49
     48
     49#define TFA9895_REVISION		0x12
     50#define TFA9897_REVISION		0x97
     51
     52struct tfa989x_rev {
     53	unsigned int rev;
     54	int (*init)(struct regmap *regmap);
     55};
     56
     57struct tfa989x {
     58	const struct tfa989x_rev *rev;
     59	struct regulator *vddd_supply;
     60	struct gpio_desc *rcv_gpiod;
     61};
     62
     63static bool tfa989x_writeable_reg(struct device *dev, unsigned int reg)
     64{
     65	return reg > TFA989X_REVISIONNUMBER;
     66}
     67
     68static bool tfa989x_volatile_reg(struct device *dev, unsigned int reg)
     69{
     70	return reg < TFA989X_REVISIONNUMBER;
     71}
     72
     73static const struct regmap_config tfa989x_regmap = {
     74	.reg_bits = 8,
     75	.val_bits = 16,
     76
     77	.writeable_reg	= tfa989x_writeable_reg,
     78	.volatile_reg	= tfa989x_volatile_reg,
     79	.cache_type	= REGCACHE_RBTREE,
     80};
     81
     82static const char * const chsa_text[] = { "Left", "Right", /* "DSP" */ };
     83static SOC_ENUM_SINGLE_DECL(chsa_enum, TFA989X_I2SREG, TFA989X_I2SREG_CHSA, chsa_text);
     84static const struct snd_kcontrol_new chsa_mux = SOC_DAPM_ENUM("Amp Input", chsa_enum);
     85
     86static const struct snd_soc_dapm_widget tfa989x_dapm_widgets[] = {
     87	SND_SOC_DAPM_OUTPUT("OUT"),
     88	SND_SOC_DAPM_SUPPLY("POWER", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_PWDN, 1, NULL, 0),
     89	SND_SOC_DAPM_OUT_DRV("AMPE", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_AMPE, 0, NULL, 0),
     90
     91	SND_SOC_DAPM_MUX("Amp Input", SND_SOC_NOPM, 0, 0, &chsa_mux),
     92	SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
     93	SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0),
     94};
     95
     96static const struct snd_soc_dapm_route tfa989x_dapm_routes[] = {
     97	{"OUT", NULL, "AMPE"},
     98	{"AMPE", NULL, "POWER"},
     99	{"AMPE", NULL, "Amp Input"},
    100	{"Amp Input", "Left", "AIFINL"},
    101	{"Amp Input", "Right", "AIFINR"},
    102};
    103
    104static int tfa989x_put_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    105{
    106	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    107	struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component);
    108
    109	gpiod_set_value_cansleep(tfa989x->rcv_gpiod, ucontrol->value.enumerated.item[0]);
    110
    111	return snd_soc_put_enum_double(kcontrol, ucontrol);
    112}
    113
    114static const char * const mode_text[] = { "Speaker", "Receiver" };
    115static SOC_ENUM_SINGLE_DECL(mode_enum, TFA989X_I2SREG, TFA989X_I2SREG_RCV, mode_text);
    116static const struct snd_kcontrol_new tfa989x_mode_controls[] = {
    117	SOC_ENUM_EXT("Mode", mode_enum, snd_soc_get_enum_double, tfa989x_put_mode),
    118};
    119
    120static int tfa989x_probe(struct snd_soc_component *component)
    121{
    122	struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component);
    123
    124	if (tfa989x->rev->rev == TFA9897_REVISION)
    125		return snd_soc_add_component_controls(component, tfa989x_mode_controls,
    126						      ARRAY_SIZE(tfa989x_mode_controls));
    127
    128	return 0;
    129}
    130
    131static const struct snd_soc_component_driver tfa989x_component = {
    132	.probe			= tfa989x_probe,
    133	.dapm_widgets		= tfa989x_dapm_widgets,
    134	.num_dapm_widgets	= ARRAY_SIZE(tfa989x_dapm_widgets),
    135	.dapm_routes		= tfa989x_dapm_routes,
    136	.num_dapm_routes	= ARRAY_SIZE(tfa989x_dapm_routes),
    137	.use_pmdown_time	= 1,
    138	.endianness		= 1,
    139	.non_legacy_dai_naming	= 1,
    140};
    141
    142static const unsigned int tfa989x_rates[] = {
    143	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
    144};
    145
    146static int tfa989x_find_sample_rate(unsigned int rate)
    147{
    148	int i;
    149
    150	for (i = 0; i < ARRAY_SIZE(tfa989x_rates); ++i)
    151		if (tfa989x_rates[i] == rate)
    152			return i;
    153
    154	return -EINVAL;
    155}
    156
    157static int tfa989x_hw_params(struct snd_pcm_substream *substream,
    158			     struct snd_pcm_hw_params *params,
    159			     struct snd_soc_dai *dai)
    160{
    161	struct snd_soc_component *component = dai->component;
    162	int sr;
    163
    164	sr = tfa989x_find_sample_rate(params_rate(params));
    165	if (sr < 0)
    166		return sr;
    167
    168	return snd_soc_component_update_bits(component, TFA989X_I2SREG,
    169					     TFA989X_I2SREG_I2SSR_MSK,
    170					     sr << TFA989X_I2SREG_I2SSR);
    171}
    172
    173static const struct snd_soc_dai_ops tfa989x_dai_ops = {
    174	.hw_params = tfa989x_hw_params,
    175};
    176
    177static struct snd_soc_dai_driver tfa989x_dai = {
    178	.name = "tfa989x-hifi",
    179	.playback = {
    180		.stream_name	= "HiFi Playback",
    181		.formats	= SNDRV_PCM_FMTBIT_S16_LE,
    182		.rates		= SNDRV_PCM_RATE_8000_48000,
    183		.rate_min	= 8000,
    184		.rate_max	= 48000,
    185		.channels_min	= 1,
    186		.channels_max	= 2,
    187	},
    188	.ops = &tfa989x_dai_ops,
    189};
    190
    191static const struct reg_sequence tfa9895_reg_init[] = {
    192	/* some other registers must be set for optimal amplifier behaviour */
    193	{ TFA989X_BAT_PROT, 0x13ab },
    194	{ TFA989X_AUDIO_CTR, 0x001f },
    195
    196	/* peak voltage protection is always on, but may be written */
    197	{ TFA989X_SPKR_CALIBRATION, 0x3c4e },
    198
    199	/* TFA989X_SYSCTRL_DCA = 0 */
    200	{ TFA989X_SYS_CTRL, 0x024d },
    201	{ TFA989X_PWM_CONTROL, 0x0308 },
    202	{ TFA989X_CURRENTSENSE4, 0x0e82 },
    203};
    204
    205static int tfa9895_init(struct regmap *regmap)
    206{
    207	return regmap_multi_reg_write(regmap, tfa9895_reg_init,
    208				      ARRAY_SIZE(tfa9895_reg_init));
    209}
    210
    211static const struct tfa989x_rev tfa9895_rev = {
    212	.rev	= TFA9895_REVISION,
    213	.init	= tfa9895_init,
    214};
    215
    216static int tfa9897_init(struct regmap *regmap)
    217{
    218	int ret;
    219
    220	/* Reduce slewrate by clearing iddqtestbst to avoid booster damage */
    221	ret = regmap_write(regmap, TFA989X_CURRENTSENSE3, 0x0300);
    222	if (ret)
    223		return ret;
    224
    225	/* Enable clipping */
    226	ret = regmap_clear_bits(regmap, TFA989X_CURRENTSENSE4, 0x1);
    227	if (ret)
    228		return ret;
    229
    230	/* Set required TDM configuration */
    231	return regmap_write(regmap, 0x14, 0x0);
    232}
    233
    234static const struct tfa989x_rev tfa9897_rev = {
    235	.rev	= TFA9897_REVISION,
    236	.init	= tfa9897_init,
    237};
    238
    239/*
    240 * Note: At the moment this driver bypasses the "CoolFlux DSP" built into the
    241 * TFA989X amplifiers. Unfortunately, there seems to be absolutely
    242 * no documentation for it - the public "short datasheets" do not provide
    243 * any information about the DSP or available registers.
    244 *
    245 * Usually the TFA989X amplifiers are configured through proprietary userspace
    246 * libraries. There are also some (rather complex) kernel drivers but even those
    247 * rely on obscure firmware blobs for configuration (so-called "containers").
    248 * They seem to contain different "profiles" with tuned speaker settings, sample
    249 * rates and volume steps (which would be better exposed as separate ALSA mixers).
    250 *
    251 * Bypassing the DSP disables volume control (and perhaps some speaker
    252 * optimization?), but at least allows using the speaker without obscure
    253 * kernel drivers and firmware.
    254 *
    255 * Ideally NXP (or now Goodix) should release proper documentation for these
    256 * amplifiers so that support for the "CoolFlux DSP" can be implemented properly.
    257 */
    258static int tfa989x_dsp_bypass(struct regmap *regmap)
    259{
    260	int ret;
    261
    262	/* Clear CHSA to bypass DSP and take input from I2S 1 left channel */
    263	ret = regmap_clear_bits(regmap, TFA989X_I2SREG, TFA989X_I2SREG_CHSA_MSK);
    264	if (ret)
    265		return ret;
    266
    267	/* Set DCDC compensation to off and speaker impedance to 8 ohm */
    268	ret = regmap_update_bits(regmap, TFA989X_I2S_SEL_REG,
    269				 TFA989X_I2S_SEL_REG_DCFG_MSK |
    270				 TFA989X_I2S_SEL_REG_SPKR_MSK,
    271				 TFA989X_I2S_SEL_REG_SPKR_MSK);
    272	if (ret)
    273		return ret;
    274
    275	/* Set DCDC to follower mode and disable CoolFlux DSP */
    276	return regmap_clear_bits(regmap, TFA989X_SYS_CTRL,
    277				 BIT(TFA989X_SYS_CTRL_DCA) |
    278				 BIT(TFA989X_SYS_CTRL_CFE) |
    279				 BIT(TFA989X_SYS_CTRL_AMPC));
    280}
    281
    282static void tfa989x_regulator_disable(void *data)
    283{
    284	struct tfa989x *tfa989x = data;
    285
    286	regulator_disable(tfa989x->vddd_supply);
    287}
    288
    289static int tfa989x_i2c_probe(struct i2c_client *i2c)
    290{
    291	struct device *dev = &i2c->dev;
    292	const struct tfa989x_rev *rev;
    293	struct tfa989x *tfa989x;
    294	struct regmap *regmap;
    295	unsigned int val;
    296	int ret;
    297
    298	rev = device_get_match_data(dev);
    299	if (!rev) {
    300		dev_err(dev, "unknown device revision\n");
    301		return -ENODEV;
    302	}
    303
    304	tfa989x = devm_kzalloc(dev, sizeof(*tfa989x), GFP_KERNEL);
    305	if (!tfa989x)
    306		return -ENOMEM;
    307
    308	tfa989x->rev = rev;
    309	i2c_set_clientdata(i2c, tfa989x);
    310
    311	tfa989x->vddd_supply = devm_regulator_get(dev, "vddd");
    312	if (IS_ERR(tfa989x->vddd_supply))
    313		return dev_err_probe(dev, PTR_ERR(tfa989x->vddd_supply),
    314				     "Failed to get vddd regulator\n");
    315
    316	if (tfa989x->rev->rev == TFA9897_REVISION) {
    317		tfa989x->rcv_gpiod = devm_gpiod_get_optional(dev, "rcv", GPIOD_OUT_LOW);
    318		if (IS_ERR(tfa989x->rcv_gpiod))
    319			return PTR_ERR(tfa989x->rcv_gpiod);
    320	}
    321
    322	regmap = devm_regmap_init_i2c(i2c, &tfa989x_regmap);
    323	if (IS_ERR(regmap))
    324		return PTR_ERR(regmap);
    325
    326	ret = regulator_enable(tfa989x->vddd_supply);
    327	if (ret) {
    328		dev_err(dev, "Failed to enable vddd regulator: %d\n", ret);
    329		return ret;
    330	}
    331
    332	ret = devm_add_action_or_reset(dev, tfa989x_regulator_disable, tfa989x);
    333	if (ret)
    334		return ret;
    335
    336	/* Bypass regcache for reset and init sequence */
    337	regcache_cache_bypass(regmap, true);
    338
    339	/* Dummy read to generate i2c clocks, required on some devices */
    340	regmap_read(regmap, TFA989X_REVISIONNUMBER, &val);
    341
    342	ret = regmap_read(regmap, TFA989X_REVISIONNUMBER, &val);
    343	if (ret) {
    344		dev_err(dev, "failed to read revision number: %d\n", ret);
    345		return ret;
    346	}
    347
    348	val &= TFA989X_REVISIONNUMBER_REV_MSK;
    349	if (val != rev->rev) {
    350		dev_err(dev, "invalid revision number, expected %#x, got %#x\n",
    351			rev->rev, val);
    352		return -ENODEV;
    353	}
    354
    355	ret = regmap_write(regmap, TFA989X_SYS_CTRL, BIT(TFA989X_SYS_CTRL_I2CR));
    356	if (ret) {
    357		dev_err(dev, "failed to reset I2C registers: %d\n", ret);
    358		return ret;
    359	}
    360
    361	ret = rev->init(regmap);
    362	if (ret) {
    363		dev_err(dev, "failed to initialize registers: %d\n", ret);
    364		return ret;
    365	}
    366
    367	ret = tfa989x_dsp_bypass(regmap);
    368	if (ret) {
    369		dev_err(dev, "failed to enable DSP bypass: %d\n", ret);
    370		return ret;
    371	}
    372	regcache_cache_bypass(regmap, false);
    373
    374	return devm_snd_soc_register_component(dev, &tfa989x_component,
    375					       &tfa989x_dai, 1);
    376}
    377
    378static const struct of_device_id tfa989x_of_match[] = {
    379	{ .compatible = "nxp,tfa9895", .data = &tfa9895_rev },
    380	{ .compatible = "nxp,tfa9897", .data = &tfa9897_rev },
    381	{ }
    382};
    383MODULE_DEVICE_TABLE(of, tfa989x_of_match);
    384
    385static struct i2c_driver tfa989x_i2c_driver = {
    386	.driver = {
    387		.name = "tfa989x",
    388		.of_match_table = tfa989x_of_match,
    389	},
    390	.probe_new = tfa989x_i2c_probe,
    391};
    392module_i2c_driver(tfa989x_i2c_driver);
    393
    394MODULE_DESCRIPTION("ASoC NXP/Goodix TFA989X (TFA1) driver");
    395MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>");
    396MODULE_LICENSE("GPL");