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

max9850.c (8864B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * max9850.c  --  codec driver for max9850
      4 *
      5 * Copyright (C) 2011 taskit GmbH
      6 *
      7 * Author: Christian Glindkamp <christian.glindkamp@taskit.de>
      8 *
      9 * Initial development of this code was funded by
     10 * MICRONIC Computer Systeme GmbH, https://www.mcsberlin.de/
     11 */
     12
     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/pcm.h>
     19#include <sound/pcm_params.h>
     20#include <sound/soc.h>
     21#include <sound/tlv.h>
     22
     23#include "max9850.h"
     24
     25struct max9850_priv {
     26	struct regmap *regmap;
     27	unsigned int sysclk;
     28};
     29
     30/* these registers are not used at the moment but provided for the sake of
     31 * completeness */
     32static bool max9850_volatile_register(struct device *dev, unsigned int reg)
     33{
     34	switch (reg) {
     35	case MAX9850_STATUSA:
     36	case MAX9850_STATUSB:
     37		return true;
     38	default:
     39		return false;
     40	}
     41}
     42
     43static const struct regmap_config max9850_regmap = {
     44	.reg_bits = 8,
     45	.val_bits = 8,
     46
     47	.max_register = MAX9850_DIGITAL_AUDIO,
     48	.volatile_reg = max9850_volatile_register,
     49	.cache_type = REGCACHE_RBTREE,
     50};
     51
     52static const DECLARE_TLV_DB_RANGE(max9850_tlv,
     53	0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0),
     54	0x20, 0x33, TLV_DB_SCALE_ITEM(-4150, 200, 0),
     55	0x34, 0x37, TLV_DB_SCALE_ITEM(-150, 100, 0),
     56	0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0)
     57);
     58
     59static const struct snd_kcontrol_new max9850_controls[] = {
     60SOC_SINGLE_TLV("Headphone Volume", MAX9850_VOLUME, 0, 0x3f, 1, max9850_tlv),
     61SOC_SINGLE("Headphone Switch", MAX9850_VOLUME, 7, 1, 1),
     62SOC_SINGLE("Mono Switch", MAX9850_GENERAL_PURPOSE, 2, 1, 0),
     63};
     64
     65static const struct snd_kcontrol_new max9850_mixer_controls[] = {
     66	SOC_DAPM_SINGLE("Line In Switch", MAX9850_ENABLE, 1, 1, 0),
     67};
     68
     69static const struct snd_soc_dapm_widget max9850_dapm_widgets[] = {
     70SND_SOC_DAPM_SUPPLY("Charge Pump 1", MAX9850_ENABLE, 4, 0, NULL, 0),
     71SND_SOC_DAPM_SUPPLY("Charge Pump 2", MAX9850_ENABLE, 5, 0, NULL, 0),
     72SND_SOC_DAPM_SUPPLY("MCLK", MAX9850_ENABLE, 6, 0, NULL, 0),
     73SND_SOC_DAPM_SUPPLY("SHDN", MAX9850_ENABLE, 7, 0, NULL, 0),
     74SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", MAX9850_ENABLE, 2, 0,
     75		&max9850_mixer_controls[0],
     76		ARRAY_SIZE(max9850_mixer_controls)),
     77SND_SOC_DAPM_PGA("Headphone Output", MAX9850_ENABLE, 3, 0, NULL, 0),
     78SND_SOC_DAPM_DAC("DAC", "HiFi Playback", MAX9850_ENABLE, 0, 0),
     79SND_SOC_DAPM_OUTPUT("OUTL"),
     80SND_SOC_DAPM_OUTPUT("HPL"),
     81SND_SOC_DAPM_OUTPUT("OUTR"),
     82SND_SOC_DAPM_OUTPUT("HPR"),
     83SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
     84SND_SOC_DAPM_INPUT("INL"),
     85SND_SOC_DAPM_INPUT("INR"),
     86};
     87
     88static const struct snd_soc_dapm_route max9850_dapm_routes[] = {
     89	/* output mixer */
     90	{"Output Mixer", NULL, "DAC"},
     91	{"Output Mixer", "Line In Switch", "Line Input"},
     92
     93	/* outputs */
     94	{"Headphone Output", NULL, "Output Mixer"},
     95	{"HPL", NULL, "Headphone Output"},
     96	{"HPR", NULL, "Headphone Output"},
     97	{"OUTL", NULL, "Output Mixer"},
     98	{"OUTR", NULL, "Output Mixer"},
     99
    100	/* inputs */
    101	{"Line Input", NULL, "INL"},
    102	{"Line Input", NULL, "INR"},
    103
    104	/* supplies */
    105	{"Output Mixer", NULL, "Charge Pump 1"},
    106	{"Output Mixer", NULL, "Charge Pump 2"},
    107	{"Output Mixer", NULL, "SHDN"},
    108	{"DAC", NULL, "MCLK"},
    109};
    110
    111static int max9850_hw_params(struct snd_pcm_substream *substream,
    112			     struct snd_pcm_hw_params *params,
    113			     struct snd_soc_dai *dai)
    114{
    115	struct snd_soc_component *component = dai->component;
    116	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
    117	u64 lrclk_div;
    118	u8 sf, da;
    119
    120	if (!max9850->sysclk)
    121		return -EINVAL;
    122
    123	/* lrclk_div = 2^22 * rate / iclk with iclk = mclk / sf */
    124	sf = (snd_soc_component_read(component, MAX9850_CLOCK) >> 2) + 1;
    125	lrclk_div = (1 << 22);
    126	lrclk_div *= params_rate(params);
    127	lrclk_div *= sf;
    128	do_div(lrclk_div, max9850->sysclk);
    129
    130	snd_soc_component_write(component, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);
    131	snd_soc_component_write(component, MAX9850_LRCLK_LSB, lrclk_div & 0xff);
    132
    133	switch (params_width(params)) {
    134	case 16:
    135		da = 0;
    136		break;
    137	case 20:
    138		da = 0x2;
    139		break;
    140	case 24:
    141		da = 0x3;
    142		break;
    143	default:
    144		return -EINVAL;
    145	}
    146	snd_soc_component_update_bits(component, MAX9850_DIGITAL_AUDIO, 0x3, da);
    147
    148	return 0;
    149}
    150
    151static int max9850_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    152		int clk_id, unsigned int freq, int dir)
    153{
    154	struct snd_soc_component *component = codec_dai->component;
    155	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
    156
    157	/* calculate mclk -> iclk divider */
    158	if (freq <= 13000000)
    159		snd_soc_component_write(component, MAX9850_CLOCK, 0x0);
    160	else if (freq <= 26000000)
    161		snd_soc_component_write(component, MAX9850_CLOCK, 0x4);
    162	else if (freq <= 40000000)
    163		snd_soc_component_write(component, MAX9850_CLOCK, 0x8);
    164	else
    165		return -EINVAL;
    166
    167	max9850->sysclk = freq;
    168	return 0;
    169}
    170
    171static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
    172{
    173	struct snd_soc_component *component = codec_dai->component;
    174	u8 da = 0;
    175
    176	/* set clock provider for audio interface */
    177	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
    178	case SND_SOC_DAIFMT_CBP_CFP:
    179		da |= MAX9850_MASTER;
    180		break;
    181	case SND_SOC_DAIFMT_CBC_CFC:
    182		break;
    183	default:
    184		return -EINVAL;
    185	}
    186
    187	/* interface format */
    188	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    189	case SND_SOC_DAIFMT_I2S:
    190		da |= MAX9850_DLY;
    191		break;
    192	case SND_SOC_DAIFMT_RIGHT_J:
    193		da |= MAX9850_RTJ;
    194		break;
    195	case SND_SOC_DAIFMT_LEFT_J:
    196		break;
    197	default:
    198		return -EINVAL;
    199	}
    200
    201	/* clock inversion */
    202	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
    203	case SND_SOC_DAIFMT_NB_NF:
    204		break;
    205	case SND_SOC_DAIFMT_IB_IF:
    206		da |= MAX9850_BCINV | MAX9850_INV;
    207		break;
    208	case SND_SOC_DAIFMT_IB_NF:
    209		da |= MAX9850_BCINV;
    210		break;
    211	case SND_SOC_DAIFMT_NB_IF:
    212		da |= MAX9850_INV;
    213		break;
    214	default:
    215		return -EINVAL;
    216	}
    217
    218	/* set da */
    219	snd_soc_component_write(component, MAX9850_DIGITAL_AUDIO, da);
    220
    221	return 0;
    222}
    223
    224static int max9850_set_bias_level(struct snd_soc_component *component,
    225				  enum snd_soc_bias_level level)
    226{
    227	struct max9850_priv *max9850 = snd_soc_component_get_drvdata(component);
    228	int ret;
    229
    230	switch (level) {
    231	case SND_SOC_BIAS_ON:
    232		break;
    233	case SND_SOC_BIAS_PREPARE:
    234		break;
    235	case SND_SOC_BIAS_STANDBY:
    236		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
    237			ret = regcache_sync(max9850->regmap);
    238			if (ret) {
    239				dev_err(component->dev,
    240					"Failed to sync cache: %d\n", ret);
    241				return ret;
    242			}
    243		}
    244		break;
    245	case SND_SOC_BIAS_OFF:
    246		break;
    247	}
    248	return 0;
    249}
    250
    251#define MAX9850_RATES SNDRV_PCM_RATE_8000_48000
    252
    253#define MAX9850_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
    254	SNDRV_PCM_FMTBIT_S24_LE)
    255
    256static const struct snd_soc_dai_ops max9850_dai_ops = {
    257	.hw_params	= max9850_hw_params,
    258	.set_sysclk	= max9850_set_dai_sysclk,
    259	.set_fmt	= max9850_set_dai_fmt,
    260};
    261
    262static struct snd_soc_dai_driver max9850_dai = {
    263	.name = "max9850-hifi",
    264	.playback = {
    265		.stream_name = "Playback",
    266		.channels_min = 1,
    267		.channels_max = 2,
    268		.rates = MAX9850_RATES,
    269		.formats = MAX9850_FORMATS
    270	},
    271	.ops = &max9850_dai_ops,
    272};
    273
    274static int max9850_probe(struct snd_soc_component *component)
    275{
    276	/* enable zero-detect */
    277	snd_soc_component_update_bits(component, MAX9850_GENERAL_PURPOSE, 1, 1);
    278	/* enable slew-rate control */
    279	snd_soc_component_update_bits(component, MAX9850_VOLUME, 0x40, 0x40);
    280	/* set slew-rate 125ms */
    281	snd_soc_component_update_bits(component, MAX9850_CHARGE_PUMP, 0xff, 0xc0);
    282
    283	return 0;
    284}
    285
    286static const struct snd_soc_component_driver soc_component_dev_max9850 = {
    287	.probe			= max9850_probe,
    288	.set_bias_level		= max9850_set_bias_level,
    289	.controls		= max9850_controls,
    290	.num_controls		= ARRAY_SIZE(max9850_controls),
    291	.dapm_widgets		= max9850_dapm_widgets,
    292	.num_dapm_widgets	= ARRAY_SIZE(max9850_dapm_widgets),
    293	.dapm_routes		= max9850_dapm_routes,
    294	.num_dapm_routes	= ARRAY_SIZE(max9850_dapm_routes),
    295	.suspend_bias_off	= 1,
    296	.idle_bias_on		= 1,
    297	.use_pmdown_time	= 1,
    298	.endianness		= 1,
    299	.non_legacy_dai_naming	= 1,
    300};
    301
    302static int max9850_i2c_probe(struct i2c_client *i2c)
    303{
    304	struct max9850_priv *max9850;
    305	int ret;
    306
    307	max9850 = devm_kzalloc(&i2c->dev, sizeof(struct max9850_priv),
    308			       GFP_KERNEL);
    309	if (max9850 == NULL)
    310		return -ENOMEM;
    311
    312	max9850->regmap = devm_regmap_init_i2c(i2c, &max9850_regmap);
    313	if (IS_ERR(max9850->regmap))
    314		return PTR_ERR(max9850->regmap);
    315
    316	i2c_set_clientdata(i2c, max9850);
    317
    318	ret = devm_snd_soc_register_component(&i2c->dev,
    319			&soc_component_dev_max9850, &max9850_dai, 1);
    320	return ret;
    321}
    322
    323static const struct i2c_device_id max9850_i2c_id[] = {
    324	{ "max9850", 0 },
    325	{ }
    326};
    327MODULE_DEVICE_TABLE(i2c, max9850_i2c_id);
    328
    329static struct i2c_driver max9850_i2c_driver = {
    330	.driver = {
    331		.name = "max9850",
    332	},
    333	.probe_new = max9850_i2c_probe,
    334	.id_table = max9850_i2c_id,
    335};
    336
    337module_i2c_driver(max9850_i2c_driver);
    338
    339MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>");
    340MODULE_DESCRIPTION("ASoC MAX9850 codec driver");
    341MODULE_LICENSE("GPL");