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

ssm4567.c (13865B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * SSM4567 amplifier audio driver
      4 *
      5 * Copyright 2014 Google Chromium project.
      6 *  Author: Anatol Pomozov <anatol@chromium.org>
      7 *
      8 * Based on code copyright/by:
      9 *   Copyright 2013 Analog Devices Inc.
     10 */
     11
     12#include <linux/acpi.h>
     13#include <linux/module.h>
     14#include <linux/init.h>
     15#include <linux/i2c.h>
     16#include <linux/regmap.h>
     17#include <linux/slab.h>
     18#include <sound/core.h>
     19#include <sound/pcm.h>
     20#include <sound/pcm_params.h>
     21#include <sound/soc.h>
     22#include <sound/initval.h>
     23#include <sound/tlv.h>
     24
     25#define SSM4567_REG_POWER_CTRL		0x00
     26#define SSM4567_REG_AMP_SNS_CTRL		0x01
     27#define SSM4567_REG_DAC_CTRL		0x02
     28#define SSM4567_REG_DAC_VOLUME		0x03
     29#define SSM4567_REG_SAI_CTRL_1		0x04
     30#define SSM4567_REG_SAI_CTRL_2		0x05
     31#define SSM4567_REG_SAI_PLACEMENT_1		0x06
     32#define SSM4567_REG_SAI_PLACEMENT_2		0x07
     33#define SSM4567_REG_SAI_PLACEMENT_3		0x08
     34#define SSM4567_REG_SAI_PLACEMENT_4		0x09
     35#define SSM4567_REG_SAI_PLACEMENT_5		0x0a
     36#define SSM4567_REG_SAI_PLACEMENT_6		0x0b
     37#define SSM4567_REG_BATTERY_V_OUT		0x0c
     38#define SSM4567_REG_LIMITER_CTRL_1		0x0d
     39#define SSM4567_REG_LIMITER_CTRL_2		0x0e
     40#define SSM4567_REG_LIMITER_CTRL_3		0x0f
     41#define SSM4567_REG_STATUS_1		0x10
     42#define SSM4567_REG_STATUS_2		0x11
     43#define SSM4567_REG_FAULT_CTRL		0x12
     44#define SSM4567_REG_PDM_CTRL		0x13
     45#define SSM4567_REG_MCLK_RATIO		0x14
     46#define SSM4567_REG_BOOST_CTRL_1		0x15
     47#define SSM4567_REG_BOOST_CTRL_2		0x16
     48#define SSM4567_REG_SOFT_RESET		0xff
     49
     50/* POWER_CTRL */
     51#define SSM4567_POWER_APWDN_EN		BIT(7)
     52#define SSM4567_POWER_BSNS_PWDN		BIT(6)
     53#define SSM4567_POWER_VSNS_PWDN		BIT(5)
     54#define SSM4567_POWER_ISNS_PWDN		BIT(4)
     55#define SSM4567_POWER_BOOST_PWDN		BIT(3)
     56#define SSM4567_POWER_AMP_PWDN		BIT(2)
     57#define SSM4567_POWER_VBAT_ONLY		BIT(1)
     58#define SSM4567_POWER_SPWDN			BIT(0)
     59
     60/* DAC_CTRL */
     61#define SSM4567_DAC_HV			BIT(7)
     62#define SSM4567_DAC_MUTE		BIT(6)
     63#define SSM4567_DAC_HPF			BIT(5)
     64#define SSM4567_DAC_LPM			BIT(4)
     65#define SSM4567_DAC_FS_MASK	0x7
     66#define SSM4567_DAC_FS_8000_12000	0x0
     67#define SSM4567_DAC_FS_16000_24000	0x1
     68#define SSM4567_DAC_FS_32000_48000	0x2
     69#define SSM4567_DAC_FS_64000_96000	0x3
     70#define SSM4567_DAC_FS_128000_192000	0x4
     71
     72/* SAI_CTRL_1 */
     73#define SSM4567_SAI_CTRL_1_BCLK			BIT(6)
     74#define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK	(0x3 << 4)
     75#define SSM4567_SAI_CTRL_1_TDM_BLCKS_32		(0x0 << 4)
     76#define SSM4567_SAI_CTRL_1_TDM_BLCKS_48		(0x1 << 4)
     77#define SSM4567_SAI_CTRL_1_TDM_BLCKS_64		(0x2 << 4)
     78#define SSM4567_SAI_CTRL_1_FSYNC		BIT(3)
     79#define SSM4567_SAI_CTRL_1_LJ			BIT(2)
     80#define SSM4567_SAI_CTRL_1_TDM			BIT(1)
     81#define SSM4567_SAI_CTRL_1_PDM			BIT(0)
     82
     83/* SAI_CTRL_2 */
     84#define SSM4567_SAI_CTRL_2_AUTO_SLOT		BIT(3)
     85#define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK	0x7
     86#define SSM4567_SAI_CTRL_2_TDM_SLOT(x)		(x)
     87
     88struct ssm4567 {
     89	struct regmap *regmap;
     90};
     91
     92static const struct reg_default ssm4567_reg_defaults[] = {
     93	{ SSM4567_REG_POWER_CTRL,	0x81 },
     94	{ SSM4567_REG_AMP_SNS_CTRL, 0x09 },
     95	{ SSM4567_REG_DAC_CTRL, 0x32 },
     96	{ SSM4567_REG_DAC_VOLUME, 0x40 },
     97	{ SSM4567_REG_SAI_CTRL_1, 0x00 },
     98	{ SSM4567_REG_SAI_CTRL_2, 0x08 },
     99	{ SSM4567_REG_SAI_PLACEMENT_1, 0x01 },
    100	{ SSM4567_REG_SAI_PLACEMENT_2, 0x20 },
    101	{ SSM4567_REG_SAI_PLACEMENT_3, 0x32 },
    102	{ SSM4567_REG_SAI_PLACEMENT_4, 0x07 },
    103	{ SSM4567_REG_SAI_PLACEMENT_5, 0x07 },
    104	{ SSM4567_REG_SAI_PLACEMENT_6, 0x07 },
    105	{ SSM4567_REG_BATTERY_V_OUT, 0x00 },
    106	{ SSM4567_REG_LIMITER_CTRL_1, 0xa4 },
    107	{ SSM4567_REG_LIMITER_CTRL_2, 0x73 },
    108	{ SSM4567_REG_LIMITER_CTRL_3, 0x00 },
    109	{ SSM4567_REG_STATUS_1, 0x00 },
    110	{ SSM4567_REG_STATUS_2, 0x00 },
    111	{ SSM4567_REG_FAULT_CTRL, 0x30 },
    112	{ SSM4567_REG_PDM_CTRL, 0x40 },
    113	{ SSM4567_REG_MCLK_RATIO, 0x11 },
    114	{ SSM4567_REG_BOOST_CTRL_1, 0x03 },
    115	{ SSM4567_REG_BOOST_CTRL_2, 0x00 },
    116	{ SSM4567_REG_SOFT_RESET, 0x00 },
    117};
    118
    119
    120static bool ssm4567_readable_reg(struct device *dev, unsigned int reg)
    121{
    122	switch (reg) {
    123	case SSM4567_REG_POWER_CTRL ... SSM4567_REG_BOOST_CTRL_2:
    124		return true;
    125	default:
    126		return false;
    127	}
    128
    129}
    130
    131static bool ssm4567_writeable_reg(struct device *dev, unsigned int reg)
    132{
    133	switch (reg) {
    134	case SSM4567_REG_POWER_CTRL ... SSM4567_REG_SAI_PLACEMENT_6:
    135	case SSM4567_REG_LIMITER_CTRL_1 ... SSM4567_REG_LIMITER_CTRL_3:
    136	case SSM4567_REG_FAULT_CTRL ... SSM4567_REG_BOOST_CTRL_2:
    137	/* The datasheet states that soft reset register is read-only,
    138	 * but logically it is write-only. */
    139	case SSM4567_REG_SOFT_RESET:
    140		return true;
    141	default:
    142		return false;
    143	}
    144}
    145
    146static bool ssm4567_volatile_reg(struct device *dev, unsigned int reg)
    147{
    148	switch (reg) {
    149	case SSM4567_REG_BATTERY_V_OUT:
    150	case SSM4567_REG_STATUS_1 ... SSM4567_REG_STATUS_2:
    151	case SSM4567_REG_SOFT_RESET:
    152		return true;
    153	default:
    154		return false;
    155	}
    156}
    157
    158static const DECLARE_TLV_DB_MINMAX_MUTE(ssm4567_vol_tlv, -7125, 2400);
    159
    160static const struct snd_kcontrol_new ssm4567_snd_controls[] = {
    161	SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0,
    162		0xff, 1, ssm4567_vol_tlv),
    163	SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0),
    164	SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL,
    165		5, 1, 0),
    166};
    167
    168static const struct snd_kcontrol_new ssm4567_amplifier_boost_control =
    169	SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1);
    170
    171static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
    172	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1),
    173	SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1,
    174		&ssm4567_amplifier_boost_control),
    175
    176	SND_SOC_DAPM_SIGGEN("Sense"),
    177
    178	SND_SOC_DAPM_PGA("Current Sense", SSM4567_REG_POWER_CTRL, 4, 1, NULL, 0),
    179	SND_SOC_DAPM_PGA("Voltage Sense", SSM4567_REG_POWER_CTRL, 5, 1, NULL, 0),
    180	SND_SOC_DAPM_PGA("VBAT Sense", SSM4567_REG_POWER_CTRL, 6, 1, NULL, 0),
    181
    182	SND_SOC_DAPM_OUTPUT("OUT"),
    183};
    184
    185static const struct snd_soc_dapm_route ssm4567_routes[] = {
    186	{ "OUT", NULL, "Amplifier Boost" },
    187	{ "Amplifier Boost", "Switch", "DAC" },
    188	{ "OUT", NULL, "DAC" },
    189
    190	{ "Current Sense", NULL, "Sense" },
    191	{ "Voltage Sense", NULL, "Sense" },
    192	{ "VBAT Sense", NULL, "Sense" },
    193	{ "Capture Sense", NULL, "Current Sense" },
    194	{ "Capture Sense", NULL, "Voltage Sense" },
    195	{ "Capture Sense", NULL, "VBAT Sense" },
    196};
    197
    198static int ssm4567_hw_params(struct snd_pcm_substream *substream,
    199	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
    200{
    201	struct snd_soc_component *component = dai->component;
    202	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
    203	unsigned int rate = params_rate(params);
    204	unsigned int dacfs;
    205
    206	if (rate >= 8000 && rate <= 12000)
    207		dacfs = SSM4567_DAC_FS_8000_12000;
    208	else if (rate >= 16000 && rate <= 24000)
    209		dacfs = SSM4567_DAC_FS_16000_24000;
    210	else if (rate >= 32000 && rate <= 48000)
    211		dacfs = SSM4567_DAC_FS_32000_48000;
    212	else if (rate >= 64000 && rate <= 96000)
    213		dacfs = SSM4567_DAC_FS_64000_96000;
    214	else if (rate >= 128000 && rate <= 192000)
    215		dacfs = SSM4567_DAC_FS_128000_192000;
    216	else
    217		return -EINVAL;
    218
    219	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
    220				SSM4567_DAC_FS_MASK, dacfs);
    221}
    222
    223static int ssm4567_mute(struct snd_soc_dai *dai, int mute, int direction)
    224{
    225	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(dai->component);
    226	unsigned int val;
    227
    228	val = mute ? SSM4567_DAC_MUTE : 0;
    229	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
    230			SSM4567_DAC_MUTE, val);
    231}
    232
    233static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
    234	unsigned int rx_mask, int slots, int width)
    235{
    236	struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
    237	unsigned int blcks;
    238	int slot;
    239	int ret;
    240
    241	if (tx_mask == 0)
    242		return -EINVAL;
    243
    244	if (rx_mask && rx_mask != tx_mask)
    245		return -EINVAL;
    246
    247	slot = __ffs(tx_mask);
    248	if (tx_mask != BIT(slot))
    249		return -EINVAL;
    250
    251	switch (width) {
    252	case 32:
    253		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32;
    254		break;
    255	case 48:
    256		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48;
    257		break;
    258	case 64:
    259		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64;
    260		break;
    261	default:
    262		return -EINVAL;
    263	}
    264
    265	ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2,
    266		SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK,
    267		SSM4567_SAI_CTRL_2_TDM_SLOT(slot));
    268	if (ret)
    269		return ret;
    270
    271	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
    272		SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks);
    273}
    274
    275static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
    276{
    277	struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
    278	unsigned int ctrl1 = 0;
    279	bool invert_fclk;
    280
    281	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    282	case SND_SOC_DAIFMT_CBS_CFS:
    283		break;
    284	default:
    285		return -EINVAL;
    286	}
    287
    288	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
    289	case SND_SOC_DAIFMT_NB_NF:
    290		invert_fclk = false;
    291		break;
    292	case SND_SOC_DAIFMT_IB_NF:
    293		ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
    294		invert_fclk = false;
    295		break;
    296	case SND_SOC_DAIFMT_NB_IF:
    297		ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
    298		invert_fclk = true;
    299		break;
    300	case SND_SOC_DAIFMT_IB_IF:
    301		ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
    302		invert_fclk = true;
    303		break;
    304	default:
    305		return -EINVAL;
    306	}
    307
    308	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    309	case SND_SOC_DAIFMT_I2S:
    310		break;
    311	case SND_SOC_DAIFMT_LEFT_J:
    312		ctrl1 |= SSM4567_SAI_CTRL_1_LJ;
    313		invert_fclk = !invert_fclk;
    314		break;
    315	case SND_SOC_DAIFMT_DSP_A:
    316		ctrl1 |= SSM4567_SAI_CTRL_1_TDM;
    317		break;
    318	case SND_SOC_DAIFMT_DSP_B:
    319		ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ;
    320		break;
    321	case SND_SOC_DAIFMT_PDM:
    322		ctrl1 |= SSM4567_SAI_CTRL_1_PDM;
    323		break;
    324	default:
    325		return -EINVAL;
    326	}
    327
    328	if (invert_fclk)
    329		ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
    330
    331	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
    332			SSM4567_SAI_CTRL_1_BCLK |
    333			SSM4567_SAI_CTRL_1_FSYNC |
    334			SSM4567_SAI_CTRL_1_LJ |
    335			SSM4567_SAI_CTRL_1_TDM |
    336			SSM4567_SAI_CTRL_1_PDM,
    337			ctrl1);
    338}
    339
    340static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
    341{
    342	int ret = 0;
    343
    344	if (!enable) {
    345		ret = regmap_update_bits(ssm4567->regmap,
    346			SSM4567_REG_POWER_CTRL,
    347			SSM4567_POWER_SPWDN, SSM4567_POWER_SPWDN);
    348		regcache_mark_dirty(ssm4567->regmap);
    349	}
    350
    351	regcache_cache_only(ssm4567->regmap, !enable);
    352
    353	if (enable) {
    354		ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET,
    355			0x00);
    356		if (ret)
    357			return ret;
    358
    359		ret = regmap_update_bits(ssm4567->regmap,
    360			SSM4567_REG_POWER_CTRL,
    361			SSM4567_POWER_SPWDN, 0x00);
    362		regcache_sync(ssm4567->regmap);
    363	}
    364
    365	return ret;
    366}
    367
    368static int ssm4567_set_bias_level(struct snd_soc_component *component,
    369	enum snd_soc_bias_level level)
    370{
    371	struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
    372	int ret = 0;
    373
    374	switch (level) {
    375	case SND_SOC_BIAS_ON:
    376		break;
    377	case SND_SOC_BIAS_PREPARE:
    378		break;
    379	case SND_SOC_BIAS_STANDBY:
    380		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
    381			ret = ssm4567_set_power(ssm4567, true);
    382		break;
    383	case SND_SOC_BIAS_OFF:
    384		ret = ssm4567_set_power(ssm4567, false);
    385		break;
    386	}
    387
    388	return ret;
    389}
    390
    391static const struct snd_soc_dai_ops ssm4567_dai_ops = {
    392	.hw_params	= ssm4567_hw_params,
    393	.mute_stream	= ssm4567_mute,
    394	.set_fmt	= ssm4567_set_dai_fmt,
    395	.set_tdm_slot	= ssm4567_set_tdm_slot,
    396	.no_capture_mute = 1,
    397};
    398
    399static struct snd_soc_dai_driver ssm4567_dai = {
    400	.name = "ssm4567-hifi",
    401	.playback = {
    402		.stream_name = "Playback",
    403		.channels_min = 1,
    404		.channels_max = 1,
    405		.rates = SNDRV_PCM_RATE_8000_192000,
    406		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
    407			SNDRV_PCM_FMTBIT_S32,
    408	},
    409	.capture = {
    410		.stream_name = "Capture Sense",
    411		.channels_min = 1,
    412		.channels_max = 1,
    413		.rates = SNDRV_PCM_RATE_8000_192000,
    414		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
    415			SNDRV_PCM_FMTBIT_S32,
    416	},
    417	.ops = &ssm4567_dai_ops,
    418};
    419
    420static const struct snd_soc_component_driver ssm4567_component_driver = {
    421	.set_bias_level		= ssm4567_set_bias_level,
    422	.controls		= ssm4567_snd_controls,
    423	.num_controls		= ARRAY_SIZE(ssm4567_snd_controls),
    424	.dapm_widgets		= ssm4567_dapm_widgets,
    425	.num_dapm_widgets	= ARRAY_SIZE(ssm4567_dapm_widgets),
    426	.dapm_routes		= ssm4567_routes,
    427	.num_dapm_routes	= ARRAY_SIZE(ssm4567_routes),
    428	.use_pmdown_time	= 1,
    429	.endianness		= 1,
    430	.non_legacy_dai_naming	= 1,
    431};
    432
    433static const struct regmap_config ssm4567_regmap_config = {
    434	.val_bits = 8,
    435	.reg_bits = 8,
    436
    437	.max_register = SSM4567_REG_SOFT_RESET,
    438	.readable_reg = ssm4567_readable_reg,
    439	.writeable_reg = ssm4567_writeable_reg,
    440	.volatile_reg = ssm4567_volatile_reg,
    441
    442	.cache_type = REGCACHE_RBTREE,
    443	.reg_defaults = ssm4567_reg_defaults,
    444	.num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults),
    445};
    446
    447static int ssm4567_i2c_probe(struct i2c_client *i2c)
    448{
    449	struct ssm4567 *ssm4567;
    450	int ret;
    451
    452	ssm4567 = devm_kzalloc(&i2c->dev, sizeof(*ssm4567), GFP_KERNEL);
    453	if (ssm4567 == NULL)
    454		return -ENOMEM;
    455
    456	i2c_set_clientdata(i2c, ssm4567);
    457
    458	ssm4567->regmap = devm_regmap_init_i2c(i2c, &ssm4567_regmap_config);
    459	if (IS_ERR(ssm4567->regmap))
    460		return PTR_ERR(ssm4567->regmap);
    461
    462	ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, 0x00);
    463	if (ret)
    464		return ret;
    465
    466	ret = ssm4567_set_power(ssm4567, false);
    467	if (ret)
    468		return ret;
    469
    470	return devm_snd_soc_register_component(&i2c->dev, &ssm4567_component_driver,
    471			&ssm4567_dai, 1);
    472}
    473
    474static const struct i2c_device_id ssm4567_i2c_ids[] = {
    475	{ "ssm4567", 0 },
    476	{ }
    477};
    478MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids);
    479
    480#ifdef CONFIG_OF
    481static const struct of_device_id ssm4567_of_match[] = {
    482	{ .compatible = "adi,ssm4567", },
    483	{ }
    484};
    485MODULE_DEVICE_TABLE(of, ssm4567_of_match);
    486#endif
    487
    488#ifdef CONFIG_ACPI
    489
    490static const struct acpi_device_id ssm4567_acpi_match[] = {
    491	{ "INT343B", 0 },
    492	{},
    493};
    494MODULE_DEVICE_TABLE(acpi, ssm4567_acpi_match);
    495
    496#endif
    497
    498static struct i2c_driver ssm4567_driver = {
    499	.driver = {
    500		.name = "ssm4567",
    501		.of_match_table = of_match_ptr(ssm4567_of_match),
    502		.acpi_match_table = ACPI_PTR(ssm4567_acpi_match),
    503	},
    504	.probe_new = ssm4567_i2c_probe,
    505	.id_table = ssm4567_i2c_ids,
    506};
    507module_i2c_driver(ssm4567_driver);
    508
    509MODULE_DESCRIPTION("ASoC SSM4567 driver");
    510MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>");
    511MODULE_LICENSE("GPL");