diff options
author | Pascal Huerst <pascal.huerst@gmail.com> | 2016-02-16 10:19:06 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-02-25 21:44:32 -0500 |
commit | 9a397f473657ad47449b6ab94ff2bb3f1f2de48f (patch) | |
tree | eb5e379b3c2d20c0946e05038770e582d62967b6 | |
parent | 92e963f50fc74041b5e9e744c330dca48e04f08d (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.txt | 7 | ||||
-rw-r--r-- | sound/soc/codecs/cs4271.c | 69 |
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 | |||
36 | Examples: | 40 | Examples: |
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 | ||
161 | static const char * const supply_names[] = { | ||
162 | "vd", "vl", "va" | ||
163 | }; | ||
164 | |||
160 | struct cs4271_private { | 165 | struct 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 | ||
175 | static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = { | 181 | static 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 | ||
496 | static 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 |
491 | static int cs4271_soc_suspend(struct snd_soc_codec *codec) | 511 | static 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 | } |