aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPascal Huerst <pascal.huerst@gmail.com>2016-02-16 10:19:06 -0500
committerMark Brown <broonie@kernel.org>2016-02-25 21:44:32 -0500
commit9a397f473657ad47449b6ab94ff2bb3f1f2de48f (patch)
treeeb5e379b3c2d20c0946e05038770e582d62967b6
parent92e963f50fc74041b5e9e744c330dca48e04f08d (diff)
ASoC: cs4271: add regulator consumer support
The cs4271 has three power domains: vd, vl and va. Enable them all, as long as the codec is in use. While at it, factored out the reset code into its own function. Signed-off-by: Pascal Huerst <pascal.huerst@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/sound/cs4271.txt7
-rw-r--r--sound/soc/codecs/cs4271.c69
2 files changed, 68 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/sound/cs4271.txt b/Documentation/devicetree/bindings/sound/cs4271.txt
index e2cd1d7539e5..6e699ceabacd 100644
--- a/Documentation/devicetree/bindings/sound/cs4271.txt
+++ b/Documentation/devicetree/bindings/sound/cs4271.txt
@@ -33,12 +33,19 @@ Optional properties:
33 Note that this is not needed in case the clocks are stable 33 Note that this is not needed in case the clocks are stable
34 throughout the entire runtime of the codec. 34 throughout the entire runtime of the codec.
35 35
36 - vd-supply: Digital power
37 - vl-supply: Logic power
38 - va-supply: Analog Power
39
36Examples: 40Examples:
37 41
38 codec_i2c: cs4271@10 { 42 codec_i2c: cs4271@10 {
39 compatible = "cirrus,cs4271"; 43 compatible = "cirrus,cs4271";
40 reg = <0x10>; 44 reg = <0x10>;
41 reset-gpio = <&gpio 23 0>; 45 reset-gpio = <&gpio 23 0>;
46 vd-supply = <&vdd_3v3_reg>;
47 vl-supply = <&vdd_3v3_reg>;
48 va-supply = <&vdd_3v3_reg>;
42 }; 49 };
43 50
44 codec_spi: cs4271@0 { 51 codec_spi: cs4271@0 {
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index e770ee6f36da..0c0010b25421 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -26,6 +26,7 @@
26#include <linux/of.h> 26#include <linux/of.h>
27#include <linux/of_device.h> 27#include <linux/of_device.h>
28#include <linux/of_gpio.h> 28#include <linux/of_gpio.h>
29#include <linux/regulator/consumer.h>
29#include <sound/pcm.h> 30#include <sound/pcm.h>
30#include <sound/soc.h> 31#include <sound/soc.h>
31#include <sound/tlv.h> 32#include <sound/tlv.h>
@@ -157,6 +158,10 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
157 return reg == CS4271_CHIPID; 158 return reg == CS4271_CHIPID;
158} 159}
159 160
161static const char * const supply_names[] = {
162 "vd", "vl", "va"
163};
164
160struct cs4271_private { 165struct cs4271_private {
161 unsigned int mclk; 166 unsigned int mclk;
162 bool master; 167 bool master;
@@ -170,6 +175,7 @@ struct cs4271_private {
170 int gpio_disable; 175 int gpio_disable;
171 /* enable soft reset workaround */ 176 /* enable soft reset workaround */
172 bool enable_soft_reset; 177 bool enable_soft_reset;
178 struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
173}; 179};
174 180
175static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = { 181static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
@@ -487,6 +493,20 @@ static struct snd_soc_dai_driver cs4271_dai = {
487 .symmetric_rates = 1, 493 .symmetric_rates = 1,
488}; 494};
489 495
496static int cs4271_reset(struct snd_soc_codec *codec)
497{
498 struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
499
500 if (gpio_is_valid(cs4271->gpio_nreset)) {
501 gpio_set_value(cs4271->gpio_nreset, 0);
502 mdelay(1);
503 gpio_set_value(cs4271->gpio_nreset, 1);
504 mdelay(1);
505 }
506
507 return 0;
508}
509
490#ifdef CONFIG_PM 510#ifdef CONFIG_PM
491static int cs4271_soc_suspend(struct snd_soc_codec *codec) 511static int cs4271_soc_suspend(struct snd_soc_codec *codec)
492{ 512{
@@ -499,6 +519,9 @@ static int cs4271_soc_suspend(struct snd_soc_codec *codec)
499 if (ret < 0) 519 if (ret < 0)
500 return ret; 520 return ret;
501 521
522 regcache_mark_dirty(cs4271->regmap);
523 regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
524
502 return 0; 525 return 0;
503} 526}
504 527
@@ -507,6 +530,16 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
507 int ret; 530 int ret;
508 struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); 531 struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
509 532
533 ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
534 cs4271->supplies);
535 if (ret < 0) {
536 dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
537 return ret;
538 }
539
540 /* Do a proper reset after power up */
541 cs4271_reset(codec);
542
510 /* Restore codec state */ 543 /* Restore codec state */
511 ret = regcache_sync(cs4271->regmap); 544 ret = regcache_sync(cs4271->regmap);
512 if (ret < 0) 545 if (ret < 0)
@@ -553,19 +586,24 @@ static int cs4271_codec_probe(struct snd_soc_codec *codec)
553 } 586 }
554#endif 587#endif
555 588
589 ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
590 cs4271->supplies);
591 if (ret < 0) {
592 dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
593 return ret;
594 }
595
556 if (cs4271plat) { 596 if (cs4271plat) {
557 amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; 597 amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
558 cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; 598 cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
559 } 599 }
560 600
561 if (gpio_is_valid(cs4271->gpio_nreset)) { 601 /* Reset codec */
562 /* Reset codec */ 602 cs4271_reset(codec);
563 gpio_direction_output(cs4271->gpio_nreset, 0); 603
564 mdelay(1); 604 ret = regcache_sync(cs4271->regmap);
565 gpio_set_value(cs4271->gpio_nreset, 1); 605 if (ret < 0)
566 /* Give the codec time to wake up */ 606 return ret;
567 mdelay(1);
568 }
569 607
570 ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, 608 ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
571 CS4271_MODE2_PDN | CS4271_MODE2_CPEN, 609 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
@@ -595,6 +633,9 @@ static int cs4271_codec_remove(struct snd_soc_codec *codec)
595 /* Set codec to the reset state */ 633 /* Set codec to the reset state */
596 gpio_set_value(cs4271->gpio_nreset, 0); 634 gpio_set_value(cs4271->gpio_nreset, 0);
597 635
636 regcache_mark_dirty(cs4271->regmap);
637 regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
638
598 return 0; 639 return 0;
599}; 640};
600 641
@@ -617,6 +658,7 @@ static int cs4271_common_probe(struct device *dev,
617{ 658{
618 struct cs4271_platform_data *cs4271plat = dev->platform_data; 659 struct cs4271_platform_data *cs4271plat = dev->platform_data;
619 struct cs4271_private *cs4271; 660 struct cs4271_private *cs4271;
661 int i, ret;
620 662
621 cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL); 663 cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
622 if (!cs4271) 664 if (!cs4271)
@@ -638,6 +680,17 @@ static int cs4271_common_probe(struct device *dev,
638 return ret; 680 return ret;
639 } 681 }
640 682
683 for (i = 0; i < ARRAY_SIZE(supply_names); i++)
684 cs4271->supplies[i].supply = supply_names[i];
685
686 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs4271->supplies),
687 cs4271->supplies);
688
689 if (ret < 0) {
690 dev_err(dev, "Failed to get regulators: %d\n", ret);
691 return ret;
692 }
693
641 *c = cs4271; 694 *c = cs4271;
642 return 0; 695 return 0;
643} 696}