diff options
author | Mark Brown <broonie@kernel.org> | 2015-03-04 20:07:27 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-03-04 20:07:27 -0500 |
commit | d7e3281b52fea8917fb4a7a5b09df5e6a9d2850c (patch) | |
tree | 7114b0103a6f5b2e2bc93877c50dc52a5c054b7d | |
parent | 3a9486367b0a79d725a9ba31eee60505fdddb96f (diff) | |
parent | 6f2c9348095ae1a489abafe2ab3db7deca406e49 (diff) |
Merge remote-tracking branch 'asoc/topic/wm8804' into asoc-next
-rw-r--r-- | sound/soc/codecs/Kconfig | 18 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8804-i2c.c | 64 | ||||
-rw-r--r-- | sound/soc/codecs/wm8804-spi.c | 56 | ||||
-rw-r--r-- | sound/soc/codecs/wm8804.c | 281 | ||||
-rw-r--r-- | sound/soc/codecs/wm8804.h | 7 |
6 files changed, 225 insertions, 205 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ea9f0e31f9d4..0bddd929837f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -141,7 +141,8 @@ config SND_SOC_ALL_CODECS | |||
141 | select SND_SOC_WM8770 if SPI_MASTER | 141 | select SND_SOC_WM8770 if SPI_MASTER |
142 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI | 142 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI |
143 | select SND_SOC_WM8782 | 143 | select SND_SOC_WM8782 |
144 | select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI | 144 | select SND_SOC_WM8804_I2C if I2C |
145 | select SND_SOC_WM8804_SPI if SPI_MASTER | ||
145 | select SND_SOC_WM8900 if I2C | 146 | select SND_SOC_WM8900 if I2C |
146 | select SND_SOC_WM8903 if I2C | 147 | select SND_SOC_WM8903 if I2C |
147 | select SND_SOC_WM8904 if I2C | 148 | select SND_SOC_WM8904 if I2C |
@@ -744,8 +745,19 @@ config SND_SOC_WM8782 | |||
744 | tristate | 745 | tristate |
745 | 746 | ||
746 | config SND_SOC_WM8804 | 747 | config SND_SOC_WM8804 |
747 | tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver" | 748 | tristate |
748 | depends on SND_SOC_I2C_AND_SPI | 749 | |
750 | config SND_SOC_WM8804_I2C | ||
751 | tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C" | ||
752 | depends on I2C | ||
753 | select SND_SOC_WM8804 | ||
754 | select REGMAP_I2C | ||
755 | |||
756 | config SND_SOC_WM8804_SPI | ||
757 | tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI" | ||
758 | depends on SPI_MASTER | ||
759 | select SND_SOC_WM8804 | ||
760 | select REGMAP_SPI | ||
749 | 761 | ||
750 | config SND_SOC_WM8900 | 762 | config SND_SOC_WM8900 |
751 | tristate | 763 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 69b8666d187a..7acb6c174cb4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -145,6 +145,8 @@ snd-soc-wm8770-objs := wm8770.o | |||
145 | snd-soc-wm8776-objs := wm8776.o | 145 | snd-soc-wm8776-objs := wm8776.o |
146 | snd-soc-wm8782-objs := wm8782.o | 146 | snd-soc-wm8782-objs := wm8782.o |
147 | snd-soc-wm8804-objs := wm8804.o | 147 | snd-soc-wm8804-objs := wm8804.o |
148 | snd-soc-wm8804-i2c-objs := wm8804-i2c.o | ||
149 | snd-soc-wm8804-spi-objs := wm8804-spi.o | ||
148 | snd-soc-wm8900-objs := wm8900.o | 150 | snd-soc-wm8900-objs := wm8900.o |
149 | snd-soc-wm8903-objs := wm8903.o | 151 | snd-soc-wm8903-objs := wm8903.o |
150 | snd-soc-wm8904-objs := wm8904.o | 152 | snd-soc-wm8904-objs := wm8904.o |
@@ -323,6 +325,8 @@ obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o | |||
323 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o | 325 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o |
324 | obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o | 326 | obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o |
325 | obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o | 327 | obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o |
328 | obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o | ||
329 | obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o | ||
326 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | 330 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o |
327 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | 331 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o |
328 | obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o | 332 | obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o |
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c new file mode 100644 index 000000000000..5bd4af2b4059 --- /dev/null +++ b/sound/soc/codecs/wm8804-i2c.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * wm8804-i2c.c -- WM8804 S/PDIF transceiver driver - I2C | ||
3 | * | ||
4 | * Copyright 2015 Cirrus Logic Inc | ||
5 | * | ||
6 | * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/i2c.h> | ||
16 | |||
17 | #include "wm8804.h" | ||
18 | |||
19 | static int wm8804_i2c_probe(struct i2c_client *i2c, | ||
20 | const struct i2c_device_id *id) | ||
21 | { | ||
22 | struct regmap *regmap; | ||
23 | |||
24 | regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); | ||
25 | if (IS_ERR(regmap)) | ||
26 | return PTR_ERR(regmap); | ||
27 | |||
28 | return wm8804_probe(&i2c->dev, regmap); | ||
29 | } | ||
30 | |||
31 | static int wm8804_i2c_remove(struct i2c_client *i2c) | ||
32 | { | ||
33 | wm8804_remove(&i2c->dev); | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static const struct i2c_device_id wm8804_i2c_id[] = { | ||
38 | { "wm8804", 0 }, | ||
39 | { } | ||
40 | }; | ||
41 | MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id); | ||
42 | |||
43 | static const struct of_device_id wm8804_of_match[] = { | ||
44 | { .compatible = "wlf,wm8804", }, | ||
45 | { } | ||
46 | }; | ||
47 | MODULE_DEVICE_TABLE(of, wm8804_of_match); | ||
48 | |||
49 | static struct i2c_driver wm8804_i2c_driver = { | ||
50 | .driver = { | ||
51 | .name = "wm8804", | ||
52 | .owner = THIS_MODULE, | ||
53 | .of_match_table = wm8804_of_match, | ||
54 | }, | ||
55 | .probe = wm8804_i2c_probe, | ||
56 | .remove = wm8804_i2c_remove, | ||
57 | .id_table = wm8804_i2c_id | ||
58 | }; | ||
59 | |||
60 | module_i2c_driver(wm8804_i2c_driver); | ||
61 | |||
62 | MODULE_DESCRIPTION("ASoC WM8804 driver - I2C"); | ||
63 | MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>"); | ||
64 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c new file mode 100644 index 000000000000..287e11e90794 --- /dev/null +++ b/sound/soc/codecs/wm8804-spi.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * wm8804-spi.c -- WM8804 S/PDIF transceiver driver - SPI | ||
3 | * | ||
4 | * Copyright 2015 Cirrus Logic Inc | ||
5 | * | ||
6 | * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | |||
17 | #include "wm8804.h" | ||
18 | |||
19 | static int wm8804_spi_probe(struct spi_device *spi) | ||
20 | { | ||
21 | struct regmap *regmap; | ||
22 | |||
23 | regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); | ||
24 | if (IS_ERR(regmap)) | ||
25 | return PTR_ERR(regmap); | ||
26 | |||
27 | return wm8804_probe(&spi->dev, regmap); | ||
28 | } | ||
29 | |||
30 | static int wm8804_spi_remove(struct spi_device *spi) | ||
31 | { | ||
32 | wm8804_remove(&spi->dev); | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static const struct of_device_id wm8804_of_match[] = { | ||
37 | { .compatible = "wlf,wm8804", }, | ||
38 | { } | ||
39 | }; | ||
40 | MODULE_DEVICE_TABLE(of, wm8804_of_match); | ||
41 | |||
42 | static struct spi_driver wm8804_spi_driver = { | ||
43 | .driver = { | ||
44 | .name = "wm8804", | ||
45 | .owner = THIS_MODULE, | ||
46 | .of_match_table = wm8804_of_match, | ||
47 | }, | ||
48 | .probe = wm8804_spi_probe, | ||
49 | .remove = wm8804_spi_remove | ||
50 | }; | ||
51 | |||
52 | module_spi_driver(wm8804_spi_driver); | ||
53 | |||
54 | MODULE_DESCRIPTION("ASoC WM8804 driver - SPI"); | ||
55 | MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>"); | ||
56 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index b2b0e68f707e..1bd4ace29594 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -15,10 +15,7 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/pm.h> | 17 | #include <linux/pm.h> |
18 | #include <linux/i2c.h> | ||
19 | #include <linux/of_device.h> | 18 | #include <linux/of_device.h> |
20 | #include <linux/spi/spi.h> | ||
21 | #include <linux/regmap.h> | ||
22 | #include <linux/regulator/consumer.h> | 19 | #include <linux/regulator/consumer.h> |
23 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
24 | #include <sound/core.h> | 21 | #include <sound/core.h> |
@@ -185,9 +182,9 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg) | |||
185 | } | 182 | } |
186 | } | 183 | } |
187 | 184 | ||
188 | static int wm8804_reset(struct snd_soc_codec *codec) | 185 | static int wm8804_reset(struct wm8804_priv *wm8804) |
189 | { | 186 | { |
190 | return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0); | 187 | return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0); |
191 | } | 188 | } |
192 | 189 | ||
193 | static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 190 | static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
@@ -518,100 +515,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, | |||
518 | return 0; | 515 | return 0; |
519 | } | 516 | } |
520 | 517 | ||
521 | static int wm8804_remove(struct snd_soc_codec *codec) | ||
522 | { | ||
523 | struct wm8804_priv *wm8804; | ||
524 | int i; | ||
525 | |||
526 | wm8804 = snd_soc_codec_get_drvdata(codec); | ||
527 | |||
528 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) | ||
529 | regulator_unregister_notifier(wm8804->supplies[i].consumer, | ||
530 | &wm8804->disable_nb[i]); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static int wm8804_probe(struct snd_soc_codec *codec) | ||
535 | { | ||
536 | struct wm8804_priv *wm8804; | ||
537 | int i, id1, id2, ret; | ||
538 | |||
539 | wm8804 = snd_soc_codec_get_drvdata(codec); | ||
540 | |||
541 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) | ||
542 | wm8804->supplies[i].supply = wm8804_supply_names[i]; | ||
543 | |||
544 | ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies), | ||
545 | wm8804->supplies); | ||
546 | if (ret) { | ||
547 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0; | ||
552 | wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1; | ||
553 | |||
554 | /* This should really be moved into the regulator core */ | ||
555 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { | ||
556 | ret = regulator_register_notifier(wm8804->supplies[i].consumer, | ||
557 | &wm8804->disable_nb[i]); | ||
558 | if (ret != 0) { | ||
559 | dev_err(codec->dev, | ||
560 | "Failed to register regulator notifier: %d\n", | ||
561 | ret); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies), | ||
566 | wm8804->supplies); | ||
567 | if (ret) { | ||
568 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | id1 = snd_soc_read(codec, WM8804_RST_DEVID1); | ||
573 | if (id1 < 0) { | ||
574 | dev_err(codec->dev, "Failed to read device ID: %d\n", id1); | ||
575 | ret = id1; | ||
576 | goto err_reg_enable; | ||
577 | } | ||
578 | |||
579 | id2 = snd_soc_read(codec, WM8804_DEVID2); | ||
580 | if (id2 < 0) { | ||
581 | dev_err(codec->dev, "Failed to read device ID: %d\n", id2); | ||
582 | ret = id2; | ||
583 | goto err_reg_enable; | ||
584 | } | ||
585 | |||
586 | id2 = (id2 << 8) | id1; | ||
587 | |||
588 | if (id2 != 0x8805) { | ||
589 | dev_err(codec->dev, "Invalid device ID: %#x\n", id2); | ||
590 | ret = -EINVAL; | ||
591 | goto err_reg_enable; | ||
592 | } | ||
593 | |||
594 | ret = snd_soc_read(codec, WM8804_DEVREV); | ||
595 | if (ret < 0) { | ||
596 | dev_err(codec->dev, "Failed to read device revision: %d\n", | ||
597 | ret); | ||
598 | goto err_reg_enable; | ||
599 | } | ||
600 | dev_info(codec->dev, "revision %c\n", ret + 'A'); | ||
601 | |||
602 | ret = wm8804_reset(codec); | ||
603 | if (ret < 0) { | ||
604 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | ||
605 | goto err_reg_enable; | ||
606 | } | ||
607 | |||
608 | return 0; | ||
609 | |||
610 | err_reg_enable: | ||
611 | regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); | ||
612 | return ret; | ||
613 | } | ||
614 | |||
615 | static const struct snd_soc_dai_ops wm8804_dai_ops = { | 518 | static const struct snd_soc_dai_ops wm8804_dai_ops = { |
616 | .hw_params = wm8804_hw_params, | 519 | .hw_params = wm8804_hw_params, |
617 | .set_fmt = wm8804_set_fmt, | 520 | .set_fmt = wm8804_set_fmt, |
@@ -649,8 +552,6 @@ static struct snd_soc_dai_driver wm8804_dai = { | |||
649 | }; | 552 | }; |
650 | 553 | ||
651 | static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { | 554 | static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { |
652 | .probe = wm8804_probe, | ||
653 | .remove = wm8804_remove, | ||
654 | .set_bias_level = wm8804_set_bias_level, | 555 | .set_bias_level = wm8804_set_bias_level, |
655 | .idle_bias_off = true, | 556 | .idle_bias_off = true, |
656 | 557 | ||
@@ -658,13 +559,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { | |||
658 | .num_controls = ARRAY_SIZE(wm8804_snd_controls), | 559 | .num_controls = ARRAY_SIZE(wm8804_snd_controls), |
659 | }; | 560 | }; |
660 | 561 | ||
661 | static const struct of_device_id wm8804_of_match[] = { | 562 | const struct regmap_config wm8804_regmap_config = { |
662 | { .compatible = "wlf,wm8804", }, | ||
663 | { } | ||
664 | }; | ||
665 | MODULE_DEVICE_TABLE(of, wm8804_of_match); | ||
666 | |||
667 | static const struct regmap_config wm8804_regmap_config = { | ||
668 | .reg_bits = 8, | 563 | .reg_bits = 8, |
669 | .val_bits = 8, | 564 | .val_bits = 8, |
670 | 565 | ||
@@ -675,128 +570,110 @@ static const struct regmap_config wm8804_regmap_config = { | |||
675 | .reg_defaults = wm8804_reg_defaults, | 570 | .reg_defaults = wm8804_reg_defaults, |
676 | .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), | 571 | .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults), |
677 | }; | 572 | }; |
573 | EXPORT_SYMBOL_GPL(wm8804_regmap_config); | ||
678 | 574 | ||
679 | #if defined(CONFIG_SPI_MASTER) | 575 | int wm8804_probe(struct device *dev, struct regmap *regmap) |
680 | static int wm8804_spi_probe(struct spi_device *spi) | ||
681 | { | 576 | { |
682 | struct wm8804_priv *wm8804; | 577 | struct wm8804_priv *wm8804; |
683 | int ret; | 578 | unsigned int id1, id2; |
579 | int i, ret; | ||
684 | 580 | ||
685 | wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL); | 581 | wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL); |
686 | if (!wm8804) | 582 | if (!wm8804) |
687 | return -ENOMEM; | 583 | return -ENOMEM; |
688 | 584 | ||
689 | wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config); | 585 | dev_set_drvdata(dev, wm8804); |
690 | if (IS_ERR(wm8804->regmap)) { | 586 | |
691 | ret = PTR_ERR(wm8804->regmap); | 587 | wm8804->regmap = regmap; |
588 | |||
589 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) | ||
590 | wm8804->supplies[i].supply = wm8804_supply_names[i]; | ||
591 | |||
592 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies), | ||
593 | wm8804->supplies); | ||
594 | if (ret) { | ||
595 | dev_err(dev, "Failed to request supplies: %d\n", ret); | ||
692 | return ret; | 596 | return ret; |
693 | } | 597 | } |
694 | 598 | ||
695 | spi_set_drvdata(spi, wm8804); | 599 | wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0; |
600 | wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1; | ||
696 | 601 | ||
697 | ret = snd_soc_register_codec(&spi->dev, | 602 | /* This should really be moved into the regulator core */ |
698 | &soc_codec_dev_wm8804, &wm8804_dai, 1); | 603 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { |
604 | ret = regulator_register_notifier(wm8804->supplies[i].consumer, | ||
605 | &wm8804->disable_nb[i]); | ||
606 | if (ret != 0) { | ||
607 | dev_err(dev, | ||
608 | "Failed to register regulator notifier: %d\n", | ||
609 | ret); | ||
610 | } | ||
611 | } | ||
699 | 612 | ||
700 | return ret; | 613 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies), |
701 | } | 614 | wm8804->supplies); |
615 | if (ret) { | ||
616 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
617 | goto err_reg_enable; | ||
618 | } | ||
702 | 619 | ||
703 | static int wm8804_spi_remove(struct spi_device *spi) | 620 | ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1); |
704 | { | 621 | if (ret < 0) { |
705 | snd_soc_unregister_codec(&spi->dev); | 622 | dev_err(dev, "Failed to read device ID: %d\n", ret); |
706 | return 0; | 623 | goto err_reg_enable; |
707 | } | 624 | } |
708 | 625 | ||
709 | static struct spi_driver wm8804_spi_driver = { | 626 | ret = regmap_read(regmap, WM8804_DEVID2, &id2); |
710 | .driver = { | 627 | if (ret < 0) { |
711 | .name = "wm8804", | 628 | dev_err(dev, "Failed to read device ID: %d\n", ret); |
712 | .owner = THIS_MODULE, | 629 | goto err_reg_enable; |
713 | .of_match_table = wm8804_of_match, | 630 | } |
714 | }, | ||
715 | .probe = wm8804_spi_probe, | ||
716 | .remove = wm8804_spi_remove | ||
717 | }; | ||
718 | #endif | ||
719 | 631 | ||
720 | #if IS_ENABLED(CONFIG_I2C) | 632 | id2 = (id2 << 8) | id1; |
721 | static int wm8804_i2c_probe(struct i2c_client *i2c, | ||
722 | const struct i2c_device_id *id) | ||
723 | { | ||
724 | struct wm8804_priv *wm8804; | ||
725 | int ret; | ||
726 | 633 | ||
727 | wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL); | 634 | if (id2 != 0x8805) { |
728 | if (!wm8804) | 635 | dev_err(dev, "Invalid device ID: %#x\n", id2); |
729 | return -ENOMEM; | 636 | ret = -EINVAL; |
637 | goto err_reg_enable; | ||
638 | } | ||
730 | 639 | ||
731 | wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config); | 640 | ret = regmap_read(regmap, WM8804_DEVREV, &id1); |
732 | if (IS_ERR(wm8804->regmap)) { | 641 | if (ret < 0) { |
733 | ret = PTR_ERR(wm8804->regmap); | 642 | dev_err(dev, "Failed to read device revision: %d\n", |
734 | return ret; | 643 | ret); |
644 | goto err_reg_enable; | ||
735 | } | 645 | } |
646 | dev_info(dev, "revision %c\n", id1 + 'A'); | ||
736 | 647 | ||
737 | i2c_set_clientdata(i2c, wm8804); | 648 | ret = wm8804_reset(wm8804); |
649 | if (ret < 0) { | ||
650 | dev_err(dev, "Failed to issue reset: %d\n", ret); | ||
651 | goto err_reg_enable; | ||
652 | } | ||
738 | 653 | ||
739 | ret = snd_soc_register_codec(&i2c->dev, | 654 | return snd_soc_register_codec(dev, &soc_codec_dev_wm8804, |
740 | &soc_codec_dev_wm8804, &wm8804_dai, 1); | 655 | &wm8804_dai, 1); |
656 | |||
657 | err_reg_enable: | ||
658 | regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); | ||
741 | return ret; | 659 | return ret; |
742 | } | 660 | } |
661 | EXPORT_SYMBOL_GPL(wm8804_probe); | ||
743 | 662 | ||
744 | static int wm8804_i2c_remove(struct i2c_client *i2c) | 663 | void wm8804_remove(struct device *dev) |
745 | { | 664 | { |
746 | snd_soc_unregister_codec(&i2c->dev); | 665 | struct wm8804_priv *wm8804; |
747 | return 0; | 666 | int i; |
748 | } | ||
749 | |||
750 | static const struct i2c_device_id wm8804_i2c_id[] = { | ||
751 | { "wm8804", 0 }, | ||
752 | { } | ||
753 | }; | ||
754 | MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id); | ||
755 | |||
756 | static struct i2c_driver wm8804_i2c_driver = { | ||
757 | .driver = { | ||
758 | .name = "wm8804", | ||
759 | .owner = THIS_MODULE, | ||
760 | .of_match_table = wm8804_of_match, | ||
761 | }, | ||
762 | .probe = wm8804_i2c_probe, | ||
763 | .remove = wm8804_i2c_remove, | ||
764 | .id_table = wm8804_i2c_id | ||
765 | }; | ||
766 | #endif | ||
767 | 667 | ||
768 | static int __init wm8804_modinit(void) | 668 | wm8804 = dev_get_drvdata(dev); |
769 | { | ||
770 | int ret = 0; | ||
771 | 669 | ||
772 | #if IS_ENABLED(CONFIG_I2C) | 670 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) |
773 | ret = i2c_add_driver(&wm8804_i2c_driver); | 671 | regulator_unregister_notifier(wm8804->supplies[i].consumer, |
774 | if (ret) { | 672 | &wm8804->disable_nb[i]); |
775 | printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n", | ||
776 | ret); | ||
777 | } | ||
778 | #endif | ||
779 | #if defined(CONFIG_SPI_MASTER) | ||
780 | ret = spi_register_driver(&wm8804_spi_driver); | ||
781 | if (ret != 0) { | ||
782 | printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n", | ||
783 | ret); | ||
784 | } | ||
785 | #endif | ||
786 | return ret; | ||
787 | } | ||
788 | module_init(wm8804_modinit); | ||
789 | 673 | ||
790 | static void __exit wm8804_exit(void) | 674 | snd_soc_unregister_codec(dev); |
791 | { | ||
792 | #if IS_ENABLED(CONFIG_I2C) | ||
793 | i2c_del_driver(&wm8804_i2c_driver); | ||
794 | #endif | ||
795 | #if defined(CONFIG_SPI_MASTER) | ||
796 | spi_unregister_driver(&wm8804_spi_driver); | ||
797 | #endif | ||
798 | } | 675 | } |
799 | module_exit(wm8804_exit); | 676 | EXPORT_SYMBOL_GPL(wm8804_remove); |
800 | 677 | ||
801 | MODULE_DESCRIPTION("ASoC WM8804 driver"); | 678 | MODULE_DESCRIPTION("ASoC WM8804 driver"); |
802 | MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); | 679 | MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); |
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h index e72d4f4ba6b1..a39a2563dc67 100644 --- a/sound/soc/codecs/wm8804.h +++ b/sound/soc/codecs/wm8804.h | |||
@@ -13,6 +13,8 @@ | |||
13 | #ifndef _WM8804_H | 13 | #ifndef _WM8804_H |
14 | #define _WM8804_H | 14 | #define _WM8804_H |
15 | 15 | ||
16 | #include <linux/regmap.h> | ||
17 | |||
16 | /* | 18 | /* |
17 | * Register values. | 19 | * Register values. |
18 | */ | 20 | */ |
@@ -62,4 +64,9 @@ | |||
62 | #define WM8804_MCLKDIV_256FS 0 | 64 | #define WM8804_MCLKDIV_256FS 0 |
63 | #define WM8804_MCLKDIV_128FS 1 | 65 | #define WM8804_MCLKDIV_128FS 1 |
64 | 66 | ||
67 | extern const struct regmap_config wm8804_regmap_config; | ||
68 | |||
69 | int wm8804_probe(struct device *dev, struct regmap *regmap); | ||
70 | void wm8804_remove(struct device *dev); | ||
71 | |||
65 | #endif /* _WM8804_H */ | 72 | #endif /* _WM8804_H */ |