aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8974.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-15 07:15:10 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-15 07:15:10 -0400
commit1e97f50b7023cda00cb720e53b9e59c250cb4ed7 (patch)
treef80ecb7523428a19e2325f38b0a4b6ac0fae9a62 /sound/soc/codecs/wm8974.c
parent37cfa1950e2a24d9fa4a593186645d8e2b5042a8 (diff)
ASoC: Factor out cache I/O from WM8974
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8974.c')
-rw-r--r--sound/soc/codecs/wm8974.c149
1 files changed, 55 insertions, 94 deletions
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 5104c8aa34f..d8a013ab317 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -57,55 +57,7 @@ struct wm8974_priv {
57 57
58static struct snd_soc_codec *wm8974_codec; 58static struct snd_soc_codec *wm8974_codec;
59 59
60/* 60#define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0)
61 * read wm8974 register cache
62 */
63static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec *codec,
64 unsigned int reg)
65{
66 u16 *cache = codec->reg_cache;
67 if (reg == WM8974_RESET)
68 return 0;
69 if (reg >= WM8974_CACHEREGNUM)
70 return -1;
71 return cache[reg];
72}
73
74/*
75 * write wm8974 register cache
76 */
77static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec,
78 u16 reg, unsigned int value)
79{
80 u16 *cache = codec->reg_cache;
81 if (reg >= WM8974_CACHEREGNUM)
82 return;
83 cache[reg] = value;
84}
85
86/*
87 * write to the WM8974 register space
88 */
89static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg,
90 unsigned int value)
91{
92 u8 data[2];
93
94 /* data is
95 * D15..D9 WM8974 register offset
96 * D8...D0 register data
97 */
98 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
99 data[1] = value & 0x00ff;
100
101 wm8974_write_reg_cache(codec, reg, value);
102 if (codec->hw_write(codec->control_data, data, 2) == 2)
103 return 0;
104 else
105 return -EIO;
106}
107
108#define wm8974_reset(c) wm8974_write(c, WM8974_RESET, 0)
109 61
110static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; 62static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
111static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" }; 63static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
@@ -385,27 +337,27 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai,
385 337
386 if (freq_in == 0 || freq_out == 0) { 338 if (freq_in == 0 || freq_out == 0) {
387 /* Clock CODEC directly from MCLK */ 339 /* Clock CODEC directly from MCLK */
388 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); 340 reg = snd_soc_read(codec, WM8974_CLOCK);
389 wm8974_write(codec, WM8974_CLOCK, reg & 0x0ff); 341 snd_soc_write(codec, WM8974_CLOCK, reg & 0x0ff);
390 342
391 /* Turn off PLL */ 343 /* Turn off PLL */
392 reg = wm8974_read_reg_cache(codec, WM8974_POWER1); 344 reg = snd_soc_read(codec, WM8974_POWER1);
393 wm8974_write(codec, WM8974_POWER1, reg & 0x1df); 345 snd_soc_write(codec, WM8974_POWER1, reg & 0x1df);
394 return 0; 346 return 0;
395 } 347 }
396 348
397 pll_factors(freq_out*4, freq_in); 349 pll_factors(freq_out*4, freq_in);
398 350
399 wm8974_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); 351 snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
400 wm8974_write(codec, WM8974_PLLK1, pll_div.k >> 18); 352 snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18);
401 wm8974_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff); 353 snd_soc_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff);
402 wm8974_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff); 354 snd_soc_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff);
403 reg = wm8974_read_reg_cache(codec, WM8974_POWER1); 355 reg = snd_soc_read(codec, WM8974_POWER1);
404 wm8974_write(codec, WM8974_POWER1, reg | 0x020); 356 snd_soc_write(codec, WM8974_POWER1, reg | 0x020);
405 357
406 /* Run CODEC from PLL instead of MCLK */ 358 /* Run CODEC from PLL instead of MCLK */
407 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); 359 reg = snd_soc_read(codec, WM8974_CLOCK);
408 wm8974_write(codec, WM8974_CLOCK, reg | 0x100); 360 snd_soc_write(codec, WM8974_CLOCK, reg | 0x100);
409 361
410 return 0; 362 return 0;
411} 363}
@@ -421,24 +373,24 @@ static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
421 373
422 switch (div_id) { 374 switch (div_id) {
423 case WM8974_OPCLKDIV: 375 case WM8974_OPCLKDIV:
424 reg = wm8974_read_reg_cache(codec, WM8974_GPIO) & 0x1cf; 376 reg = snd_soc_read(codec, WM8974_GPIO) & 0x1cf;
425 wm8974_write(codec, WM8974_GPIO, reg | div); 377 snd_soc_write(codec, WM8974_GPIO, reg | div);
426 break; 378 break;
427 case WM8974_MCLKDIV: 379 case WM8974_MCLKDIV:
428 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x11f; 380 reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f;
429 wm8974_write(codec, WM8974_CLOCK, reg | div); 381 snd_soc_write(codec, WM8974_CLOCK, reg | div);
430 break; 382 break;
431 case WM8974_ADCCLK: 383 case WM8974_ADCCLK:
432 reg = wm8974_read_reg_cache(codec, WM8974_ADC) & 0x1f7; 384 reg = snd_soc_read(codec, WM8974_ADC) & 0x1f7;
433 wm8974_write(codec, WM8974_ADC, reg | div); 385 snd_soc_write(codec, WM8974_ADC, reg | div);
434 break; 386 break;
435 case WM8974_DACCLK: 387 case WM8974_DACCLK:
436 reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0x1f7; 388 reg = snd_soc_read(codec, WM8974_DAC) & 0x1f7;
437 wm8974_write(codec, WM8974_DAC, reg | div); 389 snd_soc_write(codec, WM8974_DAC, reg | div);
438 break; 390 break;
439 case WM8974_BCLKDIV: 391 case WM8974_BCLKDIV:
440 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1e3; 392 reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3;
441 wm8974_write(codec, WM8974_CLOCK, reg | div); 393 snd_soc_write(codec, WM8974_CLOCK, reg | div);
442 break; 394 break;
443 default: 395 default:
444 return -EINVAL; 396 return -EINVAL;
@@ -452,7 +404,7 @@ static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
452{ 404{
453 struct snd_soc_codec *codec = codec_dai->codec; 405 struct snd_soc_codec *codec = codec_dai->codec;
454 u16 iface = 0; 406 u16 iface = 0;
455 u16 clk = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1fe; 407 u16 clk = snd_soc_read(codec, WM8974_CLOCK) & 0x1fe;
456 408
457 /* set master/slave audio interface */ 409 /* set master/slave audio interface */
458 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 410 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -499,8 +451,8 @@ static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
499 return -EINVAL; 451 return -EINVAL;
500 } 452 }
501 453
502 wm8974_write(codec, WM8974_IFACE, iface); 454 snd_soc_write(codec, WM8974_IFACE, iface);
503 wm8974_write(codec, WM8974_CLOCK, clk); 455 snd_soc_write(codec, WM8974_CLOCK, clk);
504 return 0; 456 return 0;
505} 457}
506 458
@@ -509,8 +461,8 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream,
509 struct snd_soc_dai *dai) 461 struct snd_soc_dai *dai)
510{ 462{
511 struct snd_soc_codec *codec = dai->codec; 463 struct snd_soc_codec *codec = dai->codec;
512 u16 iface = wm8974_read_reg_cache(codec, WM8974_IFACE) & 0x19f; 464 u16 iface = snd_soc_read(codec, WM8974_IFACE) & 0x19f;
513 u16 adn = wm8974_read_reg_cache(codec, WM8974_ADD) & 0x1f1; 465 u16 adn = snd_soc_read(codec, WM8974_ADD) & 0x1f1;
514 466
515 /* bit size */ 467 /* bit size */
516 switch (params_format(params)) { 468 switch (params_format(params)) {
@@ -549,20 +501,20 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream,
549 break; 501 break;
550 } 502 }
551 503
552 wm8974_write(codec, WM8974_IFACE, iface); 504 snd_soc_write(codec, WM8974_IFACE, iface);
553 wm8974_write(codec, WM8974_ADD, adn); 505 snd_soc_write(codec, WM8974_ADD, adn);
554 return 0; 506 return 0;
555} 507}
556 508
557static int wm8974_mute(struct snd_soc_dai *dai, int mute) 509static int wm8974_mute(struct snd_soc_dai *dai, int mute)
558{ 510{
559 struct snd_soc_codec *codec = dai->codec; 511 struct snd_soc_codec *codec = dai->codec;
560 u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf; 512 u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf;
561 513
562 if (mute) 514 if (mute)
563 wm8974_write(codec, WM8974_DAC, mute_reg | 0x40); 515 snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40);
564 else 516 else
565 wm8974_write(codec, WM8974_DAC, mute_reg); 517 snd_soc_write(codec, WM8974_DAC, mute_reg);
566 return 0; 518 return 0;
567} 519}
568 520
@@ -570,13 +522,13 @@ static int wm8974_mute(struct snd_soc_dai *dai, int mute)
570static int wm8974_set_bias_level(struct snd_soc_codec *codec, 522static int wm8974_set_bias_level(struct snd_soc_codec *codec,
571 enum snd_soc_bias_level level) 523 enum snd_soc_bias_level level)
572{ 524{
573 u16 power1 = wm8974_read_reg_cache(codec, WM8974_POWER1) & ~0x3; 525 u16 power1 = snd_soc_read(codec, WM8974_POWER1) & ~0x3;
574 526
575 switch (level) { 527 switch (level) {
576 case SND_SOC_BIAS_ON: 528 case SND_SOC_BIAS_ON:
577 case SND_SOC_BIAS_PREPARE: 529 case SND_SOC_BIAS_PREPARE:
578 power1 |= 0x1; /* VMID 50k */ 530 power1 |= 0x1; /* VMID 50k */
579 wm8974_write(codec, WM8974_POWER1, power1); 531 snd_soc_write(codec, WM8974_POWER1, power1);
580 break; 532 break;
581 533
582 case SND_SOC_BIAS_STANDBY: 534 case SND_SOC_BIAS_STANDBY:
@@ -584,18 +536,18 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
584 536
585 if (codec->bias_level == SND_SOC_BIAS_OFF) { 537 if (codec->bias_level == SND_SOC_BIAS_OFF) {
586 /* Initial cap charge at VMID 5k */ 538 /* Initial cap charge at VMID 5k */
587 wm8974_write(codec, WM8974_POWER1, power1 | 0x3); 539 snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
588 mdelay(100); 540 mdelay(100);
589 } 541 }
590 542
591 power1 |= 0x2; /* VMID 500k */ 543 power1 |= 0x2; /* VMID 500k */
592 wm8974_write(codec, WM8974_POWER1, power1); 544 snd_soc_write(codec, WM8974_POWER1, power1);
593 break; 545 break;
594 546
595 case SND_SOC_BIAS_OFF: 547 case SND_SOC_BIAS_OFF:
596 wm8974_write(codec, WM8974_POWER1, 0); 548 snd_soc_write(codec, WM8974_POWER1, 0);
597 wm8974_write(codec, WM8974_POWER2, 0); 549 snd_soc_write(codec, WM8974_POWER2, 0);
598 wm8974_write(codec, WM8974_POWER3, 0); 550 snd_soc_write(codec, WM8974_POWER3, 0);
599 break; 551 break;
600 } 552 }
601 553
@@ -738,8 +690,6 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974)
738 codec->private_data = wm8974; 690 codec->private_data = wm8974;
739 codec->name = "WM8974"; 691 codec->name = "WM8974";
740 codec->owner = THIS_MODULE; 692 codec->owner = THIS_MODULE;
741 codec->read = wm8974_read_reg_cache;
742 codec->write = wm8974_write;
743 codec->bias_level = SND_SOC_BIAS_OFF; 693 codec->bias_level = SND_SOC_BIAS_OFF;
744 codec->set_bias_level = wm8974_set_bias_level; 694 codec->set_bias_level = wm8974_set_bias_level;
745 codec->dai = &wm8974_dai; 695 codec->dai = &wm8974_dai;
@@ -747,12 +697,18 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974)
747 codec->reg_cache_size = WM8974_CACHEREGNUM; 697 codec->reg_cache_size = WM8974_CACHEREGNUM;
748 codec->reg_cache = &wm8974->reg_cache; 698 codec->reg_cache = &wm8974->reg_cache;
749 699
700 ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
701 if (ret < 0) {
702 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
703 goto err;
704 }
705
750 memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg)); 706 memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
751 707
752 ret = wm8974_reset(codec); 708 ret = wm8974_reset(codec);
753 if (ret < 0) { 709 if (ret < 0) {
754 dev_err(codec->dev, "Failed to issue reset\n"); 710 dev_err(codec->dev, "Failed to issue reset\n");
755 return ret; 711 goto err;
756 } 712 }
757 713
758 wm8974_dai.dev = codec->dev; 714 wm8974_dai.dev = codec->dev;
@@ -764,17 +720,22 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974)
764 ret = snd_soc_register_codec(codec); 720 ret = snd_soc_register_codec(codec);
765 if (ret != 0) { 721 if (ret != 0) {
766 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 722 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
767 return ret; 723 goto err;
768 } 724 }
769 725
770 ret = snd_soc_register_dai(&wm8974_dai); 726 ret = snd_soc_register_dai(&wm8974_dai);
771 if (ret != 0) { 727 if (ret != 0) {
772 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 728 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
773 snd_soc_unregister_codec(codec); 729 goto err_codec;
774 return ret;
775 } 730 }
776 731
777 return 0; 732 return 0;
733
734err_codec:
735 snd_soc_unregister_codec(codec);
736err:
737 kfree(wm8974);
738 return ret;
778} 739}
779 740
780static __devexit void wm8974_unregister(struct wm8974_priv *wm8974) 741static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)