diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-08-15 07:15:10 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-08-15 07:15:10 -0400 |
commit | 1e97f50b7023cda00cb720e53b9e59c250cb4ed7 (patch) | |
tree | f80ecb7523428a19e2325f38b0a4b6ac0fae9a62 /sound/soc/codecs/wm8974.c | |
parent | 37cfa1950e2a24d9fa4a593186645d8e2b5042a8 (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.c | 149 |
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 | ||
58 | static struct snd_soc_codec *wm8974_codec; | 58 | static 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 | */ | ||
63 | static 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 | */ | ||
77 | static 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 | */ | ||
89 | static 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 | ||
110 | static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; | 62 | static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; |
111 | static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" }; | 63 | static 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 | ||
557 | static int wm8974_mute(struct snd_soc_dai *dai, int mute) | 509 | static 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) | |||
570 | static int wm8974_set_bias_level(struct snd_soc_codec *codec, | 522 | static 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 | |||
734 | err_codec: | ||
735 | snd_soc_unregister_codec(codec); | ||
736 | err: | ||
737 | kfree(wm8974); | ||
738 | return ret; | ||
778 | } | 739 | } |
779 | 740 | ||
780 | static __devexit void wm8974_unregister(struct wm8974_priv *wm8974) | 741 | static __devexit void wm8974_unregister(struct wm8974_priv *wm8974) |