diff options
Diffstat (limited to 'sound/soc/codecs/cs4270.c')
-rw-r--r-- | sound/soc/codecs/cs4270.c | 114 |
1 files changed, 74 insertions, 40 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ca1e24a8f12a..81a62d198b70 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -23,11 +23,13 @@ | |||
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/slab.h> | ||
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
28 | #include <sound/initval.h> | 29 | #include <sound/initval.h> |
29 | #include <linux/i2c.h> | 30 | #include <linux/i2c.h> |
30 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/regulator/consumer.h> | ||
31 | 33 | ||
32 | #include "cs4270.h" | 34 | #include "cs4270.h" |
33 | 35 | ||
@@ -106,6 +108,10 @@ | |||
106 | #define CS4270_MUTE_DAC_A 0x01 | 108 | #define CS4270_MUTE_DAC_A 0x01 |
107 | #define CS4270_MUTE_DAC_B 0x02 | 109 | #define CS4270_MUTE_DAC_B 0x02 |
108 | 110 | ||
111 | static const char *supply_names[] = { | ||
112 | "va", "vd", "vlc" | ||
113 | }; | ||
114 | |||
109 | /* Private data for the CS4270 */ | 115 | /* Private data for the CS4270 */ |
110 | struct cs4270_private { | 116 | struct cs4270_private { |
111 | struct snd_soc_codec codec; | 117 | struct snd_soc_codec codec; |
@@ -114,6 +120,9 @@ struct cs4270_private { | |||
114 | unsigned int mode; /* The mode (I2S or left-justified) */ | 120 | unsigned int mode; /* The mode (I2S or left-justified) */ |
115 | unsigned int slave_mode; | 121 | unsigned int slave_mode; |
116 | unsigned int manual_mute; | 122 | unsigned int manual_mute; |
123 | |||
124 | /* power domain regulators */ | ||
125 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | ||
117 | }; | 126 | }; |
118 | 127 | ||
119 | /** | 128 | /** |
@@ -192,6 +201,11 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = { | |||
192 | * This function must be called by the machine driver's 'startup' function, | 201 | * 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 | 202 | * otherwise the list of supported sample rates will not be available in |
194 | * time for ALSA. | 203 | * time for ALSA. |
204 | * | ||
205 | * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause | ||
206 | * theoretically possible sample rates to be enabled. Call it again with a | ||
207 | * proper value set one the external clock is set (most probably you would do | ||
208 | * that from a machine's driver 'hw_param' hook. | ||
195 | */ | 209 | */ |
196 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 210 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
197 | int clk_id, unsigned int freq, int dir) | 211 | int clk_id, unsigned int freq, int dir) |
@@ -205,20 +219,27 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
205 | 219 | ||
206 | cs4270->mclk = freq; | 220 | cs4270->mclk = freq; |
207 | 221 | ||
208 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { | 222 | if (cs4270->mclk) { |
209 | unsigned int rate = freq / cs4270_mode_ratios[i].ratio; | 223 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { |
210 | rates |= snd_pcm_rate_to_rate_bit(rate); | 224 | unsigned int rate = freq / cs4270_mode_ratios[i].ratio; |
211 | if (rate < rate_min) | 225 | rates |= snd_pcm_rate_to_rate_bit(rate); |
212 | rate_min = rate; | 226 | if (rate < rate_min) |
213 | if (rate > rate_max) | 227 | rate_min = rate; |
214 | rate_max = rate; | 228 | if (rate > rate_max) |
215 | } | 229 | rate_max = rate; |
216 | /* FIXME: soc should support a rate list */ | 230 | } |
217 | rates &= ~SNDRV_PCM_RATE_KNOT; | 231 | /* FIXME: soc should support a rate list */ |
232 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
218 | 233 | ||
219 | if (!rates) { | 234 | if (!rates) { |
220 | dev_err(codec->dev, "could not find a valid sample rate\n"); | 235 | dev_err(codec->dev, "could not find a valid sample rate\n"); |
221 | return -EINVAL; | 236 | return -EINVAL; |
237 | } | ||
238 | } else { | ||
239 | /* enable all possible rates */ | ||
240 | rates = SNDRV_PCM_RATE_8000_192000; | ||
241 | rate_min = 8000; | ||
242 | rate_max = 192000; | ||
222 | } | 243 | } |
223 | 244 | ||
224 | codec_dai->playback.rates = rates; | 245 | codec_dai->playback.rates = rates; |
@@ -520,6 +541,7 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { | |||
520 | SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0), | 541 | SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0), |
521 | SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0), | 542 | SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0), |
522 | SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0), | 543 | SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0), |
544 | SOC_SINGLE("De-emphasis filter", CS4270_TRANS, 0, 1, 0), | ||
523 | SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1), | 545 | SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1), |
524 | SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0), | 546 | SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0), |
525 | SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1), | 547 | SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1), |
@@ -578,7 +600,8 @@ static int cs4270_probe(struct platform_device *pdev) | |||
578 | { | 600 | { |
579 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 601 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
580 | struct snd_soc_codec *codec = cs4270_codec; | 602 | struct snd_soc_codec *codec = cs4270_codec; |
581 | int ret; | 603 | struct cs4270_private *cs4270 = codec->private_data; |
604 | int i, ret; | ||
582 | 605 | ||
583 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ | 606 | /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ |
584 | socdev->card->codec = codec; | 607 | socdev->card->codec = codec; |
@@ -598,15 +621,26 @@ static int cs4270_probe(struct platform_device *pdev) | |||
598 | goto error_free_pcms; | 621 | goto error_free_pcms; |
599 | } | 622 | } |
600 | 623 | ||
601 | /* And finally, register the socdev */ | 624 | /* get the power supply regulators */ |
602 | ret = snd_soc_init_card(socdev); | 625 | for (i = 0; i < ARRAY_SIZE(supply_names); i++) |
603 | if (ret < 0) { | 626 | cs4270->supplies[i].supply = supply_names[i]; |
604 | dev_err(codec->dev, "failed to register card\n"); | 627 | |
628 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies), | ||
629 | cs4270->supplies); | ||
630 | if (ret < 0) | ||
605 | goto error_free_pcms; | 631 | goto error_free_pcms; |
606 | } | 632 | |
633 | ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), | ||
634 | cs4270->supplies); | ||
635 | if (ret < 0) | ||
636 | goto error_free_regulators; | ||
607 | 637 | ||
608 | return 0; | 638 | return 0; |
609 | 639 | ||
640 | error_free_regulators: | ||
641 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), | ||
642 | cs4270->supplies); | ||
643 | |||
610 | error_free_pcms: | 644 | error_free_pcms: |
611 | snd_soc_free_pcms(socdev); | 645 | snd_soc_free_pcms(socdev); |
612 | 646 | ||
@@ -622,8 +656,12 @@ error_free_pcms: | |||
622 | static int cs4270_remove(struct platform_device *pdev) | 656 | static int cs4270_remove(struct platform_device *pdev) |
623 | { | 657 | { |
624 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 658 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
659 | struct snd_soc_codec *codec = cs4270_codec; | ||
660 | struct cs4270_private *cs4270 = codec->private_data; | ||
625 | 661 | ||
626 | snd_soc_free_pcms(socdev); | 662 | snd_soc_free_pcms(socdev); |
663 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | ||
664 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | ||
627 | 665 | ||
628 | return 0; | 666 | return 0; |
629 | }; | 667 | }; |
@@ -802,36 +840,36 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); | |||
802 | * and all registers are written back to the hardware when resuming. | 840 | * and all registers are written back to the hardware when resuming. |
803 | */ | 841 | */ |
804 | 842 | ||
805 | static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg) | 843 | static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) |
806 | { | 844 | { |
807 | struct cs4270_private *cs4270 = i2c_get_clientdata(client); | 845 | struct snd_soc_codec *codec = cs4270_codec; |
808 | struct snd_soc_codec *codec = &cs4270->codec; | 846 | struct cs4270_private *cs4270 = codec->private_data; |
809 | 847 | int reg, ret; | |
810 | return snd_soc_suspend_device(codec->dev); | ||
811 | } | ||
812 | 848 | ||
813 | static int cs4270_i2c_resume(struct i2c_client *client) | 849 | reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; |
814 | { | 850 | if (reg < 0) |
815 | struct cs4270_private *cs4270 = i2c_get_clientdata(client); | 851 | return reg; |
816 | struct snd_soc_codec *codec = &cs4270->codec; | ||
817 | 852 | ||
818 | return snd_soc_resume_device(codec->dev); | 853 | ret = snd_soc_write(codec, CS4270_PWRCTL, reg); |
819 | } | 854 | if (ret < 0) |
855 | return ret; | ||
820 | 856 | ||
821 | static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) | 857 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), |
822 | { | 858 | cs4270->supplies); |
823 | struct snd_soc_codec *codec = cs4270_codec; | ||
824 | int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; | ||
825 | 859 | ||
826 | return snd_soc_write(codec, CS4270_PWRCTL, reg); | 860 | return 0; |
827 | } | 861 | } |
828 | 862 | ||
829 | static int cs4270_soc_resume(struct platform_device *pdev) | 863 | static int cs4270_soc_resume(struct platform_device *pdev) |
830 | { | 864 | { |
831 | struct snd_soc_codec *codec = cs4270_codec; | 865 | struct snd_soc_codec *codec = cs4270_codec; |
866 | struct cs4270_private *cs4270 = codec->private_data; | ||
832 | struct i2c_client *i2c_client = codec->control_data; | 867 | struct i2c_client *i2c_client = codec->control_data; |
833 | int reg; | 868 | int reg; |
834 | 869 | ||
870 | regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), | ||
871 | cs4270->supplies); | ||
872 | |||
835 | /* In case the device was put to hard reset during sleep, we need to | 873 | /* In case the device was put to hard reset during sleep, we need to |
836 | * wait 500ns here before any I2C communication. */ | 874 | * wait 500ns here before any I2C communication. */ |
837 | ndelay(500); | 875 | ndelay(500); |
@@ -853,8 +891,6 @@ static int cs4270_soc_resume(struct platform_device *pdev) | |||
853 | return snd_soc_write(codec, CS4270_PWRCTL, reg); | 891 | return snd_soc_write(codec, CS4270_PWRCTL, reg); |
854 | } | 892 | } |
855 | #else | 893 | #else |
856 | #define cs4270_i2c_suspend NULL | ||
857 | #define cs4270_i2c_resume NULL | ||
858 | #define cs4270_soc_suspend NULL | 894 | #define cs4270_soc_suspend NULL |
859 | #define cs4270_soc_resume NULL | 895 | #define cs4270_soc_resume NULL |
860 | #endif /* CONFIG_PM */ | 896 | #endif /* CONFIG_PM */ |
@@ -873,8 +909,6 @@ static struct i2c_driver cs4270_i2c_driver = { | |||
873 | .id_table = cs4270_id, | 909 | .id_table = cs4270_id, |
874 | .probe = cs4270_i2c_probe, | 910 | .probe = cs4270_i2c_probe, |
875 | .remove = cs4270_i2c_remove, | 911 | .remove = cs4270_i2c_remove, |
876 | .suspend = cs4270_i2c_suspend, | ||
877 | .resume = cs4270_i2c_resume, | ||
878 | }; | 912 | }; |
879 | 913 | ||
880 | /* | 914 | /* |