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 */ |
