aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/ad1938.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/ad1938.c')
-rw-r--r--sound/soc/codecs/ad1938.c228
1 files changed, 40 insertions, 188 deletions
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c
index 5d489186c05b..c233810d463d 100644
--- a/sound/soc/codecs/ad1938.c
+++ b/sound/soc/codecs/ad1938.c
@@ -46,6 +46,11 @@ struct ad1938_priv {
46 u8 reg_cache[AD1938_NUM_REGS]; 46 u8 reg_cache[AD1938_NUM_REGS];
47}; 47};
48 48
49/* ad1938 register cache & default register settings */
50static const u8 ad1938_reg[AD1938_NUM_REGS] = {
51 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
52};
53
49static struct snd_soc_codec *ad1938_codec; 54static struct snd_soc_codec *ad1938_codec;
50struct snd_soc_codec_device soc_codec_dev_ad1938; 55struct snd_soc_codec_device soc_codec_dev_ad1938;
51static int ad1938_register(struct ad1938_priv *ad1938); 56static int ad1938_register(struct ad1938_priv *ad1938);
@@ -97,6 +102,7 @@ static const struct snd_kcontrol_new ad1938_snd_controls[] = {
97static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { 102static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
98 SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1), 103 SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),
99 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), 104 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
105 SND_SOC_DAPM_SUPPLY("PLL_PWR", AD1938_PLL_CLK_CTRL0, 0, 1, NULL, 0),
100 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0), 106 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),
101 SND_SOC_DAPM_OUTPUT("DAC1OUT"), 107 SND_SOC_DAPM_OUTPUT("DAC1OUT"),
102 SND_SOC_DAPM_OUTPUT("DAC2OUT"), 108 SND_SOC_DAPM_OUTPUT("DAC2OUT"),
@@ -107,6 +113,8 @@ static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
107}; 113};
108 114
109static const struct snd_soc_dapm_route audio_paths[] = { 115static const struct snd_soc_dapm_route audio_paths[] = {
116 { "DAC", NULL, "PLL_PWR" },
117 { "ADC", NULL, "PLL_PWR" },
110 { "DAC", NULL, "ADC_PWR" }, 118 { "DAC", NULL, "ADC_PWR" },
111 { "ADC", NULL, "ADC_PWR" }, 119 { "ADC", NULL, "ADC_PWR" },
112 { "DAC1OUT", "DAC1 Switch", "DAC" }, 120 { "DAC1OUT", "DAC1 Switch", "DAC" },
@@ -126,30 +134,20 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute)
126 struct snd_soc_codec *codec = dai->codec; 134 struct snd_soc_codec *codec = dai->codec;
127 int reg; 135 int reg;
128 136
129 reg = codec->read(codec, AD1938_DAC_CTRL2); 137 reg = snd_soc_read(codec, AD1938_DAC_CTRL2);
130 reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg & 138 reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg &
131 (~AD1938_DAC_MASTER_MUTE); 139 (~AD1938_DAC_MASTER_MUTE);
132 codec->write(codec, AD1938_DAC_CTRL2, reg); 140 snd_soc_write(codec, AD1938_DAC_CTRL2, reg);
133
134 return 0;
135}
136
137static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd)
138{
139 int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0);
140 reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg |
141 AD1938_PLL_POWERDOWN;
142 codec->write(codec, AD1938_PLL_CLK_CTRL0, reg);
143 141
144 return 0; 142 return 0;
145} 143}
146 144
147static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 145static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
148 unsigned int mask, int slots, int width) 146 unsigned int rx_mask, int slots, int width)
149{ 147{
150 struct snd_soc_codec *codec = dai->codec; 148 struct snd_soc_codec *codec = dai->codec;
151 int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); 149 int dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1);
152 int adc_reg = codec->read(codec, AD1938_ADC_CTRL2); 150 int adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2);
153 151
154 dac_reg &= ~AD1938_DAC_CHAN_MASK; 152 dac_reg &= ~AD1938_DAC_CHAN_MASK;
155 adc_reg &= ~AD1938_ADC_CHAN_MASK; 153 adc_reg &= ~AD1938_ADC_CHAN_MASK;
@@ -175,8 +173,8 @@ static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
175 return -EINVAL; 173 return -EINVAL;
176 } 174 }
177 175
178 codec->write(codec, AD1938_DAC_CTRL1, dac_reg); 176 snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg);
179 codec->write(codec, AD1938_ADC_CTRL2, adc_reg); 177 snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg);
180 178
181 return 0; 179 return 0;
182} 180}
@@ -187,8 +185,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
187 struct snd_soc_codec *codec = codec_dai->codec; 185 struct snd_soc_codec *codec = codec_dai->codec;
188 int adc_reg, dac_reg; 186 int adc_reg, dac_reg;
189 187
190 adc_reg = codec->read(codec, AD1938_ADC_CTRL2); 188 adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2);
191 dac_reg = codec->read(codec, AD1938_DAC_CTRL1); 189 dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1);
192 190
193 /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S 191 /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
194 * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) 192 * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
@@ -265,8 +263,8 @@ static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
265 return -EINVAL; 263 return -EINVAL;
266 } 264 }
267 265
268 codec->write(codec, AD1938_ADC_CTRL2, adc_reg); 266 snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg);
269 codec->write(codec, AD1938_DAC_CTRL1, dac_reg); 267 snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg);
270 268
271 return 0; 269 return 0;
272} 270}
@@ -295,134 +293,13 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream,
295 break; 293 break;
296 } 294 }
297 295
298 reg = codec->read(codec, AD1938_DAC_CTRL2); 296 reg = snd_soc_read(codec, AD1938_DAC_CTRL2);
299 reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len; 297 reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len;
300 codec->write(codec, AD1938_DAC_CTRL2, reg); 298 snd_soc_write(codec, AD1938_DAC_CTRL2, reg);
301 299
302 reg = codec->read(codec, AD1938_ADC_CTRL1); 300 reg = snd_soc_read(codec, AD1938_ADC_CTRL1);
303 reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len; 301 reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len;
304 codec->write(codec, AD1938_ADC_CTRL1, reg); 302 snd_soc_write(codec, AD1938_ADC_CTRL1, reg);
305
306 return 0;
307}
308
309static int ad1938_set_bias_level(struct snd_soc_codec *codec,
310 enum snd_soc_bias_level level)
311{
312 switch (level) {
313 case SND_SOC_BIAS_ON:
314 ad1938_pll_powerctrl(codec, 1);
315 break;
316 case SND_SOC_BIAS_PREPARE:
317 break;
318 case SND_SOC_BIAS_STANDBY:
319 case SND_SOC_BIAS_OFF:
320 ad1938_pll_powerctrl(codec, 0);
321 break;
322 }
323 codec->bias_level = level;
324 return 0;
325}
326
327/*
328 * interface to read/write ad1938 register
329 */
330
331#define AD1938_SPI_ADDR 0x4
332#define AD1938_SPI_READ 0x1
333#define AD1938_SPI_BUFLEN 3
334
335/*
336 * write to the ad1938 register space
337 */
338
339static int ad1938_write_reg(struct snd_soc_codec *codec, unsigned int reg,
340 unsigned int value)
341{
342 u8 *reg_cache = codec->reg_cache;
343 int ret = 0;
344
345 if (value != reg_cache[reg]) {
346 uint8_t buf[AD1938_SPI_BUFLEN];
347 struct spi_transfer t = {
348 .tx_buf = buf,
349 .len = AD1938_SPI_BUFLEN,
350 };
351 struct spi_message m;
352
353 buf[0] = AD1938_SPI_ADDR << 1;
354 buf[1] = reg;
355 buf[2] = value;
356 spi_message_init(&m);
357 spi_message_add_tail(&t, &m);
358 ret = spi_sync(codec->control_data, &m);
359 if (ret == 0)
360 reg_cache[reg] = value;
361 }
362
363 return ret;
364}
365
366/*
367 * read from the ad1938 register space cache
368 */
369
370static unsigned int ad1938_read_reg_cache(struct snd_soc_codec *codec,
371 unsigned int reg)
372{
373 u8 *reg_cache = codec->reg_cache;
374
375 if (reg >= codec->reg_cache_size)
376 return -EINVAL;
377
378 return reg_cache[reg];
379}
380
381/*
382 * read from the ad1938 register space
383 */
384
385static unsigned int ad1938_read_reg(struct snd_soc_codec *codec,
386 unsigned int reg)
387{
388 char w_buf[AD1938_SPI_BUFLEN];
389 char r_buf[AD1938_SPI_BUFLEN];
390 int ret;
391
392 struct spi_transfer t = {
393 .tx_buf = w_buf,
394 .rx_buf = r_buf,
395 .len = AD1938_SPI_BUFLEN,
396 };
397 struct spi_message m;
398
399 w_buf[0] = (AD1938_SPI_ADDR << 1) | AD1938_SPI_READ;
400 w_buf[1] = reg;
401 w_buf[2] = 0;
402
403 spi_message_init(&m);
404 spi_message_add_tail(&t, &m);
405 ret = spi_sync(codec->control_data, &m);
406 if (ret == 0)
407 return r_buf[2];
408 else
409 return -EIO;
410}
411
412static int ad1938_fill_cache(struct snd_soc_codec *codec)
413{
414 int i;
415 u8 *reg_cache = codec->reg_cache;
416 struct spi_device *spi = codec->control_data;
417
418 for (i = 0; i < codec->reg_cache_size; i++) {
419 int ret = ad1938_read_reg(codec, i);
420 if (ret == -EIO) {
421 dev_err(&spi->dev, "AD1938 SPI read failure\n");
422 return ret;
423 }
424 reg_cache[i] = ret;
425 }
426 303
427 return 0; 304 return 0;
428} 305}
@@ -512,32 +389,37 @@ static int ad1938_register(struct ad1938_priv *ad1938)
512 codec->owner = THIS_MODULE; 389 codec->owner = THIS_MODULE;
513 codec->dai = &ad1938_dai; 390 codec->dai = &ad1938_dai;
514 codec->num_dai = 1; 391 codec->num_dai = 1;
515 codec->write = ad1938_write_reg;
516 codec->read = ad1938_read_reg_cache;
517 codec->set_bias_level = ad1938_set_bias_level;
518 INIT_LIST_HEAD(&codec->dapm_widgets); 392 INIT_LIST_HEAD(&codec->dapm_widgets);
519 INIT_LIST_HEAD(&codec->dapm_paths); 393 INIT_LIST_HEAD(&codec->dapm_paths);
520 394
521 ad1938_dai.dev = codec->dev; 395 ad1938_dai.dev = codec->dev;
522 ad1938_codec = codec; 396 ad1938_codec = codec;
523 397
398 memcpy(codec->reg_cache, ad1938_reg, AD1938_NUM_REGS);
399
400 ret = snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_SPI);
401 if (ret < 0) {
402 dev_err(codec->dev, "failed to set cache I/O: %d\n",
403 ret);
404 kfree(ad1938);
405 return ret;
406 }
407
524 /* default setting for ad1938 */ 408 /* default setting for ad1938 */
525 409
526 /* unmute dac channels */ 410 /* unmute dac channels */
527 codec->write(codec, AD1938_DAC_CHNL_MUTE, 0x0); 411 snd_soc_write(codec, AD1938_DAC_CHNL_MUTE, 0x0);
528 /* de-emphasis: 48kHz, powedown dac */ 412 /* de-emphasis: 48kHz, powedown dac */
529 codec->write(codec, AD1938_DAC_CTRL2, 0x1A); 413 snd_soc_write(codec, AD1938_DAC_CTRL2, 0x1A);
530 /* powerdown dac, dac in tdm mode */ 414 /* powerdown dac, dac in tdm mode */
531 codec->write(codec, AD1938_DAC_CTRL0, 0x41); 415 snd_soc_write(codec, AD1938_DAC_CTRL0, 0x41);
532 /* high-pass filter enable */ 416 /* high-pass filter enable */
533 codec->write(codec, AD1938_ADC_CTRL0, 0x3); 417 snd_soc_write(codec, AD1938_ADC_CTRL0, 0x3);
534 /* sata delay=1, adc aux mode */ 418 /* sata delay=1, adc aux mode */
535 codec->write(codec, AD1938_ADC_CTRL1, 0x43); 419 snd_soc_write(codec, AD1938_ADC_CTRL1, 0x43);
536 /* pll input: mclki/xi */ 420 /* pll input: mclki/xi */
537 codec->write(codec, AD1938_PLL_CLK_CTRL0, 0x9D); 421 snd_soc_write(codec, AD1938_PLL_CLK_CTRL0, 0x9D);
538 codec->write(codec, AD1938_PLL_CLK_CTRL1, 0x04); 422 snd_soc_write(codec, AD1938_PLL_CLK_CTRL1, 0x04);
539
540 ad1938_fill_cache(codec);
541 423
542 ret = snd_soc_register_codec(codec); 424 ret = snd_soc_register_codec(codec);
543 if (ret != 0) { 425 if (ret != 0) {
@@ -559,7 +441,6 @@ static int ad1938_register(struct ad1938_priv *ad1938)
559 441
560static void ad1938_unregister(struct ad1938_priv *ad1938) 442static void ad1938_unregister(struct ad1938_priv *ad1938)
561{ 443{
562 ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF);
563 snd_soc_unregister_dai(&ad1938_dai); 444 snd_soc_unregister_dai(&ad1938_dai);
564 snd_soc_unregister_codec(&ad1938->codec); 445 snd_soc_unregister_codec(&ad1938->codec);
565 kfree(ad1938); 446 kfree(ad1938);
@@ -593,7 +474,6 @@ static int ad1938_probe(struct platform_device *pdev)
593 ARRAY_SIZE(ad1938_dapm_widgets)); 474 ARRAY_SIZE(ad1938_dapm_widgets));
594 snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); 475 snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
595 476
596 ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
597 477
598pcm_err: 478pcm_err:
599 return ret; 479 return ret;
@@ -610,37 +490,9 @@ static int ad1938_remove(struct platform_device *pdev)
610 return 0; 490 return 0;
611} 491}
612 492
613#ifdef CONFIG_PM
614static int ad1938_suspend(struct platform_device *pdev,
615 pm_message_t state)
616{
617 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
618 struct snd_soc_codec *codec = socdev->card->codec;
619
620 ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF);
621 return 0;
622}
623
624static int ad1938_resume(struct platform_device *pdev)
625{
626 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
627 struct snd_soc_codec *codec = socdev->card->codec;
628
629 if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
630 ad1938_set_bias_level(codec, SND_SOC_BIAS_ON);
631
632 return 0;
633}
634#else
635#define ad1938_suspend NULL
636#define ad1938_resume NULL
637#endif
638
639struct snd_soc_codec_device soc_codec_dev_ad1938 = { 493struct snd_soc_codec_device soc_codec_dev_ad1938 = {
640 .probe = ad1938_probe, 494 .probe = ad1938_probe,
641 .remove = ad1938_remove, 495 .remove = ad1938_remove,
642 .suspend = ad1938_suspend,
643 .resume = ad1938_resume,
644}; 496};
645EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938); 497EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938);
646 498