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 */ 33c4e7a4a2SLars-Peter Clausen static const char * const 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 38591c034aSLars-Peter Clausen static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); 39591c034aSLars-Peter Clausen 40a1533d94SBarry Song static const struct snd_kcontrol_new ad193x_snd_controls[] = { 41a1533d94SBarry Song /* DAC volume control */ 42591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL, 43591c034aSLars-Peter Clausen AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv), 44591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL, 45591c034aSLars-Peter Clausen AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv), 46591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL, 47591c034aSLars-Peter Clausen AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv), 48591c034aSLars-Peter Clausen SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL, 49591c034aSLars-Peter Clausen AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv), 50a1533d94SBarry Song 51a1533d94SBarry Song /* ADC switch control */ 52a1533d94SBarry Song SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE, 53a1533d94SBarry Song AD193X_ADCR1_MUTE, 1, 1), 54a1533d94SBarry Song SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE, 55a1533d94SBarry Song AD193X_ADCR2_MUTE, 1, 1), 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 67a1533d94SBarry Song /* ADC high-pass filter */ 68a1533d94SBarry Song SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0, 69a1533d94SBarry Song AD193X_ADC_HIGHPASS_FILTER, 1, 0), 70a1533d94SBarry Song 71a1533d94SBarry Song /* DAC de-emphasis */ 72a1533d94SBarry Song SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum), 73a1533d94SBarry Song }; 74a1533d94SBarry Song 75a1533d94SBarry Song static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { 76a1533d94SBarry Song SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1), 77a1533d94SBarry Song SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), 78a1533d94SBarry Song SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), 79a1533d94SBarry Song SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), 800718fd27SLars-Peter Clausen SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), 81a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC1OUT"), 82a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC2OUT"), 83a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC3OUT"), 84a1533d94SBarry Song SND_SOC_DAPM_OUTPUT("DAC4OUT"), 85a1533d94SBarry Song SND_SOC_DAPM_INPUT("ADC1IN"), 86a1533d94SBarry Song SND_SOC_DAPM_INPUT("ADC2IN"), 87a1533d94SBarry Song }; 88a1533d94SBarry Song 89a1533d94SBarry Song static const struct snd_soc_dapm_route audio_paths[] = { 900718fd27SLars-Peter Clausen { "DAC", NULL, "SYSCLK" }, 910718fd27SLars-Peter Clausen { "ADC", NULL, "SYSCLK" }, 92a1533d94SBarry Song { "DAC", NULL, "ADC_PWR" }, 93a1533d94SBarry Song { "ADC", NULL, "ADC_PWR" }, 94b21990b4SLars-Peter Clausen { "DAC1OUT", NULL, "DAC" }, 95b21990b4SLars-Peter Clausen { "DAC2OUT", NULL, "DAC" }, 96b21990b4SLars-Peter Clausen { "DAC3OUT", NULL, "DAC" }, 97b21990b4SLars-Peter Clausen { "DAC4OUT", NULL, "DAC" }, 98b21990b4SLars-Peter Clausen { "ADC", NULL, "ADC1IN" }, 99b21990b4SLars-Peter Clausen { "ADC", NULL, "ADC2IN" }, 1000718fd27SLars-Peter Clausen { "SYSCLK", NULL, "PLL_PWR" }, 101a1533d94SBarry Song }; 102a1533d94SBarry Song 103a1533d94SBarry Song /* 104a1533d94SBarry Song * DAI ops entries 105a1533d94SBarry Song */ 106a1533d94SBarry Song 107a1533d94SBarry Song static int ad193x_mute(struct snd_soc_dai *dai, int mute) 108a1533d94SBarry Song { 10934cbe168SLars-Peter Clausen struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec); 110a1533d94SBarry Song 11154c96cfdSAxel Lin if (mute) 11234cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, 11354c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE, 11454c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE); 11554c96cfdSAxel Lin else 11634cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, 11754c96cfdSAxel Lin AD193X_DAC_MASTER_MUTE, 0); 118a1533d94SBarry Song 119a1533d94SBarry Song return 0; 120a1533d94SBarry Song } 121a1533d94SBarry Song 122a1533d94SBarry Song static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 123a1533d94SBarry Song unsigned int rx_mask, int slots, int width) 124a1533d94SBarry Song { 12534cbe168SLars-Peter Clausen struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec); 126b82ca578SLars-Peter Clausen unsigned int channels; 127a1533d94SBarry Song 128a1533d94SBarry Song switch (slots) { 129a1533d94SBarry Song case 2: 130b82ca578SLars-Peter Clausen channels = AD193X_2_CHANNELS; 131a1533d94SBarry Song break; 132a1533d94SBarry Song case 4: 133b82ca578SLars-Peter Clausen channels = AD193X_4_CHANNELS; 134a1533d94SBarry Song break; 135a1533d94SBarry Song case 8: 136b82ca578SLars-Peter Clausen channels = AD193X_8_CHANNELS; 137a1533d94SBarry Song break; 138a1533d94SBarry Song case 16: 139b82ca578SLars-Peter Clausen channels = AD193X_16_CHANNELS; 140a1533d94SBarry Song break; 141a1533d94SBarry Song default: 142a1533d94SBarry Song return -EINVAL; 143a1533d94SBarry Song } 144a1533d94SBarry Song 14534cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, 14634cbe168SLars-Peter Clausen AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT); 14734cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, 14834cbe168SLars-Peter Clausen AD193X_ADC_CHAN_MASK, channels << AD193X_ADC_CHAN_SHFT); 149a1533d94SBarry Song 150a1533d94SBarry Song return 0; 151a1533d94SBarry Song } 152a1533d94SBarry Song 153a1533d94SBarry Song static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, 154a1533d94SBarry Song unsigned int fmt) 155a1533d94SBarry Song { 15634cbe168SLars-Peter Clausen struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec_dai->codec); 157b82ca578SLars-Peter Clausen unsigned int adc_serfmt = 0; 158b82ca578SLars-Peter Clausen unsigned int adc_fmt = 0; 159b82ca578SLars-Peter Clausen unsigned int dac_fmt = 0; 160a1533d94SBarry Song 161a1533d94SBarry Song /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S 162a1533d94SBarry Song * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) 163a1533d94SBarry Song */ 164a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 165a1533d94SBarry Song case SND_SOC_DAIFMT_I2S: 166b82ca578SLars-Peter Clausen adc_serfmt |= AD193X_ADC_SERFMT_TDM; 167a1533d94SBarry Song break; 168a1533d94SBarry Song case SND_SOC_DAIFMT_DSP_A: 169b82ca578SLars-Peter Clausen adc_serfmt |= AD193X_ADC_SERFMT_AUX; 170a1533d94SBarry Song break; 171a1533d94SBarry Song default: 172a1533d94SBarry Song return -EINVAL; 173a1533d94SBarry Song } 174a1533d94SBarry Song 175a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 176a1533d94SBarry Song case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ 177a1533d94SBarry Song break; 178a1533d94SBarry Song case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */ 179b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LEFT_HIGH; 180b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LEFT_HIGH; 181a1533d94SBarry Song break; 182a1533d94SBarry Song case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */ 183b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_INV; 184b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_INV; 185a1533d94SBarry Song break; 186a1533d94SBarry Song case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */ 187b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LEFT_HIGH; 188b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_INV; 189b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LEFT_HIGH; 190b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_INV; 191a1533d94SBarry Song break; 192a1533d94SBarry Song default: 193a1533d94SBarry Song return -EINVAL; 194a1533d94SBarry Song } 195a1533d94SBarry Song 196a1533d94SBarry Song switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 197a1533d94SBarry Song case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ 198b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LCR_MASTER; 199b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_MASTER; 200b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LCR_MASTER; 201b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_MASTER; 202a1533d94SBarry Song break; 203a1533d94SBarry Song case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */ 204b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_LCR_MASTER; 205b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_LCR_MASTER; 206a1533d94SBarry Song break; 207a1533d94SBarry Song case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ 208b82ca578SLars-Peter Clausen adc_fmt |= AD193X_ADC_BCLK_MASTER; 209b82ca578SLars-Peter Clausen dac_fmt |= AD193X_DAC_BCLK_MASTER; 210a1533d94SBarry Song break; 211a1533d94SBarry Song case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */ 212a1533d94SBarry Song break; 213a1533d94SBarry Song default: 214a1533d94SBarry Song return -EINVAL; 215a1533d94SBarry Song } 216a1533d94SBarry Song 21734cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1, 21834cbe168SLars-Peter Clausen AD193X_ADC_SERFMT_MASK, adc_serfmt); 21934cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, 22034cbe168SLars-Peter Clausen AD193X_ADC_FMT_MASK, adc_fmt); 22134cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, 22234cbe168SLars-Peter Clausen AD193X_DAC_FMT_MASK, dac_fmt); 223a1533d94SBarry Song 224a1533d94SBarry Song return 0; 225a1533d94SBarry Song } 226a1533d94SBarry Song 227fab90aa4SBarry Song static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai, 228fab90aa4SBarry Song int clk_id, unsigned int freq, int dir) 229fab90aa4SBarry Song { 230fab90aa4SBarry Song struct snd_soc_codec *codec = codec_dai->codec; 231fab90aa4SBarry Song struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); 232fab90aa4SBarry Song switch (freq) { 233fab90aa4SBarry Song case 12288000: 234fab90aa4SBarry Song case 18432000: 235fab90aa4SBarry Song case 24576000: 236fab90aa4SBarry Song case 36864000: 237fab90aa4SBarry Song ad193x->sysclk = freq; 238fab90aa4SBarry Song return 0; 239fab90aa4SBarry Song } 240fab90aa4SBarry Song return -EINVAL; 241fab90aa4SBarry Song } 242fab90aa4SBarry Song 243a1533d94SBarry Song static int ad193x_hw_params(struct snd_pcm_substream *substream, 244a1533d94SBarry Song struct snd_pcm_hw_params *params, 245a1533d94SBarry Song struct snd_soc_dai *dai) 246a1533d94SBarry Song { 24754c96cfdSAxel Lin int word_len = 0, master_rate = 0; 248e6968a17SMark Brown struct snd_soc_codec *codec = dai->codec; 249fab90aa4SBarry Song struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); 250a1533d94SBarry Song 251a1533d94SBarry Song /* bit size */ 252a1533d94SBarry Song switch (params_format(params)) { 253a1533d94SBarry Song case SNDRV_PCM_FORMAT_S16_LE: 254a1533d94SBarry Song word_len = 3; 255a1533d94SBarry Song break; 256a1533d94SBarry Song case SNDRV_PCM_FORMAT_S20_3LE: 257a1533d94SBarry Song word_len = 1; 258a1533d94SBarry Song break; 259a1533d94SBarry Song case SNDRV_PCM_FORMAT_S24_LE: 260a1533d94SBarry Song case SNDRV_PCM_FORMAT_S32_LE: 261a1533d94SBarry Song word_len = 0; 262a1533d94SBarry Song break; 263a1533d94SBarry Song } 264a1533d94SBarry Song 265fab90aa4SBarry Song switch (ad193x->sysclk) { 266fab90aa4SBarry Song case 12288000: 267fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_256; 268fab90aa4SBarry Song break; 269fab90aa4SBarry Song case 18432000: 270fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_384; 271fab90aa4SBarry Song break; 272fab90aa4SBarry Song case 24576000: 273fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_512; 274fab90aa4SBarry Song break; 275fab90aa4SBarry Song case 36864000: 276fab90aa4SBarry Song master_rate = AD193X_PLL_INPUT_768; 277fab90aa4SBarry Song break; 278fab90aa4SBarry Song } 279fab90aa4SBarry Song 28034cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 28154c96cfdSAxel Lin AD193X_PLL_INPUT_MASK, master_rate); 282fab90aa4SBarry Song 28334cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2, 28454c96cfdSAxel Lin AD193X_DAC_WORD_LEN_MASK, 28554c96cfdSAxel Lin word_len << AD193X_DAC_WORD_LEN_SHFT); 286a1533d94SBarry Song 28734cbe168SLars-Peter Clausen regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1, 28854c96cfdSAxel Lin AD193X_ADC_WORD_LEN_MASK, word_len); 289a1533d94SBarry Song 290a1533d94SBarry Song return 0; 291a1533d94SBarry Song } 292a1533d94SBarry Song 29385e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops ad193x_dai_ops = { 294f0fba2adSLiam Girdwood .hw_params = ad193x_hw_params, 295f0fba2adSLiam Girdwood .digital_mute = ad193x_mute, 296f0fba2adSLiam Girdwood .set_tdm_slot = ad193x_set_tdm_slot, 297f0fba2adSLiam Girdwood .set_sysclk = ad193x_set_dai_sysclk, 298f0fba2adSLiam Girdwood .set_fmt = ad193x_set_dai_fmt, 299f0fba2adSLiam Girdwood }; 300f0fba2adSLiam Girdwood 301f0fba2adSLiam Girdwood /* codec DAI instance */ 302f0fba2adSLiam Girdwood static struct snd_soc_dai_driver ad193x_dai = { 303f0fba2adSLiam Girdwood .name = "ad193x-hifi", 304f0fba2adSLiam Girdwood .playback = { 305f0fba2adSLiam Girdwood .stream_name = "Playback", 306f0fba2adSLiam Girdwood .channels_min = 2, 307f0fba2adSLiam Girdwood .channels_max = 8, 308f0fba2adSLiam Girdwood .rates = SNDRV_PCM_RATE_48000, 309f0fba2adSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 310f0fba2adSLiam Girdwood SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 311f0fba2adSLiam Girdwood }, 312f0fba2adSLiam Girdwood .capture = { 313f0fba2adSLiam Girdwood .stream_name = "Capture", 314f0fba2adSLiam Girdwood .channels_min = 2, 315f0fba2adSLiam Girdwood .channels_max = 4, 316f0fba2adSLiam Girdwood .rates = SNDRV_PCM_RATE_48000, 317f0fba2adSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | 318f0fba2adSLiam Girdwood SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, 319f0fba2adSLiam Girdwood }, 320f0fba2adSLiam Girdwood .ops = &ad193x_dai_ops, 321f0fba2adSLiam Girdwood }; 322f0fba2adSLiam Girdwood 323f0fba2adSLiam Girdwood static int ad193x_probe(struct snd_soc_codec *codec) 324a1533d94SBarry Song { 325f0fba2adSLiam Girdwood struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); 3269dd7b79aSBarry Song int ret; 3279dd7b79aSBarry Song 32830ab1e78SLars-Peter Clausen codec->control_data = ad193x->regmap; 32930ab1e78SLars-Peter Clausen ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); 330a1533d94SBarry Song if (ret < 0) { 331119bfef2SScott Jiang dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); 332a1533d94SBarry Song return ret; 333a1533d94SBarry Song } 334a1533d94SBarry Song 335a1533d94SBarry Song /* default setting for ad193x */ 336a1533d94SBarry Song 337a1533d94SBarry Song /* unmute dac channels */ 33834cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0); 339a1533d94SBarry Song /* de-emphasis: 48kHz, powedown dac */ 34034cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A); 341a1533d94SBarry Song /* powerdown dac, dac in tdm mode */ 34234cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41); 343a1533d94SBarry Song /* high-pass filter enable */ 34434cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3); 345a1533d94SBarry Song /* sata delay=1, adc aux mode */ 34634cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43); 347a1533d94SBarry Song /* pll input: mclki/xi */ 34834cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ 34934cbe168SLars-Peter Clausen regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04); 350a1533d94SBarry Song 351a1533d94SBarry Song return ret; 352a1533d94SBarry Song } 353a1533d94SBarry Song 354f0fba2adSLiam Girdwood static struct snd_soc_codec_driver soc_codec_dev_ad193x = { 355a1533d94SBarry Song .probe = ad193x_probe, 356b90d4183SLars-Peter Clausen .controls = ad193x_snd_controls, 357b90d4183SLars-Peter Clausen .num_controls = ARRAY_SIZE(ad193x_snd_controls), 358b90d4183SLars-Peter Clausen .dapm_widgets = ad193x_dapm_widgets, 359b90d4183SLars-Peter Clausen .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets), 360b90d4183SLars-Peter Clausen .dapm_routes = audio_paths, 361b90d4183SLars-Peter Clausen .num_dapm_routes = ARRAY_SIZE(audio_paths), 362a1533d94SBarry Song }; 363a1533d94SBarry Song 36434cbe168SLars-Peter Clausen static bool adau193x_reg_volatile(struct device *dev, unsigned int reg) 36534cbe168SLars-Peter Clausen { 36634cbe168SLars-Peter Clausen return false; 36734cbe168SLars-Peter Clausen } 36834cbe168SLars-Peter Clausen 369a1533d94SBarry Song #if defined(CONFIG_SPI_MASTER) 37030ab1e78SLars-Peter Clausen 37130ab1e78SLars-Peter Clausen static const struct regmap_config ad193x_spi_regmap_config = { 37230ab1e78SLars-Peter Clausen .val_bits = 8, 37330ab1e78SLars-Peter Clausen .reg_bits = 16, 37430ab1e78SLars-Peter Clausen .read_flag_mask = 0x09, 37530ab1e78SLars-Peter Clausen .write_flag_mask = 0x08, 37634cbe168SLars-Peter Clausen 37734cbe168SLars-Peter Clausen .max_register = AD193X_NUM_REGS - 1, 37834cbe168SLars-Peter Clausen .volatile_reg = adau193x_reg_volatile, 37930ab1e78SLars-Peter Clausen }; 38030ab1e78SLars-Peter Clausen 381a1533d94SBarry Song static int __devinit ad193x_spi_probe(struct spi_device *spi) 382a1533d94SBarry Song { 383f0fba2adSLiam Girdwood struct ad193x_priv *ad193x; 384f0fba2adSLiam Girdwood 38530c88f2cSAxel Lin ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv), 38630c88f2cSAxel Lin GFP_KERNEL); 387f0fba2adSLiam Girdwood if (ad193x == NULL) 388f0fba2adSLiam Girdwood return -ENOMEM; 389f0fba2adSLiam Girdwood 390*040242ccSLars-Peter Clausen ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config); 391*040242ccSLars-Peter Clausen if (IS_ERR(ad193x->regmap)) 392*040242ccSLars-Peter Clausen return PTR_ERR(ad193x->regmap); 39330ab1e78SLars-Peter Clausen 394f0fba2adSLiam Girdwood spi_set_drvdata(spi, ad193x); 395f0fba2adSLiam Girdwood 396*040242ccSLars-Peter Clausen return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x, 397*040242ccSLars-Peter Clausen &ad193x_dai, 1); 398a1533d94SBarry Song } 399a1533d94SBarry Song 400a1533d94SBarry Song static int __devexit ad193x_spi_remove(struct spi_device *spi) 401a1533d94SBarry Song { 402f0fba2adSLiam Girdwood snd_soc_unregister_codec(&spi->dev); 403f0fba2adSLiam Girdwood return 0; 404a1533d94SBarry Song } 405a1533d94SBarry Song 406a1533d94SBarry Song static struct spi_driver ad193x_spi_driver = { 407a1533d94SBarry Song .driver = { 408e43a7d41SMike Frysinger .name = "ad193x", 409a1533d94SBarry Song .owner = THIS_MODULE, 410a1533d94SBarry Song }, 411a1533d94SBarry Song .probe = ad193x_spi_probe, 412a1533d94SBarry Song .remove = __devexit_p(ad193x_spi_remove), 413a1533d94SBarry Song }; 414a1533d94SBarry Song #endif 415a1533d94SBarry Song 416a1533d94SBarry Song #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 41730ab1e78SLars-Peter Clausen 41830ab1e78SLars-Peter Clausen static const struct regmap_config ad193x_i2c_regmap_config = { 41930ab1e78SLars-Peter Clausen .val_bits = 8, 42030ab1e78SLars-Peter Clausen .reg_bits = 8, 42134cbe168SLars-Peter Clausen 42234cbe168SLars-Peter Clausen .max_register = AD193X_NUM_REGS - 1, 42334cbe168SLars-Peter Clausen .volatile_reg = adau193x_reg_volatile, 42430ab1e78SLars-Peter Clausen }; 42530ab1e78SLars-Peter Clausen 426a1533d94SBarry Song static const struct i2c_device_id ad193x_id[] = { 427a1533d94SBarry Song { "ad1936", 0 }, 428a1533d94SBarry Song { "ad1937", 0 }, 429a1533d94SBarry Song { } 430a1533d94SBarry Song }; 431a1533d94SBarry Song MODULE_DEVICE_TABLE(i2c, ad193x_id); 432a1533d94SBarry Song 433a1533d94SBarry Song static int __devinit ad193x_i2c_probe(struct i2c_client *client, 434a1533d94SBarry Song const struct i2c_device_id *id) 435a1533d94SBarry Song { 436f0fba2adSLiam Girdwood struct ad193x_priv *ad193x; 437f0fba2adSLiam Girdwood 43830c88f2cSAxel Lin ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv), 43930c88f2cSAxel Lin GFP_KERNEL); 440f0fba2adSLiam Girdwood if (ad193x == NULL) 441f0fba2adSLiam Girdwood return -ENOMEM; 442f0fba2adSLiam Girdwood 443*040242ccSLars-Peter Clausen ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config); 444*040242ccSLars-Peter Clausen if (IS_ERR(ad193x->regmap)) 445*040242ccSLars-Peter Clausen return PTR_ERR(ad193x->regmap); 44630ab1e78SLars-Peter Clausen 447f0fba2adSLiam Girdwood i2c_set_clientdata(client, ad193x); 448f0fba2adSLiam Girdwood 449*040242ccSLars-Peter Clausen return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x, 450*040242ccSLars-Peter Clausen &ad193x_dai, 1); 451a1533d94SBarry Song } 452a1533d94SBarry Song 453a1533d94SBarry Song static int __devexit ad193x_i2c_remove(struct i2c_client *client) 454a1533d94SBarry Song { 455f0fba2adSLiam Girdwood snd_soc_unregister_codec(&client->dev); 456f0fba2adSLiam Girdwood return 0; 457a1533d94SBarry Song } 458a1533d94SBarry Song 459a1533d94SBarry Song static struct i2c_driver ad193x_i2c_driver = { 460a1533d94SBarry Song .driver = { 461e43a7d41SMike Frysinger .name = "ad193x", 462a1533d94SBarry Song }, 463a1533d94SBarry Song .probe = ad193x_i2c_probe, 464a1533d94SBarry Song .remove = __devexit_p(ad193x_i2c_remove), 465a1533d94SBarry Song .id_table = ad193x_id, 466a1533d94SBarry Song }; 467a1533d94SBarry Song #endif 468a1533d94SBarry Song 469a1533d94SBarry Song static int __init ad193x_modinit(void) 470a1533d94SBarry Song { 471a1533d94SBarry Song int ret; 472a1533d94SBarry Song 473a1533d94SBarry Song #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 474a1533d94SBarry Song ret = i2c_add_driver(&ad193x_i2c_driver); 475a1533d94SBarry Song if (ret != 0) { 476a1533d94SBarry Song printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n", 477a1533d94SBarry Song ret); 478a1533d94SBarry Song } 479a1533d94SBarry Song #endif 480a1533d94SBarry Song 481a1533d94SBarry Song #if defined(CONFIG_SPI_MASTER) 482a1533d94SBarry Song ret = spi_register_driver(&ad193x_spi_driver); 483a1533d94SBarry Song if (ret != 0) { 484a1533d94SBarry Song printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n", 485a1533d94SBarry Song ret); 486a1533d94SBarry Song } 487a1533d94SBarry Song #endif 488a1533d94SBarry Song return ret; 489a1533d94SBarry Song } 490a1533d94SBarry Song module_init(ad193x_modinit); 491a1533d94SBarry Song 492a1533d94SBarry Song static void __exit ad193x_modexit(void) 493a1533d94SBarry Song { 494a1533d94SBarry Song #if defined(CONFIG_SPI_MASTER) 495a1533d94SBarry Song spi_unregister_driver(&ad193x_spi_driver); 496a1533d94SBarry Song #endif 497a1533d94SBarry Song 498a1533d94SBarry Song #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 499a1533d94SBarry Song i2c_del_driver(&ad193x_i2c_driver); 500a1533d94SBarry Song #endif 501a1533d94SBarry Song } 502a1533d94SBarry Song module_exit(ad193x_modexit); 503a1533d94SBarry Song 504a1533d94SBarry Song MODULE_DESCRIPTION("ASoC ad193x driver"); 505a1533d94SBarry Song MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); 506a1533d94SBarry Song MODULE_LICENSE("GPL"); 507