diff options
Diffstat (limited to 'sound/soc/codecs/cs4270.c')
-rw-r--r-- | sound/soc/codecs/cs4270.c | 91 |
1 files changed, 75 insertions, 16 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ffe122d1cd76..dfbeb2db61b3 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <sound/initval.h> | 28 | #include <sound/initval.h> |
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/regulator/consumer.h> | ||
31 | 32 | ||
32 | #include "cs4270.h" | 33 | #include "cs4270.h" |
33 | 34 | ||
@@ -106,6 +107,10 @@ | |||
106 | #define CS4270_MUTE_DAC_A 0x01 | 107 | #define CS4270_MUTE_DAC_A 0x01 |
107 | #define CS4270_MUTE_DAC_B 0x02 | 108 | #define CS4270_MUTE_DAC_B 0x02 |
108 | 109 | ||
110 | static const char *supply_names[] = { | ||
111 | "va", "vd", "vlc" | ||
112 | }; | ||
113 | |||
109 | /* Private data for the CS4270 */ | 114 | /* Private data for the CS4270 */ |
110 | struct cs4270_private { | 115 | struct cs4270_private { |
111 | struct snd_soc_codec codec; | 116 | struct snd_soc_codec codec; |
@@ -114,6 +119,9 @@ struct cs4270_private { | |||
114 | unsigned int mode; /* The mode (I2S or left-justified) */ | 119 | unsigned int mode; /* The mode (I2S or left-justified) */ |
115 | unsigned int slave_mode; | 120 | unsigned int slave_mode; |
116 | unsigned int manual_mute; | 121 | unsigned int manual_mute; |
122 | |||
123 | /* power domain regulators */ | ||
124 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | ||
117 | }; | 125 | }; |
118 | 126 | ||
119 | /** | 127 | /** |
@@ -192,6 +200,11 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = { | |||
192 | * This function must be called by the machine driver's 'startup' function, | 200 | * This function must be called by the machine driver's 'startup' function, |
193 | * otherwise the list of supported sample rates will not be available in | 201 | * otherwise the list of supported sample rates will not be available in |
194 | * time for ALSA. | 202 | * time for ALSA. |
203 | * | ||
204 | * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause | ||
205 | * theoretically possible sample rates to be enabled. Call it again with a | ||
206 | * proper value set one the external clock is set (most probably you would do | ||
207 | * that from a machine's driver 'hw_param' hook. | ||
195 | */ | 208 | */ |
196 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 209 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
197 | int clk_id, unsigned int freq, int dir) | 210 | int clk_id, unsigned int freq, int dir) |
@@ -205,20 +218,27 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
205 | 218 | ||
206 | cs4270->mclk = freq; | 219 | cs4270->mclk = freq; |
207 | 220 | ||
208 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { | 221 | if (cs4270->mclk) { |
209 | unsigned int rate = freq / cs4270_mode_ratios[i].ratio; | 222 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { |
210 | rates |= snd_pcm_rate_to_rate_bit(rate); | 223 | unsigned int rate = freq / cs4270_mode_ratios[i].ratio; |
211 | if (rate < rate_min) | 224 | rates |= snd_pcm_rate_to_rate_bit(rate); |
212 | rate_min = rate; | 225 | if (rate < rate_min) |
213 | if (rate > rate_max) | 226 | rate_min = rate; |
214 | rate_max = rate; | 227 | if (rate > rate_max) |
215 | } | 228 | rate_max = rate; |
216 | /* FIXME: soc should support a rate list */ | 229 | } |
217 | rates &= ~SNDRV_PCM_RATE_KNOT; | 230 | /* FIXME: soc should support a rate list */ |
231 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
218 | 232 | ||
219 | if (!rates) { | 233 | if (!rates) { |
220 | dev_err(codec->dev, "could not find a valid sample rate\n"); | 234 | dev_err(codec->dev, "could not find a valid sample rate\n"); |
221 | return -EINVAL; | 235 | return -EINVAL; |
236 | } | ||
237 | } else { | ||
238 | /* enable all possible rates */ | ||
239 | rates = SNDRV_PCM_RATE_8000_192000; | ||
240 | rate_min = 8000; | ||
241 | rate_max = 192000; | ||
222 | } | 242 | } |
223 | 243 | ||
224 | codec_dai->playback.rates = rates; | 244 | codec_dai->playback.rates = rates; |
@@ -579,7 +599,8 @@ static int cs4270_probe(struct platform_device *pdev) | |||
579 | { | 599 | { |
580 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 600 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
581 | struct snd_soc_codec *codec = cs4270_codec; | 601 | struct snd_soc_codec *codec = cs4270_codec; |
582 | int ret; | 602 | struct cs4270_private *cs4270 = codec->private_data; |
603 | int i, ret; | ||
583 | 604 | ||
584 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ | 605 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ |
585 | socdev->card->codec = codec; | 606 | socdev->card->codec = codec; |
@@ -599,8 +620,26 @@ static int cs4270_probe(struct platform_device *pdev) | |||
599 | goto error_free_pcms; | 620 | goto error_free_pcms; |
600 | } | 621 | } |
601 | 622 | ||
623 | /* get the power supply regulators */ | ||
624 | for (i = 0; i < ARRAY_SIZE(supply_names); i++) | ||
625 | cs4270->supplies[i].supply = supply_names[i]; | ||
626 | |||
627 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies), | ||
628 | cs4270->supplies); | ||
629 | if (ret < 0) | ||
630 | goto error_free_pcms; | ||
631 | |||
632 | ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), | ||
633 | cs4270->supplies); | ||
634 | if (ret < 0) | ||
635 | goto error_free_regulators; | ||
636 | |||
602 | return 0; | 637 | return 0; |
603 | 638 | ||
639 | error_free_regulators: | ||
640 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), | ||
641 | cs4270->supplies); | ||
642 | |||
604 | error_free_pcms: | 643 | error_free_pcms: |
605 | snd_soc_free_pcms(socdev); | 644 | snd_soc_free_pcms(socdev); |
606 | 645 | ||
@@ -616,8 +655,12 @@ error_free_pcms: | |||
616 | static int cs4270_remove(struct platform_device *pdev) | 655 | static int cs4270_remove(struct platform_device *pdev) |
617 | { | 656 | { |
618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 657 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
658 | struct snd_soc_codec *codec = cs4270_codec; | ||
659 | struct cs4270_private *cs4270 = codec->private_data; | ||
619 | 660 | ||
620 | snd_soc_free_pcms(socdev); | 661 | snd_soc_free_pcms(socdev); |
662 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | ||
663 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | ||
621 | 664 | ||
622 | return 0; | 665 | return 0; |
623 | }; | 666 | }; |
@@ -799,17 +842,33 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); | |||
799 | static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) | 842 | static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) |
800 | { | 843 | { |
801 | struct snd_soc_codec *codec = cs4270_codec; | 844 | struct snd_soc_codec *codec = cs4270_codec; |
802 | int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; | 845 | struct cs4270_private *cs4270 = codec->private_data; |
846 | int reg, ret; | ||
803 | 847 | ||
804 | return snd_soc_write(codec, CS4270_PWRCTL, reg); | 848 | reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; |
849 | if (reg < 0) | ||
850 | return reg; | ||
851 | |||
852 | ret = snd_soc_write(codec, CS4270_PWRCTL, reg); | ||
853 | if (ret < 0) | ||
854 | return ret; | ||
855 | |||
856 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), | ||
857 | cs4270->supplies); | ||
858 | |||
859 | return 0; | ||
805 | } | 860 | } |
806 | 861 | ||
807 | static int cs4270_soc_resume(struct platform_device *pdev) | 862 | static int cs4270_soc_resume(struct platform_device *pdev) |
808 | { | 863 | { |
809 | struct snd_soc_codec *codec = cs4270_codec; | 864 | struct snd_soc_codec *codec = cs4270_codec; |
865 | struct cs4270_private *cs4270 = codec->private_data; | ||
810 | struct i2c_client *i2c_client = codec->control_data; | 866 | struct i2c_client *i2c_client = codec->control_data; |
811 | int reg; | 867 | int reg; |
812 | 868 | ||
869 | regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), | ||
870 | cs4270->supplies); | ||
871 | |||
813 | /* In case the device was put to hard reset during sleep, we need to | 872 | /* In case the device was put to hard reset during sleep, we need to |
814 | * wait 500ns here before any I2C communication. */ | 873 | * wait 500ns here before any I2C communication. */ |
815 | ndelay(500); | 874 | ndelay(500); |