1a1533d94SBarry Song /* 2a1533d94SBarry Song * AD193X Audio Codec driver supporting AD1936/7/8/9 3a1533d94SBarry Song * 4a1533d94SBarry Song * Copyright 2010 Analog Devices Inc. 5a1533d94SBarry Song * 6a1533d94SBarry Song * Licensed under the GPL-2 or later. 7a1533d94SBarry Song */ 8a1533d94SBarry Song 9a1533d94SBarry Song #include <linux/init.h> 10a1533d94SBarry Song #include <linux/module.h> 11a1533d94SBarry Song #include <linux/kernel.h> 12a1533d94SBarry Song #include <linux/device.h> 13a1533d94SBarry Song #include <linux/i2c.h> 14a1533d94SBarry Song #include <linux/spi/spi.h> 151b132ea0SStephen Rothwell #include <linux/slab.h> 16a1533d94SBarry Song #include <sound/core.h> 17a1533d94SBarry Song #include <sound/pcm.h> 18a1533d94SBarry Song #include <sound/pcm_params.h> 19a1533d94SBarry Song #include <sound/initval.h> 20a1533d94SBarry Song #include <sound/soc.h> 21a1533d94SBarry Song #include <sound/tlv.h> 22a1533d94SBarry Song #include "ad193x.h" 23a1533d94SBarry Song 24a1533d94SBarry Song /* codec private data */ 25a1533d94SBarry Song struct ad193x_priv { 2630ab1e78SLars-Peter Clausen struct regmap *regmap; 27f0fba2adSLiam Girdwood int sysclk; 28a1533d94SBarry Song }; 29a1533d94SBarry Song 30a1533d94SBarry Song /* 31a1533d94SBarry Song * AD193X volume/mute/de-emphasis etc. controls 32a1533d94SBarry Song */ 33a1533d94SBarry Song static const char *ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; 34a1533d94SBarry Song 35a1533d94SBarry Song static const struct soc_enum ad193x_deemp_enum = 36a1533d94SBarry Song SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp); 37a1533d94SBarry Song 38a1533d94SBarry Song static const struct snd_kcontrol_new ad193x_snd_controls[] = { 39a1533d94SBarry Song /* DAC volume control */ 40a1533d94SBarry Song SOC_DOUBLE_R("DAC1 Volume", AD193X_DAC_L1_VOL, 41a1533d94SBarry Song AD193X_DAC_R1_VOL, 0, 0xFF, 1), 42a1533d94SBarry Song SOC_DOUBLE_R("DAC2 Volume", AD193X_DAC_L2_VOL, 43a1533d94SBarry Song AD193X_DAC_R2_VOL, 0, 0xFF, 1), 44a1533d94SBarry Song SOC_DOUBLE_R("DAC3 Volume", AD193X_DAC_L3_VOL, 45a1533d94SBarry Song AD193X_DAC_R3_VOL, 0, 0xFF, 1), 46a1533d94SBarry Song SOC_DOUBLE_R("DAC4 Volume", AD193X_DAC_L4_VOL, 47a1533d94SBarry Song AD193X_DAC_R4_VOL, 0, 0xFF, 1), 48a1533d94SBarry Song 49a1533d94SBarry Song /* ADC switch control */ 50a1533d94SBarry Song SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE, 51a1533d94SBarry Song AD193X_ADCR1_MUTE, 1, 1), 52a1533d94SBarry Song SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE, 53a1533d94SBarry Song AD193X_ADCR2_MUTE, 1, 1), 54a1533d94SBarry Song 55a1533d94SBarry Song /* DAC switch control */ 56a1533d94SBarry Song SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE, 57a1533d94SBarry Song AD193X_DACR1_MUTE, 1, 1), 58a1533d94SBarry Song SOC_DOUBLE("DAC2 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL2_MUTE, 59a1533d94SBarry Song AD193X_DACR2_MUTE, 1, 1), 60a1533d94SBarry Song SOC_DOUBLE("DAC3 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL3_MUTE, 61a1533d94SBarry Song AD193X_DACR3_MUTE, 1, 1), 62a1533d94SBarry Song SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE, 63a1533d94SBarry Song AD193X_DACR4_MUTE, 1, 1), 64a1533d94SBarry Song 65a1533d94SBarry Song /* ADC high-pass filter */ 66a1533d94SBarry Song SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0, 67a1533d94SBarry Song AD193X_ADC_HIGHPASS_FILTER, 1, 0), 68a1533d94SBarry Song 69a1533d94SBarry Song /* DAC de-emphasis */ 70a1533d94SBarry Song SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum), 71a1533d94SBarry Song }; 72a1533d94SBarry Song 73a1533d94SBarry Song static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { 74a1533d94SBarry Song SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1), 75a1533d94SBarry Song SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), 76a1533d94SBarry Song SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), 77a1533d94SBarry Song SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), 78a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC1OUT"), 79a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC2OUT"), 80a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC3OUT"), 81a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC4OUT"), 82a1533d94SBarry Song SND_SOC_DAPM_INPUT("ADC1IN"), 83a1533d94SBarry Song SND_SOC_DAPM_INPUT("ADC2IN"), 84a1533d94SBarry Song }; 85a1533d94SBarry Song 86a1533d94SBarry Song static const struct snd_soc_dapm_route audio_paths[] = { 87a1533d94SBarry Song { "DAC", NULL, "PLL_PWR" }, 88a1533d94SBarry Song { "ADC", NULL, "PLL_PWR" }, 89a1533d94SBarry Song { "DAC", NULL, "ADC_PWR" }, 90a1533d94SBarry Song { "ADC", NULL, "ADC_PWR" }, 91a1533d94SBarry Song { "DAC1OUT", "DAC1 Switch", "DAC" }, 92a1533d94SBarry Song { "DAC2OUT", "DAC2 Switch", "DAC" }, 93a1533d94SBarry Song { "DAC3OUT", "DAC3 Switch", "DAC" }, 94a1533d94SBarry Song { "DAC4OUT", "DAC4 Switch", "DAC" }, 95a1533d94SBarry Song { "ADC", "ADC1 Switch", "ADC1IN" }, 96a1533d94SBarry Song { "ADC", "ADC2 Switch", "ADC2IN" }, 97a1533d94SBarry Song }; 98a1533d94SBarry Song 99a1533d94SBarry Song /* 100a1533d94SBarry Song * DAI ops entries 101a1533d94SBarry Song */ 102a1533d94SBarry Song 103a1533d94SBarry Song static int ad193x_mute(struct snd_soc_dai *dai, int mute) 104a1533d94SBarry Song { 105a1533d94SBarry Song struct snd_soc_codec *codec = dai->codec; 106a1533d94SBarry Song 10754c96cfdSAxel Lin if (mute) 10854c96cfdSAxel Lin snd_soc_update_bits(codec, AD193X_DAC_CTRL2, 10954c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE, 11054c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE); 11154c96cfdSAxel Lin else 11254c96cfdSAxel Lin snd_soc_update_bits(codec, AD193X_DAC_CTRL2, 11354c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE, 0); 114a1533d94SBarry Song 115a1533d94SBarry Song return 0; 116a1533d94SBarry Song } 117a1533d94SBarry Song 118a1533d94SBarry Song static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 119a1533d94SBarry Song unsigned int rx_mask, int slots, int width) 120a1533d94SBarry Song { 121a1533d94SBarry Song struct snd_soc_codec *codec = dai->codec; 122a1533d94SBarry Song int dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1); 123a1533d94SBarry Song int adc_reg = snd_soc_read(codec, AD193X_ADC_CTRL2); 124a1533d94SBarry Song 125a1533d94SBarry Song dac_reg &= ~AD193X_DAC_CHAN_MASK; 126a1533d94SBarry Song adc_reg &= ~AD193X_ADC_CHAN_MASK; 127a1533d94SBarry Song 128a1533d94SBarry Song switch (slots) { 129a1533d94SBarry Song case 2: 130a1533d94SBarry Song dac_reg |= AD193X_DAC_2_CHANNELS << AD193X_DAC_CHAN_SHFT; 131a1533d94SBarry Song adc_reg |= AD193X_ADC_2_CHANNELS << AD193X_ADC_CHAN_SHFT; 132a1533d94SBarry Song break; 133a1533d94SBarry Song case 4: 134a1533d94SBarry Song dac_reg |= AD193X_DAC_4_CHANNELS << AD193X_DAC_CHAN_SHFT; 135a1533d94SBarry Song adc_reg |= AD193X_ADC_4_CHANNELS << AD193X_ADC_CHAN_SHFT; 136a1533d94SBarry Song break; 137a1533d94SBarry Song case 8: 138a1533d94SBarry Song dac_reg |= AD193X_DAC_8_CHANNELS << AD193X_DAC_CHAN_SHFT; 139a1533d94SBarry Song adc_reg |= AD193X_ADC_8_CHANNELS << AD193X_ADC_CHAN_SHFT; 140a1533d94SBarry Song break; 141a1533d94SBarry Song case 16: 142a1533d94SBarry Song dac_reg |= AD193X_DAC_16_CHANNELS << AD193X_DAC_CHAN_SHFT; 143a1533d94SBarry Song adc_reg |= AD193X_ADC_16_CHANNELS << AD193X_ADC_CHAN_SHFT; 144a1533d94SBarry Song break; 145a1533d94SBarry Song default: 146a1533d94SBarry Song return -EINVAL; 147a1533d94SBarry Song } 148a1533d94SBarry Song 149a1533d94SBarry Song snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg); 150a1533d94SBarry Song snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg); 151a1533d94SBarry Song 152a1533d94SBarry Song return 0; 153a1533d94SBarry Song } 154a1533d94SBarry Song 155a1533d94SBarry Song static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, 156a1533d94SBarry Song unsigned int fmt) 157a1533d94SBarry Song { 158a1533d94SBarry Song struct snd_soc_codec *codec = codec_dai->codec; 159d6bdc0f7SBarry Song int adc_reg1, adc_reg2, dac_reg; 160a1533d94SBarry Song 161d6bdc0f7SBarry Song adc_reg1 = snd_soc_read(codec, AD193X_ADC_CTRL1); 162d6bdc0f7SBarry Song adc_reg2 = snd_soc_read(codec, AD193X_ADC_CTRL2); 163a1533d94SBarry Song dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1); 164a1533d94SBarry Song 165a1533d94SBarry Song /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S 166a1533d94SBarry Song * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) 167a1533d94SBarry Song */ 168a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 169a1533d94SBarry Song case SND_SOC_DAIFMT_I2S: 170d6bdc0f7SBarry Song adc_reg1 &= ~AD193X_ADC_SERFMT_MASK; 171d6bdc0f7SBarry Song adc_reg1 |= AD193X_ADC_SERFMT_TDM; 172a1533d94SBarry Song break; 173a1533d94SBarry Song case SND_SOC_DAIFMT_DSP_A: 174d6bdc0f7SBarry Song adc_reg1 &= ~AD193X_ADC_SERFMT_MASK; 175d6bdc0f7SBarry Song adc_reg1 |= AD193X_ADC_SERFMT_AUX; 176a1533d94SBarry Song break; 177a1533d94SBarry Song default: 178a1533d94SBarry Song return -EINVAL; 179a1533d94SBarry Song } 180a1533d94SBarry Song 181a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 182a1533d94SBarry Song case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ 183d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_LEFT_HIGH; 184d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_BCLK_INV; 185a1533d94SBarry Song dac_reg &= ~AD193X_DAC_LEFT_HIGH; 186a1533d94SBarry Song dac_reg &= ~AD193X_DAC_BCLK_INV; 187a1533d94SBarry Song break; 188a1533d94SBarry Song case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */ 189d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_LEFT_HIGH; 190d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_BCLK_INV; 191a1533d94SBarry Song dac_reg |= AD193X_DAC_LEFT_HIGH; 192a1533d94SBarry Song dac_reg &= ~AD193X_DAC_BCLK_INV; 193a1533d94SBarry Song break; 194a1533d94SBarry Song case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */ 195d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_LEFT_HIGH; 196d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_BCLK_INV; 197a1533d94SBarry Song dac_reg &= ~AD193X_DAC_LEFT_HIGH; 198a1533d94SBarry Song dac_reg |= AD193X_DAC_BCLK_INV; 199a1533d94SBarry Song break; 200a1533d94SBarry Song 201a1533d94SBarry Song case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */ 202d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_LEFT_HIGH; 203d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_BCLK_INV; 204a1533d94SBarry Song dac_reg |= AD193X_DAC_LEFT_HIGH; 205a1533d94SBarry Song dac_reg |= AD193X_DAC_BCLK_INV; 206a1533d94SBarry Song break; 207a1533d94SBarry Song default: 208a1533d94SBarry Song return -EINVAL; 209a1533d94SBarry Song } 210a1533d94SBarry Song 211a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 212a1533d94SBarry Song case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ 213d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_LCR_MASTER; 214d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_BCLK_MASTER; 215a1533d94SBarry Song dac_reg |= AD193X_DAC_LCR_MASTER; 216a1533d94SBarry Song dac_reg |= AD193X_DAC_BCLK_MASTER; 217a1533d94SBarry Song break; 218a1533d94SBarry Song case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */ 219d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_LCR_MASTER; 220d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_BCLK_MASTER; 221a1533d94SBarry Song dac_reg |= AD193X_DAC_LCR_MASTER; 222a1533d94SBarry Song dac_reg &= ~AD193X_DAC_BCLK_MASTER; 223a1533d94SBarry Song break; 224a1533d94SBarry Song case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ 225d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_LCR_MASTER; 226d6bdc0f7SBarry Song adc_reg2 |= AD193X_ADC_BCLK_MASTER; 227a1533d94SBarry Song dac_reg &= ~AD193X_DAC_LCR_MASTER; 228a1533d94SBarry Song dac_reg |= AD193X_DAC_BCLK_MASTER; 229a1533d94SBarry Song break; 230a1533d94SBarry Song case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */ 231d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_LCR_MASTER; 232d6bdc0f7SBarry Song adc_reg2 &= ~AD193X_ADC_BCLK_MASTER; 233a1533d94SBarry Song dac_reg &= ~AD193X_DAC_LCR_MASTER; 234a1533d94SBarry Song dac_reg &= ~AD193X_DAC_BCLK_MASTER; 235a1533d94SBarry Song break; 236a1533d94SBarry Song default: 237a1533d94SBarry Song return -EINVAL; 238a1533d94SBarry Song } 239a1533d94SBarry Song 240d6bdc0f7SBarry Song snd_soc_write(codec, AD193X_ADC_CTRL1, adc_reg1); 241d6bdc0f7SBarry Song snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg2); 242a1533d94SBarry Song snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg); 243a1533d94SBarry Song 244a1533d94SBarry Song return 0; 245a1533d94SBarry Song } 246a1533d94SBarry Song 247fab90aa4SBarry Song static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai, 248fab90aa4SBarry Song int clk_id, unsigned int freq, int dir) 249fab90aa4SBarry Song { 250fab90aa4SBarry Song struct snd_soc_codec *codec = codec_dai->codec; 251fab90aa4SBarry Song struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); 252fab90aa4SBarry Song switch (freq) { 253fab90aa4SBarry Song case 12288000: 254fab90aa4SBarry Song case 18432000: 255fab90aa4SBarry Song case 24576000: 256fab90aa4SBarry Song case 36864000: 257fab90aa4SBarry Song ad193x->sysclk = freq; 258fab90aa4SBarry Song return 0; 259fab90aa4SBarry Song } 260fab90aa4SBarry Song return -EINVAL; 261fab90aa4SBarry Song } 262fab90aa4SBarry Song 263a1533d94SBarry Song static int ad193x_hw_params(struct snd_pcm_substream *substream, 264a1533d94SBarry Song struct snd_pcm_hw_params *params, 265a1533d94SBarry Song struct snd_soc_dai *dai) 266a1533d94SBarry Song { 26754c96cfdSAxel Lin int word_len = 0, master_rate = 0; 268a1533d94SBarry Song 269a1533d94SBarry Song struct snd_soc_pcm_runtime *rtd = substream->private_data; 270f0fba2adSLiam Girdwood struct snd_soc_codec *codec = rtd->codec; 271fab90aa4SBarry Song struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); 272a1533d94SBarry Song 273a1533d94SBarry Song /* bit size */ 274a1533d94SBarry Song switch (params_format(params)) { 275a1533d94SBarry Song case SNDRV_PCM_FORMAT_S16_LE: 276a1533d94SBarry Song word_len = 3; 277a1533d94SBarry Song break; 278a1533d94SBarry Song case SNDRV_PCM_FORMAT_S20_3LE: 279a1533d94SBarry Song word_len = 1; 280a1533d94SBarry Song break; 281a1533d94SBarry Song case SNDRV_PCM_FORMAT_S24_LE: 282a1533d94SBarry Song case SNDRV_PCM_FORMAT_S32_LE: 283a1533d94SBarry Song word_len = 0; 284a1533d94SBarry Song break; 285a1533d94SBarry Song } 286a1533d94SBarry Song 287fab90aa4SBarry Song switch (ad193x->sysclk) { 288fab90aa4SBarry Song case 12288000: 289fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_256; 290fab90aa4SBarry Song break; 291fab90aa4SBarry Song case 18432000: 292fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_384; 293fab90aa4SBarry Song break; 294fab90aa4SBarry Song case 24576000: 295fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_512; 296fab90aa4SBarry Song break; 297fab90aa4SBarry Song case 36864000: 298fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_768; 299fab90aa4SBarry Song break; 300fab90aa4SBarry Song } 301fab90aa4SBarry Song 30254c96cfdSAxel Lin snd_soc_update_bits(codec, AD193X_PLL_CLK_CTRL0, 30354c96cfdSAxel Lin AD193X_PLL_INPUT_MASK, master_rate); 304fab90aa4SBarry Song 30554c96cfdSAxel Lin snd_soc_update_bits(codec, AD193X_DAC_CTRL2, 30654c96cfdSAxel Lin AD193X_DAC_WORD_LEN_MASK, 30754c96cfdSAxel Lin word_len << AD193X_DAC_WORD_LEN_SHFT); 308a1533d94SBarry Song 30954c96cfdSAxel Lin snd_soc_update_bits(codec, AD193X_ADC_CTRL1, 31054c96cfdSAxel Lin AD193X_ADC_WORD_LEN_MASK, word_len); 311a1533d94SBarry Song 312a1533d94SBarry Song return 0; 313a1533d94SBarry Song } 314a1533d94SBarry Song 31585e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops ad193x_dai_ops = { 316f0fba2adSLiam Girdwood .hw_params = ad193x_hw_params, 317f0fba2adSLiam Girdwood .digital_mute = ad193x_mute, 318f0fba2adSLiam Girdwood .set_tdm_slot = ad193x_set_tdm_slot, 319f0fba2adSLiam Girdwood .set_sysclk = ad193x_set_dai_sysclk, 320f0fba2adSLiam Girdwood .set_fmt = ad193x_set_dai_fmt, 321f0fba2adSLiam Girdwood }; 322f0fba2adSLiam Girdwood 323f0fba2adSLiam Girdwood /* codec DAI instance */ 324f0fba2adSLiam Girdwood static struct snd_soc_dai_driver ad193x_dai = { 325f0fba2adSLiam Girdwood .name = "ad193x-hifi", 326f0fba2adSLiam Girdwood .playback = { 327f0fba2adSLiam Girdwood .stream_name = "Playback", 328f0fba2adSLiam Girdwood .channels_min = 2, 329f0fba2adSLiam Girdwood .channels_max = 8, 330f0fba2adSLiam Girdwood .rates = SNDRV_PCM_RATE_48000, 331f0fba2adSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 332f0fba2adSLiam Girdwood SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 333f0fba2adSLiam Girdwood }, 334f0fba2adSLiam Girdwood .capture = { 335f0fba2adSLiam Girdwood .stream_name = "Capture", 336f0fba2adSLiam Girdwood .channels_min = 2, 337f0fba2adSLiam Girdwood .channels_max = 4, 338f0fba2adSLiam Girdwood .rates = SNDRV_PCM_RATE_48000, 339f0fba2adSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 340f0fba2adSLiam Girdwood SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 341f0fba2adSLiam Girdwood }, 342f0fba2adSLiam Girdwood .ops = &ad193x_dai_ops, 343f0fba2adSLiam Girdwood }; 344f0fba2adSLiam Girdwood 345f0fba2adSLiam Girdwood static int ad193x_probe(struct snd_soc_codec *codec) 346a1533d94SBarry Song { 347f0fba2adSLiam Girdwood struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); 3489dd7b79aSBarry Song int ret; 3499dd7b79aSBarry Song 35030ab1e78SLars-Peter Clausen codec->control_data = ad193x->regmap; 35130ab1e78SLars-Peter Clausen ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); 352a1533d94SBarry Song if (ret < 0) { 353119bfef2SScott Jiang dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); 354a1533d94SBarry Song return ret; 355a1533d94SBarry Song } 356a1533d94SBarry Song 357a1533d94SBarry Song /* default setting for ad193x */ 358a1533d94SBarry Song 359a1533d94SBarry Song /* unmute dac channels */ 360a1533d94SBarry Song snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0); 361a1533d94SBarry Song /* de-emphasis: 48kHz, powedown dac */ 362a1533d94SBarry Song snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A); 363a1533d94SBarry Song /* powerdown dac, dac in tdm mode */ 364a1533d94SBarry Song snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41); 365a1533d94SBarry Song /* high-pass filter enable */ 366a1533d94SBarry Song snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3); 367a1533d94SBarry Song /* sata delay=1, adc aux mode */ 368a1533d94SBarry Song snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43); 369a1533d94SBarry Song /* pll input: mclki/xi */ 370a1533d94SBarry Song snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ 371a1533d94SBarry Song snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); 372a1533d94SBarry Song 373a1533d94SBarry Song return ret; 374a1533d94SBarry Song } 375a1533d94SBarry Song 376f0fba2adSLiam Girdwood static struct snd_soc_codec_driver soc_codec_dev_ad193x = { 377a1533d94SBarry Song .probe = ad193x_probe, 378*b90d4183SLars-Peter Clausen .controls = ad193x_snd_controls, 379*b90d4183SLars-Peter Clausen .num_controls = ARRAY_SIZE(ad193x_snd_controls), 380*b90d4183SLars-Peter Clausen .dapm_widgets = ad193x_dapm_widgets, 381*b90d4183SLars-Peter Clausen .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets), 382*b90d4183SLars-Peter Clausen .dapm_routes = audio_paths, 383*b90d4183SLars-Peter Clausen .num_dapm_routes = ARRAY_SIZE(audio_paths), 384a1533d94SBarry Song }; 385a1533d94SBarry Song 386a1533d94SBarry Song #if defined(CONFIG_SPI_MASTER) 38730ab1e78SLars-Peter Clausen 38830ab1e78SLars-Peter Clausen static const struct regmap_config ad193x_spi_regmap_config = { 38930ab1e78SLars-Peter Clausen .val_bits = 8, 39030ab1e78SLars-Peter Clausen .reg_bits = 16, 39130ab1e78SLars-Peter Clausen .read_flag_mask = 0x09, 39230ab1e78SLars-Peter Clausen .write_flag_mask = 0x08, 39330ab1e78SLars-Peter Clausen }; 39430ab1e78SLars-Peter Clausen 395a1533d94SBarry Song static int __devinit ad193x_spi_probe(struct spi_device *spi) 396a1533d94SBarry Song { 397f0fba2adSLiam Girdwood struct ad193x_priv *ad193x; 398f0fba2adSLiam Girdwood int ret; 399f0fba2adSLiam Girdwood 400f0fba2adSLiam Girdwood ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL); 401f0fba2adSLiam Girdwood if (ad193x == NULL) 402f0fba2adSLiam Girdwood return -ENOMEM; 403f0fba2adSLiam Girdwood 40430ab1e78SLars-Peter Clausen ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config); 40530ab1e78SLars-Peter Clausen if (IS_ERR(ad193x->regmap)) { 40630ab1e78SLars-Peter Clausen ret = PTR_ERR(ad193x->regmap); 40730ab1e78SLars-Peter Clausen goto err_free; 40830ab1e78SLars-Peter Clausen } 40930ab1e78SLars-Peter Clausen 410f0fba2adSLiam Girdwood spi_set_drvdata(spi, ad193x); 411f0fba2adSLiam Girdwood 412f0fba2adSLiam Girdwood ret = snd_soc_register_codec(&spi->dev, 413f0fba2adSLiam Girdwood &soc_codec_dev_ad193x, &ad193x_dai, 1); 414f0fba2adSLiam Girdwood if (ret < 0) 41530ab1e78SLars-Peter Clausen goto err_regmap_exit; 41630ab1e78SLars-Peter Clausen 41730ab1e78SLars-Peter Clausen return 0; 41830ab1e78SLars-Peter Clausen 41930ab1e78SLars-Peter Clausen err_regmap_exit: 42030ab1e78SLars-Peter Clausen regmap_exit(ad193x->regmap); 42130ab1e78SLars-Peter Clausen err_free: 422f0fba2adSLiam Girdwood kfree(ad193x); 42330ab1e78SLars-Peter Clausen 424f0fba2adSLiam Girdwood return ret; 425a1533d94SBarry Song } 426a1533d94SBarry Song 427a1533d94SBarry Song static int __devexit ad193x_spi_remove(struct spi_device *spi) 428a1533d94SBarry Song { 42930ab1e78SLars-Peter Clausen struct ad193x_priv *ad193x = spi_get_drvdata(spi); 43030ab1e78SLars-Peter Clausen 431f0fba2adSLiam Girdwood snd_soc_unregister_codec(&spi->dev); 43230ab1e78SLars-Peter Clausen regmap_exit(ad193x->regmap); 43330ab1e78SLars-Peter Clausen kfree(ad193x); 434f0fba2adSLiam Girdwood return 0; 435a1533d94SBarry Song } 436a1533d94SBarry Song 437a1533d94SBarry Song static struct spi_driver ad193x_spi_driver = { 438a1533d94SBarry Song .driver = { 439e43a7d41SMike Frysinger .name = "ad193x", 440a1533d94SBarry Song .owner = THIS_MODULE, 441a1533d94SBarry Song }, 442a1533d94SBarry Song .probe = ad193x_spi_probe, 443a1533d94SBarry Song .remove = __devexit_p(ad193x_spi_remove), 444a1533d94SBarry Song }; 445a1533d94SBarry Song #endif 446a1533d94SBarry Song 447a1533d94SBarry Song #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 44830ab1e78SLars-Peter Clausen 44930ab1e78SLars-Peter Clausen static const struct regmap_config ad193x_i2c_regmap_config = { 45030ab1e78SLars-Peter Clausen .val_bits = 8, 45130ab1e78SLars-Peter Clausen .reg_bits = 8, 45230ab1e78SLars-Peter Clausen }; 45330ab1e78SLars-Peter Clausen 454a1533d94SBarry Song static const struct i2c_device_id ad193x_id[] = { 455a1533d94SBarry Song { "ad1936", 0 }, 456a1533d94SBarry Song { "ad1937", 0 }, 457a1533d94SBarry Song { } 458a1533d94SBarry Song }; 459a1533d94SBarry Song MODULE_DEVICE_TABLE(i2c, ad193x_id); 460a1533d94SBarry Song 461a1533d94SBarry Song static int __devinit ad193x_i2c_probe(struct i2c_client *client, 462a1533d94SBarry Song const struct i2c_device_id *id) 463a1533d94SBarry Song { 464f0fba2adSLiam Girdwood struct ad193x_priv *ad193x; 465f0fba2adSLiam Girdwood int ret; 466f0fba2adSLiam Girdwood 467f0fba2adSLiam Girdwood ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL); 468f0fba2adSLiam Girdwood if (ad193x == NULL) 469f0fba2adSLiam Girdwood return -ENOMEM; 470f0fba2adSLiam Girdwood 47130ab1e78SLars-Peter Clausen ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config); 47230ab1e78SLars-Peter Clausen if (IS_ERR(ad193x->regmap)) { 47330ab1e78SLars-Peter Clausen ret = PTR_ERR(ad193x->regmap); 47430ab1e78SLars-Peter Clausen goto err_free; 47530ab1e78SLars-Peter Clausen } 47630ab1e78SLars-Peter Clausen 477f0fba2adSLiam Girdwood i2c_set_clientdata(client, ad193x); 478f0fba2adSLiam Girdwood 479f0fba2adSLiam Girdwood ret = snd_soc_register_codec(&client->dev, 480f0fba2adSLiam Girdwood &soc_codec_dev_ad193x, &ad193x_dai, 1); 481f0fba2adSLiam Girdwood if (ret < 0) 48230ab1e78SLars-Peter Clausen goto err_regmap_exit; 48330ab1e78SLars-Peter Clausen 48430ab1e78SLars-Peter Clausen return 0; 48530ab1e78SLars-Peter Clausen 48630ab1e78SLars-Peter Clausen err_regmap_exit: 48730ab1e78SLars-Peter Clausen regmap_exit(ad193x->regmap); 48830ab1e78SLars-Peter Clausen err_free: 489f0fba2adSLiam Girdwood kfree(ad193x); 490f0fba2adSLiam Girdwood return ret; 491a1533d94SBarry Song } 492a1533d94SBarry Song 493a1533d94SBarry Song static int __devexit ad193x_i2c_remove(struct i2c_client *client) 494a1533d94SBarry Song { 49530ab1e78SLars-Peter Clausen struct ad193x_priv *ad193x = i2c_get_clientdata(client); 49630ab1e78SLars-Peter Clausen 497f0fba2adSLiam Girdwood snd_soc_unregister_codec(&client->dev); 49830ab1e78SLars-Peter Clausen regmap_exit(ad193x->regmap); 49930ab1e78SLars-Peter Clausen kfree(ad193x); 500f0fba2adSLiam Girdwood return 0; 501a1533d94SBarry Song } 502a1533d94SBarry Song 503a1533d94SBarry Song static struct i2c_driver ad193x_i2c_driver = { 504a1533d94SBarry Song .driver = { 505e43a7d41SMike Frysinger .name = "ad193x", 506a1533d94SBarry Song }, 507a1533d94SBarry Song .probe = ad193x_i2c_probe, 508a1533d94SBarry Song .remove = __devexit_p(ad193x_i2c_remove), 509a1533d94SBarry Song .id_table = ad193x_id, 510a1533d94SBarry Song }; 511a1533d94SBarry Song #endif 512a1533d94SBarry Song 513a1533d94SBarry Song static int __init ad193x_modinit(void) 514a1533d94SBarry Song { 515a1533d94SBarry Song int ret; 516a1533d94SBarry Song 517a1533d94SBarry Song #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 518a1533d94SBarry Song ret = i2c_add_driver(&ad193x_i2c_driver); 519a1533d94SBarry Song if (ret != 0) { 520a1533d94SBarry Song printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n", 521a1533d94SBarry Song ret); 522a1533d94SBarry Song } 523a1533d94SBarry Song #endif 524a1533d94SBarry Song 525a1533d94SBarry Song #if defined(CONFIG_SPI_MASTER) 526a1533d94SBarry Song ret = spi_register_driver(&ad193x_spi_driver); 527a1533d94SBarry Song if (ret != 0) { 528a1533d94SBarry Song printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n", 529a1533d94SBarry Song ret); 530a1533d94SBarry Song } 531a1533d94SBarry Song #endif 532a1533d94SBarry Song return ret; 533a1533d94SBarry Song } 534a1533d94SBarry Song module_init(ad193x_modinit); 535a1533d94SBarry Song 536a1533d94SBarry Song static void __exit ad193x_modexit(void) 537a1533d94SBarry Song { 538a1533d94SBarry Song #if defined(CONFIG_SPI_MASTER) 539a1533d94SBarry Song spi_unregister_driver(&ad193x_spi_driver); 540a1533d94SBarry Song #endif 541a1533d94SBarry Song 542a1533d94SBarry Song #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 543a1533d94SBarry Song i2c_del_driver(&ad193x_i2c_driver); 544a1533d94SBarry Song #endif 545a1533d94SBarry Song } 546a1533d94SBarry Song module_exit(ad193x_modexit); 547a1533d94SBarry Song 548a1533d94SBarry Song MODULE_DESCRIPTION("ASoC ad193x driver"); 549a1533d94SBarry Song MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); 550a1533d94SBarry Song MODULE_LICENSE("GPL"); 551