1*80503b23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2a1533d94SBarry Song /* 3a1533d94SBarry Song * AD193X Audio Codec driver supporting AD1936/7/8/9 4a1533d94SBarry Song * 5a1533d94SBarry Song * Copyright 2010 Analog Devices Inc. 6a1533d94SBarry Song */ 7a1533d94SBarry Song 8a1533d94SBarry Song #include <linux/module.h> 9a1533d94SBarry Song #include <linux/kernel.h> 10a1533d94SBarry Song #include <linux/device.h> 116c3d713eSLars-Peter Clausen #include <linux/regmap.h> 121b132ea0SStephen Rothwell #include <linux/slab.h> 13a1533d94SBarry Song #include <sound/core.h> 14a1533d94SBarry Song #include <sound/pcm.h> 15a1533d94SBarry Song #include <sound/pcm_params.h> 16a1533d94SBarry Song #include <sound/initval.h> 17a1533d94SBarry Song #include <sound/soc.h> 18a1533d94SBarry Song #include <sound/tlv.h> 196c3d713eSLars-Peter Clausen 20a1533d94SBarry Song #include "ad193x.h" 21a1533d94SBarry Song 22a1533d94SBarry Song /* codec private data */ 23a1533d94SBarry Song struct ad193x_priv { 2430ab1e78SLars-Peter Clausen struct regmap *regmap; 25e5224f58SCyrille Pitchen enum ad193x_type type; 26f0fba2adSLiam Girdwood int sysclk; 27a1533d94SBarry Song }; 28a1533d94SBarry Song 29a1533d94SBarry Song /* 30a1533d94SBarry Song * AD193X volume/mute/de-emphasis etc. controls 31a1533d94SBarry Song */ 32c4e7a4a2SLars-Peter Clausen static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; 33a1533d94SBarry Song 34b6592d88STakashi Iwai static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1, 35b6592d88STakashi Iwai ad193x_deemp); 36a1533d94SBarry Song 37591c034aSLars-Peter Clausen static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); 38591c034aSLars-Peter Clausen 3975c2ecb4SCodrin Ciubotariu static const unsigned int ad193x_sb[] = {32}; 4075c2ecb4SCodrin Ciubotariu 4175c2ecb4SCodrin Ciubotariu static struct snd_pcm_hw_constraint_list constr = { 4275c2ecb4SCodrin Ciubotariu .list = ad193x_sb, 4375c2ecb4SCodrin Ciubotariu .count = ARRAY_SIZE(ad193x_sb), 4475c2ecb4SCodrin Ciubotariu }; 4575c2ecb4SCodrin Ciubotariu 46a1533d94SBarry Song static const struct snd_kcontrol_new ad193x_snd_controls[] = { 47a1533d94SBarry Song /* DAC volume control */ 48591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL, 49591c034aSLars-Peter Clausen AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv), 50591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL, 51591c034aSLars-Peter Clausen AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv), 52591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL, 53591c034aSLars-Peter Clausen AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv), 54591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL, 55591c034aSLars-Peter Clausen AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv), 56a1533d94SBarry Song 57a1533d94SBarry Song /* DAC switch control */ 58a1533d94SBarry Song SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE, 59a1533d94SBarry Song AD193X_DACR1_MUTE, 1, 1), 60a1533d94SBarry Song SOC_DOUBLE("DAC2 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL2_MUTE, 61a1533d94SBarry Song AD193X_DACR2_MUTE, 1, 1), 62a1533d94SBarry Song SOC_DOUBLE("DAC3 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL3_MUTE, 63a1533d94SBarry Song AD193X_DACR3_MUTE, 1, 1), 64a1533d94SBarry Song SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE, 65a1533d94SBarry Song AD193X_DACR4_MUTE, 1, 1), 66a1533d94SBarry Song 67e5224f58SCyrille Pitchen /* DAC de-emphasis */ 68e5224f58SCyrille Pitchen SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum), 69e5224f58SCyrille Pitchen }; 70e5224f58SCyrille Pitchen 71e5224f58SCyrille Pitchen static const struct snd_kcontrol_new ad193x_adc_snd_controls[] = { 72e5224f58SCyrille Pitchen /* ADC switch control */ 73e5224f58SCyrille Pitchen SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE, 74e5224f58SCyrille Pitchen AD193X_ADCR1_MUTE, 1, 1), 75e5224f58SCyrille Pitchen SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE, 76e5224f58SCyrille Pitchen AD193X_ADCR2_MUTE, 1, 1), 77e5224f58SCyrille Pitchen 78a1533d94SBarry Song /* ADC high-pass filter */ 79a1533d94SBarry Song SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0, 80a1533d94SBarry Song AD193X_ADC_HIGHPASS_FILTER, 1, 0), 81a1533d94SBarry Song }; 82a1533d94SBarry Song 83a1533d94SBarry Song static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { 841b86a3faSLars-Peter Clausen SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), 851b86a3faSLars-Peter Clausen SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0), 86a1533d94SBarry Song SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), 870718fd27SLars-Peter Clausen SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), 881b86a3faSLars-Peter Clausen SND_SOC_DAPM_VMID("VMID"), 89a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC1OUT"), 90a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC2OUT"), 91a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC3OUT"), 92a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC4OUT"), 93e5224f58SCyrille Pitchen }; 94e5224f58SCyrille Pitchen 95e5224f58SCyrille Pitchen static const struct snd_soc_dapm_widget ad193x_adc_widgets[] = { 96e5224f58SCyrille Pitchen SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), 97e5224f58SCyrille Pitchen SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), 98a1533d94SBarry Song SND_SOC_DAPM_INPUT("ADC1IN"), 99a1533d94SBarry Song SND_SOC_DAPM_INPUT("ADC2IN"), 100a1533d94SBarry Song }; 101a1533d94SBarry Song 10259529473SCodrin Ciubotariu static int ad193x_check_pll(struct snd_soc_dapm_widget *source, 10359529473SCodrin Ciubotariu struct snd_soc_dapm_widget *sink) 10459529473SCodrin Ciubotariu { 10559529473SCodrin Ciubotariu struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm); 10659529473SCodrin Ciubotariu struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); 10759529473SCodrin Ciubotariu 10859529473SCodrin Ciubotariu return !!ad193x->sysclk; 10959529473SCodrin Ciubotariu } 11059529473SCodrin Ciubotariu 111a1533d94SBarry Song static const struct snd_soc_dapm_route audio_paths[] = { 1120718fd27SLars-Peter Clausen { "DAC", NULL, "SYSCLK" }, 1131b86a3faSLars-Peter Clausen { "DAC Output", NULL, "DAC" }, 1141b86a3faSLars-Peter Clausen { "DAC Output", NULL, "VMID" }, 1151b86a3faSLars-Peter Clausen { "DAC1OUT", NULL, "DAC Output" }, 1161b86a3faSLars-Peter Clausen { "DAC2OUT", NULL, "DAC Output" }, 1171b86a3faSLars-Peter Clausen { "DAC3OUT", NULL, "DAC Output" }, 1181b86a3faSLars-Peter Clausen { "DAC4OUT", NULL, "DAC Output" }, 11959529473SCodrin Ciubotariu { "SYSCLK", NULL, "PLL_PWR", &ad193x_check_pll }, 120a1533d94SBarry Song }; 121a1533d94SBarry Song 122e5224f58SCyrille Pitchen static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = { 123e5224f58SCyrille Pitchen { "ADC", NULL, "SYSCLK" }, 124e5224f58SCyrille Pitchen { "ADC", NULL, "ADC_PWR" }, 125e5224f58SCyrille Pitchen { "ADC", NULL, "ADC1IN" }, 126e5224f58SCyrille Pitchen { "ADC", NULL, "ADC2IN" }, 127e5224f58SCyrille Pitchen }; 128e5224f58SCyrille Pitchen 129e5224f58SCyrille Pitchen static inline bool ad193x_has_adc(const struct ad193x_priv *ad193x) 130e5224f58SCyrille Pitchen { 131e5224f58SCyrille Pitchen switch (ad193x->type) { 132e5224f58SCyrille Pitchen case AD1933: 133e5224f58SCyrille Pitchen case AD1934: 134e5224f58SCyrille Pitchen return false; 135e5224f58SCyrille Pitchen default: 136e5224f58SCyrille Pitchen break; 137e5224f58SCyrille Pitchen } 138e5224f58SCyrille Pitchen 139e5224f58SCyrille Pitchen return true; 140e5224f58SCyrille Pitchen } 141e5224f58SCyrille Pitchen 142a1533d94SBarry Song /* 143a1533d94SBarry Song * DAI ops entries 144a1533d94SBarry Song */ 145a1533d94SBarry Song 146a1533d94SBarry Song static int ad193x_mute(struct snd_soc_dai *dai, int mute) 147a1533d94SBarry Song { 14889cea5c9SKuninori Morimoto struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component); 149a1533d94SBarry Song 15054c96cfdSAxel Lin if (mute) 15134cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, 15254c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE, 15354c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE); 15454c96cfdSAxel Lin else 15534cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, 15654c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE, 0); 157a1533d94SBarry Song 158a1533d94SBarry Song return 0; 159a1533d94SBarry Song } 160a1533d94SBarry Song 161a1533d94SBarry Song static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 162a1533d94SBarry Song unsigned int rx_mask, int slots, int width) 163a1533d94SBarry Song { 16489cea5c9SKuninori Morimoto struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component); 165b82ca578SLars-Peter Clausen unsigned int channels; 166a1533d94SBarry Song 167a1533d94SBarry Song switch (slots) { 168a1533d94SBarry Song case 2: 169b82ca578SLars-Peter Clausen channels = AD193X_2_CHANNELS; 170a1533d94SBarry Song break; 171a1533d94SBarry Song case 4: 172b82ca578SLars-Peter Clausen channels = AD193X_4_CHANNELS; 173a1533d94SBarry Song break; 174a1533d94SBarry Song case 8: 175b82ca578SLars-Peter Clausen channels = AD193X_8_CHANNELS; 176a1533d94SBarry Song break; 177a1533d94SBarry Song case 16: 178b82ca578SLars-Peter Clausen channels = AD193X_16_CHANNELS; 179a1533d94SBarry Song break; 180a1533d94SBarry Song default: 181a1533d94SBarry Song return -EINVAL; 182a1533d94SBarry Song } 183a1533d94SBarry Song 18434cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, 18534cbe168SLars-Peter Clausen AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT); 186e5224f58SCyrille Pitchen if (ad193x_has_adc(ad193x)) 18734cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, 188e5224f58SCyrille Pitchen AD193X_ADC_CHAN_MASK, 189e5224f58SCyrille Pitchen channels << AD193X_ADC_CHAN_SHFT); 190a1533d94SBarry Song 191a1533d94SBarry Song return 0; 192a1533d94SBarry Song } 193a1533d94SBarry Song 194a1533d94SBarry Song static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, 195a1533d94SBarry Song unsigned int fmt) 196a1533d94SBarry Song { 19789cea5c9SKuninori Morimoto struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(codec_dai->component); 198b82ca578SLars-Peter Clausen unsigned int adc_serfmt = 0; 199bccf9c7eSCodrin Ciubotariu unsigned int dac_serfmt = 0; 200b82ca578SLars-Peter Clausen unsigned int adc_fmt = 0; 201b82ca578SLars-Peter Clausen unsigned int dac_fmt = 0; 202a1533d94SBarry Song 203a1533d94SBarry Song /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S 204bccf9c7eSCodrin Ciubotariu * with TDM), ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) and DAC I2S mode 205bccf9c7eSCodrin Ciubotariu * (SND_SOC_DAIFMT_I2S) 206a1533d94SBarry Song */ 207a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 208a1533d94SBarry Song case SND_SOC_DAIFMT_I2S: 209b82ca578SLars-Peter Clausen adc_serfmt |= AD193X_ADC_SERFMT_TDM; 210bccf9c7eSCodrin Ciubotariu dac_serfmt |= AD193X_DAC_SERFMT_STEREO; 211a1533d94SBarry Song break; 212a1533d94SBarry Song case SND_SOC_DAIFMT_DSP_A: 213b82ca578SLars-Peter Clausen adc_serfmt |= AD193X_ADC_SERFMT_AUX; 214bccf9c7eSCodrin Ciubotariu dac_serfmt |= AD193X_DAC_SERFMT_TDM; 215a1533d94SBarry Song break; 216a1533d94SBarry Song default: 217e5224f58SCyrille Pitchen if (ad193x_has_adc(ad193x)) 218a1533d94SBarry Song return -EINVAL; 219a1533d94SBarry Song } 220a1533d94SBarry Song 221a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 222a1533d94SBarry Song case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ 223a1533d94SBarry Song break; 224a1533d94SBarry Song case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */ 225b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LEFT_HIGH; 226b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LEFT_HIGH; 227a1533d94SBarry Song break; 228a1533d94SBarry Song case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */ 229b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_INV; 230b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_INV; 231a1533d94SBarry Song break; 232a1533d94SBarry Song case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */ 233b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LEFT_HIGH; 234b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_INV; 235b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LEFT_HIGH; 236b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_INV; 237a1533d94SBarry Song break; 238a1533d94SBarry Song default: 239a1533d94SBarry Song return -EINVAL; 240a1533d94SBarry Song } 241a1533d94SBarry Song 24290f6e680SCodrin Ciubotariu /* For DSP_*, LRCLK's polarity must be inverted */ 24390f6e680SCodrin Ciubotariu if (fmt & SND_SOC_DAIFMT_DSP_A) { 24490f6e680SCodrin Ciubotariu change_bit(ffs(AD193X_DAC_LEFT_HIGH) - 1, 24590f6e680SCodrin Ciubotariu (unsigned long *)&dac_fmt); 24690f6e680SCodrin Ciubotariu } 24790f6e680SCodrin Ciubotariu 248a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 249a1533d94SBarry Song case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ 250b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LCR_MASTER; 251b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_MASTER; 252b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LCR_MASTER; 253b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_MASTER; 254a1533d94SBarry Song break; 255a1533d94SBarry Song case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */ 256b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LCR_MASTER; 257b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LCR_MASTER; 258a1533d94SBarry Song break; 259a1533d94SBarry Song case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ 260b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_MASTER; 261b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_MASTER; 262a1533d94SBarry Song break; 263a1533d94SBarry Song case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */ 264a1533d94SBarry Song break; 265a1533d94SBarry Song default: 266a1533d94SBarry Song return -EINVAL; 267a1533d94SBarry Song } 268a1533d94SBarry Song 269e5224f58SCyrille Pitchen if (ad193x_has_adc(ad193x)) { 27034cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1, 27134cbe168SLars-Peter Clausen AD193X_ADC_SERFMT_MASK, adc_serfmt); 27234cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, 27334cbe168SLars-Peter Clausen AD193X_ADC_FMT_MASK, adc_fmt); 274e5224f58SCyrille Pitchen } 275bccf9c7eSCodrin Ciubotariu regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL0, 276bccf9c7eSCodrin Ciubotariu AD193X_DAC_SERFMT_MASK, dac_serfmt); 27734cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, 27834cbe168SLars-Peter Clausen AD193X_DAC_FMT_MASK, dac_fmt); 279a1533d94SBarry Song 280a1533d94SBarry Song return 0; 281a1533d94SBarry Song } 282a1533d94SBarry Song 283fab90aa4SBarry Song static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai, 284fab90aa4SBarry Song int clk_id, unsigned int freq, int dir) 285fab90aa4SBarry Song { 28689cea5c9SKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 28759529473SCodrin Ciubotariu struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 28889cea5c9SKuninori Morimoto struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); 28959529473SCodrin Ciubotariu 29059529473SCodrin Ciubotariu if (clk_id == AD193X_SYSCLK_MCLK) { 29159529473SCodrin Ciubotariu /* MCLK must be 512 x fs */ 29259529473SCodrin Ciubotariu if (dir == SND_SOC_CLOCK_OUT || freq != 24576000) 29359529473SCodrin Ciubotariu return -EINVAL; 29459529473SCodrin Ciubotariu 29559529473SCodrin Ciubotariu regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 29659529473SCodrin Ciubotariu AD193X_PLL_SRC_MASK, 29759529473SCodrin Ciubotariu AD193X_PLL_DAC_SRC_MCLK | 29859529473SCodrin Ciubotariu AD193X_PLL_CLK_SRC_MCLK); 29959529473SCodrin Ciubotariu 30059529473SCodrin Ciubotariu snd_soc_dapm_sync(dapm); 30159529473SCodrin Ciubotariu return 0; 30259529473SCodrin Ciubotariu } 303fab90aa4SBarry Song switch (freq) { 304fab90aa4SBarry Song case 12288000: 305fab90aa4SBarry Song case 18432000: 306fab90aa4SBarry Song case 24576000: 307fab90aa4SBarry Song case 36864000: 308fab90aa4SBarry Song ad193x->sysclk = freq; 309fab90aa4SBarry Song return 0; 310fab90aa4SBarry Song } 311fab90aa4SBarry Song return -EINVAL; 312fab90aa4SBarry Song } 313fab90aa4SBarry Song 314a1533d94SBarry Song static int ad193x_hw_params(struct snd_pcm_substream *substream, 315a1533d94SBarry Song struct snd_pcm_hw_params *params, 316a1533d94SBarry Song struct snd_soc_dai *dai) 317a1533d94SBarry Song { 31854c96cfdSAxel Lin int word_len = 0, master_rate = 0; 31989cea5c9SKuninori Morimoto struct snd_soc_component *component = dai->component; 32089cea5c9SKuninori Morimoto struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); 321a1533d94SBarry Song 322a1533d94SBarry Song /* bit size */ 323d4dd1fdfSMark Brown switch (params_width(params)) { 324d4dd1fdfSMark Brown case 16: 325a1533d94SBarry Song word_len = 3; 326a1533d94SBarry Song break; 327d4dd1fdfSMark Brown case 20: 328a1533d94SBarry Song word_len = 1; 329a1533d94SBarry Song break; 330d4dd1fdfSMark Brown case 24: 331d4dd1fdfSMark Brown case 32: 332a1533d94SBarry Song word_len = 0; 333a1533d94SBarry Song break; 334a1533d94SBarry Song } 335a1533d94SBarry Song 336fab90aa4SBarry Song switch (ad193x->sysclk) { 337fab90aa4SBarry Song case 12288000: 338fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_256; 339fab90aa4SBarry Song break; 340fab90aa4SBarry Song case 18432000: 341fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_384; 342fab90aa4SBarry Song break; 343fab90aa4SBarry Song case 24576000: 344fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_512; 345fab90aa4SBarry Song break; 346fab90aa4SBarry Song case 36864000: 347fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_768; 348fab90aa4SBarry Song break; 349fab90aa4SBarry Song } 350fab90aa4SBarry Song 35134cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 35254c96cfdSAxel Lin AD193X_PLL_INPUT_MASK, master_rate); 353fab90aa4SBarry Song 35434cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, 35554c96cfdSAxel Lin AD193X_DAC_WORD_LEN_MASK, 35654c96cfdSAxel Lin word_len << AD193X_DAC_WORD_LEN_SHFT); 357a1533d94SBarry Song 358e5224f58SCyrille Pitchen if (ad193x_has_adc(ad193x)) 35934cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1, 36054c96cfdSAxel Lin AD193X_ADC_WORD_LEN_MASK, word_len); 361a1533d94SBarry Song 362a1533d94SBarry Song return 0; 363a1533d94SBarry Song } 364a1533d94SBarry Song 36575c2ecb4SCodrin Ciubotariu static int ad193x_startup(struct snd_pcm_substream *substream, 36675c2ecb4SCodrin Ciubotariu struct snd_soc_dai *dai) 36775c2ecb4SCodrin Ciubotariu { 36875c2ecb4SCodrin Ciubotariu return snd_pcm_hw_constraint_list(substream->runtime, 0, 36975c2ecb4SCodrin Ciubotariu SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 37075c2ecb4SCodrin Ciubotariu &constr); 37175c2ecb4SCodrin Ciubotariu } 37275c2ecb4SCodrin Ciubotariu 37385e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops ad193x_dai_ops = { 37475c2ecb4SCodrin Ciubotariu .startup = ad193x_startup, 375f0fba2adSLiam Girdwood .hw_params = ad193x_hw_params, 376f0fba2adSLiam Girdwood .digital_mute = ad193x_mute, 377f0fba2adSLiam Girdwood .set_tdm_slot = ad193x_set_tdm_slot, 378f0fba2adSLiam Girdwood .set_sysclk = ad193x_set_dai_sysclk, 379f0fba2adSLiam Girdwood .set_fmt = ad193x_set_dai_fmt, 380f0fba2adSLiam Girdwood }; 381f0fba2adSLiam Girdwood 382f0fba2adSLiam Girdwood /* codec DAI instance */ 383f0fba2adSLiam Girdwood static struct snd_soc_dai_driver ad193x_dai = { 384f0fba2adSLiam Girdwood .name = "ad193x-hifi", 385f0fba2adSLiam Girdwood .playback = { 386f0fba2adSLiam Girdwood .stream_name = "Playback", 387f0fba2adSLiam Girdwood .channels_min = 2, 388f0fba2adSLiam Girdwood .channels_max = 8, 389f0fba2adSLiam Girdwood .rates = SNDRV_PCM_RATE_48000, 390f0fba2adSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 391f0fba2adSLiam Girdwood SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 392f0fba2adSLiam Girdwood }, 393f0fba2adSLiam Girdwood .capture = { 394f0fba2adSLiam Girdwood .stream_name = "Capture", 395f0fba2adSLiam Girdwood .channels_min = 2, 396f0fba2adSLiam Girdwood .channels_max = 4, 397f0fba2adSLiam Girdwood .rates = SNDRV_PCM_RATE_48000, 398f0fba2adSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 399f0fba2adSLiam Girdwood SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 400f0fba2adSLiam Girdwood }, 401f0fba2adSLiam Girdwood .ops = &ad193x_dai_ops, 402f0fba2adSLiam Girdwood }; 403f0fba2adSLiam Girdwood 4047aac8d13SCodrin Ciubotariu /* codec DAI instance for DAC only */ 4057aac8d13SCodrin Ciubotariu static struct snd_soc_dai_driver ad193x_no_adc_dai = { 4067aac8d13SCodrin Ciubotariu .name = "ad193x-hifi", 4077aac8d13SCodrin Ciubotariu .playback = { 4087aac8d13SCodrin Ciubotariu .stream_name = "Playback", 4097aac8d13SCodrin Ciubotariu .channels_min = 2, 4107aac8d13SCodrin Ciubotariu .channels_max = 8, 4117aac8d13SCodrin Ciubotariu .rates = SNDRV_PCM_RATE_48000, 4127aac8d13SCodrin Ciubotariu .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 4137aac8d13SCodrin Ciubotariu SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 4147aac8d13SCodrin Ciubotariu }, 4157aac8d13SCodrin Ciubotariu .ops = &ad193x_dai_ops, 4167aac8d13SCodrin Ciubotariu }; 4177aac8d13SCodrin Ciubotariu 41889cea5c9SKuninori Morimoto static int ad193x_component_probe(struct snd_soc_component *component) 419a1533d94SBarry Song { 42089cea5c9SKuninori Morimoto struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); 42189cea5c9SKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 422e5224f58SCyrille Pitchen int num, ret; 423a1533d94SBarry Song 424a1533d94SBarry Song /* default setting for ad193x */ 425a1533d94SBarry Song 426a1533d94SBarry Song /* unmute dac channels */ 42734cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0); 428a1533d94SBarry Song /* de-emphasis: 48kHz, powedown dac */ 42934cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A); 430bdb2c74dSLars-Peter Clausen /* dac in tdm mode */ 431bdb2c74dSLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40); 432e5224f58SCyrille Pitchen 433e5224f58SCyrille Pitchen /* adc only */ 434e5224f58SCyrille Pitchen if (ad193x_has_adc(ad193x)) { 435a1533d94SBarry Song /* high-pass filter enable */ 43634cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3); 437a1533d94SBarry Song /* sata delay=1, adc aux mode */ 43834cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43); 439e5224f58SCyrille Pitchen } 440e5224f58SCyrille Pitchen 441a1533d94SBarry Song /* pll input: mclki/xi */ 44234cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ 44334cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04); 444a1533d94SBarry Song 445e5224f58SCyrille Pitchen /* adc only */ 446e5224f58SCyrille Pitchen if (ad193x_has_adc(ad193x)) { 447e5224f58SCyrille Pitchen /* add adc controls */ 448e5224f58SCyrille Pitchen num = ARRAY_SIZE(ad193x_adc_snd_controls); 44989cea5c9SKuninori Morimoto ret = snd_soc_add_component_controls(component, 450e5224f58SCyrille Pitchen ad193x_adc_snd_controls, 451e5224f58SCyrille Pitchen num); 452e5224f58SCyrille Pitchen if (ret) 453e5224f58SCyrille Pitchen return ret; 454e5224f58SCyrille Pitchen 455e5224f58SCyrille Pitchen /* add adc widgets */ 456e5224f58SCyrille Pitchen num = ARRAY_SIZE(ad193x_adc_widgets); 457e5224f58SCyrille Pitchen ret = snd_soc_dapm_new_controls(dapm, 458e5224f58SCyrille Pitchen ad193x_adc_widgets, 459e5224f58SCyrille Pitchen num); 460e5224f58SCyrille Pitchen if (ret) 461e5224f58SCyrille Pitchen return ret; 462e5224f58SCyrille Pitchen 463e5224f58SCyrille Pitchen /* add adc routes */ 464e5224f58SCyrille Pitchen num = ARRAY_SIZE(ad193x_adc_audio_paths); 465e5224f58SCyrille Pitchen ret = snd_soc_dapm_add_routes(dapm, 466e5224f58SCyrille Pitchen ad193x_adc_audio_paths, 467e5224f58SCyrille Pitchen num); 468e5224f58SCyrille Pitchen if (ret) 469e5224f58SCyrille Pitchen return ret; 470e5224f58SCyrille Pitchen } 471e5224f58SCyrille Pitchen 4725d6be5aaSXiubo Li return 0; 473a1533d94SBarry Song } 474a1533d94SBarry Song 47589cea5c9SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_ad193x = { 47689cea5c9SKuninori Morimoto .probe = ad193x_component_probe, 477b90d4183SLars-Peter Clausen .controls = ad193x_snd_controls, 478b90d4183SLars-Peter Clausen .num_controls = ARRAY_SIZE(ad193x_snd_controls), 479b90d4183SLars-Peter Clausen .dapm_widgets = ad193x_dapm_widgets, 480b90d4183SLars-Peter Clausen .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets), 481b90d4183SLars-Peter Clausen .dapm_routes = audio_paths, 482b90d4183SLars-Peter Clausen .num_dapm_routes = ARRAY_SIZE(audio_paths), 48389cea5c9SKuninori Morimoto .idle_bias_on = 1, 48489cea5c9SKuninori Morimoto .use_pmdown_time = 1, 48589cea5c9SKuninori Morimoto .endianness = 1, 48689cea5c9SKuninori Morimoto .non_legacy_dai_naming = 1, 487a1533d94SBarry Song }; 488a1533d94SBarry Song 4896c3d713eSLars-Peter Clausen const struct regmap_config ad193x_regmap_config = { 49034cbe168SLars-Peter Clausen .max_register = AD193X_NUM_REGS - 1, 49130ab1e78SLars-Peter Clausen }; 4926c3d713eSLars-Peter Clausen EXPORT_SYMBOL_GPL(ad193x_regmap_config); 49330ab1e78SLars-Peter Clausen 494e5224f58SCyrille Pitchen int ad193x_probe(struct device *dev, struct regmap *regmap, 495e5224f58SCyrille Pitchen enum ad193x_type type) 496a1533d94SBarry Song { 497f0fba2adSLiam Girdwood struct ad193x_priv *ad193x; 498f0fba2adSLiam Girdwood 4996c3d713eSLars-Peter Clausen if (IS_ERR(regmap)) 5006c3d713eSLars-Peter Clausen return PTR_ERR(regmap); 5016c3d713eSLars-Peter Clausen 5026c3d713eSLars-Peter Clausen ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL); 503f0fba2adSLiam Girdwood if (ad193x == NULL) 504f0fba2adSLiam Girdwood return -ENOMEM; 505f0fba2adSLiam Girdwood 5066c3d713eSLars-Peter Clausen ad193x->regmap = regmap; 507e5224f58SCyrille Pitchen ad193x->type = type; 50830ab1e78SLars-Peter Clausen 5096c3d713eSLars-Peter Clausen dev_set_drvdata(dev, ad193x); 510f0fba2adSLiam Girdwood 5117aac8d13SCodrin Ciubotariu if (ad193x_has_adc(ad193x)) 51289cea5c9SKuninori Morimoto return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x, 513040242ccSLars-Peter Clausen &ad193x_dai, 1); 5147aac8d13SCodrin Ciubotariu return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x, 5157aac8d13SCodrin Ciubotariu &ad193x_no_adc_dai, 1); 516a1533d94SBarry Song } 5176c3d713eSLars-Peter Clausen EXPORT_SYMBOL_GPL(ad193x_probe); 518a1533d94SBarry Song 519a1533d94SBarry Song MODULE_DESCRIPTION("ASoC ad193x driver"); 520a1533d94SBarry Song MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); 521a1533d94SBarry Song MODULE_LICENSE("GPL"); 522