brintos

brintos / linux-shallow public Read only

0
0
Text · 15.1 KiB · 1d3c4d9 Raw
561 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * AD193X Audio Codec driver supporting AD1936/7/8/94 *5 * Copyright 2010 Analog Devices Inc.6 */7 8#include <linux/module.h>9#include <linux/kernel.h>10#include <linux/device.h>11#include <linux/regmap.h>12#include <linux/slab.h>13#include <sound/core.h>14#include <sound/pcm.h>15#include <sound/pcm_params.h>16#include <sound/initval.h>17#include <sound/soc.h>18#include <sound/tlv.h>19 20#include "ad193x.h"21 22/* codec private data */23struct ad193x_priv {24	struct regmap *regmap;25	enum ad193x_type type;26	int sysclk;27};28 29/*30 * AD193X volume/mute/de-emphasis etc. controls31 */32static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};33 34static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1,35			    ad193x_deemp);36 37static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);38 39static const unsigned int ad193x_sb[] = {32};40 41static struct snd_pcm_hw_constraint_list constr = {42	.list = ad193x_sb,43	.count = ARRAY_SIZE(ad193x_sb),44};45 46static const struct snd_kcontrol_new ad193x_snd_controls[] = {47	/* DAC volume control */48	SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL,49			AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv),50	SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL,51			AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv),52	SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL,53			AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv),54	SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL,55			AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv),56 57	/* DAC switch control */58	SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE,59		AD193X_DACR1_MUTE, 1, 1),60	SOC_DOUBLE("DAC2 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL2_MUTE,61		AD193X_DACR2_MUTE, 1, 1),62	SOC_DOUBLE("DAC3 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL3_MUTE,63		AD193X_DACR3_MUTE, 1, 1),64	SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE,65		AD193X_DACR4_MUTE, 1, 1),66 67	/* DAC de-emphasis */68	SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum),69};70 71static const struct snd_kcontrol_new ad193x_adc_snd_controls[] = {72	/* ADC switch control */73	SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,74		AD193X_ADCR1_MUTE, 1, 1),75	SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE,76		AD193X_ADCR2_MUTE, 1, 1),77 78	/* ADC high-pass filter */79	SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0,80			AD193X_ADC_HIGHPASS_FILTER, 1, 0),81};82 83static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {84	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),85	SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),86	SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),87	SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),88	SND_SOC_DAPM_VMID("VMID"),89	SND_SOC_DAPM_OUTPUT("DAC1OUT"),90	SND_SOC_DAPM_OUTPUT("DAC2OUT"),91	SND_SOC_DAPM_OUTPUT("DAC3OUT"),92	SND_SOC_DAPM_OUTPUT("DAC4OUT"),93};94 95static const struct snd_soc_dapm_widget ad193x_adc_widgets[] = {96	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),97	SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),98	SND_SOC_DAPM_INPUT("ADC1IN"),99	SND_SOC_DAPM_INPUT("ADC2IN"),100};101 102static int ad193x_check_pll(struct snd_soc_dapm_widget *source,103			    struct snd_soc_dapm_widget *sink)104{105	struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);106	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);107 108	return !!ad193x->sysclk;109}110 111static const struct snd_soc_dapm_route audio_paths[] = {112	{ "DAC", NULL, "SYSCLK" },113	{ "DAC Output", NULL, "DAC" },114	{ "DAC Output", NULL, "VMID" },115	{ "DAC1OUT", NULL, "DAC Output" },116	{ "DAC2OUT", NULL, "DAC Output" },117	{ "DAC3OUT", NULL, "DAC Output" },118	{ "DAC4OUT", NULL, "DAC Output" },119	{ "SYSCLK", NULL, "PLL_PWR", &ad193x_check_pll },120};121 122static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = {123	{ "ADC", NULL, "SYSCLK" },124	{ "ADC", NULL, "ADC_PWR" },125	{ "ADC", NULL, "ADC1IN" },126	{ "ADC", NULL, "ADC2IN" },127};128 129static inline bool ad193x_has_adc(const struct ad193x_priv *ad193x)130{131	switch (ad193x->type) {132	case AD1933:133	case AD1934:134		return false;135	default:136		break;137	}138 139	return true;140}141 142/*143 * DAI ops entries144 */145 146static int ad193x_mute(struct snd_soc_dai *dai, int mute, int direction)147{148	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);149 150	if (mute)151		regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,152				    AD193X_DAC_MASTER_MUTE,153				    AD193X_DAC_MASTER_MUTE);154	else155		regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,156				    AD193X_DAC_MASTER_MUTE, 0);157 158	return 0;159}160 161static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,162			       unsigned int rx_mask, int slots, int width)163{164	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);165	unsigned int channels;166 167	switch (slots) {168	case 2:169		channels = AD193X_2_CHANNELS;170		break;171	case 4:172		channels = AD193X_4_CHANNELS;173		break;174	case 8:175		channels = AD193X_8_CHANNELS;176		break;177	case 16:178		channels = AD193X_16_CHANNELS;179		break;180	default:181		return -EINVAL;182	}183 184	regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,185		AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT);186	if (ad193x_has_adc(ad193x))187		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,188				   AD193X_ADC_CHAN_MASK,189				   channels << AD193X_ADC_CHAN_SHFT);190 191	return 0;192}193 194static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,195		unsigned int fmt)196{197	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(codec_dai->component);198	unsigned int adc_serfmt = 0;199	unsigned int dac_serfmt = 0;200	unsigned int adc_fmt = 0;201	unsigned int dac_fmt = 0;202 203	/* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S204	 * with TDM), ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) and DAC I2S mode205	 * (SND_SOC_DAIFMT_I2S)206	 */207	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {208	case SND_SOC_DAIFMT_I2S:209		adc_serfmt |= AD193X_ADC_SERFMT_TDM;210		dac_serfmt |= AD193X_DAC_SERFMT_STEREO;211		break;212	case SND_SOC_DAIFMT_DSP_A:213		adc_serfmt |= AD193X_ADC_SERFMT_AUX;214		dac_serfmt |= AD193X_DAC_SERFMT_TDM;215		break;216	default:217		if (ad193x_has_adc(ad193x))218			return -EINVAL;219	}220 221	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {222	case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */223		break;224	case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */225		adc_fmt |= AD193X_ADC_LEFT_HIGH;226		dac_fmt |= AD193X_DAC_LEFT_HIGH;227		break;228	case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */229		adc_fmt |= AD193X_ADC_BCLK_INV;230		dac_fmt |= AD193X_DAC_BCLK_INV;231		break;232	case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */233		adc_fmt |= AD193X_ADC_LEFT_HIGH;234		adc_fmt |= AD193X_ADC_BCLK_INV;235		dac_fmt |= AD193X_DAC_LEFT_HIGH;236		dac_fmt |= AD193X_DAC_BCLK_INV;237		break;238	default:239		return -EINVAL;240	}241 242	/* For DSP_*, LRCLK's polarity must be inverted */243	if (fmt & SND_SOC_DAIFMT_DSP_A)244		dac_fmt ^= AD193X_DAC_LEFT_HIGH;245 246	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {247	case SND_SOC_DAIFMT_CBP_CFP:248		adc_fmt |= AD193X_ADC_LCR_MASTER;249		adc_fmt |= AD193X_ADC_BCLK_MASTER;250		dac_fmt |= AD193X_DAC_LCR_MASTER;251		dac_fmt |= AD193X_DAC_BCLK_MASTER;252		break;253	case SND_SOC_DAIFMT_CBC_CFP:254		adc_fmt |= AD193X_ADC_LCR_MASTER;255		dac_fmt |= AD193X_DAC_LCR_MASTER;256		break;257	case SND_SOC_DAIFMT_CBP_CFC:258		adc_fmt |= AD193X_ADC_BCLK_MASTER;259		dac_fmt |= AD193X_DAC_BCLK_MASTER;260		break;261	case SND_SOC_DAIFMT_CBC_CFC:262		break;263	default:264		return -EINVAL;265	}266 267	if (ad193x_has_adc(ad193x)) {268		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,269				   AD193X_ADC_SERFMT_MASK, adc_serfmt);270		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,271				   AD193X_ADC_FMT_MASK, adc_fmt);272	}273	regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL0,274			   AD193X_DAC_SERFMT_MASK, dac_serfmt);275	regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,276		AD193X_DAC_FMT_MASK, dac_fmt);277 278	return 0;279}280 281static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,282		int clk_id, unsigned int freq, int dir)283{284	struct snd_soc_component *component = codec_dai->component;285	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);286	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);287 288	if (clk_id == AD193X_SYSCLK_MCLK) {289		/* MCLK must be 512 x fs */290		if (dir == SND_SOC_CLOCK_OUT || freq != 24576000)291			return -EINVAL;292 293		regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL1,294				   AD193X_PLL_SRC_MASK,295				   AD193X_PLL_DAC_SRC_MCLK |296				   AD193X_PLL_CLK_SRC_MCLK);297 298		snd_soc_dapm_sync(dapm);299		return 0;300	}301	switch (freq) {302	case 12288000:303	case 18432000:304	case 24576000:305	case 36864000:306		ad193x->sysclk = freq;307		return 0;308	}309	return -EINVAL;310}311 312static int ad193x_hw_params(struct snd_pcm_substream *substream,313		struct snd_pcm_hw_params *params,314		struct snd_soc_dai *dai)315{316	int word_len = 0, master_rate = 0;317	struct snd_soc_component *component = dai->component;318	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);319	bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;320	u8 dacc0;321 322	dev_dbg(dai->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",323		__func__, params_rate(params), params_format(params),324		params_width(params), params_channels(params));325 326 327	/* bit size */328	switch (params_width(params)) {329	case 16:330		word_len = 3;331		break;332	case 20:333		word_len = 1;334		break;335	case 24:336	case 32:337		word_len = 0;338		break;339	}340 341	switch (ad193x->sysclk) {342	case 12288000:343		master_rate = AD193X_PLL_INPUT_256;344		break;345	case 18432000:346		master_rate = AD193X_PLL_INPUT_384;347		break;348	case 24576000:349		master_rate = AD193X_PLL_INPUT_512;350		break;351	case 36864000:352		master_rate = AD193X_PLL_INPUT_768;353		break;354	}355 356	if (is_playback) {357		switch (params_rate(params)) {358		case 48000:359			dacc0 = AD193X_DAC_SR_48;360			break;361		case 96000:362			dacc0 = AD193X_DAC_SR_96;363			break;364		case 192000:365			dacc0 = AD193X_DAC_SR_192;366			break;367		default:368			dev_err(dai->dev, "invalid sampling rate: %d\n", params_rate(params));369			return -EINVAL;370		}371 372		regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL0, AD193X_DAC_SR_MASK, dacc0);373	}374 375	regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0,376			    AD193X_PLL_INPUT_MASK, master_rate);377 378	regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,379			    AD193X_DAC_WORD_LEN_MASK,380			    word_len << AD193X_DAC_WORD_LEN_SHFT);381 382	if (ad193x_has_adc(ad193x))383		regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,384				   AD193X_ADC_WORD_LEN_MASK, word_len);385 386	return 0;387}388 389static int ad193x_startup(struct snd_pcm_substream *substream,390			  struct snd_soc_dai *dai)391{392	return snd_pcm_hw_constraint_list(substream->runtime, 0,393				   SNDRV_PCM_HW_PARAM_SAMPLE_BITS,394				   &constr);395}396 397static const struct snd_soc_dai_ops ad193x_dai_ops = {398	.startup = ad193x_startup,399	.hw_params = ad193x_hw_params,400	.mute_stream = ad193x_mute,401	.set_tdm_slot = ad193x_set_tdm_slot,402	.set_sysclk	= ad193x_set_dai_sysclk,403	.set_fmt = ad193x_set_dai_fmt,404	.no_capture_mute = 1,405};406 407/* codec DAI instance */408static struct snd_soc_dai_driver ad193x_dai = {409	.name = "ad193x-hifi",410	.playback = {411		.stream_name = "Playback",412		.channels_min = 2,413		.channels_max = 8,414		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,415		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |416			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,417	},418	.capture = {419		.stream_name = "Capture",420		.channels_min = 2,421		.channels_max = 4,422		.rates = SNDRV_PCM_RATE_48000,423		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |424			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,425	},426	.ops = &ad193x_dai_ops,427};428 429/* codec DAI instance for DAC only */430static struct snd_soc_dai_driver ad193x_no_adc_dai = {431	.name = "ad193x-hifi",432	.playback = {433		.stream_name = "Playback",434		.channels_min = 2,435		.channels_max = 8,436		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,437		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |438			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,439	},440	.ops = &ad193x_dai_ops,441};442 443/* codec register values to set after reset */444static void ad193x_reg_default_init(struct ad193x_priv *ad193x)445{446	static const struct reg_sequence reg_init[] = {447		{  0, 0x99 },	/* PLL_CLK_CTRL0: pll input: mclki/xi 12.288Mhz */448		{  1, 0x04 },	/* PLL_CLK_CTRL1: no on-chip Vref */449		{  2, 0x40 },	/* DAC_CTRL0: TDM mode */450		{  3, 0x00 },	/* DAC_CTRL1: reset */451		{  4, 0x1A },	/* DAC_CTRL2: 48kHz de-emphasis, unmute dac */452		{  5, 0x00 },	/* DAC_CHNL_MUTE: unmute DAC channels */453		{  6, 0x00 },	/* DAC_L1_VOL: no attenuation */454		{  7, 0x00 },	/* DAC_R1_VOL: no attenuation */455		{  8, 0x00 },	/* DAC_L2_VOL: no attenuation */456		{  9, 0x00 },	/* DAC_R2_VOL: no attenuation */457		{ 10, 0x00 },	/* DAC_L3_VOL: no attenuation */458		{ 11, 0x00 },	/* DAC_R3_VOL: no attenuation */459		{ 12, 0x00 },	/* DAC_L4_VOL: no attenuation */460		{ 13, 0x00 },	/* DAC_R4_VOL: no attenuation */461	};462	static const struct reg_sequence reg_adc_init[] = {463		{ 14, 0x03 },	/* ADC_CTRL0: high-pass filter enable */464		{ 15, 0x43 },	/* ADC_CTRL1: sata delay=1, adc aux mode */465		{ 16, 0x00 },	/* ADC_CTRL2: reset */466	};467 468	regmap_multi_reg_write(ad193x->regmap, reg_init, ARRAY_SIZE(reg_init));469 470	if (ad193x_has_adc(ad193x)) {471		regmap_multi_reg_write(ad193x->regmap, reg_adc_init,472				       ARRAY_SIZE(reg_adc_init));473	}474}475 476static int ad193x_component_probe(struct snd_soc_component *component)477{478	struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);479	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);480	int num, ret;481 482	/* default setting for ad193x */483	ad193x_reg_default_init(ad193x);484 485	/* adc only */486	if (ad193x_has_adc(ad193x)) {487		/* add adc controls */488		num = ARRAY_SIZE(ad193x_adc_snd_controls);489		ret = snd_soc_add_component_controls(component,490						 ad193x_adc_snd_controls,491						 num);492		if (ret)493			return ret;494 495		/* add adc widgets */496		num = ARRAY_SIZE(ad193x_adc_widgets);497		ret = snd_soc_dapm_new_controls(dapm,498						ad193x_adc_widgets,499						num);500		if (ret)501			return ret;502 503		/* add adc routes */504		num = ARRAY_SIZE(ad193x_adc_audio_paths);505		ret = snd_soc_dapm_add_routes(dapm,506					      ad193x_adc_audio_paths,507					      num);508		if (ret)509			return ret;510	}511 512	return 0;513}514 515static const struct snd_soc_component_driver soc_component_dev_ad193x = {516	.probe			= ad193x_component_probe,517	.controls		= ad193x_snd_controls,518	.num_controls		= ARRAY_SIZE(ad193x_snd_controls),519	.dapm_widgets		= ad193x_dapm_widgets,520	.num_dapm_widgets	= ARRAY_SIZE(ad193x_dapm_widgets),521	.dapm_routes		= audio_paths,522	.num_dapm_routes	= ARRAY_SIZE(audio_paths),523	.idle_bias_on		= 1,524	.use_pmdown_time	= 1,525	.endianness		= 1,526};527 528const struct regmap_config ad193x_regmap_config = {529	.max_register = AD193X_NUM_REGS - 1,530};531EXPORT_SYMBOL_GPL(ad193x_regmap_config);532 533int ad193x_probe(struct device *dev, struct regmap *regmap,534		 enum ad193x_type type)535{536	struct ad193x_priv *ad193x;537 538	if (IS_ERR(regmap))539		return PTR_ERR(regmap);540 541	ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);542	if (ad193x == NULL)543		return -ENOMEM;544 545	ad193x->regmap = regmap;546	ad193x->type = type;547 548	dev_set_drvdata(dev, ad193x);549 550	if (ad193x_has_adc(ad193x))551		return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x,552						       &ad193x_dai, 1);553	return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x,554		&ad193x_no_adc_dai, 1);555}556EXPORT_SYMBOL_GPL(ad193x_probe);557 558MODULE_DESCRIPTION("ASoC ad193x driver");559MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");560MODULE_LICENSE("GPL");561