diff options
Diffstat (limited to 'sound/soc/codecs/wm8804.c')
-rw-r--r-- | sound/soc/codecs/wm8804.c | 154 |
1 files changed, 74 insertions, 80 deletions
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index d54a3ca5e19e..6bd1b767b138 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/of_device.h> | 19 | #include <linux/of_device.h> |
20 | #include <linux/spi/spi.h> | 20 | #include <linux/spi/spi.h> |
21 | #include <linux/regmap.h> | ||
21 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
@@ -35,45 +36,33 @@ static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = { | |||
35 | "DVDD" | 36 | "DVDD" |
36 | }; | 37 | }; |
37 | 38 | ||
38 | static const u8 wm8804_reg_defs[] = { | 39 | static const struct reg_default wm8804_reg_defaults[] = { |
39 | 0x05, /* R0 - RST/DEVID1 */ | 40 | { 3, 0x21 }, /* R3 - PLL1 */ |
40 | 0x88, /* R1 - DEVID2 */ | 41 | { 4, 0xFD }, /* R4 - PLL2 */ |
41 | 0x04, /* R2 - DEVREV */ | 42 | { 5, 0x36 }, /* R5 - PLL3 */ |
42 | 0x21, /* R3 - PLL1 */ | 43 | { 6, 0x07 }, /* R6 - PLL4 */ |
43 | 0xFD, /* R4 - PLL2 */ | 44 | { 7, 0x16 }, /* R7 - PLL5 */ |
44 | 0x36, /* R5 - PLL3 */ | 45 | { 8, 0x18 }, /* R8 - PLL6 */ |
45 | 0x07, /* R6 - PLL4 */ | 46 | { 9, 0xFF }, /* R9 - SPDMODE */ |
46 | 0x16, /* R7 - PLL5 */ | 47 | { 10, 0x00 }, /* R10 - INTMASK */ |
47 | 0x18, /* R8 - PLL6 */ | 48 | { 18, 0x00 }, /* R18 - SPDTX1 */ |
48 | 0xFF, /* R9 - SPDMODE */ | 49 | { 19, 0x00 }, /* R19 - SPDTX2 */ |
49 | 0x00, /* R10 - INTMASK */ | 50 | { 20, 0x00 }, /* R20 - SPDTX3 */ |
50 | 0x00, /* R11 - INTSTAT */ | 51 | { 21, 0x71 }, /* R21 - SPDTX4 */ |
51 | 0x00, /* R12 - SPDSTAT */ | 52 | { 22, 0x0B }, /* R22 - SPDTX5 */ |
52 | 0x00, /* R13 - RXCHAN1 */ | 53 | { 23, 0x70 }, /* R23 - GPO0 */ |
53 | 0x00, /* R14 - RXCHAN2 */ | 54 | { 24, 0x57 }, /* R24 - GPO1 */ |
54 | 0x00, /* R15 - RXCHAN3 */ | 55 | { 26, 0x42 }, /* R26 - GPO2 */ |
55 | 0x00, /* R16 - RXCHAN4 */ | 56 | { 27, 0x06 }, /* R27 - AIFTX */ |
56 | 0x00, /* R17 - RXCHAN5 */ | 57 | { 28, 0x06 }, /* R28 - AIFRX */ |
57 | 0x00, /* R18 - SPDTX1 */ | 58 | { 29, 0x80 }, /* R29 - SPDRX1 */ |
58 | 0x00, /* R19 - SPDTX2 */ | 59 | { 30, 0x07 }, /* R30 - PWRDN */ |
59 | 0x00, /* R20 - SPDTX3 */ | ||
60 | 0x71, /* R21 - SPDTX4 */ | ||
61 | 0x0B, /* R22 - SPDTX5 */ | ||
62 | 0x70, /* R23 - GPO0 */ | ||
63 | 0x57, /* R24 - GPO1 */ | ||
64 | 0x00, /* R25 */ | ||
65 | 0x42, /* R26 - GPO2 */ | ||
66 | 0x06, /* R27 - AIFTX */ | ||
67 | 0x06, /* R28 - AIFRX */ | ||
68 | 0x80, /* R29 - SPDRX1 */ | ||
69 | 0x07, /* R30 - PWRDN */ | ||
70 | }; | 60 | }; |
71 | 61 | ||
72 | struct wm8804_priv { | 62 | struct wm8804_priv { |
73 | enum snd_soc_control_type control_type; | 63 | struct regmap *regmap; |
74 | struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES]; | 64 | struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES]; |
75 | struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; | 65 | struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; |
76 | struct snd_soc_codec *codec; | ||
77 | }; | 66 | }; |
78 | 67 | ||
79 | static int txsrc_get(struct snd_kcontrol *kcontrol, | 68 | static int txsrc_get(struct snd_kcontrol *kcontrol, |
@@ -94,7 +83,7 @@ static int wm8804_regulator_event_##n(struct notifier_block *nb, \ | |||
94 | struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \ | 83 | struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \ |
95 | disable_nb[n]); \ | 84 | disable_nb[n]); \ |
96 | if (event & REGULATOR_EVENT_DISABLE) { \ | 85 | if (event & REGULATOR_EVENT_DISABLE) { \ |
97 | wm8804->codec->cache_sync = 1; \ | 86 | regcache_mark_dirty(wm8804->regmap); \ |
98 | } \ | 87 | } \ |
99 | return 0; \ | 88 | return 0; \ |
100 | } | 89 | } |
@@ -176,7 +165,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol, | |||
176 | return 0; | 165 | return 0; |
177 | } | 166 | } |
178 | 167 | ||
179 | static int wm8804_volatile(struct snd_soc_codec *codec, unsigned int reg) | 168 | static bool wm8804_volatile(struct device *dev, unsigned int reg) |
180 | { | 169 | { |
181 | switch (reg) { | 170 | switch (reg) { |
182 | case WM8804_RST_DEVID1: | 171 | case WM8804_RST_DEVID1: |
@@ -189,12 +178,10 @@ static int wm8804_volatile(struct snd_soc_codec *codec, unsigned int reg) | |||
189 | case WM8804_RXCHAN3: | 178 | case WM8804_RXCHAN3: |
190 | case WM8804_RXCHAN4: | 179 | case WM8804_RXCHAN4: |
191 | case WM8804_RXCHAN5: | 180 | case WM8804_RXCHAN5: |
192 | return 1; | 181 | return true; |
193 | default: | 182 | default: |
194 | break; | 183 | return false; |
195 | } | 184 | } |
196 | |||
197 | return 0; | ||
198 | } | 185 | } |
199 | 186 | ||
200 | static int wm8804_reset(struct snd_soc_codec *codec) | 187 | static int wm8804_reset(struct snd_soc_codec *codec) |
@@ -482,24 +469,6 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai, | |||
482 | return 0; | 469 | return 0; |
483 | } | 470 | } |
484 | 471 | ||
485 | static void wm8804_sync_cache(struct snd_soc_codec *codec) | ||
486 | { | ||
487 | short i; | ||
488 | u8 *cache; | ||
489 | |||
490 | if (!codec->cache_sync) | ||
491 | return; | ||
492 | |||
493 | codec->cache_only = 0; | ||
494 | cache = codec->reg_cache; | ||
495 | for (i = 0; i < codec->driver->reg_cache_size; i++) { | ||
496 | if (i == WM8804_RST_DEVID1 || cache[i] == wm8804_reg_defs[i]) | ||
497 | continue; | ||
498 | snd_soc_write(codec, i, cache[i]); | ||
499 | } | ||
500 | codec->cache_sync = 0; | ||
501 | } | ||
502 | |||
503 | static int wm8804_set_bias_level(struct snd_soc_codec *codec, | 472 | static int wm8804_set_bias_level(struct snd_soc_codec *codec, |
504 | enum snd_soc_bias_level level) | 473 | enum snd_soc_bias_level level) |
505 | { | 474 | { |
@@ -524,7 +493,7 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, | |||
524 | ret); | 493 | ret); |
525 | return ret; | 494 | return ret; |
526 | } | 495 | } |
527 | wm8804_sync_cache(codec); | 496 | regcache_sync(wm8804->regmap); |
528 | } | 497 | } |
529 | /* power down the OSC and the PLL */ | 498 | /* power down the OSC and the PLL */ |
530 | snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9); | 499 | snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9); |
@@ -579,11 +548,10 @@ static int wm8804_probe(struct snd_soc_codec *codec) | |||
579 | int i, id1, id2, ret; | 548 | int i, id1, id2, ret; |
580 | 549 | ||
581 | wm8804 = snd_soc_codec_get_drvdata(codec); | 550 | wm8804 = snd_soc_codec_get_drvdata(codec); |
582 | wm8804->codec = codec; | ||
583 | 551 | ||
584 | codec->dapm.idle_bias_off = 1; | 552 | codec->control_data = wm8804->regmap; |
585 | 553 | ||
586 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->control_type); | 554 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); |
587 | if (ret < 0) { | 555 | if (ret < 0) { |
588 | dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); | 556 | dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); |
589 | return ret; | 557 | return ret; |
@@ -636,8 +604,7 @@ static int wm8804_probe(struct snd_soc_codec *codec) | |||
636 | 604 | ||
637 | id2 = (id2 << 8) | id1; | 605 | id2 = (id2 << 8) | id1; |
638 | 606 | ||
639 | if (id2 != ((wm8804_reg_defs[WM8804_DEVID2] << 8) | 607 | if (id2 != 0x8805) { |
640 | | wm8804_reg_defs[WM8804_RST_DEVID1])) { | ||
641 | dev_err(codec->dev, "Invalid device ID: %#x\n", id2); | 608 | dev_err(codec->dev, "Invalid device ID: %#x\n", id2); |
642 | ret = -EINVAL; | 609 | ret = -EINVAL; |
643 | goto err_reg_enable; | 610 | goto err_reg_enable; |
@@ -710,10 +677,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { | |||
710 | .suspend = wm8804_suspend, | 677 | .suspend = wm8804_suspend, |
711 | .resume = wm8804_resume, | 678 | .resume = wm8804_resume, |
712 | .set_bias_level = wm8804_set_bias_level, | 679 | .set_bias_level = wm8804_set_bias_level, |
713 | .reg_cache_size = ARRAY_SIZE(wm8804_reg_defs), | 680 | .idle_bias_off = true, |
714 | .reg_word_size = sizeof(u8), | ||
715 | .reg_cache_default = wm8804_reg_defs, | ||
716 | .volatile_register = wm8804_volatile, | ||
717 | 681 | ||
718 | .controls = wm8804_snd_controls, | 682 | .controls = wm8804_snd_controls, |
719 | .num_controls = ARRAY_SIZE(wm8804_snd_controls), | 683 | .num_controls = ARRAY_SIZE(wm8804_snd_controls), |
@@ -725,30 +689,47 @@ static const struct of_device_id wm8804_of_match[] = { | |||
725 | }; | 689 | }; |
726 | MODULE_DEVICE_TABLE(of, wm8804_of_match); | 690 | MODULE_DEVICE_TABLE(of, wm8804_of_match); |
727 | 691 | ||
692 | static struct regmap_config wm8804_regmap_config = { | ||
693 | .reg_bits = 8, | ||
694 | .val_bits = 8, | ||
695 | |||
696 | .max_register = WM8804_MAX_REGISTER, | ||
697 | .volatile_reg = wm8804_volatile, | ||
698 | |||
699 | .cache_type = REGCACHE_RBTREE, | ||
700 | .reg_defaults = wm8804_reg_defaults, | ||
701 | .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), | ||
702 | }; | ||
703 | |||
728 | #if defined(CONFIG_SPI_MASTER) | 704 | #if defined(CONFIG_SPI_MASTER) |
729 | static int __devinit wm8804_spi_probe(struct spi_device *spi) | 705 | static int __devinit wm8804_spi_probe(struct spi_device *spi) |
730 | { | 706 | { |
731 | struct wm8804_priv *wm8804; | 707 | struct wm8804_priv *wm8804; |
732 | int ret; | 708 | int ret; |
733 | 709 | ||
734 | wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL); | 710 | wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL); |
735 | if (!wm8804) | 711 | if (!wm8804) |
736 | return -ENOMEM; | 712 | return -ENOMEM; |
737 | 713 | ||
738 | wm8804->control_type = SND_SOC_SPI; | 714 | wm8804->regmap = regmap_init_spi(spi, &wm8804_regmap_config); |
715 | if (IS_ERR(wm8804->regmap)) { | ||
716 | ret = PTR_ERR(wm8804->regmap); | ||
717 | return ret; | ||
718 | } | ||
719 | |||
739 | spi_set_drvdata(spi, wm8804); | 720 | spi_set_drvdata(spi, wm8804); |
740 | 721 | ||
741 | ret = snd_soc_register_codec(&spi->dev, | 722 | ret = snd_soc_register_codec(&spi->dev, |
742 | &soc_codec_dev_wm8804, &wm8804_dai, 1); | 723 | &soc_codec_dev_wm8804, &wm8804_dai, 1); |
743 | if (ret < 0) | 724 | |
744 | kfree(wm8804); | ||
745 | return ret; | 725 | return ret; |
746 | } | 726 | } |
747 | 727 | ||
748 | static int __devexit wm8804_spi_remove(struct spi_device *spi) | 728 | static int __devexit wm8804_spi_remove(struct spi_device *spi) |
749 | { | 729 | { |
730 | struct wm8804_priv *wm8804 = spi_get_drvdata(spi); | ||
750 | snd_soc_unregister_codec(&spi->dev); | 731 | snd_soc_unregister_codec(&spi->dev); |
751 | kfree(spi_get_drvdata(spi)); | 732 | regmap_exit(wm8804->regmap); |
752 | return 0; | 733 | return 0; |
753 | } | 734 | } |
754 | 735 | ||
@@ -770,24 +751,37 @@ static __devinit int wm8804_i2c_probe(struct i2c_client *i2c, | |||
770 | struct wm8804_priv *wm8804; | 751 | struct wm8804_priv *wm8804; |
771 | int ret; | 752 | int ret; |
772 | 753 | ||
773 | wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL); | 754 | wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL); |
774 | if (!wm8804) | 755 | if (!wm8804) |
775 | return -ENOMEM; | 756 | return -ENOMEM; |
776 | 757 | ||
777 | wm8804->control_type = SND_SOC_I2C; | 758 | wm8804->regmap = regmap_init_i2c(i2c, &wm8804_regmap_config); |
759 | if (IS_ERR(wm8804->regmap)) { | ||
760 | ret = PTR_ERR(wm8804->regmap); | ||
761 | return ret; | ||
762 | } | ||
763 | |||
778 | i2c_set_clientdata(i2c, wm8804); | 764 | i2c_set_clientdata(i2c, wm8804); |
779 | 765 | ||
780 | ret = snd_soc_register_codec(&i2c->dev, | 766 | ret = snd_soc_register_codec(&i2c->dev, |
781 | &soc_codec_dev_wm8804, &wm8804_dai, 1); | 767 | &soc_codec_dev_wm8804, &wm8804_dai, 1); |
782 | if (ret < 0) | 768 | if (ret != 0) |
783 | kfree(wm8804); | 769 | goto err; |
770 | |||
771 | return 0; | ||
772 | |||
773 | err: | ||
774 | regmap_exit(wm8804->regmap); | ||
784 | return ret; | 775 | return ret; |
785 | } | 776 | } |
786 | 777 | ||
787 | static __devexit int wm8804_i2c_remove(struct i2c_client *client) | 778 | static __devexit int wm8804_i2c_remove(struct i2c_client *i2c) |
788 | { | 779 | { |
789 | snd_soc_unregister_codec(&client->dev); | 780 | struct wm8804_priv *wm8804 = i2c_get_clientdata(i2c); |
790 | kfree(i2c_get_clientdata(client)); | 781 | |
782 | snd_soc_unregister_codec(&i2c->dev); | ||
783 | regmap_exit(wm8804->regmap); | ||
784 | |||
791 | return 0; | 785 | return 0; |
792 | } | 786 | } |
793 | 787 | ||