diff options
| -rw-r--r-- | Documentation/devicetree/bindings/sound/tlv320aic32x4.txt | 8 | ||||
| -rw-r--r-- | sound/soc/codecs/tlv320aic32x4.c | 126 |
2 files changed, 133 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index 352be7b1f7e2..5e2741af27be 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt | |||
| @@ -5,6 +5,14 @@ The tlv320aic32x4 serial control bus communicates through I2C protocols | |||
| 5 | Required properties: | 5 | Required properties: |
| 6 | - compatible: Should be "ti,tlv320aic32x4" | 6 | - compatible: Should be "ti,tlv320aic32x4" |
| 7 | - reg: I2C slave address | 7 | - reg: I2C slave address |
| 8 | - supply-*: Required supply regulators are: | ||
| 9 | "iov" - digital IO power supply | ||
| 10 | "ldoin" - LDO power supply | ||
| 11 | "dv" - Digital core power supply | ||
| 12 | "av" - Analog core power supply | ||
| 13 | If you supply ldoin, dv and av are optional. Otherwise they are required | ||
| 14 | See regulator/regulator.txt for more information about the detailed binding | ||
| 15 | format. | ||
| 8 | 16 | ||
| 9 | Optional properties: | 17 | Optional properties: |
| 10 | - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt | 18 | - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt |
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 643fa53beaab..d69c61ffcda8 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/cdev.h> | 34 | #include <linux/cdev.h> |
| 35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
| 36 | #include <linux/clk.h> | 36 | #include <linux/clk.h> |
| 37 | #include <linux/regulator/consumer.h> | ||
| 37 | 38 | ||
| 38 | #include <sound/tlv320aic32x4.h> | 39 | #include <sound/tlv320aic32x4.h> |
| 39 | #include <sound/core.h> | 40 | #include <sound/core.h> |
| @@ -69,6 +70,11 @@ struct aic32x4_priv { | |||
| 69 | bool swapdacs; | 70 | bool swapdacs; |
| 70 | int rstn_gpio; | 71 | int rstn_gpio; |
| 71 | struct clk *mclk; | 72 | struct clk *mclk; |
| 73 | |||
| 74 | struct regulator *supply_ldo; | ||
| 75 | struct regulator *supply_iov; | ||
| 76 | struct regulator *supply_dv; | ||
| 77 | struct regulator *supply_av; | ||
| 72 | }; | 78 | }; |
| 73 | 79 | ||
| 74 | /* 0dB min, 0.5dB steps */ | 80 | /* 0dB min, 0.5dB steps */ |
| @@ -695,6 +701,106 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, | |||
| 695 | return 0; | 701 | return 0; |
| 696 | } | 702 | } |
| 697 | 703 | ||
| 704 | static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4) | ||
| 705 | { | ||
| 706 | regulator_disable(aic32x4->supply_iov); | ||
| 707 | |||
| 708 | if (!IS_ERR(aic32x4->supply_ldo)) | ||
| 709 | regulator_disable(aic32x4->supply_ldo); | ||
| 710 | |||
| 711 | if (!IS_ERR(aic32x4->supply_dv)) | ||
| 712 | regulator_disable(aic32x4->supply_dv); | ||
| 713 | |||
| 714 | if (!IS_ERR(aic32x4->supply_av)) | ||
| 715 | regulator_disable(aic32x4->supply_av); | ||
| 716 | } | ||
| 717 | |||
| 718 | static int aic32x4_setup_regulators(struct device *dev, | ||
| 719 | struct aic32x4_priv *aic32x4) | ||
| 720 | { | ||
| 721 | int ret = 0; | ||
| 722 | |||
| 723 | aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin"); | ||
| 724 | aic32x4->supply_iov = devm_regulator_get(dev, "iov"); | ||
| 725 | aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv"); | ||
| 726 | aic32x4->supply_av = devm_regulator_get_optional(dev, "av"); | ||
| 727 | |||
| 728 | /* Check if the regulator requirements are fulfilled */ | ||
| 729 | |||
| 730 | if (IS_ERR(aic32x4->supply_iov)) { | ||
| 731 | dev_err(dev, "Missing supply 'iov'\n"); | ||
| 732 | return PTR_ERR(aic32x4->supply_iov); | ||
| 733 | } | ||
| 734 | |||
| 735 | if (IS_ERR(aic32x4->supply_ldo)) { | ||
| 736 | if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER) | ||
| 737 | return -EPROBE_DEFER; | ||
| 738 | |||
| 739 | if (IS_ERR(aic32x4->supply_dv)) { | ||
| 740 | dev_err(dev, "Missing supply 'dv' or 'ldoin'\n"); | ||
| 741 | return PTR_ERR(aic32x4->supply_dv); | ||
| 742 | } | ||
| 743 | if (IS_ERR(aic32x4->supply_av)) { | ||
| 744 | dev_err(dev, "Missing supply 'av' or 'ldoin'\n"); | ||
| 745 | return PTR_ERR(aic32x4->supply_av); | ||
| 746 | } | ||
| 747 | } else { | ||
| 748 | if (IS_ERR(aic32x4->supply_dv) && | ||
| 749 | PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER) | ||
| 750 | return -EPROBE_DEFER; | ||
| 751 | if (IS_ERR(aic32x4->supply_av) && | ||
| 752 | PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER) | ||
| 753 | return -EPROBE_DEFER; | ||
| 754 | } | ||
| 755 | |||
| 756 | ret = regulator_enable(aic32x4->supply_iov); | ||
| 757 | if (ret) { | ||
| 758 | dev_err(dev, "Failed to enable regulator iov\n"); | ||
| 759 | return ret; | ||
| 760 | } | ||
| 761 | |||
| 762 | if (!IS_ERR(aic32x4->supply_ldo)) { | ||
| 763 | ret = regulator_enable(aic32x4->supply_ldo); | ||
| 764 | if (ret) { | ||
| 765 | dev_err(dev, "Failed to enable regulator ldo\n"); | ||
| 766 | goto error_ldo; | ||
| 767 | } | ||
| 768 | } | ||
| 769 | |||
| 770 | if (!IS_ERR(aic32x4->supply_dv)) { | ||
| 771 | ret = regulator_enable(aic32x4->supply_dv); | ||
| 772 | if (ret) { | ||
| 773 | dev_err(dev, "Failed to enable regulator dv\n"); | ||
| 774 | goto error_dv; | ||
| 775 | } | ||
| 776 | } | ||
| 777 | |||
| 778 | if (!IS_ERR(aic32x4->supply_av)) { | ||
| 779 | ret = regulator_enable(aic32x4->supply_av); | ||
| 780 | if (ret) { | ||
| 781 | dev_err(dev, "Failed to enable regulator av\n"); | ||
| 782 | goto error_av; | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 786 | if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av)) | ||
| 787 | aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE; | ||
| 788 | |||
| 789 | return 0; | ||
| 790 | |||
| 791 | error_av: | ||
| 792 | if (!IS_ERR(aic32x4->supply_dv)) | ||
| 793 | regulator_disable(aic32x4->supply_dv); | ||
| 794 | |||
| 795 | error_dv: | ||
| 796 | if (!IS_ERR(aic32x4->supply_ldo)) | ||
| 797 | regulator_disable(aic32x4->supply_ldo); | ||
| 798 | |||
| 799 | error_ldo: | ||
| 800 | regulator_disable(aic32x4->supply_iov); | ||
| 801 | return ret; | ||
| 802 | } | ||
| 803 | |||
| 698 | static int aic32x4_i2c_probe(struct i2c_client *i2c, | 804 | static int aic32x4_i2c_probe(struct i2c_client *i2c, |
| 699 | const struct i2c_device_id *id) | 805 | const struct i2c_device_id *id) |
| 700 | { | 806 | { |
| @@ -745,13 +851,31 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, | |||
| 745 | return ret; | 851 | return ret; |
| 746 | } | 852 | } |
| 747 | 853 | ||
| 854 | ret = aic32x4_setup_regulators(&i2c->dev, aic32x4); | ||
| 855 | if (ret) { | ||
| 856 | dev_err(&i2c->dev, "Failed to setup regulators\n"); | ||
| 857 | return ret; | ||
| 858 | } | ||
| 859 | |||
| 748 | ret = snd_soc_register_codec(&i2c->dev, | 860 | ret = snd_soc_register_codec(&i2c->dev, |
| 749 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); | 861 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); |
| 750 | return ret; | 862 | if (ret) { |
| 863 | dev_err(&i2c->dev, "Failed to register codec\n"); | ||
| 864 | aic32x4_disable_regulators(aic32x4); | ||
| 865 | return ret; | ||
| 866 | } | ||
| 867 | |||
| 868 | i2c_set_clientdata(i2c, aic32x4); | ||
| 869 | |||
| 870 | return 0; | ||
| 751 | } | 871 | } |
| 752 | 872 | ||
| 753 | static int aic32x4_i2c_remove(struct i2c_client *client) | 873 | static int aic32x4_i2c_remove(struct i2c_client *client) |
| 754 | { | 874 | { |
| 875 | struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client); | ||
| 876 | |||
| 877 | aic32x4_disable_regulators(aic32x4); | ||
| 878 | |||
| 755 | snd_soc_unregister_codec(&client->dev); | 879 | snd_soc_unregister_codec(&client->dev); |
| 756 | return 0; | 880 | return 0; |
| 757 | } | 881 | } |
